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

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
@@ -851,7 +851,7 @@ function registerPackageTools(server2) {
851
851
  "Ensures pro packages are present in a project's package.json. Safe to call multiple times \u2014 never overwrites existing version pins. Use this to bootstrap dependencies before specialist otters run. Pass includeBaseline: true to automatically include all required @stackwright-pro/* baseline dependencies. Safe to call on existing projects \u2014 never overwrites pinned versions.",
852
852
  {
853
853
  // FIX 3 (B-new-1): Zod v4 requires two-arg z.record(keySchema, valueSchema)
854
- packages: z7.record(z7.string(), z7.string()).optional().default({}).describe(
854
+ packages: jsonCoerce(z7.record(z7.string(), z7.string()).optional().default({})).describe(
855
855
  'Dependencies to add. Record<packageName, version>. e.g. { "@stackwright-pro/auth": "latest" }. Omit or pass {} when using includeBaseline: true.'
856
856
  ),
857
857
  devPackages: jsonCoerce(z7.record(z7.string(), z7.string()).optional()).describe(
@@ -1383,12 +1383,12 @@ function registerQuestionTools(server2) {
1383
1383
  content: [
1384
1384
  {
1385
1385
  type: "text",
1386
- text: JSON.stringify({
1387
- phase,
1388
- skipped: true,
1389
- reason: "No questions to present (all filtered by dependsOn conditions)",
1390
- answers: []
1391
- })
1386
+ text: `Phase "${phase}" has no questions to present. Do NOT call ask_user_question. Call stackwright_pro_save_phase_answers({ phase: "${phase}", rawAnswers: [] }) directly, then proceed to the execution step for this phase.`
1387
+ },
1388
+ {
1389
+ type: "text",
1390
+ // Empty array — second block always present so the foreman's two-block contract holds
1391
+ text: JSON.stringify([])
1392
1392
  }
1393
1393
  ],
1394
1394
  isError: false
@@ -1580,7 +1580,57 @@ function handleGetOtterName(input) {
1580
1580
  isError: false
1581
1581
  };
1582
1582
  }
1583
+ function handleSaveBuildContext(input) {
1584
+ const cwd = input._cwd ?? process.cwd();
1585
+ const dir = join2(cwd, ".stackwright");
1586
+ const filePath = join2(dir, "build-context.json");
1587
+ try {
1588
+ mkdirSync(dir, { recursive: true });
1589
+ if (existsSync2(filePath)) {
1590
+ const stat = lstatSync2(filePath);
1591
+ if (stat.isSymbolicLink()) {
1592
+ return {
1593
+ text: JSON.stringify({
1594
+ success: false,
1595
+ error: `Refusing to write to symlink: ${filePath}`
1596
+ }),
1597
+ isError: true
1598
+ };
1599
+ }
1600
+ }
1601
+ const payload = {
1602
+ version: "1.0",
1603
+ savedAt: (/* @__PURE__ */ new Date()).toISOString(),
1604
+ buildContext: input.buildContext
1605
+ };
1606
+ writeFileSync2(filePath, JSON.stringify(payload, null, 2) + "\n");
1607
+ return {
1608
+ text: JSON.stringify({ success: true, path: filePath }),
1609
+ isError: false
1610
+ };
1611
+ } catch (err) {
1612
+ const message = err instanceof Error ? err.message : String(err);
1613
+ return {
1614
+ text: JSON.stringify({ success: false, error: message }),
1615
+ isError: true
1616
+ };
1617
+ }
1618
+ }
1583
1619
  function registerOrchestrationTools(server2) {
1620
+ server2.tool(
1621
+ "stackwright_pro_save_build_context",
1622
+ `Save the user's initial build description to .stackwright/build-context.json. Call this once at startup after the user answers the opening "what are you building" question. The saved context is automatically prepended to specialist prompts by stackwright_pro_build_specialist_prompt.`,
1623
+ {
1624
+ buildContext: z9.string().describe("Free-text description of what the user wants to build")
1625
+ },
1626
+ async ({ buildContext }) => {
1627
+ const { text, isError } = handleSaveBuildContext({ buildContext });
1628
+ return {
1629
+ content: [{ type: "text", text }],
1630
+ isError
1631
+ };
1632
+ }
1633
+ );
1584
1634
  server2.tool(
1585
1635
  "stackwright_pro_parse_otter_response",
1586
1636
  "Parse and validate a specialist otter's QUESTION_COLLECTION_MODE JSON response. Handles JSON extraction from LLM responses (strips markdown, fixes single quotes, trailing commas). Detects the phase from the otter name. Use this immediately after invoke_agent() to get a validated manifest phase object.",
@@ -1859,28 +1909,62 @@ function handleSetPipelineState(input) {
1859
1909
  return { text: JSON.stringify({ error: true, message: String(err) }), isError: true };
1860
1910
  }
1861
1911
  }
1862
- function handleCheckExecutionReady(_cwd) {
1912
+ function handleCheckExecutionReady(_cwd, phase) {
1863
1913
  const cwd = _cwd ?? process.cwd();
1914
+ if (phase) {
1915
+ if (!isValidPhase(phase)) {
1916
+ return {
1917
+ text: JSON.stringify({
1918
+ error: true,
1919
+ message: `Invalid phase: ${phase}. Valid phases are: ${PHASE_ORDER.join(", ")}`
1920
+ }),
1921
+ isError: true
1922
+ };
1923
+ }
1924
+ const answerFile = join3(cwd, ".stackwright", "answers", `${phase}.json`);
1925
+ if (!existsSync3(answerFile)) {
1926
+ return {
1927
+ text: JSON.stringify({ ready: false, phase, reason: "Answer file not found" }),
1928
+ isError: false
1929
+ };
1930
+ }
1931
+ try {
1932
+ const raw = safeReadSync(answerFile);
1933
+ const parsed = JSON.parse(raw);
1934
+ if (typeof parsed["version"] !== "string" || typeof parsed["phase"] !== "string" || typeof parsed["answers"] !== "object" || parsed["answers"] === null) {
1935
+ return {
1936
+ text: JSON.stringify({ ready: false, phase, reason: "Answer file is malformed" }),
1937
+ isError: false
1938
+ };
1939
+ }
1940
+ return { text: JSON.stringify({ ready: true, phase }), isError: false };
1941
+ } catch {
1942
+ return {
1943
+ text: JSON.stringify({ ready: false, phase, reason: "Answer file could not be parsed" }),
1944
+ isError: false
1945
+ };
1946
+ }
1947
+ }
1864
1948
  try {
1865
1949
  const answersDir = join3(cwd, ".stackwright", "answers");
1866
1950
  const answeredPhases = [];
1867
1951
  const missingPhases = [];
1868
- for (const phase of PHASE_ORDER) {
1869
- const answerFile = join3(answersDir, `${phase}.json`);
1952
+ for (const phase2 of PHASE_ORDER) {
1953
+ const answerFile = join3(answersDir, `${phase2}.json`);
1870
1954
  if (existsSync3(answerFile)) {
1871
1955
  try {
1872
1956
  const raw = safeReadSync(answerFile);
1873
1957
  const parsed = JSON.parse(raw);
1874
1958
  if (typeof parsed["version"] !== "string" || typeof parsed["phase"] !== "string" || typeof parsed["answers"] !== "object" || parsed["answers"] === null) {
1875
- missingPhases.push(phase);
1959
+ missingPhases.push(phase2);
1876
1960
  continue;
1877
1961
  }
1878
- answeredPhases.push(phase);
1962
+ answeredPhases.push(phase2);
1879
1963
  } catch {
1880
- missingPhases.push(phase);
1964
+ missingPhases.push(phase2);
1881
1965
  }
1882
1966
  } else {
1883
- missingPhases.push(phase);
1967
+ missingPhases.push(phase2);
1884
1968
  }
1885
1969
  }
1886
1970
  return {
@@ -1990,6 +2074,17 @@ function handleBuildSpecialistPrompt(input) {
1990
2074
  if (existsSync3(answersPath)) {
1991
2075
  answers = JSON.parse(safeReadSync(answersPath));
1992
2076
  }
2077
+ let buildContextText = "";
2078
+ const buildContextPath = join3(cwd, ".stackwright", "build-context.json");
2079
+ if (existsSync3(buildContextPath)) {
2080
+ try {
2081
+ const bcRaw = JSON.parse(safeReadSync(buildContextPath));
2082
+ if (typeof bcRaw.buildContext === "string" && bcRaw.buildContext.trim().length > 0) {
2083
+ buildContextText = bcRaw.buildContext.trim();
2084
+ }
2085
+ } catch {
2086
+ }
2087
+ }
1993
2088
  const deps = PHASE_DEPENDENCIES[phase];
1994
2089
  const artifactSections = [];
1995
2090
  const missingDependencies = [];
@@ -2022,7 +2117,11 @@ ${JSON.stringify(content, null, 2)}`);
2022
2117
  (not yet available)`);
2023
2118
  }
2024
2119
  }
2025
- const parts = ["ANSWERS:", JSON.stringify(answers, null, 2)];
2120
+ const parts = [];
2121
+ if (buildContextText) {
2122
+ parts.push("BUILD_CONTEXT:", buildContextText, "");
2123
+ }
2124
+ parts.push("ANSWERS:", JSON.stringify(answers, null, 2));
2026
2125
  if (artifactSections.length > 0) {
2027
2126
  parts.push("", "UPSTREAM ARTIFACTS:", "", ...artifactSections);
2028
2127
  }
@@ -2181,9 +2280,11 @@ function registerPipelineTools(server2) {
2181
2280
  );
2182
2281
  server2.tool(
2183
2282
  "stackwright_pro_check_execution_ready",
2184
- `Check all phases have answer files in .stackwright/answers/. ${DESC}`,
2185
- {},
2186
- async () => res(handleCheckExecutionReady())
2283
+ `Check all phases have answer files in .stackwright/answers/. If phase is provided, check only that phase. ${DESC}`,
2284
+ {
2285
+ phase: z10.string().optional().describe("If provided, check only this phase's readiness. Omit to check all phases.")
2286
+ },
2287
+ async ({ phase }) => res(handleCheckExecutionReady(void 0, phase))
2187
2288
  );
2188
2289
  server2.tool(
2189
2290
  "stackwright_pro_list_artifacts",
@@ -2867,39 +2968,39 @@ import { join as join6, basename } from "path";
2867
2968
  var _checksums = /* @__PURE__ */ new Map([
2868
2969
  [
2869
2970
  "stackwright-pro-api-otter.json",
2870
- "f1cc9edf2dd1df3ebcea1d0ab33d17a358faaf8aa97ee232cd7994042f2eac0d"
2971
+ "d72f365d7eb16f6195148d09f8d42249cc1b01fab21e769d991533a31b0b588a"
2871
2972
  ],
2872
2973
  [
2873
2974
  "stackwright-pro-auth-otter.json",
2874
- "a19e06c503209a8a35fe321d30448623545b36b48c47a6ec064d13406ad1f725"
2975
+ "6610a5a4e1f981a00771494832a5dbf2e7897f993ed2cfad388528578d15955c"
2875
2976
  ],
2876
2977
  [
2877
2978
  "stackwright-pro-dashboard-otter.json",
2878
- "b3cb3d7554f2e9eed3b57d5e0e3bf85d6ba5b4db5d3af5514391cf0575fcc001"
2979
+ "f0316349b38e0923c2fa5385e24c4393511c61cea410a2b080a5ece14ace4801"
2879
2980
  ],
2880
2981
  [
2881
2982
  "stackwright-pro-data-otter.json",
2882
- "bfacb87ae82867472a75982215554336a105a658d6cd3dd2c8b819fa1e11d7ac"
2983
+ "bd85c01c352630088c3f27110bcd23b6f8f7d2eb72d62a324214ac405a4c1c65"
2883
2984
  ],
2884
2985
  [
2885
2986
  "stackwright-pro-designer-otter.json",
2886
- "c58fa7c7ead9e6398074e1c7ce3f31a8ef4eb3679f5fa18cc03cae3a87878c88"
2987
+ "aadac659f170c24a3921fe0940464b5dd22db290fb2d7340647c3c4795cfe246"
2887
2988
  ],
2888
2989
  [
2889
2990
  "stackwright-pro-foreman-otter.json",
2890
- "f52264c1f6297b72f3da6d92d41b6d63356db776242caeab25571e6a8df628e4"
2991
+ "5bb8eca6d24efa970acc24974d3789a1ce48ead42624236bb7211c1c881b2584"
2891
2992
  ],
2892
2993
  [
2893
2994
  "stackwright-pro-page-otter.json",
2894
- "65bec3a3a0dda6b7591bba2de9399f1e3a4fb99cfe1075342f4f4be98d917b67"
2995
+ "c5ad7b312e1c4f83183c489291233adfb5466050d6db44b8816817ac601faca8"
2895
2996
  ],
2896
2997
  [
2897
2998
  "stackwright-pro-theme-otter.json",
2898
- "1f182326f1acd3d4091a38c7012085cbb4945893e95be4ca3de72318ad092767"
2999
+ "a303ec6c045420f2c916583e3f6efcda469e9610fedfc84a508ed8a8a75866bc"
2899
3000
  ],
2900
3001
  [
2901
3002
  "stackwright-pro-workflow-otter.json",
2902
- "0eec9d6a731678cf547c2a7b0b6fc338ca143c35501365a1e4e5dd2779dd5510"
3003
+ "2b2d132c536148bcd1fa5598d575f2a40b572c050e1cfe17a387d306b62fd855"
2903
3004
  ]
2904
3005
  ]);
2905
3006
  Object.freeze(_checksums);
@@ -3505,7 +3606,7 @@ var package_default = {
3505
3606
  "test:coverage": "vitest run --coverage"
3506
3607
  },
3507
3608
  name: "@stackwright-pro/mcp",
3508
- version: "0.2.0-alpha.15",
3609
+ version: "0.2.0-alpha.17",
3509
3610
  description: "MCP tools for Stackwright Pro - Data Explorer, Security, ISR, and Dashboard generation",
3510
3611
  license: "PROPRIETARY",
3511
3612
  main: "./dist/server.js",