@stackwright-pro/mcp 0.2.0-alpha.17 → 0.2.0-alpha.18

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.mjs CHANGED
@@ -1110,7 +1110,8 @@ function setupPackages(opts) {
1110
1110
  }
1111
1111
 
1112
1112
  // src/tools/questions.ts
1113
- import { readFile } from "fs/promises";
1113
+ import { readFile, writeFile } from "fs/promises";
1114
+ import { existsSync as existsSync2, lstatSync as lstatSync2, mkdirSync, renameSync } from "fs";
1114
1115
  import { join } from "path";
1115
1116
  import { z as z8 } from "zod";
1116
1117
 
@@ -1409,11 +1410,149 @@ function registerQuestionTools(server2) {
1409
1410
  };
1410
1411
  }
1411
1412
  );
1413
+ server2.tool(
1414
+ "stackwright_pro_get_next_question",
1415
+ "Returns the next unanswered question for a phase as a plain JSON object \u2014 one question at a time. Returns { done: true } when all questions are answered or the phase has no questions. Call this in a loop: present the question in plain chat, get user reply, call record_answer, repeat.",
1416
+ { phase: z8.string().describe('Phase name e.g. "designer", "api", "auth"') },
1417
+ async ({ phase }) => {
1418
+ const SAFE_PHASE = /^[a-z][a-z0-9-]{0,30}$/;
1419
+ if (!SAFE_PHASE.test(phase)) {
1420
+ return {
1421
+ content: [
1422
+ {
1423
+ type: "text",
1424
+ text: JSON.stringify({ error: `Invalid phase name: "${phase.slice(0, 50)}"` })
1425
+ }
1426
+ ],
1427
+ isError: true
1428
+ };
1429
+ }
1430
+ const cwd = process.cwd();
1431
+ const questionsPath = join(cwd, ".stackwright", "questions", `${phase}.json`);
1432
+ let questions = [];
1433
+ try {
1434
+ const raw = await readFile(questionsPath, "utf-8");
1435
+ const parsed = JSON.parse(raw);
1436
+ questions = parsed.questions ?? [];
1437
+ } catch {
1438
+ return { content: [{ type: "text", text: JSON.stringify({ done: true }) }] };
1439
+ }
1440
+ if (questions.length === 0) {
1441
+ return { content: [{ type: "text", text: JSON.stringify({ done: true }) }] };
1442
+ }
1443
+ const answersPath = join(cwd, ".stackwright", "answers", `${phase}.json`);
1444
+ let answeredIds = /* @__PURE__ */ new Set();
1445
+ try {
1446
+ const raw = await readFile(answersPath, "utf-8");
1447
+ const parsed = JSON.parse(raw);
1448
+ answeredIds = new Set(Object.keys(parsed.answers ?? {}));
1449
+ } catch {
1450
+ }
1451
+ const next = questions.find((q) => !answeredIds.has(q.id));
1452
+ if (!next) {
1453
+ return { content: [{ type: "text", text: JSON.stringify({ done: true }) }] };
1454
+ }
1455
+ return {
1456
+ content: [
1457
+ {
1458
+ type: "text",
1459
+ text: JSON.stringify({
1460
+ done: false,
1461
+ questionId: next.id,
1462
+ question: next.question,
1463
+ type: next.type,
1464
+ options: next.options ?? null,
1465
+ help: next.help ?? null,
1466
+ index: questions.indexOf(next) + 1,
1467
+ total: questions.length
1468
+ })
1469
+ }
1470
+ ]
1471
+ };
1472
+ }
1473
+ );
1474
+ server2.tool(
1475
+ "stackwright_pro_record_answer",
1476
+ "Records a single answer to a phase question. Appends to .stackwright/answers/{phase}.json incrementally. Idempotent \u2014 calling twice for the same questionId overwrites. Call after receiving each user reply in the conversational question loop.",
1477
+ {
1478
+ phase: z8.string().describe('Phase name e.g. "designer"'),
1479
+ questionId: z8.string().describe('The question ID from get_next_question, e.g. "designer-1"'),
1480
+ answer: z8.string().describe("The user's free-text answer")
1481
+ },
1482
+ async ({ phase, questionId, answer }) => {
1483
+ const SAFE_PHASE = /^[a-z][a-z0-9-]{0,30}$/;
1484
+ if (!SAFE_PHASE.test(phase)) {
1485
+ return {
1486
+ content: [
1487
+ { type: "text", text: JSON.stringify({ error: "Invalid phase name" }) }
1488
+ ],
1489
+ isError: true
1490
+ };
1491
+ }
1492
+ if (!/^[a-z0-9][a-z0-9-]{0,63}$/i.test(questionId)) {
1493
+ return {
1494
+ content: [
1495
+ { type: "text", text: JSON.stringify({ error: "Invalid questionId" }) }
1496
+ ],
1497
+ isError: true
1498
+ };
1499
+ }
1500
+ const safeAnswer = answer.slice(0, 2e3);
1501
+ const cwd = process.cwd();
1502
+ const answersDir = join(cwd, ".stackwright", "answers");
1503
+ const answersPath = join(answersDir, `${phase}.json`);
1504
+ if (existsSync2(answersDir) && lstatSync2(answersDir).isSymbolicLink()) {
1505
+ return {
1506
+ content: [
1507
+ {
1508
+ type: "text",
1509
+ text: JSON.stringify({ error: "answers dir is a symlink \u2014 refusing to write" })
1510
+ }
1511
+ ],
1512
+ isError: true
1513
+ };
1514
+ }
1515
+ mkdirSync(answersDir, { recursive: true });
1516
+ let existing = {
1517
+ version: "1.0",
1518
+ phase,
1519
+ answers: {}
1520
+ };
1521
+ try {
1522
+ if (existsSync2(answersPath)) {
1523
+ if (lstatSync2(answersPath).isSymbolicLink()) {
1524
+ return {
1525
+ content: [
1526
+ {
1527
+ type: "text",
1528
+ text: JSON.stringify({ error: "answers file is a symlink \u2014 refusing to write" })
1529
+ }
1530
+ ],
1531
+ isError: true
1532
+ };
1533
+ }
1534
+ const raw = await readFile(answersPath, "utf-8");
1535
+ existing = JSON.parse(raw);
1536
+ }
1537
+ } catch {
1538
+ }
1539
+ existing.answers[questionId] = safeAnswer;
1540
+ existing.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
1541
+ const tmp = `${answersPath}.tmp`;
1542
+ await writeFile(tmp, JSON.stringify(existing, null, 2), "utf-8");
1543
+ renameSync(tmp, answersPath);
1544
+ return {
1545
+ content: [
1546
+ { type: "text", text: JSON.stringify({ recorded: true, phase, questionId }) }
1547
+ ]
1548
+ };
1549
+ }
1550
+ );
1412
1551
  }
