@stackwright-pro/mcp 0.2.0-alpha.109 → 0.2.0-alpha.111

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
@@ -849,6 +849,9 @@ var BASELINE_DEPS = {
849
849
  "@stackwright-pro/openapi": "latest",
850
850
  "@stackwright-pro/auth": "latest",
851
851
  "@stackwright-pro/auth-nextjs": "latest",
852
+ // SBOM compliance — every Pro raft is a compliance product (swp-ryqz)
853
+ "@stackwright-pro/sbom-enterprise": "latest",
854
+ "@stackwright/sbom-generator": "^0.2.2",
852
855
  zod: "^3.23.0"
853
856
  };
854
857
  var BASELINE_DEV_DEPS = {
@@ -2002,7 +2005,7 @@ function registerOrchestrationTools(server2) {
2002
2005
  }
2003
2006
 
2004
2007
  // src/tools/pipeline.ts
2005
- import { z as z13 } from "zod";
2008
+ import { z as z14 } from "zod";
2006
2009
  import { readFileSync as readFileSync7, writeFileSync as writeFileSync4, existsSync as existsSync7, mkdirSync as mkdirSync4, lstatSync as lstatSync6, readdirSync as readdirSync5 } from "fs";
2007
2010
  import { lockSync } from "proper-lockfile";
2008
2011
  import { join as join7 } from "path";
@@ -2742,6 +2745,19 @@ function validateAuthConfig(artifact, artifactPath) {
2742
2745
  // src/tools/auth-manifest-aggregator.ts
2743
2746
  import { existsSync as existsSync6, readFileSync as readFileSync5, readdirSync as readdirSync3 } from "fs";
2744
2747
  import { join as join5 } from "path";
2748
+ import { z as z11 } from "zod";
2749
+ function computeLowestRole(requiredRoles, rbacRoles) {
2750
+ let lowestIndex = -1;
2751
+ let lowestRole = requiredRoles[0];
2752
+ for (const role of requiredRoles) {
2753
+ const idx = rbacRoles.indexOf(role);
2754
+ if (idx > lowestIndex) {
2755
+ lowestIndex = idx;
2756
+ lowestRole = role;
2757
+ }
2758
+ }
2759
+ return lowestRole;
2760
+ }
2745
2761
  function extractPatternBaseSlug(pattern) {
2746
2762
  const stripped = pattern.replace(/^\//, "");
2747
2763
  if (!stripped) return null;
@@ -2775,12 +2791,101 @@ function extractManifestSlugs(artifactsDir) {
2775
2791
  }
2776
2792
  return slugs;
2777
2793
  }
2794
+ function normalizeNextJsSlug(slug) {
2795
+ return slug.replace(/\[\[\.\.\.([\w]+)\]\]/g, ":$1*").replace(/\[\.\.\.([\w]+)\]/g, ":$1*").replace(/\[([\w]+)\]/g, ":$1");
2796
+ }
2797
+ function deriveProtectedRoutes(pages, rbacRoles) {
2798
+ const protectedRoutes = [];
2799
+ const uncoveredSlugs = [];
2800
+ const seen = /* @__PURE__ */ new Set();
2801
+ for (const page of pages) {
2802
+ if (seen.has(page.slug)) continue;
2803
+ seen.add(page.slug);
2804
+ if (page.authRequired === false) continue;
2805
+ if (page.authRequired === true && Array.isArray(page.requiredRoles) && page.requiredRoles.length > 0) {
2806
+ const normalizedSlug = normalizeNextJsSlug(page.slug);
2807
+ const lowestRole = computeLowestRole(page.requiredRoles, rbacRoles);
2808
+ protectedRoutes.push({ pattern: `/${normalizedSlug}`, requiredRole: lowestRole });
2809
+ if (!normalizedSlug.endsWith("*")) {
2810
+ protectedRoutes.push({ pattern: `/${normalizedSlug}/:path*`, requiredRole: lowestRole });
2811
+ }
2812
+ continue;
2813
+ }
2814
+ const reason = page.authRequired === true ? "authRequired: true but requiredRoles is missing or empty" : "page emitter did not declare authRequired + requiredRoles";
2815
+ uncoveredSlugs.push({ source: page.source, slug: page.slug, reason });
2816
+ }
2817
+ return { protectedRoutes, uncoveredSlugs };
2818
+ }
2819
+ function readAllManifestPages(artifactsDir) {
2820
+ const allPages = [];
2821
+ if (!existsSync6(artifactsDir)) return allPages;
2822
+ let entries;
2823
+ try {
2824
+ entries = readdirSync3(artifactsDir);
2825
+ } catch {
2826
+ return allPages;
2827
+ }
2828
+ for (const entry of entries) {
2829
+ if (!entry.endsWith("-manifest.json")) continue;
2830
+ const filePath = join5(artifactsDir, entry);
2831
+ try {
2832
+ const raw = JSON.parse(readFileSync5(filePath, "utf-8"));
2833
+ if (!Array.isArray(raw.pages)) continue;
2834
+ for (const page of raw.pages) {
2835
+ if (typeof page.slug !== "string" || !page.slug) continue;
2836
+ allPages.push({
2837
+ slug: page.slug,
2838
+ authRequired: page.authRequired,
2839
+ requiredRoles: page.requiredRoles,
2840
+ source: entry
2841
+ });
2842
+ }
2843
+ } catch {
2844
+ }
2845
+ }
2846
+ return allPages;
2847
+ }
2848
+ function registerReadAuthManifestsTool(server2) {
2849
+ server2.tool(
2850
+ "stackwright_pro_read_auth_manifests",
2851
+ "Read ALL *-manifest.json files from the pipeline artifacts directory (pages-manifest.json, dashboard-manifest.json, geo-manifest.json, etc.) and deterministically derive protectedRoutes and uncoveredSlugs. Uses the both-forms invariant (swp-n7kk): every authRequired route registers BOTH /{slug} (exact) AND /{slug}/:path* (sub-path). Call this in Step 1 of auth configuration instead of manually reading each manifest file. Fixes the Bead C issue where dashboard-manifest.json and geo-manifest.json were silently missed.",
2852
+ {
2853
+ rbacRoles: z11.array(z11.string()).describe(
2854
+ 'RBAC role hierarchy in descending privilege order, e.g. ["ESF8_COORDINATOR", "HOSPITAL_EM", "OBSERVER"]. Used to compute the lowestRole for each authRequired page.'
2855
+ ),
2856
+ artifactsDir: z11.string().optional().describe(
2857
+ "Absolute or relative path to the pipeline artifacts directory. Defaults to .stackwright/artifacts relative to cwd."
2858
+ )
2859
+ },
2860
+ (params) => {
2861
+ const cwd = process.cwd();
2862
+ const artifactsDir = params.artifactsDir ? params.artifactsDir : join5(cwd, ".stackwright", "artifacts");
2863
+ const allPages = readAllManifestPages(artifactsDir);
2864
+ const { protectedRoutes, uncoveredSlugs } = deriveProtectedRoutes(allPages, params.rbacRoles);
2865
+ const manifestsRead = [...new Set(allPages.map((p) => p.source))].sort();
2866
+ const result = {
2867
+ protectedRoutes,
2868
+ uncoveredSlugs,
2869
+ manifestsRead,
2870
+ summary: {
2871
+ totalPages: allPages.length,
2872
+ protectedCount: protectedRoutes.length,
2873
+ uncoveredCount: uncoveredSlugs.length,
2874
+ artifactsDir
2875
+ }
2876
+ };
2877
+ return {
2878
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
2879
+ };
2880
+ }
2881
+ );
2882
+ }
2778
2883
 
2779
2884
  // src/tools/pipeline.ts
2780
2885
  import { WorkflowFileSchema, authConfigSchema as authConfigSchema3 } from "@stackwright-pro/types";
2781
2886
 
2782
2887
  // src/tools/get-schema.ts
2783
- import { z as z12 } from "zod";
2888
+ import { z as z13 } from "zod";
2784
2889
  import {
2785
2890
  WorkflowStepSchema as WorkflowStepSchema2,
2786
2891
  WorkflowDefinitionSchema as WorkflowDefinitionSchema2,
@@ -2790,7 +2895,7 @@ import {
2790
2895
  } from "@stackwright-pro/types";
2791
2896
 
2792
2897
  // src/tools/validate-yaml-fragment.ts
2793
- import { z as z11 } from "zod";
2898
+ import { z as z12 } from "zod";
2794
2899
  import { load as yamlLoad2 } from "js-yaml";
2795
2900
  import {
2796
2901
  WorkflowStepSchema,
@@ -2807,18 +2912,18 @@ var SUPPORTED_SCHEMA_NAMES = [
2807
2912
  "navigation_item",
2808
2913
  "auth_config"
2809
2914
  ];
2810
- var NavigationLinkSchema = z11.lazy(
2811
- () => z11.object({
2812
- label: z11.string().min(1),
2813
- href: z11.string().min(1),
2814
- children: z11.array(NavigationLinkSchema).optional()
2915
+ var NavigationLinkSchema = z12.lazy(
2916
+ () => z12.object({
2917
+ label: z12.string().min(1),
2918
+ href: z12.string().min(1),
2919
+ children: z12.array(NavigationLinkSchema).optional()
2815
2920
  })
2816
2921
  );
2817
- var NavigationSectionSchema = z11.object({
2818
- section: z11.string().min(1),
2819
- items: z11.array(NavigationLinkSchema)
2922
+ var NavigationSectionSchema = z12.object({
2923
+ section: z12.string().min(1),
2924
+ items: z12.array(NavigationLinkSchema)
2820
2925
  });
2821
- var NavigationItemSchema = z11.union([
2926
+ var NavigationItemSchema = z12.union([
2822
2927
  NavigationLinkSchema,
2823
2928
  NavigationSectionSchema
2824
2929
  ]);
@@ -2920,10 +3025,10 @@ function registerValidateYamlFragmentTool(server2) {
2920
3025
  "stackwright_pro_validate_yaml_fragment",
2921
3026
  'Validates a YAML snippet against a canonical Zod schema before writing to disk. Returns actionable errors with "did you mean?" suggestions for common field-name drift (title vs label, id vs name, style vs theme.variant, etc.). Call this before stackwright_pro_safe_write to catch schema violations in-session.',
2922
3027
  {
2923
- schemaName: z11.enum(SUPPORTED_SCHEMA_NAMES).describe(
3028
+ schemaName: z12.enum(SUPPORTED_SCHEMA_NAMES).describe(
2924
3029
  "Schema to validate against. One of: workflow_step, workflow_definition, workflow_field, workflow_action, navigation_item, auth_config"
2925
3030
  ),
2926
- yaml: z11.string().describe("YAML string to validate (can also be JSON \u2014 js-yaml parses both)")
3031
+ yaml: z12.string().describe("YAML string to validate (can also be JSON \u2014 js-yaml parses both)")
2927
3032
  },
2928
3033
  async ({ schemaName, yaml: yaml3 }) => {
2929
3034
  const result = handleValidateYamlFragment({ schemaName, yaml: yaml3 });
@@ -2935,18 +3040,18 @@ function registerValidateYamlFragmentTool(server2) {
2935
3040
  }
2936
3041
 
2937
3042
  // src/tools/get-schema.ts
2938
- var NavigationLinkSchema2 = z12.lazy(
2939
- () => z12.object({
2940
- label: z12.string().min(1),
2941
- href: z12.string().min(1),
2942
- children: z12.array(NavigationLinkSchema2).optional()
3043
+ var NavigationLinkSchema2 = z13.lazy(
3044
+ () => z13.object({
3045
+ label: z13.string().min(1),
3046
+ href: z13.string().min(1),
3047
+ children: z13.array(NavigationLinkSchema2).optional()
2943
3048
  })
2944
3049
  );
2945
- var NavigationSectionSchema2 = z12.object({
2946
- section: z12.string().min(1),
2947
- items: z12.array(NavigationLinkSchema2)
3050
+ var NavigationSectionSchema2 = z13.object({
3051
+ section: z13.string().min(1),
3052
+ items: z13.array(NavigationLinkSchema2)
2948
3053
  });
2949
- var NavigationItemSchema2 = z12.union([
3054
+ var NavigationItemSchema2 = z13.union([
2950
3055
  NavigationLinkSchema2,
2951
3056
  NavigationSectionSchema2
2952
3057
  ]);
@@ -3047,7 +3152,7 @@ function handleGetSchema(input) {
3047
3152
  const synonyms = FIELD_SYNONYMS[name];
3048
3153
  let jsonSchema;
3049
3154
  try {
3050
- const raw = z12.toJSONSchema(schema, { unrepresentable: "any" });
3155
+ const raw = z13.toJSONSchema(schema, { unrepresentable: "any" });
3051
3156
  jsonSchema = raw;
3052
3157
  } catch {
3053
3158
  jsonSchema = { type: "object", description: "Schema introspection unavailable for this type" };
@@ -3101,7 +3206,7 @@ function registerGetSchemaTool(server2) {
3101
3206
  "stackwright_pro_get_schema",
3102
3207
  'Returns a compact, LLM-friendly summary of a canonical schema derived programmatically from Zod. Includes required/optional fields, types, constraints, and "did you mean?" warnings for common field-name drift. Use before authoring YAML to confirm exact field names.',
3103
3208
  {
3104
- schemaName: z12.enum(SUPPORTED_SCHEMA_NAMES).describe(
3209
+ schemaName: z13.enum(SUPPORTED_SCHEMA_NAMES).describe(
3105
3210
  "Schema to summarize. One of: workflow_step, workflow_definition, workflow_field, workflow_action, navigation_item, auth_config"
3106
3211
  )
3107
3212
  },
@@ -4812,28 +4917,28 @@ function registerPipelineTools(server2) {
4812
4917
  "stackwright_pro_set_pipeline_state",
4813
4918
  `Atomic read\u2192modify\u2192write pipeline state. ${DESC}`,
4814
4919
  {
4815
- phase: z13.string().optional().describe('Phase to update, e.g. "designer"'),
4816
- field: z13.enum(["questionsCollected", "answered", "executed", "artifactWritten", "inFlight"]).optional().describe("Boolean field to set"),
4920
+ phase: z14.string().optional().describe('Phase to update, e.g. "designer"'),
4921
+ field: z14.enum(["questionsCollected", "answered", "executed", "artifactWritten", "inFlight"]).optional().describe("Boolean field to set"),
4817
4922
  // inFlight: set true BEFORE specialist invoke (dataflow mode, swp-ioc7); false after.
4818
- value: boolCoerce(z13.boolean().optional()).describe(
4923
+ value: boolCoerce(z14.boolean().optional()).describe(
4819
4924
  'Value for the field \u2014 must be a JSON boolean (true/false), NOT the string "true"/"false"'
4820
4925
  ),
4821
- status: z13.enum(["setup", "questions", "execution", "done"]).optional().describe("Top-level status override"),
4822
- incrementRetry: boolCoerce(z13.boolean().optional()).describe(
4926
+ status: z14.enum(["setup", "questions", "execution", "done"]).optional().describe("Top-level status override"),
4927
+ incrementRetry: boolCoerce(z14.boolean().optional()).describe(
4823
4928
  "Bump retryCount by 1 \u2014 must be a JSON boolean"
4824
4929
  ),
4825
4930
  updates: jsonCoerce(
4826
- z13.array(
4827
- z13.object({
4828
- phase: z13.string(),
4829
- field: z13.enum([
4931
+ z14.array(
4932
+ z14.object({
4933
+ phase: z14.string(),
4934
+ field: z14.enum([
4830
4935
  "questionsCollected",
4831
4936
  "answered",
4832
4937
  "executed",
4833
4938
  "artifactWritten",
4834
4939
  "inFlight"
4835
4940
  ]),
4836
- value: z13.boolean()
4941
+ value: z14.boolean()
4837
4942
  })
4838
4943
  ).optional()
4839
4944
  ).describe("Batch updates \u2014 apply multiple field changes in one atomic read\u2192modify\u2192write")
@@ -4853,7 +4958,7 @@ function registerPipelineTools(server2) {
4853
4958
  "stackwright_pro_check_execution_ready",
4854
4959
  `Check all phases have answer files in .stackwright/answers/. If phase is provided, check only that phase. ${DESC}`,
4855
4960
  {
4856
- phase: z13.string().optional().describe("If provided, check only this phase's readiness. Omit to check all phases.")
4961
+ phase: z14.string().optional().describe("If provided, check only this phase's readiness. Omit to check all phases.")
4857
4962
  },
4858
4963
  async ({ phase }) => res(handleCheckExecutionReady(void 0, phase))
4859
4964
  );
@@ -4873,9 +4978,9 @@ function registerPipelineTools(server2) {
4873
4978
  "stackwright_pro_write_phase_questions",
4874
4979
  `Parse otter question-collection response \u2192 .stackwright/questions/{phase}.json. Specialists may also call this directly with a parsed questions array. ${DESC}`,
4875
4980
  {
4876
- phase: z13.string().optional().describe('Phase name, e.g. "designer" (required for direct write)'),
4877
- responseText: z13.string().optional().describe("Raw LLM response from QUESTION_COLLECTION_MODE"),
4878
- questions: jsonCoerce(z13.array(z13.any()).optional()).describe(
4981
+ phase: z14.string().optional().describe('Phase name, e.g. "designer" (required for direct write)'),
4982
+ responseText: z14.string().optional().describe("Raw LLM response from QUESTION_COLLECTION_MODE"),
4983
+ questions: jsonCoerce(z14.array(z14.any()).optional()).describe(
4879
4984
  "Questions array for direct specialist write"
4880
4985
  )
4881
4986
  },
@@ -4917,22 +5022,22 @@ function registerPipelineTools(server2) {
4917
5022
  server2.tool(
4918
5023
  "stackwright_pro_build_specialist_prompt",
4919
5024
  `Assemble execution prompt from answers + upstream artifacts. Foreman passes verbatim. ${DESC}`,
4920
- { phase: z13.string().describe('Phase to build prompt for, e.g. "pages"') },
5025
+ { phase: z14.string().describe('Phase to build prompt for, e.g. "pages"') },
4921
5026
  async ({ phase }) => res(handleBuildSpecialistPrompt({ phase }))
4922
5027
  );
4923
5028
  server2.tool(
4924
5029
  "stackwright_pro_validate_artifact",
4925
5030
  `Validate and write artifact to .stackwright/artifacts/. Returns retryPrompt on failure. ${DESC}`,
4926
5031
  {
4927
- phase: z13.string().describe('Phase that produced this artifact, e.g. "designer"'),
4928
- responseText: z13.string().optional().describe("Raw response text from the specialist otter (Foreman-mediated path, legacy)"),
4929
- artifact: jsonCoerce(z13.record(z13.string(), z13.unknown()).optional()).describe(
5032
+ phase: z14.string().describe('Phase that produced this artifact, e.g. "designer"'),
5033
+ responseText: z14.string().optional().describe("Raw response text from the specialist otter (Foreman-mediated path, legacy)"),
5034
+ artifact: jsonCoerce(z14.record(z14.string(), z14.unknown()).optional()).describe(
4930
5035
  "Artifact object to validate and write directly (specialist direct path \u2014 skips off-script detection and JSON parsing)"
4931
5036
  ),
4932
- integrationName: z13.string().optional().describe(
5037
+ integrationName: z14.string().optional().describe(
4933
5038
  'When phase="api": write to api-config-<integrationName>.json instead of api-config.json. Enables concurrent per-spec fan-out without collision (swp-530y).'
4934
5039
  ),
4935
- workflowName: z13.string().optional().describe(
5040
+ workflowName: z14.string().optional().describe(
4936
5041
  `When phase="workflow": write to workflow-config-<workflowName>.json instead of workflow-config.json. Enables concurrent per-workflow fan-out without collision (swp-x8sm). Must be a kebab-case slug matching the workflow's id field.`
4937
5042
  )
4938
5043
  },
@@ -4961,7 +5066,7 @@ function registerPipelineTools(server2) {
4961
5066
  "stackwright_pro_emit_event",
4962
5067
  `FOREMAN ONLY \u2014 specialist otters that call this will receive an authorization rejection (no-op, not an error). Emit a telemetry event to .stackwright/pipeline-events.ndjson. Foreman calls this at phase boundaries and agent-invoke boundaries. Best-effort: failures are silent and never block. ${DESC}`,
4963
5068
  {
4964
- type: z13.enum([
5069
+ type: z14.enum([
4965
5070
  "phase_start",
4966
5071
  "phase_complete",
4967
5072
  "phase_ready",
@@ -4970,20 +5075,20 @@ function registerPipelineTools(server2) {
4970
5075
  ]).describe("Event type to emit"),
4971
5076
  // phase_ready: emitted in dataflow mode (swp-ioc7) when a phase enters the ready set
4972
5077
  // (deps satisfied, not inFlight, not yet complete) — BEFORE invoking the specialist.
4973
- phase: z13.string().optional().describe("Current phase name"),
4974
- targetOtter: z13.string().optional().describe("For agent_invoke_* events: which otter is being invoked"),
4975
- success: boolCoerce(z13.boolean().optional()).describe(
5078
+ phase: z14.string().optional().describe("Current phase name"),
5079
+ targetOtter: z14.string().optional().describe("For agent_invoke_* events: which otter is being invoked"),
5080
+ success: boolCoerce(z14.boolean().optional()).describe(
4976
5081
  'For agent_invoke_complete: did the invocation succeed? (boolean; string "true"/"false" also accepted for caller tolerance)'
4977
5082
  ),
4978
- otter: z13.string().optional().describe('Which otter is emitting (defaults to "foreman")'),
4979
- durationSec: z13.number().optional().describe("Duration in seconds (for *_complete events)")
5083
+ otter: z14.string().optional().describe('Which otter is emitting (defaults to "foreman")'),
5084
+ durationSec: z14.number().optional().describe("Duration in seconds (for *_complete events)")
4980
5085
  },
4981
5086
  async ({ type, phase, targetOtter, success, otter, durationSec }) => res(handleEmitEvent({ type, phase, targetOtter, success, otter, durationSec }))
4982
5087
  );
4983
5088
  }
4984
5089
 
4985
5090
  // src/tools/safe-write.ts
4986
- import { z as z14 } from "zod";
5091
+ import { z as z15 } from "zod";
4987
5092
  import { writeFileSync as writeFileSync5, readFileSync as readFileSync8, existsSync as existsSync8, mkdirSync as mkdirSync5, lstatSync as lstatSync7 } from "fs";
4988
5093
  import { normalize, isAbsolute, dirname, join as join8 } from "path";
4989
5094
  import { emit as emit2 } from "@stackwright-pro/telemetry";
@@ -5479,10 +5584,10 @@ function registerSafeWriteTools(server2) {
5479
5584
  "stackwright_pro_safe_write",
5480
5585
  DESC,
5481
5586
  {
5482
- callerOtter: z14.string().describe('The otter agent name requesting the write, e.g. "stackwright-pro-page-otter"'),
5483
- filePath: z14.string().describe('Relative path from project root, e.g. "pages/dashboard/content.yml"'),
5484
- content: z14.string().describe("File content to write"),
5485
- createDirectories: boolCoerce(z14.boolean().optional().default(true)).describe(
5587
+ callerOtter: z15.string().describe('The otter agent name requesting the write, e.g. "stackwright-pro-page-otter"'),
5588
+ filePath: z15.string().describe('Relative path from project root, e.g. "pages/dashboard/content.yml"'),
5589
+ content: z15.string().describe("File content to write"),
5590
+ createDirectories: boolCoerce(z15.boolean().optional().default(true)).describe(
5486
5591
  "Create parent directories if they don't exist. Default: true"
5487
5592
  )
5488
5593
  },
@@ -5499,9 +5604,12 @@ function registerSafeWriteTools(server2) {
5499
5604
  }
5500
5605
 
5501
5606
  // src/tools/auth.ts
5502
- import { z as z15 } from "zod";
5607
+ import { z as z16 } from "zod";
5503
5608
  import { readFileSync as readFileSync9, writeFileSync as writeFileSync6, existsSync as existsSync9, mkdirSync as mkdirSync6 } from "fs";
5504
5609
  import { join as join9 } from "path";
5610
+ function normalizeProviderSlug(slug) {
5611
+ return slug.replace(/-/g, "_");
5612
+ }
5505
5613
  function buildHierarchy(roles) {
5506
5614
  const h = {};
5507
5615
  for (let i = 0; i < roles.length - 1; i++) {
@@ -5756,13 +5864,12 @@ ${hierarchyToYaml(hierarchy, " ")}`;
5756
5864
  const ocspEndpoint = params.cacOcspEndpoint ?? "https://ocsp.disa.mil";
5757
5865
  const certHeader = params.cacCertHeader ?? "X-SSL-Client-Cert";
5758
5866
  return `# stackwright.auth.yml \u2014 generated by Auth Otter
5759
- method: cac
5760
- ${providerLine}${useProxy ? "proxy" : "middleware"}: ./${useProxy ? "proxy" : "middleware"}.ts
5761
- cac:
5762
- caBundle: \${CAC_CA_BUNDLE}
5763
- edipiLookup: ${edipiLookup}
5764
- ocspEndpoint: \${CAC_OCSP_ENDPOINT}
5765
- certHeader: ${certHeader}
5867
+ type: pki
5868
+ ${useProxy ? "proxy" : "middleware"}: ./${useProxy ? "proxy" : "middleware"}.ts
5869
+ caBundle: \${CAC_CA_BUNDLE}
5870
+ edipiLookup: ${edipiLookup}
5871
+ ocspEndpoint: \${CAC_OCSP_ENDPOINT}
5872
+ certHeader: ${certHeader}
5766
5873
  ${rbacSection}
5767
5874
  protectedRoutes:
5768
5875
  ${routeLines}
@@ -5773,14 +5880,13 @@ ${auditSection}
5773
5880
  const scopes2 = params.oidcScopes ?? "openid profile email";
5774
5881
  const roleClaim = params.oidcRoleClaim ?? "roles";
5775
5882
  return `# stackwright.auth.yml \u2014 generated by Auth Otter
5776
- method: oidc
5883
+ type: oidc
5777
5884
  ${providerLine}${useProxy ? "proxy" : "middleware"}: ./${useProxy ? "proxy" : "middleware"}.ts
5778
- oidc:
5779
- discoveryUrl: \${OIDC_DISCOVERY_URL}
5780
- clientId: \${OIDC_CLIENT_ID}
5781
- clientSecret: \${OIDC_CLIENT_SECRET}
5782
- scopes: ${scopes2}
5783
- roleClaim: ${roleClaim}
5885
+ discoveryUrl: \${OIDC_DISCOVERY_URL}
5886
+ clientId: \${OIDC_CLIENT_ID}
5887
+ clientSecret: \${OIDC_CLIENT_SECRET}
5888
+ scopes: ${scopes2}
5889
+ roleClaim: ${roleClaim}
5784
5890
  ${rbacSection}
5785
5891
  protectedRoutes:
5786
5892
  ${routeLines}
@@ -5789,14 +5895,13 @@ ${auditSection}
5789
5895
  }
5790
5896
  const scopes = params.oauth2Scopes ?? "read write";
5791
5897
  return `# stackwright.auth.yml \u2014 generated by Auth Otter
5792
- method: oauth2
5898
+ type: oauth2
5793
5899
  ${providerLine}${useProxy ? "proxy" : "middleware"}: ./${useProxy ? "proxy" : "middleware"}.ts
5794
- oauth2:
5795
- authorizationUrl: \${OAUTH2_AUTH_URL}
5796
- tokenUrl: \${OAUTH2_TOKEN_URL}
5797
- clientId: \${OAUTH2_CLIENT_ID}
5798
- clientSecret: \${OAUTH2_CLIENT_SECRET}
5799
- scopes: ${scopes}
5900
+ authorizationUrl: \${OAUTH2_AUTH_URL}
5901
+ tokenUrl: \${OAUTH2_TOKEN_URL}
5902
+ clientId: \${OAUTH2_CLIENT_ID}
5903
+ clientSecret: \${OAUTH2_CLIENT_SECRET}
5904
+ scopes: ${scopes}
5800
5905
  ${rbacSection}
5801
5906
  protectedRoutes:
5802
5907
  ${routeLines}
@@ -6003,14 +6108,13 @@ ${hierarchyToYaml(hierarchy, " ")}`;
6003
6108
  const ocspEndpoint = params.cacOcspEndpoint ?? "https://ocsp.disa.mil";
6004
6109
  const certHeader = params.cacCertHeader ?? "X-SSL-Client-Cert";
6005
6110
  return `# stackwright.auth.yml \u2014 generated by Auth Otter
6006
- method: cac
6111
+ type: pki
6007
6112
  devOnly: true
6008
- ${providerLine}${useProxy ? "proxy" : "middleware"}: ./${useProxy ? "proxy" : "middleware"}.ts
6009
- cac:
6010
- caBundle: ${caBundle}
6011
- edipiLookup: ${edipiLookup}
6012
- ocspEndpoint: ${ocspEndpoint}
6013
- certHeader: ${certHeader}
6113
+ ${useProxy ? "proxy" : "middleware"}: ./${useProxy ? "proxy" : "middleware"}.ts
6114
+ caBundle: ${caBundle}
6115
+ edipiLookup: ${edipiLookup}
6116
+ ocspEndpoint: ${ocspEndpoint}
6117
+ certHeader: ${certHeader}
6014
6118
  ${rbacSection}
6015
6119
  protectedRoutes:
6016
6120
  ${routeLines}
@@ -6021,15 +6125,14 @@ ${auditSection}
6021
6125
  const scopes2 = params.oidcScopes ?? "openid profile email";
6022
6126
  const roleClaim = params.oidcRoleClaim ?? "roles";
6023
6127
  return `# stackwright.auth.yml \u2014 generated by Auth Otter
6024
- method: oidc
6128
+ type: oidc
6025
6129
  devOnly: true
6026
6130
  ${providerLine}${useProxy ? "proxy" : "middleware"}: ./${useProxy ? "proxy" : "middleware"}.ts
6027
- oidc:
6028
- discoveryUrl: https://dev-mock-oidc/.well-known/openid-configuration
6029
- clientId: dev-mock-client
6030
- clientSecret: dev-mock-secret
6031
- scopes: ${scopes2}
6032
- roleClaim: ${roleClaim}
6131
+ discoveryUrl: https://dev-mock-oidc/.well-known/openid-configuration
6132
+ clientId: dev-mock-client
6133
+ clientSecret: dev-mock-secret
6134
+ scopes: ${scopes2}
6135
+ roleClaim: ${roleClaim}
6033
6136
  ${rbacSection}
6034
6137
  protectedRoutes:
6035
6138
  ${routeLines}
@@ -6038,15 +6141,14 @@ ${auditSection}
6038
6141
  }
6039
6142
  const scopes = params.oauth2Scopes ?? "read write";
6040
6143
  return `# stackwright.auth.yml \u2014 generated by Auth Otter
6041
- method: oauth2
6144
+ type: oauth2
6042
6145
  devOnly: true
6043
6146
  ${providerLine}${useProxy ? "proxy" : "middleware"}: ./${useProxy ? "proxy" : "middleware"}.ts
6044
- oauth2:
6045
- authorizationUrl: https://dev-mock-oauth2/authorize
6046
- tokenUrl: https://dev-mock-oauth2/token
6047
- clientId: dev-mock-client
6048
- clientSecret: dev-mock-secret
6049
- scopes: ${scopes}
6147
+ authorizationUrl: https://dev-mock-oauth2/authorize
6148
+ tokenUrl: https://dev-mock-oauth2/token
6149
+ clientId: dev-mock-client
6150
+ clientSecret: dev-mock-secret
6151
+ scopes: ${scopes}
6050
6152
  ${rbacSection}
6051
6153
  protectedRoutes:
6052
6154
  ${routeLines}
@@ -6116,6 +6218,10 @@ function updatePackageJsonScripts(existingJson, roles, mockUsers) {
6116
6218
  return JSON.stringify(pkg, null, 2) + "\n";
6117
6219
  }
6118
6220
  async function configureAuthHandler(params, cwd) {
6221
+ params = {
6222
+ ...params,
6223
+ provider: params.provider != null ? normalizeProviderSlug(params.provider) : void 0
6224
+ };
6119
6225
  const {
6120
6226
  method,
6121
6227
  provider,
@@ -6367,45 +6473,46 @@ function registerAuthTools(server2) {
6367
6473
  "stackwright_pro_configure_auth",
6368
6474
  "Generate authentication middleware and configuration for a Next.js Stackwright application. Writes `middleware.ts` (or `proxy.ts` for Next.js >=16) from a secure template, writes a standalone `stackwright.auth.yml` sibling file, and generates `.env.example` with required environment variables. \u26A0\uFE0F For CAC/PKI: generated `middleware.ts` carries a SECURITY REVIEW REQUIRED comment \u2014 certificate chain validation must be verified by a DoD security officer before production deployment. This is the ONLY approved path to generating `middleware.ts`. Never write TypeScript auth files directly.",
6369
6475
  {
6370
- method: z15.enum(["cac", "oidc", "oauth2", "none"]),
6371
- provider: z15.enum(["azure-ad", "okta", "ping", "cognito", "custom"]).optional(),
6476
+ method: z16.enum(["cac", "oidc", "oauth2", "none"]),
6477
+ // Both hyphen and underscore accepted at the tool surface; normalized to underscore downstream.
6478
+ provider: z16.enum(["azure-ad", "azure_ad", "okta", "ping", "cognito", "custom"]).optional(),
6372
6479
  // CAC
6373
- cacCaBundle: z15.string().optional(),
6374
- cacEdipiLookup: z15.string().optional(),
6375
- cacOcspEndpoint: z15.string().optional(),
6376
- cacCertHeader: z15.string().optional(),
6480
+ cacCaBundle: z16.string().optional(),
6481
+ cacEdipiLookup: z16.string().optional(),
6482
+ cacOcspEndpoint: z16.string().optional(),
6483
+ cacCertHeader: z16.string().optional(),
6377
6484
  // OIDC
6378
- oidcDiscoveryUrl: z15.string().optional(),
6379
- oidcClientId: z15.string().optional(),
6380
- oidcClientSecret: z15.string().optional(),
6381
- oidcScopes: z15.string().optional(),
6382
- oidcRoleClaim: z15.string().optional(),
6485
+ oidcDiscoveryUrl: z16.string().optional(),
6486
+ oidcClientId: z16.string().optional(),
6487
+ oidcClientSecret: z16.string().optional(),
6488
+ oidcScopes: z16.string().optional(),
6489
+ oidcRoleClaim: z16.string().optional(),
6383
6490
  // OAuth2
6384
- oauth2AuthUrl: z15.string().optional(),
6385
- oauth2TokenUrl: z15.string().optional(),
6386
- oauth2ClientId: z15.string().optional(),
6387
- oauth2ClientSecret: z15.string().optional(),
6388
- oauth2Scopes: z15.string().optional(),
6491
+ oauth2AuthUrl: z16.string().optional(),
6492
+ oauth2TokenUrl: z16.string().optional(),
6493
+ oauth2ClientId: z16.string().optional(),
6494
+ oauth2ClientSecret: z16.string().optional(),
6495
+ oauth2Scopes: z16.string().optional(),
6389
6496
  // RBAC
6390
- rbacRoles: jsonCoerce(z15.array(z15.string()).optional()),
6391
- rbacDefaultRole: z15.string().optional(),
6497
+ rbacRoles: jsonCoerce(z16.array(z16.string()).optional()),
6498
+ rbacDefaultRole: z16.string().optional(),
6392
6499
  // Audit
6393
- auditEnabled: boolCoerce(z15.boolean().optional()),
6394
- auditRetentionDays: numCoerce(z15.number().int().positive().optional()),
6500
+ auditEnabled: boolCoerce(z16.boolean().optional()),
6501
+ auditRetentionDays: numCoerce(z16.number().int().positive().optional()),
6395
6502
  // Routes — accepts bare strings (backward-compat) or per-route objects (swp-owu0)
6396
6503
  protectedRoutes: jsonCoerce(
6397
- z15.array(
6398
- z15.union([
6399
- z15.string(),
6400
- z15.object({ pattern: z15.string(), requiredRole: z15.string().optional() })
6504
+ z16.array(
6505
+ z16.union([
6506
+ z16.string(),
6507
+ z16.object({ pattern: z16.string(), requiredRole: z16.string().optional() })
6401
6508
  ])
6402
6509
  ).optional()
6403
6510
  ),
6404
6511
  // Injection for tests
6405
- _cwd: z15.string().optional(),
6406
- devOnly: boolCoerce(z15.boolean().optional()),
6407
- mockUsers: jsonCoerce(z15.array(z15.object({ name: z15.string(), email: z15.string() })).optional()),
6408
- nextMajorVersion: numCoerce(z15.number().int().positive().optional())
6512
+ _cwd: z16.string().optional(),
6513
+ devOnly: boolCoerce(z16.boolean().optional()),
6514
+ mockUsers: jsonCoerce(z16.array(z16.object({ name: z16.string(), email: z16.string() })).optional()),
6515
+ nextMajorVersion: numCoerce(z16.number().int().positive().optional())
6409
6516
  },
6410
6517
  async (params) => {
6411
6518
  const cwd = params._cwd ?? process.cwd();
@@ -6425,7 +6532,7 @@ var _checksums = /* @__PURE__ */ new Map([
6425
6532
  ],
6426
6533
  [
6427
6534
  "stackwright-pro-auth-otter.json",
6428
- "69fa03c5532ef617c86fe7af41e8174c168d282baf602b1b269a7e933ea86b7c"
6535
+ "eee511fa214203ce88d51996c6b1b483b6ad3a0ae474cc7be5d380fdbbc43bb1"
6429
6536
  ],
6430
6537
  [
6431
6538
  "stackwright-pro-dashboard-otter.json",
@@ -6461,7 +6568,7 @@ var _checksums = /* @__PURE__ */ new Map([
6461
6568
  ],
6462
6569
  [
6463
6570
  "stackwright-pro-polish-otter.json",
6464
- "fd8f8963266c6179eebf8eac4f656e8274aa3a721e5296abdbde5b00ad8a2297"
6571
+ "4b8223d89af7f92b9051fee7bb29fc4b1ee2a5a9ab87e8e67a6d8be6122fa029"
6465
6572
  ],
6466
6573
  [
6467
6574
  "stackwright-pro-qa-otter.json",
@@ -6694,7 +6801,7 @@ function registerIntegrityTools(server2) {
6694
6801
  }
6695
6802
 
6696
6803
  // src/tools/domain.ts
6697
- import { z as z16 } from "zod";
6804
+ import { z as z17 } from "zod";
6698
6805
  import { readFileSync as readFileSync11, existsSync as existsSync10 } from "fs";
6699
6806
  import { join as join11 } from "path";
6700
6807
  function handleListCollections(input) {
@@ -7080,7 +7187,7 @@ function registerDomainTools(server2) {
7080
7187
  "stackwright_pro_resolve_data_strategy",
7081
7188
  "Look up the data freshness strategy configuration from the user's answer. Returns mechanism, revalidation seconds, required packages, and the exact MCP tool call to make. Replaces the strategy table in the data-otter prompt.",
7082
7189
  {
7083
- strategy: z16.string().describe(
7190
+ strategy: z17.string().describe(
7084
7191
  'The data-1 answer value: "pulse-fast", "isr-fast", "isr-standard", or "isr-slow"'
7085
7192
  )
7086
7193
  },
@@ -7090,7 +7197,7 @@ function registerDomainTools(server2) {
7090
7197
  "stackwright_pro_validate_workflow",
7091
7198
  "Validate a workflow definition against the Stackwright workflow schema. Checks step ID uniqueness, transition targets, terminal state existence, and service references. Call this after the workflow otter produces output.",
7092
7199
  {
7093
- workflow: jsonCoerce(z16.record(z16.string(), z16.unknown()).optional()).describe(
7200
+ workflow: jsonCoerce(z17.record(z17.string(), z17.unknown()).optional()).describe(
7094
7201
  "Parsed workflow object. If omitted, reads from .stackwright/artifacts/workflow-config.json"
7095
7202
  )
7096
7203
  },
@@ -7099,7 +7206,7 @@ function registerDomainTools(server2) {
7099
7206
  }
7100
7207
 
7101
7208
  // src/tools/type-schemas.ts
7102
- import { z as z17 } from "zod";
7209
+ import { z as z18 } from "zod";
7103
7210
  function buildTypeSchemaSummary() {
7104
7211
  return {
7105
7212
  version: "1.0",
@@ -7176,7 +7283,7 @@ function registerTypeSchemasTool(server2) {
7176
7283
  "stackwright_pro_get_type_schemas",
7177
7284
  "Returns a structured summary of all canonical @stackwright-pro/types schemas, organized by domain. Use this to determine which otter owns a given schema and what artifact key to expect.",
7178
7285
  {
7179
- format: z17.enum(["full", "domains-only"]).optional().default("full").describe("full = complete summary with all fields; domains-only = just domain names")
7286
+ format: z18.enum(["full", "domains-only"]).optional().default("full").describe("full = complete summary with all fields; domains-only = just domain names")
7180
7287
  },
7181
7288
  async ({ format }) => {
7182
7289
  const summary = buildTypeSchemaSummary();
@@ -7192,7 +7299,7 @@ function registerTypeSchemasTool(server2) {
7192
7299
  import * as fs2 from "fs";
7193
7300
  import * as os from "os";
7194
7301
  import * as path3 from "path";
7195
- import { z as z18 } from "zod";
7302
+ import { z as z19 } from "zod";
7196
7303
  import { load as yamlLoad3, dump as yamlDump } from "js-yaml";
7197
7304
  import { writePage, resolvePagesDir } from "@stackwright/cli";
7198
7305
  import { isProContentType, isOssTypeWithProExtension } from "@stackwright-pro/types";
@@ -7304,10 +7411,10 @@ function registerProPageTools(server2) {
7304
7411
  "stackwright_pro_write_page",
7305
7412
  "Write or update a page's YAML content with Pro content-type awareness. Validates against the Stackwright schema (including Pro types like stats_grid, data_table_pulse, map_pulse, alert_banner). Invalid YAML or schema violations on OSS-type fields are rejected with field-level errors. Use this instead of stackwright_write_page for any page containing Pro content types.",
7306
7413
  {
7307
- projectRoot: z18.string().describe("Absolute path to the Stackwright project root"),
7308
- slug: z18.string().describe('Page slug (e.g. "dashboard/main" or "/dashboard/main")'),
7309
- content: z18.string().describe("Full YAML content for the page (content.yml contents)"),
7310
- locale: z18.string().optional().describe(
7414
+ projectRoot: z19.string().describe("Absolute path to the Stackwright project root"),
7415
+ slug: z19.string().describe('Page slug (e.g. "dashboard/main" or "/dashboard/main")'),
7416
+ content: z19.string().describe("Full YAML content for the page (content.yml contents)"),
7417
+ locale: z19.string().optional().describe(
7311
7418
  'BCP 47 locale tag (e.g. "fr", "de"). If provided, writes content.<locale>.yml instead of content.yml.'
7312
7419
  )
7313
7420
  },
@@ -7566,7 +7673,7 @@ function registerScaffoldCleanupTools(server2) {
7566
7673
  }
7567
7674
 
7568
7675
  // src/tools/contrast.ts
7569
- import { z as z19 } from "zod";
7676
+ import { z as z20 } from "zod";
7570
7677
  function linearizeChannel(c255) {
7571
7678
  const c = c255 / 255;
7572
7679
  return c <= 0.04045 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
@@ -7738,8 +7845,8 @@ function registerContrastTools(server2) {
7738
7845
  "stackwright_pro_check_contrast",
7739
7846
  'Compute the exact WCAG 2.1 contrast ratio between a foreground and background color. Returns the ratio and AA/AAA pass/fail flags. Use this to verify any foreground/background color pair before writing it to the token set. Accepts #RGB, #RRGGBB, hsl(...), or shadcn HSL format ("H S% L%").',
7740
7847
  {
7741
- fg: z19.string().describe("Foreground (text) color \u2014 hex or HSL"),
7742
- bg: z19.string().describe("Background color \u2014 hex or HSL")
7848
+ fg: z20.string().describe("Foreground (text) color \u2014 hex or HSL"),
7849
+ bg: z20.string().describe("Background color \u2014 hex or HSL")
7743
7850
  },
7744
7851
  async ({ fg, bg }) => {
7745
7852
  let result;
@@ -7769,8 +7876,8 @@ function registerContrastTools(server2) {
7769
7876
  "stackwright_pro_derive_accessible_palette",
7770
7877
  'Given a seed color (treated as a background), derive the best accessible foreground (text) color that meets the target contrast ratio. Evaluates #ffffff and #000000 against the seed and picks whichever satisfies the target ratio with the highest contrast. Use this for every {name}-foreground token derivation instead of guessing white vs black. Accepts #RGB, #RRGGBB, hsl(...), or shadcn HSL format ("H S% L%").',
7771
7878
  {
7772
- seed: z19.string().describe("Background (seed) color \u2014 hex or HSL"),
7773
- targetRatio: numCoerce(z19.number().default(4.5)).describe(
7879
+ seed: z20.string().describe("Background (seed) color \u2014 hex or HSL"),
7880
+ targetRatio: numCoerce(z20.number().default(4.5)).describe(
7774
7881
  "Minimum required contrast ratio (default 4.5 for WCAG AA)"
7775
7882
  )
7776
7883
  },
@@ -7805,7 +7912,7 @@ function registerContrastTools(server2) {
7805
7912
  }
7806
7913
 
7807
7914
  // src/tools/compile.ts
7808
- import { z as z20 } from "zod";
7915
+ import { z as z21 } from "zod";
7809
7916
  import fs3 from "fs";
7810
7917
  import path4 from "path";
7811
7918
  import { compileCollections } from "@stackwright-pro/pulse/server";
@@ -7851,7 +7958,7 @@ async function tryOssCompile(fn, ctx, extra) {
7851
7958
  }
7852
7959
  }
7853
7960
  function registerCompileTools(server2) {
7854
- const projectRootArg = z20.string().optional().describe("Absolute path to project root (defaults to cwd)");
7961
+ const projectRootArg = z21.string().optional().describe("Absolute path to project root (defaults to cwd)");
7855
7962
  server2.tool(
7856
7963
  "stackwright_pro_compile_collections",
7857
7964
  "Compile stackwright.collections.yml \u2192 public/stackwright-content/_collections.json. Reads and validates the live-collections sidecar config file and emits the JSON sink consumed at runtime by PulseCollectionProvider.",
@@ -8027,7 +8134,7 @@ ${results.join("\n")}`;
8027
8134
  "stackwright_pro_compile_page",
8028
8135
  "Compile a single page by slug. Delegates to compilePage from @stackwright/build-scripts installed in the project.",
8029
8136
  {
8030
- slug: z20.string().describe('Page slug (relative path under pages/, e.g. "dashboard")'),
8137
+ slug: z21.string().describe('Page slug (relative path under pages/, e.g. "dashboard")'),
8031
8138
  projectRoot: projectRootArg
8032
8139
  },
8033
8140
  async ({ slug, projectRoot }) => {
@@ -8047,7 +8154,7 @@ ${results.join("\n")}`;
8047
8154
  }
8048
8155
 
8049
8156
  // src/tools/strip-legacy-integrations.ts
8050
- import { z as z21 } from "zod";
8157
+ import { z as z22 } from "zod";
8051
8158
  import { existsSync as existsSync13, readFileSync as readFileSync13, writeFileSync as writeFileSync9 } from "fs";
8052
8159
  import { join as join14 } from "path";
8053
8160
  function handleStripLegacyIntegrations(input) {
@@ -8110,7 +8217,7 @@ function registerStripLegacyIntegrationsTool(server2) {
8110
8217
  "stackwright_pro_strip_legacy_integrations",
8111
8218
  "Removes the deprecated top-level integrations[] block from stackwright.yml. The authoritative source for integration config is stackwright.integrations.yml \u2014 this tool cleans up legacy entries from older raft runs. Idempotent: no-op if no legacy block present. Preserves all other top-level keys, comments, and formatting.",
8112
8219
  {
8113
- projectRoot: z21.string().describe("Absolute path to the project root directory")
8220
+ projectRoot: z22.string().describe("Absolute path to the project root directory")
8114
8221
  },
8115
8222
  async ({ projectRoot }) => {
8116
8223
  const result = handleStripLegacyIntegrations({ projectRoot });
@@ -8122,7 +8229,7 @@ function registerStripLegacyIntegrationsTool(server2) {
8122
8229
  }
8123
8230
 
8124
8231
  // src/tools/emitters.ts
8125
- import { z as z22 } from "zod";
8232
+ import { z as z23 } from "zod";
8126
8233
  import { readFileSync as readFileSync14, existsSync as existsSync14, readdirSync as readdirSync8 } from "fs";
8127
8234
  import { join as join15 } from "path";
8128
8235
  import yaml from "js-yaml";
@@ -8181,7 +8288,7 @@ Call this tool, then write both files with stackwright_pro_safe_write:
8181
8288
 
8182
8289
  Do NOT compose the contents by hand. This emitter is the source of truth. If an env var is missing, update integrations.yml or the emitter \u2014 not the file. This is the first concrete instance of the swp-zf9y deterministic emitter pattern. ${ENV_LOCAL_DESC}`,
8183
8290
  {
8184
- cwd: z22.string().describe(
8291
+ cwd: z23.string().describe(
8185
8292
  "Absolute path to the project root containing stackwright.integrations.yml and optionally services/*.yml"
8186
8293
  )
8187
8294
  },
@@ -8228,8 +8335,8 @@ mapProvider options:
8228
8335
 
8229
8336
  This is the second concrete instance of the swp-zf9y deterministic emitter pattern. Refs: swp-57ku, swp-2m89, swp-zf9y, drawer 957. ${PROVIDERS_DESC}`,
8230
8337
  {
8231
- cwd: z22.string().describe("Absolute path to the project root containing stackwright.integrations.yml"),
8232
- mapProvider: z22.enum(["maplibre", "cesium", "none"]).optional().describe(
8338
+ cwd: z23.string().describe("Absolute path to the project root containing stackwright.integrations.yml"),
8339
+ mapProvider: z23.enum(["maplibre", "cesium", "none"]).optional().describe(
8233
8340
  "Map provider to register (default: cesium for Pro \u2014 3D globe + terrain). Use maplibre for OSS-style 2D dashboards (explicit opt-out). Use none if pages have no map content_items."
8234
8341
  )
8235
8342
  },
@@ -8270,7 +8377,7 @@ Workflow:
8270
8377
 
8271
8378
  This is the third concrete instance of the swp-zf9y deterministic emitter pattern. Refs: swp-phkh, swp-zf9y. ${PORTS_DESC}`,
8272
8379
  {
8273
- cwd: z22.string().describe("Absolute path to the project root containing stackwright.integrations.yml")
8380
+ cwd: z23.string().describe("Absolute path to the project root containing stackwright.integrations.yml")
8274
8381
  },
8275
8382
  async ({ cwd }) => {
8276
8383
  const integrations = readIntegrations(cwd);
@@ -8299,7 +8406,7 @@ This is the third concrete instance of the swp-zf9y deterministic emitter patter
8299
8406
  }
8300
8407
 
8301
8408
  // src/tools/list-specs.ts
8302
- import { z as z23 } from "zod";
8409
+ import { z as z24 } from "zod";
8303
8410
  import { readdirSync as readdirSync9, readFileSync as readFileSync15, statSync as statSync2, existsSync as existsSync15 } from "fs";
8304
8411
  import { join as join16, extname, basename as basename2 } from "path";
8305
8412
  var STRIP_SUFFIXES = ["-openapi", "-asyncapi", "-api", "-spec"];
@@ -8364,7 +8471,7 @@ function registerListSpecsTool(server2) {
8364
8471
  "stackwright_pro_list_specs",
8365
8472
  "Enumerate OpenAPI/AsyncAPI specs in the project's specs/ directory. Returns one entry per spec with integration name (derived from filename), detected format, and size. Used by the foreman to fan out the api phase with one api-otter invocation per spec.",
8366
8473
  {
8367
- projectRoot: z23.string().describe("Absolute path to the project root directory")
8474
+ projectRoot: z24.string().describe("Absolute path to the project root directory")
8368
8475
  },
8369
8476
  async ({ projectRoot }) => {
8370
8477
  const result = handleListSpecs({ projectRoot });
@@ -8376,7 +8483,7 @@ function registerListSpecsTool(server2) {
8376
8483
  }
8377
8484
 
8378
8485
  // src/tools/consolidate-integrations.ts
8379
- import { z as z24 } from "zod";
8486
+ import { z as z25 } from "zod";
8380
8487
  import { readdirSync as readdirSync10, readFileSync as readFileSync16, writeFileSync as writeFileSync10, existsSync as existsSync16, mkdirSync as mkdirSync9 } from "fs";
8381
8488
  import { lockSync as lockSync2 } from "proper-lockfile";
8382
8489
  import { join as join17, basename as basename3 } from "path";
@@ -8497,7 +8604,7 @@ function registerConsolidateIntegrationsTool(server2) {
8497
8604
  "no per-spec artifacts are found."
8498
8605
  ].join(" "),
8499
8606
  {
8500
- projectRoot: z24.string().describe("Absolute path to the project root directory")
8607
+ projectRoot: z25.string().describe("Absolute path to the project root directory")
8501
8608
  },
8502
8609
  async ({ projectRoot }) => {
8503
8610
  try {
@@ -8555,7 +8662,7 @@ var package_default = {
8555
8662
  "test:coverage": "vitest run --coverage"
8556
8663
  },
8557
8664
  name: "@stackwright-pro/mcp",
8558
- version: "0.2.0-alpha.109",
8665
+ version: "0.2.0-alpha.111",
8559
8666
  description: "MCP tools for Stackwright Pro - Data Explorer, Security, ISR, and Dashboard generation",
8560
8667
  license: "SEE LICENSE IN LICENSE",
8561
8668
  main: "./dist/server.js",
@@ -8624,6 +8731,7 @@ registerOrchestrationTools(server);
8624
8731
  registerPipelineTools(server);
8625
8732
  registerSafeWriteTools(server);
8626
8733
  registerAuthTools(server);
8734
+ registerReadAuthManifestsTool(server);
8627
8735
  registerIntegrityTools(server);
8628
8736
  registerArtifactSigningTools(server);
8629
8737
  registerDomainTools(server);