@stackwright-pro/mcp 0.2.0-alpha.108 → 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/integrity.js +3 -3
- package/dist/integrity.js.map +1 -1
- package/dist/integrity.mjs +3 -3
- package/dist/integrity.mjs.map +1 -1
- package/dist/pipeline-constants.js +24 -21
- package/dist/pipeline-constants.js.map +1 -1
- package/dist/pipeline-constants.mjs +24 -21
- package/dist/pipeline-constants.mjs.map +1 -1
- package/dist/server.js +293 -160
- package/dist/server.js.map +1 -1
- package/dist/server.mjs +293 -160
- package/dist/server.mjs.map +1 -1
- package/package.json +6 -6
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
|
|
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
|
|
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
|
|
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 =
|
|
2811
|
-
() =>
|
|
2812
|
-
label:
|
|
2813
|
-
href:
|
|
2814
|
-
children:
|
|
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 =
|
|
2818
|
-
section:
|
|
2819
|
-
items:
|
|
2922
|
+
var NavigationSectionSchema = z12.object({
|
|
2923
|
+
section: z12.string().min(1),
|
|
2924
|
+
items: z12.array(NavigationLinkSchema)
|
|
2820
2925
|
});
|
|
2821
|
-
var NavigationItemSchema =
|
|
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:
|
|
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:
|
|
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 =
|
|
2939
|
-
() =>
|
|
2940
|
-
label:
|
|
2941
|
-
href:
|
|
2942
|
-
children:
|
|
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 =
|
|
2946
|
-
section:
|
|
2947
|
-
items:
|
|
3050
|
+
var NavigationSectionSchema2 = z13.object({
|
|
3051
|
+
section: z13.string().min(1),
|
|
3052
|
+
items: z13.array(NavigationLinkSchema2)
|
|
2948
3053
|
});
|
|
2949
|
-
var NavigationItemSchema2 =
|
|
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 =
|
|
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:
|
|
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
|
},
|
|
@@ -4428,6 +4533,31 @@ function _validateArtifactInner(input) {
|
|
|
4428
4533
|
}
|
|
4429
4534
|
}
|
|
4430
4535
|
const PHASE_ZOD_VALIDATORS = {
|
|
4536
|
+
// 5.0 Theme defaultColorMode hygiene (swp-0ryn / swp-mw97)
|
|
4537
|
+
//
|
|
4538
|
+
// DHL raft runs produced `defaultColorMode: "auto"` (not a valid value) and
|
|
4539
|
+
// `defaultColorMode: "dark"` when the designer said "respect OS preference".
|
|
4540
|
+
// This validator catches the `auto` literal at write-time so the otter
|
|
4541
|
+
// self-corrects before the artifact lands on disk.
|
|
4542
|
+
//
|
|
4543
|
+
// Valid values: 'light' | 'dark' | 'system'
|
|
4544
|
+
// Omitting the key entirely is also valid (app shell honors prefers-color-scheme).
|
|
4545
|
+
theme: (artifact2) => {
|
|
4546
|
+
const dcm = artifact2["defaultColorMode"];
|
|
4547
|
+
if (dcm === void 0 || dcm === null) {
|
|
4548
|
+
return { success: true };
|
|
4549
|
+
}
|
|
4550
|
+
const VALID_COLOR_MODES = ["light", "dark", "system"];
|
|
4551
|
+
if (!VALID_COLOR_MODES.includes(dcm)) {
|
|
4552
|
+
return {
|
|
4553
|
+
success: false,
|
|
4554
|
+
error: {
|
|
4555
|
+
message: `theme-tokens.json: \`defaultColorMode: "${String(dcm)}"\` is not a valid value. Valid values are \`light\`, \`dark\`, or \`system\`. Use \`system\` for OS-following behavior (respects \`prefers-color-scheme\`). Alternatively, OMIT the \`defaultColorMode\` key entirely when the designer has specified in design-language.json operationalNotes that OS preference should be respected (trigger phrases: "respect OS preference", "no forced default").`
|
|
4556
|
+
}
|
|
4557
|
+
};
|
|
4558
|
+
}
|
|
4559
|
+
return { success: true };
|
|
4560
|
+
},
|
|
4431
4561
|
workflow: (artifact2) => {
|
|
4432
4562
|
const workflowData = artifact2["workflow"];
|
|
4433
4563
|
if (!workflowData) {
|
|
@@ -4787,28 +4917,28 @@ function registerPipelineTools(server2) {
|
|
|
4787
4917
|
"stackwright_pro_set_pipeline_state",
|
|
4788
4918
|
`Atomic read\u2192modify\u2192write pipeline state. ${DESC}`,
|
|
4789
4919
|
{
|
|
4790
|
-
phase:
|
|
4791
|
-
field:
|
|
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"),
|
|
4792
4922
|
// inFlight: set true BEFORE specialist invoke (dataflow mode, swp-ioc7); false after.
|
|
4793
|
-
value: boolCoerce(
|
|
4923
|
+
value: boolCoerce(z14.boolean().optional()).describe(
|
|
4794
4924
|
'Value for the field \u2014 must be a JSON boolean (true/false), NOT the string "true"/"false"'
|
|
4795
4925
|
),
|
|
4796
|
-
status:
|
|
4797
|
-
incrementRetry: boolCoerce(
|
|
4926
|
+
status: z14.enum(["setup", "questions", "execution", "done"]).optional().describe("Top-level status override"),
|
|
4927
|
+
incrementRetry: boolCoerce(z14.boolean().optional()).describe(
|
|
4798
4928
|
"Bump retryCount by 1 \u2014 must be a JSON boolean"
|
|
4799
4929
|
),
|
|
4800
4930
|
updates: jsonCoerce(
|
|
4801
|
-
|
|
4802
|
-
|
|
4803
|
-
phase:
|
|
4804
|
-
field:
|
|
4931
|
+
z14.array(
|
|
4932
|
+
z14.object({
|
|
4933
|
+
phase: z14.string(),
|
|
4934
|
+
field: z14.enum([
|
|
4805
4935
|
"questionsCollected",
|
|
4806
4936
|
"answered",
|
|
4807
4937
|
"executed",
|
|
4808
4938
|
"artifactWritten",
|
|
4809
4939
|
"inFlight"
|
|
4810
4940
|
]),
|
|
4811
|
-
value:
|
|
4941
|
+
value: z14.boolean()
|
|
4812
4942
|
})
|
|
4813
4943
|
).optional()
|
|
4814
4944
|
).describe("Batch updates \u2014 apply multiple field changes in one atomic read\u2192modify\u2192write")
|
|
@@ -4828,7 +4958,7 @@ function registerPipelineTools(server2) {
|
|
|
4828
4958
|
"stackwright_pro_check_execution_ready",
|
|
4829
4959
|
`Check all phases have answer files in .stackwright/answers/. If phase is provided, check only that phase. ${DESC}`,
|
|
4830
4960
|
{
|
|
4831
|
-
phase:
|
|
4961
|
+
phase: z14.string().optional().describe("If provided, check only this phase's readiness. Omit to check all phases.")
|
|
4832
4962
|
},
|
|
4833
4963
|
async ({ phase }) => res(handleCheckExecutionReady(void 0, phase))
|
|
4834
4964
|
);
|
|
@@ -4848,9 +4978,9 @@ function registerPipelineTools(server2) {
|
|
|
4848
4978
|
"stackwright_pro_write_phase_questions",
|
|
4849
4979
|
`Parse otter question-collection response \u2192 .stackwright/questions/{phase}.json. Specialists may also call this directly with a parsed questions array. ${DESC}`,
|
|
4850
4980
|
{
|
|
4851
|
-
phase:
|
|
4852
|
-
responseText:
|
|
4853
|
-
questions: jsonCoerce(
|
|
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(
|
|
4854
4984
|
"Questions array for direct specialist write"
|
|
4855
4985
|
)
|
|
4856
4986
|
},
|
|
@@ -4892,22 +5022,22 @@ function registerPipelineTools(server2) {
|
|
|
4892
5022
|
server2.tool(
|
|
4893
5023
|
"stackwright_pro_build_specialist_prompt",
|
|
4894
5024
|
`Assemble execution prompt from answers + upstream artifacts. Foreman passes verbatim. ${DESC}`,
|
|
4895
|
-
{ phase:
|
|
5025
|
+
{ phase: z14.string().describe('Phase to build prompt for, e.g. "pages"') },
|
|
4896
5026
|
async ({ phase }) => res(handleBuildSpecialistPrompt({ phase }))
|
|
4897
5027
|
);
|
|
4898
5028
|
server2.tool(
|
|
4899
5029
|
"stackwright_pro_validate_artifact",
|
|
4900
5030
|
`Validate and write artifact to .stackwright/artifacts/. Returns retryPrompt on failure. ${DESC}`,
|
|
4901
5031
|
{
|
|
4902
|
-
phase:
|
|
4903
|
-
responseText:
|
|
4904
|
-
artifact: jsonCoerce(
|
|
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(
|
|
4905
5035
|
"Artifact object to validate and write directly (specialist direct path \u2014 skips off-script detection and JSON parsing)"
|
|
4906
5036
|
),
|
|
4907
|
-
integrationName:
|
|
5037
|
+
integrationName: z14.string().optional().describe(
|
|
4908
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).'
|
|
4909
5039
|
),
|
|
4910
|
-
workflowName:
|
|
5040
|
+
workflowName: z14.string().optional().describe(
|
|
4911
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.`
|
|
4912
5042
|
)
|
|
4913
5043
|
},
|
|
@@ -4936,7 +5066,7 @@ function registerPipelineTools(server2) {
|
|
|
4936
5066
|
"stackwright_pro_emit_event",
|
|
4937
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}`,
|
|
4938
5068
|
{
|
|
4939
|
-
type:
|
|
5069
|
+
type: z14.enum([
|
|
4940
5070
|
"phase_start",
|
|
4941
5071
|
"phase_complete",
|
|
4942
5072
|
"phase_ready",
|
|
@@ -4945,20 +5075,20 @@ function registerPipelineTools(server2) {
|
|
|
4945
5075
|
]).describe("Event type to emit"),
|
|
4946
5076
|
// phase_ready: emitted in dataflow mode (swp-ioc7) when a phase enters the ready set
|
|
4947
5077
|
// (deps satisfied, not inFlight, not yet complete) — BEFORE invoking the specialist.
|
|
4948
|
-
phase:
|
|
4949
|
-
targetOtter:
|
|
4950
|
-
success: boolCoerce(
|
|
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(
|
|
4951
5081
|
'For agent_invoke_complete: did the invocation succeed? (boolean; string "true"/"false" also accepted for caller tolerance)'
|
|
4952
5082
|
),
|
|
4953
|
-
otter:
|
|
4954
|
-
durationSec:
|
|
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)")
|
|
4955
5085
|
},
|
|
4956
5086
|
async ({ type, phase, targetOtter, success, otter, durationSec }) => res(handleEmitEvent({ type, phase, targetOtter, success, otter, durationSec }))
|
|
4957
5087
|
);
|
|
4958
5088
|
}
|
|
4959
5089
|
|
|
4960
5090
|
// src/tools/safe-write.ts
|
|
4961
|
-
import { z as
|
|
5091
|
+
import { z as z15 } from "zod";
|
|
4962
5092
|
import { writeFileSync as writeFileSync5, readFileSync as readFileSync8, existsSync as existsSync8, mkdirSync as mkdirSync5, lstatSync as lstatSync7 } from "fs";
|
|
4963
5093
|
import { normalize, isAbsolute, dirname, join as join8 } from "path";
|
|
4964
5094
|
import { emit as emit2 } from "@stackwright-pro/telemetry";
|
|
@@ -5454,10 +5584,10 @@ function registerSafeWriteTools(server2) {
|
|
|
5454
5584
|
"stackwright_pro_safe_write",
|
|
5455
5585
|
DESC,
|
|
5456
5586
|
{
|
|
5457
|
-
callerOtter:
|
|
5458
|
-
filePath:
|
|
5459
|
-
content:
|
|
5460
|
-
createDirectories: boolCoerce(
|
|
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(
|
|
5461
5591
|
"Create parent directories if they don't exist. Default: true"
|
|
5462
5592
|
)
|
|
5463
5593
|
},
|
|
@@ -5474,9 +5604,12 @@ function registerSafeWriteTools(server2) {
|
|
|
5474
5604
|
}
|
|
5475
5605
|
|
|
5476
5606
|
// src/tools/auth.ts
|
|
5477
|
-
import { z as
|
|
5607
|
+
import { z as z16 } from "zod";
|
|
5478
5608
|
import { readFileSync as readFileSync9, writeFileSync as writeFileSync6, existsSync as existsSync9, mkdirSync as mkdirSync6 } from "fs";
|
|
5479
5609
|
import { join as join9 } from "path";
|
|
5610
|
+
function normalizeProviderSlug(slug) {
|
|
5611
|
+
return slug.replace(/-/g, "_");
|
|
5612
|
+
}
|
|
5480
5613
|
function buildHierarchy(roles) {
|
|
5481
5614
|
const h = {};
|
|
5482
5615
|
for (let i = 0; i < roles.length - 1; i++) {
|
|
@@ -5731,13 +5864,12 @@ ${hierarchyToYaml(hierarchy, " ")}`;
|
|
|
5731
5864
|
const ocspEndpoint = params.cacOcspEndpoint ?? "https://ocsp.disa.mil";
|
|
5732
5865
|
const certHeader = params.cacCertHeader ?? "X-SSL-Client-Cert";
|
|
5733
5866
|
return `# stackwright.auth.yml \u2014 generated by Auth Otter
|
|
5734
|
-
|
|
5735
|
-
${
|
|
5736
|
-
|
|
5737
|
-
|
|
5738
|
-
|
|
5739
|
-
|
|
5740
|
-
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}
|
|
5741
5873
|
${rbacSection}
|
|
5742
5874
|
protectedRoutes:
|
|
5743
5875
|
${routeLines}
|
|
@@ -5748,14 +5880,13 @@ ${auditSection}
|
|
|
5748
5880
|
const scopes2 = params.oidcScopes ?? "openid profile email";
|
|
5749
5881
|
const roleClaim = params.oidcRoleClaim ?? "roles";
|
|
5750
5882
|
return `# stackwright.auth.yml \u2014 generated by Auth Otter
|
|
5751
|
-
|
|
5883
|
+
type: oidc
|
|
5752
5884
|
${providerLine}${useProxy ? "proxy" : "middleware"}: ./${useProxy ? "proxy" : "middleware"}.ts
|
|
5753
|
-
|
|
5754
|
-
|
|
5755
|
-
|
|
5756
|
-
|
|
5757
|
-
|
|
5758
|
-
roleClaim: ${roleClaim}
|
|
5885
|
+
discoveryUrl: \${OIDC_DISCOVERY_URL}
|
|
5886
|
+
clientId: \${OIDC_CLIENT_ID}
|
|
5887
|
+
clientSecret: \${OIDC_CLIENT_SECRET}
|
|
5888
|
+
scopes: ${scopes2}
|
|
5889
|
+
roleClaim: ${roleClaim}
|
|
5759
5890
|
${rbacSection}
|
|
5760
5891
|
protectedRoutes:
|
|
5761
5892
|
${routeLines}
|
|
@@ -5764,14 +5895,13 @@ ${auditSection}
|
|
|
5764
5895
|
}
|
|
5765
5896
|
const scopes = params.oauth2Scopes ?? "read write";
|
|
5766
5897
|
return `# stackwright.auth.yml \u2014 generated by Auth Otter
|
|
5767
|
-
|
|
5898
|
+
type: oauth2
|
|
5768
5899
|
${providerLine}${useProxy ? "proxy" : "middleware"}: ./${useProxy ? "proxy" : "middleware"}.ts
|
|
5769
|
-
|
|
5770
|
-
|
|
5771
|
-
|
|
5772
|
-
|
|
5773
|
-
|
|
5774
|
-
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}
|
|
5775
5905
|
${rbacSection}
|
|
5776
5906
|
protectedRoutes:
|
|
5777
5907
|
${routeLines}
|
|
@@ -5978,14 +6108,13 @@ ${hierarchyToYaml(hierarchy, " ")}`;
|
|
|
5978
6108
|
const ocspEndpoint = params.cacOcspEndpoint ?? "https://ocsp.disa.mil";
|
|
5979
6109
|
const certHeader = params.cacCertHeader ?? "X-SSL-Client-Cert";
|
|
5980
6110
|
return `# stackwright.auth.yml \u2014 generated by Auth Otter
|
|
5981
|
-
|
|
6111
|
+
type: pki
|
|
5982
6112
|
devOnly: true
|
|
5983
|
-
${
|
|
5984
|
-
|
|
5985
|
-
|
|
5986
|
-
|
|
5987
|
-
|
|
5988
|
-
certHeader: ${certHeader}
|
|
6113
|
+
${useProxy ? "proxy" : "middleware"}: ./${useProxy ? "proxy" : "middleware"}.ts
|
|
6114
|
+
caBundle: ${caBundle}
|
|
6115
|
+
edipiLookup: ${edipiLookup}
|
|
6116
|
+
ocspEndpoint: ${ocspEndpoint}
|
|
6117
|
+
certHeader: ${certHeader}
|
|
5989
6118
|
${rbacSection}
|
|
5990
6119
|
protectedRoutes:
|
|
5991
6120
|
${routeLines}
|
|
@@ -5996,15 +6125,14 @@ ${auditSection}
|
|
|
5996
6125
|
const scopes2 = params.oidcScopes ?? "openid profile email";
|
|
5997
6126
|
const roleClaim = params.oidcRoleClaim ?? "roles";
|
|
5998
6127
|
return `# stackwright.auth.yml \u2014 generated by Auth Otter
|
|
5999
|
-
|
|
6128
|
+
type: oidc
|
|
6000
6129
|
devOnly: true
|
|
6001
6130
|
${providerLine}${useProxy ? "proxy" : "middleware"}: ./${useProxy ? "proxy" : "middleware"}.ts
|
|
6002
|
-
oidc
|
|
6003
|
-
|
|
6004
|
-
|
|
6005
|
-
|
|
6006
|
-
|
|
6007
|
-
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}
|
|
6008
6136
|
${rbacSection}
|
|
6009
6137
|
protectedRoutes:
|
|
6010
6138
|
${routeLines}
|
|
@@ -6013,15 +6141,14 @@ ${auditSection}
|
|
|
6013
6141
|
}
|
|
6014
6142
|
const scopes = params.oauth2Scopes ?? "read write";
|
|
6015
6143
|
return `# stackwright.auth.yml \u2014 generated by Auth Otter
|
|
6016
|
-
|
|
6144
|
+
type: oauth2
|
|
6017
6145
|
devOnly: true
|
|
6018
6146
|
${providerLine}${useProxy ? "proxy" : "middleware"}: ./${useProxy ? "proxy" : "middleware"}.ts
|
|
6019
|
-
oauth2
|
|
6020
|
-
|
|
6021
|
-
|
|
6022
|
-
|
|
6023
|
-
|
|
6024
|
-
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}
|
|
6025
6152
|
${rbacSection}
|
|
6026
6153
|
protectedRoutes:
|
|
6027
6154
|
${routeLines}
|
|
@@ -6091,6 +6218,10 @@ function updatePackageJsonScripts(existingJson, roles, mockUsers) {
|
|
|
6091
6218
|
return JSON.stringify(pkg, null, 2) + "\n";
|
|
6092
6219
|
}
|
|
6093
6220
|
async function configureAuthHandler(params, cwd) {
|
|
6221
|
+
params = {
|
|
6222
|
+
...params,
|
|
6223
|
+
provider: params.provider != null ? normalizeProviderSlug(params.provider) : void 0
|
|
6224
|
+
};
|
|
6094
6225
|
const {
|
|
6095
6226
|
method,
|
|
6096
6227
|
provider,
|
|
@@ -6342,45 +6473,46 @@ function registerAuthTools(server2) {
|
|
|
6342
6473
|
"stackwright_pro_configure_auth",
|
|
6343
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.",
|
|
6344
6475
|
{
|
|
6345
|
-
method:
|
|
6346
|
-
|
|
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(),
|
|
6347
6479
|
// CAC
|
|
6348
|
-
cacCaBundle:
|
|
6349
|
-
cacEdipiLookup:
|
|
6350
|
-
cacOcspEndpoint:
|
|
6351
|
-
cacCertHeader:
|
|
6480
|
+
cacCaBundle: z16.string().optional(),
|
|
6481
|
+
cacEdipiLookup: z16.string().optional(),
|
|
6482
|
+
cacOcspEndpoint: z16.string().optional(),
|
|
6483
|
+
cacCertHeader: z16.string().optional(),
|
|
6352
6484
|
// OIDC
|
|
6353
|
-
oidcDiscoveryUrl:
|
|
6354
|
-
oidcClientId:
|
|
6355
|
-
oidcClientSecret:
|
|
6356
|
-
oidcScopes:
|
|
6357
|
-
oidcRoleClaim:
|
|
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(),
|
|
6358
6490
|
// OAuth2
|
|
6359
|
-
oauth2AuthUrl:
|
|
6360
|
-
oauth2TokenUrl:
|
|
6361
|
-
oauth2ClientId:
|
|
6362
|
-
oauth2ClientSecret:
|
|
6363
|
-
oauth2Scopes:
|
|
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(),
|
|
6364
6496
|
// RBAC
|
|
6365
|
-
rbacRoles: jsonCoerce(
|
|
6366
|
-
rbacDefaultRole:
|
|
6497
|
+
rbacRoles: jsonCoerce(z16.array(z16.string()).optional()),
|
|
6498
|
+
rbacDefaultRole: z16.string().optional(),
|
|
6367
6499
|
// Audit
|
|
6368
|
-
auditEnabled: boolCoerce(
|
|
6369
|
-
auditRetentionDays: numCoerce(
|
|
6500
|
+
auditEnabled: boolCoerce(z16.boolean().optional()),
|
|
6501
|
+
auditRetentionDays: numCoerce(z16.number().int().positive().optional()),
|
|
6370
6502
|
// Routes — accepts bare strings (backward-compat) or per-route objects (swp-owu0)
|
|
6371
6503
|
protectedRoutes: jsonCoerce(
|
|
6372
|
-
|
|
6373
|
-
|
|
6374
|
-
|
|
6375
|
-
|
|
6504
|
+
z16.array(
|
|
6505
|
+
z16.union([
|
|
6506
|
+
z16.string(),
|
|
6507
|
+
z16.object({ pattern: z16.string(), requiredRole: z16.string().optional() })
|
|
6376
6508
|
])
|
|
6377
6509
|
).optional()
|
|
6378
6510
|
),
|
|
6379
6511
|
// Injection for tests
|
|
6380
|
-
_cwd:
|
|
6381
|
-
devOnly: boolCoerce(
|
|
6382
|
-
mockUsers: jsonCoerce(
|
|
6383
|
-
nextMajorVersion: numCoerce(
|
|
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())
|
|
6384
6516
|
},
|
|
6385
6517
|
async (params) => {
|
|
6386
6518
|
const cwd = params._cwd ?? process.cwd();
|
|
@@ -6400,7 +6532,7 @@ var _checksums = /* @__PURE__ */ new Map([
|
|
|
6400
6532
|
],
|
|
6401
6533
|
[
|
|
6402
6534
|
"stackwright-pro-auth-otter.json",
|
|
6403
|
-
"
|
|
6535
|
+
"eee511fa214203ce88d51996c6b1b483b6ad3a0ae474cc7be5d380fdbbc43bb1"
|
|
6404
6536
|
],
|
|
6405
6537
|
[
|
|
6406
6538
|
"stackwright-pro-dashboard-otter.json",
|
|
@@ -6436,7 +6568,7 @@ var _checksums = /* @__PURE__ */ new Map([
|
|
|
6436
6568
|
],
|
|
6437
6569
|
[
|
|
6438
6570
|
"stackwright-pro-polish-otter.json",
|
|
6439
|
-
"
|
|
6571
|
+
"4b8223d89af7f92b9051fee7bb29fc4b1ee2a5a9ab87e8e67a6d8be6122fa029"
|
|
6440
6572
|
],
|
|
6441
6573
|
[
|
|
6442
6574
|
"stackwright-pro-qa-otter.json",
|
|
@@ -6448,7 +6580,7 @@ var _checksums = /* @__PURE__ */ new Map([
|
|
|
6448
6580
|
],
|
|
6449
6581
|
[
|
|
6450
6582
|
"stackwright-pro-theme-otter.json",
|
|
6451
|
-
"
|
|
6583
|
+
"afb47f8381907145c0e098bdcaae4dd9f5c4ff825a8e88d00a218d2f6858820b"
|
|
6452
6584
|
],
|
|
6453
6585
|
[
|
|
6454
6586
|
"stackwright-services-otter.json",
|
|
@@ -6669,7 +6801,7 @@ function registerIntegrityTools(server2) {
|
|
|
6669
6801
|
}
|
|
6670
6802
|
|
|
6671
6803
|
// src/tools/domain.ts
|
|
6672
|
-
import { z as
|
|
6804
|
+
import { z as z17 } from "zod";
|
|
6673
6805
|
import { readFileSync as readFileSync11, existsSync as existsSync10 } from "fs";
|
|
6674
6806
|
import { join as join11 } from "path";
|
|
6675
6807
|
function handleListCollections(input) {
|
|
@@ -7055,7 +7187,7 @@ function registerDomainTools(server2) {
|
|
|
7055
7187
|
"stackwright_pro_resolve_data_strategy",
|
|
7056
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.",
|
|
7057
7189
|
{
|
|
7058
|
-
strategy:
|
|
7190
|
+
strategy: z17.string().describe(
|
|
7059
7191
|
'The data-1 answer value: "pulse-fast", "isr-fast", "isr-standard", or "isr-slow"'
|
|
7060
7192
|
)
|
|
7061
7193
|
},
|
|
@@ -7065,7 +7197,7 @@ function registerDomainTools(server2) {
|
|
|
7065
7197
|
"stackwright_pro_validate_workflow",
|
|
7066
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.",
|
|
7067
7199
|
{
|
|
7068
|
-
workflow: jsonCoerce(
|
|
7200
|
+
workflow: jsonCoerce(z17.record(z17.string(), z17.unknown()).optional()).describe(
|
|
7069
7201
|
"Parsed workflow object. If omitted, reads from .stackwright/artifacts/workflow-config.json"
|
|
7070
7202
|
)
|
|
7071
7203
|
},
|
|
@@ -7074,7 +7206,7 @@ function registerDomainTools(server2) {
|
|
|
7074
7206
|
}
|
|
7075
7207
|
|
|
7076
7208
|
// src/tools/type-schemas.ts
|
|
7077
|
-
import { z as
|
|
7209
|
+
import { z as z18 } from "zod";
|
|
7078
7210
|
function buildTypeSchemaSummary() {
|
|
7079
7211
|
return {
|
|
7080
7212
|
version: "1.0",
|
|
@@ -7151,7 +7283,7 @@ function registerTypeSchemasTool(server2) {
|
|
|
7151
7283
|
"stackwright_pro_get_type_schemas",
|
|
7152
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.",
|
|
7153
7285
|
{
|
|
7154
|
-
format:
|
|
7286
|
+
format: z18.enum(["full", "domains-only"]).optional().default("full").describe("full = complete summary with all fields; domains-only = just domain names")
|
|
7155
7287
|
},
|
|
7156
7288
|
async ({ format }) => {
|
|
7157
7289
|
const summary = buildTypeSchemaSummary();
|
|
@@ -7167,7 +7299,7 @@ function registerTypeSchemasTool(server2) {
|
|
|
7167
7299
|
import * as fs2 from "fs";
|
|
7168
7300
|
import * as os from "os";
|
|
7169
7301
|
import * as path3 from "path";
|
|
7170
|
-
import { z as
|
|
7302
|
+
import { z as z19 } from "zod";
|
|
7171
7303
|
import { load as yamlLoad3, dump as yamlDump } from "js-yaml";
|
|
7172
7304
|
import { writePage, resolvePagesDir } from "@stackwright/cli";
|
|
7173
7305
|
import { isProContentType, isOssTypeWithProExtension } from "@stackwright-pro/types";
|
|
@@ -7279,10 +7411,10 @@ function registerProPageTools(server2) {
|
|
|
7279
7411
|
"stackwright_pro_write_page",
|
|
7280
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.",
|
|
7281
7413
|
{
|
|
7282
|
-
projectRoot:
|
|
7283
|
-
slug:
|
|
7284
|
-
content:
|
|
7285
|
-
locale:
|
|
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(
|
|
7286
7418
|
'BCP 47 locale tag (e.g. "fr", "de"). If provided, writes content.<locale>.yml instead of content.yml.'
|
|
7287
7419
|
)
|
|
7288
7420
|
},
|
|
@@ -7541,7 +7673,7 @@ function registerScaffoldCleanupTools(server2) {
|
|
|
7541
7673
|
}
|
|
7542
7674
|
|
|
7543
7675
|
// src/tools/contrast.ts
|
|
7544
|
-
import { z as
|
|
7676
|
+
import { z as z20 } from "zod";
|
|
7545
7677
|
function linearizeChannel(c255) {
|
|
7546
7678
|
const c = c255 / 255;
|
|
7547
7679
|
return c <= 0.04045 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
|
|
@@ -7713,8 +7845,8 @@ function registerContrastTools(server2) {
|
|
|
7713
7845
|
"stackwright_pro_check_contrast",
|
|
7714
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%").',
|
|
7715
7847
|
{
|
|
7716
|
-
fg:
|
|
7717
|
-
bg:
|
|
7848
|
+
fg: z20.string().describe("Foreground (text) color \u2014 hex or HSL"),
|
|
7849
|
+
bg: z20.string().describe("Background color \u2014 hex or HSL")
|
|
7718
7850
|
},
|
|
7719
7851
|
async ({ fg, bg }) => {
|
|
7720
7852
|
let result;
|
|
@@ -7744,8 +7876,8 @@ function registerContrastTools(server2) {
|
|
|
7744
7876
|
"stackwright_pro_derive_accessible_palette",
|
|
7745
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%").',
|
|
7746
7878
|
{
|
|
7747
|
-
seed:
|
|
7748
|
-
targetRatio: numCoerce(
|
|
7879
|
+
seed: z20.string().describe("Background (seed) color \u2014 hex or HSL"),
|
|
7880
|
+
targetRatio: numCoerce(z20.number().default(4.5)).describe(
|
|
7749
7881
|
"Minimum required contrast ratio (default 4.5 for WCAG AA)"
|
|
7750
7882
|
)
|
|
7751
7883
|
},
|
|
@@ -7780,7 +7912,7 @@ function registerContrastTools(server2) {
|
|
|
7780
7912
|
}
|
|
7781
7913
|
|
|
7782
7914
|
// src/tools/compile.ts
|
|
7783
|
-
import { z as
|
|
7915
|
+
import { z as z21 } from "zod";
|
|
7784
7916
|
import fs3 from "fs";
|
|
7785
7917
|
import path4 from "path";
|
|
7786
7918
|
import { compileCollections } from "@stackwright-pro/pulse/server";
|
|
@@ -7826,7 +7958,7 @@ async function tryOssCompile(fn, ctx, extra) {
|
|
|
7826
7958
|
}
|
|
7827
7959
|
}
|
|
7828
7960
|
function registerCompileTools(server2) {
|
|
7829
|
-
const projectRootArg =
|
|
7961
|
+
const projectRootArg = z21.string().optional().describe("Absolute path to project root (defaults to cwd)");
|
|
7830
7962
|
server2.tool(
|
|
7831
7963
|
"stackwright_pro_compile_collections",
|
|
7832
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.",
|
|
@@ -8002,7 +8134,7 @@ ${results.join("\n")}`;
|
|
|
8002
8134
|
"stackwright_pro_compile_page",
|
|
8003
8135
|
"Compile a single page by slug. Delegates to compilePage from @stackwright/build-scripts installed in the project.",
|
|
8004
8136
|
{
|
|
8005
|
-
slug:
|
|
8137
|
+
slug: z21.string().describe('Page slug (relative path under pages/, e.g. "dashboard")'),
|
|
8006
8138
|
projectRoot: projectRootArg
|
|
8007
8139
|
},
|
|
8008
8140
|
async ({ slug, projectRoot }) => {
|
|
@@ -8022,7 +8154,7 @@ ${results.join("\n")}`;
|
|
|
8022
8154
|
}
|
|
8023
8155
|
|
|
8024
8156
|
// src/tools/strip-legacy-integrations.ts
|
|
8025
|
-
import { z as
|
|
8157
|
+
import { z as z22 } from "zod";
|
|
8026
8158
|
import { existsSync as existsSync13, readFileSync as readFileSync13, writeFileSync as writeFileSync9 } from "fs";
|
|
8027
8159
|
import { join as join14 } from "path";
|
|
8028
8160
|
function handleStripLegacyIntegrations(input) {
|
|
@@ -8085,7 +8217,7 @@ function registerStripLegacyIntegrationsTool(server2) {
|
|
|
8085
8217
|
"stackwright_pro_strip_legacy_integrations",
|
|
8086
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.",
|
|
8087
8219
|
{
|
|
8088
|
-
projectRoot:
|
|
8220
|
+
projectRoot: z22.string().describe("Absolute path to the project root directory")
|
|
8089
8221
|
},
|
|
8090
8222
|
async ({ projectRoot }) => {
|
|
8091
8223
|
const result = handleStripLegacyIntegrations({ projectRoot });
|
|
@@ -8097,7 +8229,7 @@ function registerStripLegacyIntegrationsTool(server2) {
|
|
|
8097
8229
|
}
|
|
8098
8230
|
|
|
8099
8231
|
// src/tools/emitters.ts
|
|
8100
|
-
import { z as
|
|
8232
|
+
import { z as z23 } from "zod";
|
|
8101
8233
|
import { readFileSync as readFileSync14, existsSync as existsSync14, readdirSync as readdirSync8 } from "fs";
|
|
8102
8234
|
import { join as join15 } from "path";
|
|
8103
8235
|
import yaml from "js-yaml";
|
|
@@ -8156,7 +8288,7 @@ Call this tool, then write both files with stackwright_pro_safe_write:
|
|
|
8156
8288
|
|
|
8157
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}`,
|
|
8158
8290
|
{
|
|
8159
|
-
cwd:
|
|
8291
|
+
cwd: z23.string().describe(
|
|
8160
8292
|
"Absolute path to the project root containing stackwright.integrations.yml and optionally services/*.yml"
|
|
8161
8293
|
)
|
|
8162
8294
|
},
|
|
@@ -8203,8 +8335,8 @@ mapProvider options:
|
|
|
8203
8335
|
|
|
8204
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}`,
|
|
8205
8337
|
{
|
|
8206
|
-
cwd:
|
|
8207
|
-
mapProvider:
|
|
8338
|
+
cwd: z23.string().describe("Absolute path to the project root containing stackwright.integrations.yml"),
|
|
8339
|
+
mapProvider: z23.enum(["maplibre", "cesium", "none"]).optional().describe(
|
|
8208
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."
|
|
8209
8341
|
)
|
|
8210
8342
|
},
|
|
@@ -8245,7 +8377,7 @@ Workflow:
|
|
|
8245
8377
|
|
|
8246
8378
|
This is the third concrete instance of the swp-zf9y deterministic emitter pattern. Refs: swp-phkh, swp-zf9y. ${PORTS_DESC}`,
|
|
8247
8379
|
{
|
|
8248
|
-
cwd:
|
|
8380
|
+
cwd: z23.string().describe("Absolute path to the project root containing stackwright.integrations.yml")
|
|
8249
8381
|
},
|
|
8250
8382
|
async ({ cwd }) => {
|
|
8251
8383
|
const integrations = readIntegrations(cwd);
|
|
@@ -8274,7 +8406,7 @@ This is the third concrete instance of the swp-zf9y deterministic emitter patter
|
|
|
8274
8406
|
}
|
|
8275
8407
|
|
|
8276
8408
|
// src/tools/list-specs.ts
|
|
8277
|
-
import { z as
|
|
8409
|
+
import { z as z24 } from "zod";
|
|
8278
8410
|
import { readdirSync as readdirSync9, readFileSync as readFileSync15, statSync as statSync2, existsSync as existsSync15 } from "fs";
|
|
8279
8411
|
import { join as join16, extname, basename as basename2 } from "path";
|
|
8280
8412
|
var STRIP_SUFFIXES = ["-openapi", "-asyncapi", "-api", "-spec"];
|
|
@@ -8339,7 +8471,7 @@ function registerListSpecsTool(server2) {
|
|
|
8339
8471
|
"stackwright_pro_list_specs",
|
|
8340
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.",
|
|
8341
8473
|
{
|
|
8342
|
-
projectRoot:
|
|
8474
|
+
projectRoot: z24.string().describe("Absolute path to the project root directory")
|
|
8343
8475
|
},
|
|
8344
8476
|
async ({ projectRoot }) => {
|
|
8345
8477
|
const result = handleListSpecs({ projectRoot });
|
|
@@ -8351,7 +8483,7 @@ function registerListSpecsTool(server2) {
|
|
|
8351
8483
|
}
|
|
8352
8484
|
|
|
8353
8485
|
// src/tools/consolidate-integrations.ts
|
|
8354
|
-
import { z as
|
|
8486
|
+
import { z as z25 } from "zod";
|
|
8355
8487
|
import { readdirSync as readdirSync10, readFileSync as readFileSync16, writeFileSync as writeFileSync10, existsSync as existsSync16, mkdirSync as mkdirSync9 } from "fs";
|
|
8356
8488
|
import { lockSync as lockSync2 } from "proper-lockfile";
|
|
8357
8489
|
import { join as join17, basename as basename3 } from "path";
|
|
@@ -8472,7 +8604,7 @@ function registerConsolidateIntegrationsTool(server2) {
|
|
|
8472
8604
|
"no per-spec artifacts are found."
|
|
8473
8605
|
].join(" "),
|
|
8474
8606
|
{
|
|
8475
|
-
projectRoot:
|
|
8607
|
+
projectRoot: z25.string().describe("Absolute path to the project root directory")
|
|
8476
8608
|
},
|
|
8477
8609
|
async ({ projectRoot }) => {
|
|
8478
8610
|
try {
|
|
@@ -8530,7 +8662,7 @@ var package_default = {
|
|
|
8530
8662
|
"test:coverage": "vitest run --coverage"
|
|
8531
8663
|
},
|
|
8532
8664
|
name: "@stackwright-pro/mcp",
|
|
8533
|
-
version: "0.2.0-alpha.
|
|
8665
|
+
version: "0.2.0-alpha.111",
|
|
8534
8666
|
description: "MCP tools for Stackwright Pro - Data Explorer, Security, ISR, and Dashboard generation",
|
|
8535
8667
|
license: "SEE LICENSE IN LICENSE",
|
|
8536
8668
|
main: "./dist/server.js",
|
|
@@ -8599,6 +8731,7 @@ registerOrchestrationTools(server);
|
|
|
8599
8731
|
registerPipelineTools(server);
|
|
8600
8732
|
registerSafeWriteTools(server);
|
|
8601
8733
|
registerAuthTools(server);
|
|
8734
|
+
registerReadAuthManifestsTool(server);
|
|
8602
8735
|
registerIntegrityTools(server);
|
|
8603
8736
|
registerArtifactSigningTools(server);
|
|
8604
8737
|
registerDomainTools(server);
|