1413
1552
 
1414
1553
  // src/tools/orchestration.ts
1415
1554
  import { z as z9 } from "zod";
1416
- import { readFileSync as readFileSync2, writeFileSync as writeFileSync2, existsSync as existsSync2, mkdirSync, lstatSync as lstatSync2 } from "fs";
1555
+ import { readFileSync as readFileSync2, writeFileSync as writeFileSync2, existsSync as existsSync3, mkdirSync as mkdirSync2, lstatSync as lstatSync3 } from "fs";
1417
1556
  import { join as join2 } from "path";
1418
1557
  var OTTER_NAME_TO_PHASE = [
1419
1558
  ["designer", "designer"],
@@ -1469,9 +1608,9 @@ function handleSaveManifest(input) {
1469
1608
  const dir = join2(cwd, ".stackwright");
1470
1609
  const filePath = join2(dir, "question-manifest.json");
1471
1610
  try {
1472
- mkdirSync(dir, { recursive: true });
1473
- if (existsSync2(filePath)) {
1474
- const stat = lstatSync2(filePath);
1611
+ mkdirSync2(dir, { recursive: true });
1612
+ if (existsSync3(filePath)) {
1613
+ const stat = lstatSync3(filePath);
1475
1614
  if (stat.isSymbolicLink()) {
1476
1615
  const message = `Refusing to write to symlink: ${filePath}`;
1477
1616
  return {
@@ -1503,7 +1642,7 @@ function handleSavePhaseAnswers(input) {
1503
1642
  const dir = join2(cwd, ".stackwright", "answers");
1504
1643
  const filePath = join2(dir, `${input.phase}.json`);
1505
1644
  try {
1506
- mkdirSync(dir, { recursive: true });
1645
+ mkdirSync2(dir, { recursive: true });
1507
1646
  let answers;
1508
1647
  if (input.questions && input.questions.length > 0) {
1509
1648
  answers = answersToManifestFormat(input.rawAnswers, input.questions);
@@ -1518,8 +1657,8 @@ function handleSavePhaseAnswers(input) {
1518
1657
  completedAt: (/* @__PURE__ */ new Date()).toISOString(),
1519
1658
  answers
1520
1659
  };
1521
- if (existsSync2(filePath)) {
1522
- const stat = lstatSync2(filePath);
1660
+ if (existsSync3(filePath)) {
1661
+ const stat = lstatSync3(filePath);
1523
1662
  if (stat.isSymbolicLink()) {
1524
1663
  const message = `Refusing to write to symlink: ${filePath}`;
1525
1664
  return {
@@ -1548,7 +1687,7 @@ function handleSavePhaseAnswers(input) {
1548
1687
  function handleReadPhaseAnswers(input) {
1549
1688
  const cwd = input._cwd ?? process.cwd();
1550
1689
  const filePath = join2(cwd, ".stackwright", "answers", `${input.phase}.json`);
1551
- if (!existsSync2(filePath)) {
1690
+ if (!existsSync3(filePath)) {
1552
1691
  return {
1553
1692
  text: JSON.stringify({ missing: true, phase: input.phase }),
1554
1693
  isError: false
@@ -1585,9 +1724,9 @@ function handleSaveBuildContext(input) {
1585
1724
  const dir = join2(cwd, ".stackwright");
1586
1725
  const filePath = join2(dir, "build-context.json");
1587
1726
  try {
1588
- mkdirSync(dir, { recursive: true });
1589
- if (existsSync2(filePath)) {
1590
- const stat = lstatSync2(filePath);
1727
+ mkdirSync2(dir, { recursive: true });
1728
+ if (existsSync3(filePath)) {
1729
+ const stat = lstatSync3(filePath);
1591
1730
  if (stat.isSymbolicLink()) {
1592
1731
  return {
1593
1732
  text: JSON.stringify({
@@ -1736,7 +1875,7 @@ function registerOrchestrationTools(server2) {
1736
1875
 
1737
1876
  // src/tools/pipeline.ts
1738
1877
  import { z as z10 } from "zod";
1739
- import { readFileSync as readFileSync3, writeFileSync as writeFileSync3, existsSync as existsSync3, mkdirSync as mkdirSync2, lstatSync as lstatSync3 } from "fs";
1878
+ import { readFileSync as readFileSync3, writeFileSync as writeFileSync3, existsSync as existsSync4, mkdirSync as mkdirSync3, lstatSync as lstatSync4 } from "fs";
1740
1879
  import { join as join3 } from "path";
1741
1880
  var PHASE_ORDER = [
1742
1881
  "designer",
@@ -1810,7 +1949,7 @@ function statePath(cwd) {
1810
1949
  }
1811
1950
  function readState(cwd) {
1812
1951
  const p = statePath(cwd);
1813
- if (!existsSync3(p)) return createDefaultState();
1952
+ if (!existsSync4(p)) return createDefaultState();
1814
1953
  const raw = JSON.parse(safeReadSync(p));
1815
1954
  if (typeof raw !== "object" || raw === null || raw.version !== "1.0") {
1816
1955
  return createDefaultState();
@@ -1818,8 +1957,8 @@ function readState(cwd) {
1818
1957
  return raw;
1819
1958
  }
1820
1959
  function safeWriteSync(filePath, content) {
1821
- if (existsSync3(filePath)) {
1822
- const stat = lstatSync3(filePath);
1960
+ if (existsSync4(filePath)) {
1961
+ const stat = lstatSync4(filePath);
1823
1962
  if (stat.isSymbolicLink()) {
1824
1963
  throw new Error(`Refusing to write to symlink: ${filePath}`);
1825
1964
  }
@@ -1827,8 +1966,8 @@ function safeWriteSync(filePath, content) {
1827
1966
  writeFileSync3(filePath, content);
1828
1967
  }
1829
1968
  function safeReadSync(filePath) {
1830
- if (existsSync3(filePath)) {
1831
- const stat = lstatSync3(filePath);
1969
+ if (existsSync4(filePath)) {
1970
+ const stat = lstatSync4(filePath);
1832
1971
  if (stat.isSymbolicLink()) {
1833
1972
  throw new Error(`Refusing to read symlink: ${filePath}`);
1834
1973
  }
@@ -1837,7 +1976,7 @@ function safeReadSync(filePath) {
1837
1976
  }
1838
1977
  function writeState(cwd, state) {
1839
1978
  const dir = join3(cwd, ".stackwright");
1840
- mkdirSync2(dir, { recursive: true });
1979
+ mkdirSync3(dir, { recursive: true });
1841
1980
  state.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
1842
1981
  safeWriteSync(statePath(cwd), JSON.stringify(state, null, 2) + "\n");
1843
1982
  }
@@ -1922,7 +2061,7 @@ function handleCheckExecutionReady(_cwd, phase) {
1922
2061
  };
1923
2062
  }
1924
2063
  const answerFile = join3(cwd, ".stackwright", "answers", `${phase}.json`);
1925
- if (!existsSync3(answerFile)) {
2064
+ if (!existsSync4(answerFile)) {
1926
2065
  return {
1927
2066
  text: JSON.stringify({ ready: false, phase, reason: "Answer file not found" }),
1928
2067
  isError: false
@@ -1951,7 +2090,7 @@ function handleCheckExecutionReady(_cwd, phase) {
1951
2090
  const missingPhases = [];
1952
2091
  for (const phase2 of PHASE_ORDER) {
1953
2092
  const answerFile = join3(answersDir, `${phase2}.json`);
1954
- if (existsSync3(answerFile)) {
2093
+ if (existsSync4(answerFile)) {
1955
2094
  try {
1956
2095
  const raw = safeReadSync(answerFile);
1957
2096
  const parsed = JSON.parse(raw);
@@ -1989,7 +2128,7 @@ function handleListArtifacts(_cwd) {
1989
2128
  for (const phase of PHASE_ORDER) {
1990
2129
  const expectedFile = PHASE_ARTIFACT[phase];
1991
2130
  const fullPath = join3(artifactsDir, expectedFile);
1992
- const exists = existsSync3(fullPath);
2131
+ const exists = existsSync4(fullPath);
1993
2132
  if (exists) completedCount++;
1994
2133
  artifacts.push({ phase, expectedFile, exists, path: fullPath });
1995
2134
  }
@@ -2028,7 +2167,7 @@ function handleWritePhaseQuestions(input) {
2028
2167
  } catch {
2029
2168
  }
2030
2169
  const questionsDir = join3(cwd, ".stackwright", "questions");
2031
- mkdirSync2(questionsDir, { recursive: true });
2170
+ mkdirSync3(questionsDir, { recursive: true });
2032
2171
  const filePath = join3(questionsDir, `${phase}.json`);
2033
2172
  const payload = {
2034
2173
  version: "1.0",
@@ -2071,12 +2210,12 @@ function handleBuildSpecialistPrompt(input) {
2071
2210
  try {
2072
2211
  const answersPath = join3(cwd, ".stackwright", "answers", `${phase}.json`);
2073
2212
  let answers = {};
2074
- if (existsSync3(answersPath)) {
2213
+ if (existsSync4(answersPath)) {
2075
2214
  answers = JSON.parse(safeReadSync(answersPath));
2076
2215
  }
2077
2216
  let buildContextText = "";
2078
2217
  const buildContextPath = join3(cwd, ".stackwright", "build-context.json");
2079
- if (existsSync3(buildContextPath)) {
2218
+ if (existsSync4(buildContextPath)) {
2080
2219
  try {
2081
2220
  const bcRaw = JSON.parse(safeReadSync(buildContextPath));
2082
2221
  if (typeof bcRaw.buildContext === "string" && bcRaw.buildContext.trim().length > 0) {
@@ -2091,7 +2230,7 @@ function handleBuildSpecialistPrompt(input) {
2091
2230
  for (const dep of deps) {
2092
2231
  const artifactFile = PHASE_ARTIFACT[dep];
2093
2232
  const artifactPath = join3(cwd, ".stackwright", "artifacts", artifactFile);
2094
- if (existsSync3(artifactPath)) {
2233
+ if (existsSync4(artifactPath)) {
2095
2234
  const content = JSON.parse(safeReadSync(artifactPath));
2096
2235
  const expectedOtter = PHASE_TO_OTTER2[dep];
2097
2236
  const artifactOtter = content["generatedBy"];
@@ -2220,7 +2359,7 @@ function handleValidateArtifact(input) {
2220
2359
  }
2221
2360
  try {
2222
2361
  const artifactsDir = join3(cwd, ".stackwright", "artifacts");
2223
- mkdirSync2(artifactsDir, { recursive: true });
2362
+ mkdirSync3(artifactsDir, { recursive: true });
2224
2363
  const artifactFile = PHASE_ARTIFACT[phase];
2225
2364
  const artifactPath = join3(artifactsDir, artifactFile);
2226
2365
  safeWriteSync(artifactPath, JSON.stringify(artifact, null, 2) + "\n");
@@ -2294,12 +2433,49 @@ function registerPipelineTools(server2) {
2294
2433
  );
2295
2434
  server2.tool(
2296
2435
  "stackwright_pro_write_phase_questions",
2297
- `Parse otter question-collection response \u2192 .stackwright/questions/{phase}.json. ${DESC}`,
2436
+ `Parse otter question-collection response \u2192 .stackwright/questions/{phase}.json. Specialists may also call this directly with a parsed questions array. ${DESC}`,
2298
2437
  {
2299
- phase: z10.string().describe('Phase name, e.g. "designer"'),
2300
- responseText: z10.string().describe("Raw LLM response from QUESTION_COLLECTION_MODE")
2438
+ phase: z10.string().optional().describe('Phase name, e.g. "designer" (required for direct write)'),
2439
+ responseText: z10.string().optional().describe("Raw LLM response from QUESTION_COLLECTION_MODE"),
2440
+ questions: jsonCoerce(z10.array(z10.any()).optional()).describe(
2441
+ "Questions array for direct specialist write"
2442
+ )
2301
2443
  },
2302
- async ({ phase, responseText }) => res(handleWritePhaseQuestions({ phase, responseText }))
2444
+ async ({ phase, responseText, questions }) => {
2445
+ if (phase && questions && Array.isArray(questions)) {
2446
+ const SAFE_PHASE = /^[a-z][a-z0-9-]{0,30}$/;
2447
+ if (!SAFE_PHASE.test(phase)) {
2448
+ return {
2449
+ content: [
2450
+ { type: "text", text: JSON.stringify({ error: `Invalid phase name` }) }
2451
+ ],
2452
+ isError: true
2453
+ };
2454
+ }
2455
+ const questionsDir = join3(process.cwd(), ".stackwright", "questions");
2456
+ mkdirSync3(questionsDir, { recursive: true });
2457
+ const outPath = join3(questionsDir, `${phase}.json`);
2458
+ writeFileSync3(
2459
+ outPath,
2460
+ JSON.stringify({ phase, questions, writtenAt: (/* @__PURE__ */ new Date()).toISOString() }, null, 2)
2461
+ );
2462
+ return {
2463
+ content: [
2464
+ {
2465
+ type: "text",
2466
+ text: JSON.stringify({
2467
+ written: true,
2468
+ phase,
2469
+ count: questions.length
2470
+ })
2471
+ }
2472
+ ]
2473
+ };
2474
+ }
2475
+ return res(
2476
+ handleWritePhaseQuestions({ phase: phase ?? "", responseText: responseText ?? "" })
2477
+ );
2478
+ }
2303
2479
  );
2304
2480
  server2.tool(
2305
2481
  "stackwright_pro_build_specialist_prompt",
@@ -2320,7 +2496,7 @@ function registerPipelineTools(server2) {
2320
2496
 
2321
2497
  // src/tools/safe-write.ts
2322
2498
  import { z as z11 } from "zod";
2323
- import { writeFileSync as writeFileSync4, existsSync as existsSync4, mkdirSync as mkdirSync3, lstatSync as lstatSync4 } from "fs";
2499
+ import { writeFileSync as writeFileSync4, existsSync as existsSync5, mkdirSync as mkdirSync4, lstatSync as lstatSync5 } from "fs";
2324
2500
  import { normalize, isAbsolute, dirname, join as join4 } from "path";
2325
2501
  var OTTER_WRITE_ALLOWLISTS = {
2326
2502
  "stackwright-pro-designer-otter": [
@@ -2494,9 +2670,9 @@ function handleSafeWrite(input) {
2494
2670
  }
2495
2671
  const normalized = normalize(filePath);
2496
2672
  const fullPath = join4(cwd, normalized);
2497
- if (existsSync4(fullPath)) {
2673
+ if (existsSync5(fullPath)) {
2498
2674
  try {
2499
- const stat = lstatSync4(fullPath);
2675
+ const stat = lstatSync5(fullPath);
2500
2676
  if (stat.isSymbolicLink()) {
2501
2677
  const result = {
2502
2678
  success: false,
@@ -2523,7 +2699,7 @@ function handleSafeWrite(input) {
2523
2699
  }
2524
2700
  try {
2525
2701
  if (createDirectories) {
2526
- mkdirSync3(dirname(fullPath), { recursive: true });
2702
+ mkdirSync4(dirname(fullPath), { recursive: true });
2527
2703
  }
2528
2704
  writeFileSync4(fullPath, content, { encoding: "utf-8" });
2529
2705
  const result = {
@@ -2570,7 +2746,7 @@ function registerSafeWriteTools(server2) {
2570
2746
 
2571
2747
  // src/tools/auth.ts
2572
2748
  import { z as z12 } from "zod";
2573
- import { readFileSync as readFileSync4, writeFileSync as writeFileSync5, existsSync as existsSync5 } from "fs";
2749
+ import { readFileSync as readFileSync4, writeFileSync as writeFileSync5, existsSync as existsSync6 } from "fs";
2574
2750
  import { join as join5 } from "path";
2575
2751
  function buildHierarchy(roles) {
2576
2752
  const h = {};
@@ -2850,7 +3026,7 @@ async function configureAuthHandler(params, cwd) {
2850
3026
  try {
2851
3027
  const envBlock = generateEnvBlock(method, params);
2852
3028
  const envPath = join5(cwd, ".env.example");
2853
- if (existsSync5(envPath)) {
3029
+ if (existsSync6(envPath)) {
2854
3030
  const existing = readFileSync4(envPath, "utf8");
2855
3031
  writeFileSync5(envPath, existing.trimEnd() + "\n\n" + envBlock, "utf8");
2856
3032
  } else {
@@ -2881,7 +3057,7 @@ async function configureAuthHandler(params, cwd) {
2881
3057
  protectedRoutes
2882
3058
  );
2883
3059
  const ymlPath = join5(cwd, "stackwright.yml");
2884
- if (!existsSync5(ymlPath)) {
3060
+ if (!existsSync6(ymlPath)) {
2885
3061
  writeFileSync5(ymlPath, authYaml, "utf8");
2886
3062
  } else {
2887
3063
  const existing = readFileSync4(ymlPath, "utf8");
@@ -2963,36 +3139,36 @@ function registerAuthTools(server2) {
2963
3139
 
2964
3140
  // src/integrity.ts
2965
3141
  import { createHash as createHash2, timingSafeEqual } from "crypto";
2966
- import { readFileSync as readFileSync5, readdirSync, lstatSync as lstatSync5 } from "fs";
3142
+ import { readFileSync as readFileSync5, readdirSync, lstatSync as lstatSync6 } from "fs";
2967
3143
  import { join as join6, basename } from "path";
2968
3144
  var _checksums = /* @__PURE__ */ new Map([
2969
3145
  [
2970
3146
  "stackwright-pro-api-otter.json",
2971
- "d72f365d7eb16f6195148d09f8d42249cc1b01fab21e769d991533a31b0b588a"
3147
+ "0ac26d85a5ad35b072a58965e1d5e090dd5c5f16dc14e68c452c3e99fcbb5510"
2972
3148
  ],
2973
3149
  [
2974
3150
  "stackwright-pro-auth-otter.json",
2975
- "6610a5a4e1f981a00771494832a5dbf2e7897f993ed2cfad388528578d15955c"
3151
+ "d789b71f196659d5745ebfca87a7bda60a1bb63cfeccd17b4a273ac1e29bb08d"
2976
3152
  ],
2977
3153
  [
2978
3154
  "stackwright-pro-dashboard-otter.json",
2979
- "f0316349b38e0923c2fa5385e24c4393511c61cea410a2b080a5ece14ace4801"
3155
+ "600e8597429c353e5b886f316731be84a86cd8b93617bf046e3cbf390b31a431"
2980
3156
  ],
2981
3157
  [
2982
3158
  "stackwright-pro-data-otter.json",
2983
- "bd85c01c352630088c3f27110bcd23b6f8f7d2eb72d62a324214ac405a4c1c65"
3159
+ "b2946e3da3b53282c122d150e6db86b0cb89d2edba2a94a7666b26d27051be96"
2984
3160
  ],
2985
3161
  [
2986
3162
  "stackwright-pro-designer-otter.json",
2987
- "aadac659f170c24a3921fe0940464b5dd22db290fb2d7340647c3c4795cfe246"
3163
+ "f4dbff5149051c77be1645de5ee12c0bd7d590c687a0b2d86737b915a5a6d5f0"
2988
3164
  ],
2989
3165
  [
2990
3166
  "stackwright-pro-foreman-otter.json",
2991
- "5bb8eca6d24efa970acc24974d3789a1ce48ead42624236bb7211c1c881b2584"
3167
+ "dc86d6f234d073ead2ccb179c45f911add901ebd3ebf541824addc124df639ee"
2992
3168
  ],
2993
3169
  [
2994
3170
  "stackwright-pro-page-otter.json",
2995
- "c5ad7b312e1c4f83183c489291233adfb5466050d6db44b8816817ac601faca8"
3171
+ "d75a71afa489478a6874abfbaa05baa46dcb2c16e4a5108f50f8187c9f67da60"
2996
3172
  ],
2997
3173
  [
2998
3174
  "stackwright-pro-theme-otter.json",
@@ -3000,7 +3176,7 @@ var _checksums = /* @__PURE__ */ new Map([
3000
3176
  ],
3001
3177
  [
3002
3178
  "stackwright-pro-workflow-otter.json",
3003
- "2b2d132c536148bcd1fa5598d575f2a40b572c050e1cfe17a387d306b62fd855"
3179
+ "16da6c109d0b5ee60d0a14e009dbeab02a7bbac3b0947795769da053565b9821"
3004
3180
  ]
3005
3181
  ]);
3006
3182
  Object.freeze(_checksums);
@@ -3029,7 +3205,7 @@ function verifyOtterFile(filePath) {
3029
3205
  }
3030
3206
  let stat;
3031
3207
  try {
3032
- stat = lstatSync5(filePath);
3208
+ stat = lstatSync6(filePath);
3033
3209
  } catch (err) {
3034
3210
  const msg = err instanceof Error ? err.message : String(err);
3035
3211
  return { verified: false, filename, error: `Cannot stat file: ${msg}` };
@@ -3098,7 +3274,7 @@ function verifyAllOtters(otterDir) {
3098
3274
  for (const filename of otterFiles) {
3099
3275
  const filePath = join6(otterDir, filename);
3100
3276
  try {
3101
- if (lstatSync5(filePath).isSymbolicLink()) {
3277
+ if (lstatSync6(filePath).isSymbolicLink()) {
3102
3278
  failed.push({ filename, error: "Skipped: symlink" });
3103
3279
  continue;
3104
3280
  }
@@ -3126,7 +3302,7 @@ function resolveOtterDir() {
3126
3302
  for (const relative of DEFAULT_SEARCH_PATHS) {
3127
3303
  const candidate = join6(cwd, relative);
3128
3304
  try {
3129
- lstatSync5(candidate);
3305
+ lstatSync6(candidate);
3130
3306
  return candidate;
3131
3307
  } catch {
3132
3308
  }
@@ -3181,7 +3357,7 @@ function registerIntegrityTools(server2) {
3181
3357
 
3182
3358
  // src/tools/domain.ts
3183
3359
  import { z as z13 } from "zod";
3184
- import { readFileSync as readFileSync6, existsSync as existsSync6 } from "fs";
3360
+ import { readFileSync as readFileSync6, existsSync as existsSync7 } from "fs";
3185
3361
  import { join as join7 } from "path";
3186
3362
  function handleListCollections(input) {
3187
3363
  const cwd = input._cwd ?? process.cwd();
@@ -3204,7 +3380,7 @@ function handleListCollections(input) {
3204
3380
  }
3205
3381
  ];
3206
3382
  for (const { path: path3, source, parse } of sources) {
3207
- if (!existsSync6(path3)) continue;
3383
+ if (!existsSync7(path3)) continue;
3208
3384
  try {
3209
3385
  const collections = parse(readFileSync6(path3, "utf8"));
3210
3386
  return {
@@ -3358,7 +3534,7 @@ function handleValidateWorkflow(input) {
3358
3534
  raw = input.workflow;
3359
3535
  } else {
3360
3536
  const artifactPath = join7(cwd, ".stackwright", "artifacts", "workflow-config.json");
3361
- if (!existsSync6(artifactPath)) {
3537
+ if (!existsSync7(artifactPath)) {
3362
3538
  return fail([
3363
3539
  {
3364
3540
  code: "NO_WORKFLOW",
@@ -3606,7 +3782,7 @@ var package_default = {
3606
3782
  "test:coverage": "vitest run --coverage"
3607
3783
  },
3608
3784
  name: "@stackwright-pro/mcp",
3609
- version: "0.2.0-alpha.17",
3785
+ version: "0.2.0-alpha.18",
3610
3786
  description: "MCP tools for Stackwright Pro - Data Explorer, Security, ISR, and Dashboard generation",
3611
3787
  license: "PROPRIETARY",
3612
3788
  main: "./dist/server.js",