@stackwright-pro/mcp 0.2.0-alpha.109 → 0.2.0-alpha.112
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 +41 -21
- package/dist/pipeline-constants.js.map +1 -1
- package/dist/pipeline-constants.mjs +41 -21
- package/dist/pipeline-constants.mjs.map +1 -1
- package/dist/server.js +322 -182
- package/dist/server.js.map +1 -1
- package/dist/server.mjs +322 -182
- package/dist/server.mjs.map +1 -1
- package/package.json +7 -7
package/dist/server.js
CHANGED
|
@@ -873,6 +873,9 @@ var BASELINE_DEPS = {
|
|
|
873
873
|
"@stackwright-pro/openapi": "latest",
|
|
874
874
|
"@stackwright-pro/auth": "latest",
|
|
875
875
|
"@stackwright-pro/auth-nextjs": "latest",
|
|
876
|
+
// SBOM compliance — every Pro raft is a compliance product (swp-ryqz)
|
|
877
|
+
"@stackwright-pro/sbom-enterprise": "latest",
|
|
878
|
+
"@stackwright/sbom-generator": "^0.2.2",
|
|
876
879
|
zod: "^3.23.0"
|
|
877
880
|
};
|
|
878
881
|
var BASELINE_DEV_DEPS = {
|
|
@@ -2026,7 +2029,7 @@ function registerOrchestrationTools(server2) {
|
|
|
2026
2029
|
}
|
|
2027
2030
|
|
|
2028
2031
|
// src/tools/pipeline.ts
|
|
2029
|
-
var
|
|
2032
|
+
var import_zod14 = require("zod");
|
|
2030
2033
|
var import_fs8 = require("fs");
|
|
2031
2034
|
var import_proper_lockfile = require("proper-lockfile");
|
|
2032
2035
|
var import_path8 = require("path");
|
|
@@ -2750,6 +2753,19 @@ function validateAuthConfig(artifact, artifactPath) {
|
|
|
2750
2753
|
// src/tools/auth-manifest-aggregator.ts
|
|
2751
2754
|
var import_fs6 = require("fs");
|
|
2752
2755
|
var import_path6 = require("path");
|
|
2756
|
+
var import_zod11 = require("zod");
|
|
2757
|
+
function computeLowestRole(requiredRoles, rbacRoles) {
|
|
2758
|
+
let lowestIndex = -1;
|
|
2759
|
+
let lowestRole = requiredRoles[0];
|
|
2760
|
+
for (const role of requiredRoles) {
|
|
2761
|
+
const idx = rbacRoles.indexOf(role);
|
|
2762
|
+
if (idx > lowestIndex) {
|
|
2763
|
+
lowestIndex = idx;
|
|
2764
|
+
lowestRole = role;
|
|
2765
|
+
}
|
|
2766
|
+
}
|
|
2767
|
+
return lowestRole;
|
|
2768
|
+
}
|
|
2753
2769
|
function extractPatternBaseSlug(pattern) {
|
|
2754
2770
|
const stripped = pattern.replace(/^\//, "");
|
|
2755
2771
|
if (!stripped) return null;
|
|
@@ -2783,16 +2799,105 @@ function extractManifestSlugs(artifactsDir) {
|
|
|
2783
2799
|
}
|
|
2784
2800
|
return slugs;
|
|
2785
2801
|
}
|
|
2802
|
+
function normalizeNextJsSlug(slug) {
|
|
2803
|
+
return slug.replace(/\[\[\.\.\.([\w]+)\]\]/g, ":$1*").replace(/\[\.\.\.([\w]+)\]/g, ":$1*").replace(/\[([\w]+)\]/g, ":$1");
|
|
2804
|
+
}
|
|
2805
|
+
function deriveProtectedRoutes(pages, rbacRoles) {
|
|
2806
|
+
const protectedRoutes = [];
|
|
2807
|
+
const uncoveredSlugs = [];
|
|
2808
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2809
|
+
for (const page of pages) {
|
|
2810
|
+
if (seen.has(page.slug)) continue;
|
|
2811
|
+
seen.add(page.slug);
|
|
2812
|
+
if (page.authRequired === false) continue;
|
|
2813
|
+
if (page.authRequired === true && Array.isArray(page.requiredRoles) && page.requiredRoles.length > 0) {
|
|
2814
|
+
const normalizedSlug = normalizeNextJsSlug(page.slug);
|
|
2815
|
+
const lowestRole = computeLowestRole(page.requiredRoles, rbacRoles);
|
|
2816
|
+
protectedRoutes.push({ pattern: `/${normalizedSlug}`, requiredRole: lowestRole });
|
|
2817
|
+
if (!normalizedSlug.endsWith("*")) {
|
|
2818
|
+
protectedRoutes.push({ pattern: `/${normalizedSlug}/:path*`, requiredRole: lowestRole });
|
|
2819
|
+
}
|
|
2820
|
+
continue;
|
|
2821
|
+
}
|
|
2822
|
+
const reason = page.authRequired === true ? "authRequired: true but requiredRoles is missing or empty" : "page emitter did not declare authRequired + requiredRoles";
|
|
2823
|
+
uncoveredSlugs.push({ source: page.source, slug: page.slug, reason });
|
|
2824
|
+
}
|
|
2825
|
+
return { protectedRoutes, uncoveredSlugs };
|
|
2826
|
+
}
|
|
2827
|
+
function readAllManifestPages(artifactsDir) {
|
|
2828
|
+
const allPages = [];
|
|
2829
|
+
if (!(0, import_fs6.existsSync)(artifactsDir)) return allPages;
|
|
2830
|
+
let entries;
|
|
2831
|
+
try {
|
|
2832
|
+
entries = (0, import_fs6.readdirSync)(artifactsDir);
|
|
2833
|
+
} catch {
|
|
2834
|
+
return allPages;
|
|
2835
|
+
}
|
|
2836
|
+
for (const entry of entries) {
|
|
2837
|
+
if (!entry.endsWith("-manifest.json")) continue;
|
|
2838
|
+
const filePath = (0, import_path6.join)(artifactsDir, entry);
|
|
2839
|
+
try {
|
|
2840
|
+
const raw = JSON.parse((0, import_fs6.readFileSync)(filePath, "utf-8"));
|
|
2841
|
+
if (!Array.isArray(raw.pages)) continue;
|
|
2842
|
+
for (const page of raw.pages) {
|
|
2843
|
+
if (typeof page.slug !== "string" || !page.slug) continue;
|
|
2844
|
+
allPages.push({
|
|
2845
|
+
slug: page.slug,
|
|
2846
|
+
authRequired: page.authRequired,
|
|
2847
|
+
requiredRoles: page.requiredRoles,
|
|
2848
|
+
source: entry
|
|
2849
|
+
});
|
|
2850
|
+
}
|
|
2851
|
+
} catch {
|
|
2852
|
+
}
|
|
2853
|
+
}
|
|
2854
|
+
return allPages;
|
|
2855
|
+
}
|
|
2856
|
+
function registerReadAuthManifestsTool(server2) {
|
|
2857
|
+
server2.tool(
|
|
2858
|
+
"stackwright_pro_read_auth_manifests",
|
|
2859
|
+
"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.",
|
|
2860
|
+
{
|
|
2861
|
+
rbacRoles: import_zod11.z.array(import_zod11.z.string()).describe(
|
|
2862
|
+
'RBAC role hierarchy in descending privilege order, e.g. ["ESF8_COORDINATOR", "HOSPITAL_EM", "OBSERVER"]. Used to compute the lowestRole for each authRequired page.'
|
|
2863
|
+
),
|
|
2864
|
+
artifactsDir: import_zod11.z.string().optional().describe(
|
|
2865
|
+
"Absolute or relative path to the pipeline artifacts directory. Defaults to .stackwright/artifacts relative to cwd."
|
|
2866
|
+
)
|
|
2867
|
+
},
|
|
2868
|
+
(params) => {
|
|
2869
|
+
const cwd = process.cwd();
|
|
2870
|
+
const artifactsDir = params.artifactsDir ? params.artifactsDir : (0, import_path6.join)(cwd, ".stackwright", "artifacts");
|
|
2871
|
+
const allPages = readAllManifestPages(artifactsDir);
|
|
2872
|
+
const { protectedRoutes, uncoveredSlugs } = deriveProtectedRoutes(allPages, params.rbacRoles);
|
|
2873
|
+
const manifestsRead = [...new Set(allPages.map((p) => p.source))].sort();
|
|
2874
|
+
const result = {
|
|
2875
|
+
protectedRoutes,
|
|
2876
|
+
uncoveredSlugs,
|
|
2877
|
+
manifestsRead,
|
|
2878
|
+
summary: {
|
|
2879
|
+
totalPages: allPages.length,
|
|
2880
|
+
protectedCount: protectedRoutes.length,
|
|
2881
|
+
uncoveredCount: uncoveredSlugs.length,
|
|
2882
|
+
artifactsDir
|
|
2883
|
+
}
|
|
2884
|
+
};
|
|
2885
|
+
return {
|
|
2886
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
2887
|
+
};
|
|
2888
|
+
}
|
|
2889
|
+
);
|
|
2890
|
+
}
|
|
2786
2891
|
|
|
2787
2892
|
// src/tools/pipeline.ts
|
|
2788
2893
|
var import_types3 = require("@stackwright-pro/types");
|
|
2789
2894
|
|
|
2790
2895
|
// src/tools/get-schema.ts
|
|
2791
|
-
var
|
|
2896
|
+
var import_zod13 = require("zod");
|
|
2792
2897
|
var import_types2 = require("@stackwright-pro/types");
|
|
2793
2898
|
|
|
2794
2899
|
// src/tools/validate-yaml-fragment.ts
|
|
2795
|
-
var
|
|
2900
|
+
var import_zod12 = require("zod");
|
|
2796
2901
|
var import_js_yaml2 = require("js-yaml");
|
|
2797
2902
|
var import_types = require("@stackwright-pro/types");
|
|
2798
2903
|
var SUPPORTED_SCHEMA_NAMES = [
|
|
@@ -2803,18 +2908,18 @@ var SUPPORTED_SCHEMA_NAMES = [
|
|
|
2803
2908
|
"navigation_item",
|
|
2804
2909
|
"auth_config"
|
|
2805
2910
|
];
|
|
2806
|
-
var NavigationLinkSchema =
|
|
2807
|
-
() =>
|
|
2808
|
-
label:
|
|
2809
|
-
href:
|
|
2810
|
-
children:
|
|
2911
|
+
var NavigationLinkSchema = import_zod12.z.lazy(
|
|
2912
|
+
() => import_zod12.z.object({
|
|
2913
|
+
label: import_zod12.z.string().min(1),
|
|
2914
|
+
href: import_zod12.z.string().min(1),
|
|
2915
|
+
children: import_zod12.z.array(NavigationLinkSchema).optional()
|
|
2811
2916
|
})
|
|
2812
2917
|
);
|
|
2813
|
-
var NavigationSectionSchema =
|
|
2814
|
-
section:
|
|
2815
|
-
items:
|
|
2918
|
+
var NavigationSectionSchema = import_zod12.z.object({
|
|
2919
|
+
section: import_zod12.z.string().min(1),
|
|
2920
|
+
items: import_zod12.z.array(NavigationLinkSchema)
|
|
2816
2921
|
});
|
|
2817
|
-
var NavigationItemSchema =
|
|
2922
|
+
var NavigationItemSchema = import_zod12.z.union([
|
|
2818
2923
|
NavigationLinkSchema,
|
|
2819
2924
|
NavigationSectionSchema
|
|
2820
2925
|
]);
|
|
@@ -2916,10 +3021,10 @@ function registerValidateYamlFragmentTool(server2) {
|
|
|
2916
3021
|
"stackwright_pro_validate_yaml_fragment",
|
|
2917
3022
|
'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.',
|
|
2918
3023
|
{
|
|
2919
|
-
schemaName:
|
|
3024
|
+
schemaName: import_zod12.z.enum(SUPPORTED_SCHEMA_NAMES).describe(
|
|
2920
3025
|
"Schema to validate against. One of: workflow_step, workflow_definition, workflow_field, workflow_action, navigation_item, auth_config"
|
|
2921
3026
|
),
|
|
2922
|
-
yaml:
|
|
3027
|
+
yaml: import_zod12.z.string().describe("YAML string to validate (can also be JSON \u2014 js-yaml parses both)")
|
|
2923
3028
|
},
|
|
2924
3029
|
async ({ schemaName, yaml: yaml3 }) => {
|
|
2925
3030
|
const result = handleValidateYamlFragment({ schemaName, yaml: yaml3 });
|
|
@@ -2931,18 +3036,18 @@ function registerValidateYamlFragmentTool(server2) {
|
|
|
2931
3036
|
}
|
|
2932
3037
|
|
|
2933
3038
|
// src/tools/get-schema.ts
|
|
2934
|
-
var NavigationLinkSchema2 =
|
|
2935
|
-
() =>
|
|
2936
|
-
label:
|
|
2937
|
-
href:
|
|
2938
|
-
children:
|
|
3039
|
+
var NavigationLinkSchema2 = import_zod13.z.lazy(
|
|
3040
|
+
() => import_zod13.z.object({
|
|
3041
|
+
label: import_zod13.z.string().min(1),
|
|
3042
|
+
href: import_zod13.z.string().min(1),
|
|
3043
|
+
children: import_zod13.z.array(NavigationLinkSchema2).optional()
|
|
2939
3044
|
})
|
|
2940
3045
|
);
|
|
2941
|
-
var NavigationSectionSchema2 =
|
|
2942
|
-
section:
|
|
2943
|
-
items:
|
|
3046
|
+
var NavigationSectionSchema2 = import_zod13.z.object({
|
|
3047
|
+
section: import_zod13.z.string().min(1),
|
|
3048
|
+
items: import_zod13.z.array(NavigationLinkSchema2)
|
|
2944
3049
|
});
|
|
2945
|
-
var NavigationItemSchema2 =
|
|
3050
|
+
var NavigationItemSchema2 = import_zod13.z.union([
|
|
2946
3051
|
NavigationLinkSchema2,
|
|
2947
3052
|
NavigationSectionSchema2
|
|
2948
3053
|
]);
|
|
@@ -3043,7 +3148,7 @@ function handleGetSchema(input) {
|
|
|
3043
3148
|
const synonyms = FIELD_SYNONYMS[name];
|
|
3044
3149
|
let jsonSchema;
|
|
3045
3150
|
try {
|
|
3046
|
-
const raw =
|
|
3151
|
+
const raw = import_zod13.z.toJSONSchema(schema, { unrepresentable: "any" });
|
|
3047
3152
|
jsonSchema = raw;
|
|
3048
3153
|
} catch {
|
|
3049
3154
|
jsonSchema = { type: "object", description: "Schema introspection unavailable for this type" };
|
|
@@ -3097,7 +3202,7 @@ function registerGetSchemaTool(server2) {
|
|
|
3097
3202
|
"stackwright_pro_get_schema",
|
|
3098
3203
|
'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.',
|
|
3099
3204
|
{
|
|
3100
|
-
schemaName:
|
|
3205
|
+
schemaName: import_zod13.z.enum(SUPPORTED_SCHEMA_NAMES).describe(
|
|
3101
3206
|
"Schema to summarize. One of: workflow_step, workflow_definition, workflow_field, workflow_action, navigation_item, auth_config"
|
|
3102
3207
|
)
|
|
3103
3208
|
},
|
|
@@ -3389,11 +3494,29 @@ var PHASE_TO_OTTER2 = {
|
|
|
3389
3494
|
geo: "stackwright-pro-geo-otter",
|
|
3390
3495
|
qa: "stackwright-pro-qa-otter"
|
|
3391
3496
|
};
|
|
3497
|
+
var PhaseStatusSchema = import_zod14.z.object({
|
|
3498
|
+
status: import_zod14.z.enum(["pending", "running", "completed", "skipped", "failed"]).default("pending"),
|
|
3499
|
+
questionsCollected: import_zod14.z.boolean().default(false),
|
|
3500
|
+
answered: import_zod14.z.boolean().default(false),
|
|
3501
|
+
executed: import_zod14.z.boolean().default(false),
|
|
3502
|
+
artifactWritten: import_zod14.z.boolean().default(false),
|
|
3503
|
+
retryCount: import_zod14.z.number().default(0),
|
|
3504
|
+
inFlight: import_zod14.z.boolean().default(false)
|
|
3505
|
+
});
|
|
3506
|
+
var PipelineStateSchema = import_zod14.z.object({
|
|
3507
|
+
version: import_zod14.z.literal("1.0"),
|
|
3508
|
+
currentPhase: import_zod14.z.string(),
|
|
3509
|
+
status: import_zod14.z.enum(["setup", "questions", "execution", "done"]),
|
|
3510
|
+
phases: import_zod14.z.record(import_zod14.z.string(), PhaseStatusSchema),
|
|
3511
|
+
startedAt: import_zod14.z.string(),
|
|
3512
|
+
updatedAt: import_zod14.z.string()
|
|
3513
|
+
});
|
|
3392
3514
|
function isValidPhase2(phase) {
|
|
3393
3515
|
return PHASE_ORDER.includes(phase);
|
|
3394
3516
|
}
|
|
3395
3517
|
function defaultPhaseStatus() {
|
|
3396
3518
|
return {
|
|
3519
|
+
status: "pending",
|
|
3397
3520
|
questionsCollected: false,
|
|
3398
3521
|
answered: false,
|
|
3399
3522
|
executed: false,
|
|
@@ -3424,10 +3547,9 @@ function readState(cwd) {
|
|
|
3424
3547
|
const p = statePath(cwd);
|
|
3425
3548
|
if (!(0, import_fs8.existsSync)(p)) return createDefaultState();
|
|
3426
3549
|
const raw = JSON.parse(safeReadSync(p));
|
|
3427
|
-
|
|
3428
|
-
|
|
3429
|
-
|
|
3430
|
-
return raw;
|
|
3550
|
+
const result = PipelineStateSchema.safeParse(raw);
|
|
3551
|
+
if (!result.success) return createDefaultState();
|
|
3552
|
+
return result.data;
|
|
3431
3553
|
}
|
|
3432
3554
|
function safeWriteSync(filePath, content) {
|
|
3433
3555
|
if ((0, import_fs8.existsSync)(filePath)) {
|
|
@@ -3516,13 +3638,16 @@ function handleSetPipelineState(input) {
|
|
|
3516
3638
|
isError: true
|
|
3517
3639
|
};
|
|
3518
3640
|
}
|
|
3519
|
-
|
|
3520
|
-
|
|
3521
|
-
|
|
3522
|
-
|
|
3523
|
-
|
|
3524
|
-
|
|
3525
|
-
|
|
3641
|
+
if (input.field === "artifactWritten") {
|
|
3642
|
+
return {
|
|
3643
|
+
text: JSON.stringify({
|
|
3644
|
+
error: true,
|
|
3645
|
+
message: "Cannot set 'artifactWritten' directly. Use stackwright_pro_validate_artifact instead \u2014 it verifies the file exists on disk before flagging."
|
|
3646
|
+
}),
|
|
3647
|
+
isError: true
|
|
3648
|
+
};
|
|
3649
|
+
}
|
|
3650
|
+
const VALID_FIELDS = ["questionsCollected", "answered", "executed", "inFlight"];
|
|
3526
3651
|
if (input.field && !VALID_FIELDS.includes(input.field)) {
|
|
3527
3652
|
return {
|
|
3528
3653
|
text: JSON.stringify({
|
|
@@ -3543,6 +3668,15 @@ function handleSetPipelineState(input) {
|
|
|
3543
3668
|
isError: true
|
|
3544
3669
|
};
|
|
3545
3670
|
}
|
|
3671
|
+
if (update.field === "artifactWritten") {
|
|
3672
|
+
return {
|
|
3673
|
+
text: JSON.stringify({
|
|
3674
|
+
error: true,
|
|
3675
|
+
message: "Cannot set 'artifactWritten' directly. Use stackwright_pro_validate_artifact instead \u2014 it verifies the file exists on disk before flagging."
|
|
3676
|
+
}),
|
|
3677
|
+
isError: true
|
|
3678
|
+
};
|
|
3679
|
+
}
|
|
3546
3680
|
if (!VALID_FIELDS.includes(update.field)) {
|
|
3547
3681
|
return {
|
|
3548
3682
|
text: JSON.stringify({
|
|
@@ -3568,6 +3702,9 @@ function handleSetPipelineState(input) {
|
|
|
3568
3702
|
if (input.field && input.value !== void 0) {
|
|
3569
3703
|
phaseState[input.field] = input.value;
|
|
3570
3704
|
}
|
|
3705
|
+
if (input.phaseStatus !== void 0) {
|
|
3706
|
+
phaseState.status = input.phaseStatus;
|
|
3707
|
+
}
|
|
3571
3708
|
if (input.incrementRetry) {
|
|
3572
3709
|
phaseState.retryCount += 1;
|
|
3573
3710
|
}
|
|
@@ -3594,16 +3731,6 @@ function handleSetPipelineState(input) {
|
|
|
3594
3731
|
},
|
|
3595
3732
|
{ cwd }
|
|
3596
3733
|
);
|
|
3597
|
-
if (input.field === "artifactWritten" && input.value === true && input.phase) {
|
|
3598
|
-
(0, import_telemetry.emit)({ type: "phase_complete", phase: input.phase }, { cwd });
|
|
3599
|
-
}
|
|
3600
|
-
if (input.updates) {
|
|
3601
|
-
for (const update of input.updates) {
|
|
3602
|
-
if (update.field === "artifactWritten" && update.value === true) {
|
|
3603
|
-
(0, import_telemetry.emit)({ type: "phase_complete", phase: update.phase }, { cwd });
|
|
3604
|
-
}
|
|
3605
|
-
}
|
|
3606
|
-
}
|
|
3607
3734
|
} catch {
|
|
3608
3735
|
}
|
|
3609
3736
|
return { text: JSON.stringify(state), isError: false };
|
|
@@ -4682,6 +4809,7 @@ function _validateArtifactInner(input) {
|
|
|
4682
4809
|
if (!state.phases[phase]) state.phases[phase] = defaultPhaseStatus();
|
|
4683
4810
|
const ps = state.phases[phase];
|
|
4684
4811
|
ps.artifactWritten = true;
|
|
4812
|
+
ps.status = "completed";
|
|
4685
4813
|
});
|
|
4686
4814
|
const topKeys = Object.keys(artifact).slice(0, 5).join(", ");
|
|
4687
4815
|
const result = {
|
|
@@ -4709,6 +4837,7 @@ function handleValidateArtifact(input) {
|
|
|
4709
4837
|
const parsed = JSON.parse(result.text);
|
|
4710
4838
|
if (parsed.valid === true && parsed.artifactPath) {
|
|
4711
4839
|
(0, import_telemetry.emit)({ type: "file_write", path: parsed.artifactPath, phase }, { cwd });
|
|
4840
|
+
(0, import_telemetry.emit)({ type: "phase_complete", phase }, { cwd });
|
|
4712
4841
|
}
|
|
4713
4842
|
(0, import_telemetry.emit)(
|
|
4714
4843
|
{
|
|
@@ -4808,28 +4937,35 @@ function registerPipelineTools(server2) {
|
|
|
4808
4937
|
"stackwright_pro_set_pipeline_state",
|
|
4809
4938
|
`Atomic read\u2192modify\u2192write pipeline state. ${DESC}`,
|
|
4810
4939
|
{
|
|
4811
|
-
phase:
|
|
4812
|
-
field:
|
|
4940
|
+
phase: import_zod14.z.string().optional().describe('Phase to update, e.g. "designer"'),
|
|
4941
|
+
field: import_zod14.z.enum(["questionsCollected", "answered", "executed", "inFlight"]).optional().describe(
|
|
4942
|
+
"Boolean field to set. NOTE: artifactWritten is intentionally absent \u2014 use stackwright_pro_validate_artifact instead (it verifies the file exists on disk before flagging)."
|
|
4943
|
+
),
|
|
4813
4944
|
// inFlight: set true BEFORE specialist invoke (dataflow mode, swp-ioc7); false after.
|
|
4814
|
-
value: boolCoerce(
|
|
4945
|
+
value: boolCoerce(import_zod14.z.boolean().optional()).describe(
|
|
4815
4946
|
'Value for the field \u2014 must be a JSON boolean (true/false), NOT the string "true"/"false"'
|
|
4816
4947
|
),
|
|
4817
|
-
|
|
4818
|
-
|
|
4948
|
+
// phaseStatus: per-phase execution enum — DISTINCT from top-level `status` (pipeline flow).
|
|
4949
|
+
// Named `phaseStatus` to avoid ambiguity. Sets PhaseStatus.status on the given phase.
|
|
4950
|
+
phaseStatus: import_zod14.z.enum(["pending", "running", "completed", "skipped", "failed"]).optional().describe(
|
|
4951
|
+
"Per-phase execution status (pending/running/completed/skipped/failed). Distinct from top-level `status` (pipeline flow). Use phaseStatus: 'skipped' when a specialist otter is unregistered."
|
|
4952
|
+
),
|
|
4953
|
+
status: import_zod14.z.enum(["setup", "questions", "execution", "done"]).optional().describe("Top-level pipeline flow status override \u2014 distinct from phaseStatus"),
|
|
4954
|
+
incrementRetry: boolCoerce(import_zod14.z.boolean().optional()).describe(
|
|
4819
4955
|
"Bump retryCount by 1 \u2014 must be a JSON boolean"
|
|
4820
4956
|
),
|
|
4821
4957
|
updates: jsonCoerce(
|
|
4822
|
-
|
|
4823
|
-
|
|
4824
|
-
phase:
|
|
4825
|
-
field:
|
|
4958
|
+
import_zod14.z.array(
|
|
4959
|
+
import_zod14.z.object({
|
|
4960
|
+
phase: import_zod14.z.string(),
|
|
4961
|
+
field: import_zod14.z.enum([
|
|
4826
4962
|
"questionsCollected",
|
|
4827
4963
|
"answered",
|
|
4828
4964
|
"executed",
|
|
4829
|
-
"artifactWritten",
|
|
4830
4965
|
"inFlight"
|
|
4966
|
+
// artifactWritten intentionally absent — use validate_artifact (swp-og9c)
|
|
4831
4967
|
]),
|
|
4832
|
-
value:
|
|
4968
|
+
value: import_zod14.z.boolean()
|
|
4833
4969
|
})
|
|
4834
4970
|
).optional()
|
|
4835
4971
|
).describe("Batch updates \u2014 apply multiple field changes in one atomic read\u2192modify\u2192write")
|
|
@@ -4839,6 +4975,7 @@ function registerPipelineTools(server2) {
|
|
|
4839
4975
|
...args.phase != null ? { phase: args.phase } : {},
|
|
4840
4976
|
...args.field != null ? { field: args.field } : {},
|
|
4841
4977
|
...args.value != null ? { value: args.value } : {},
|
|
4978
|
+
...args.phaseStatus != null ? { phaseStatus: args.phaseStatus } : {},
|
|
4842
4979
|
...args.status != null ? { status: args.status } : {},
|
|
4843
4980
|
...args.incrementRetry != null ? { incrementRetry: args.incrementRetry } : {},
|
|
4844
4981
|
...args.updates != null ? { updates: args.updates } : {}
|
|
@@ -4849,7 +4986,7 @@ function registerPipelineTools(server2) {
|
|
|
4849
4986
|
"stackwright_pro_check_execution_ready",
|
|
4850
4987
|
`Check all phases have answer files in .stackwright/answers/. If phase is provided, check only that phase. ${DESC}`,
|
|
4851
4988
|
{
|
|
4852
|
-
phase:
|
|
4989
|
+
phase: import_zod14.z.string().optional().describe("If provided, check only this phase's readiness. Omit to check all phases.")
|
|
4853
4990
|
},
|
|
4854
4991
|
async ({ phase }) => res(handleCheckExecutionReady(void 0, phase))
|
|
4855
4992
|
);
|
|
@@ -4869,9 +5006,9 @@ function registerPipelineTools(server2) {
|
|
|
4869
5006
|
"stackwright_pro_write_phase_questions",
|
|
4870
5007
|
`Parse otter question-collection response \u2192 .stackwright/questions/{phase}.json. Specialists may also call this directly with a parsed questions array. ${DESC}`,
|
|
4871
5008
|
{
|
|
4872
|
-
phase:
|
|
4873
|
-
responseText:
|
|
4874
|
-
questions: jsonCoerce(
|
|
5009
|
+
phase: import_zod14.z.string().optional().describe('Phase name, e.g. "designer" (required for direct write)'),
|
|
5010
|
+
responseText: import_zod14.z.string().optional().describe("Raw LLM response from QUESTION_COLLECTION_MODE"),
|
|
5011
|
+
questions: jsonCoerce(import_zod14.z.array(import_zod14.z.any()).optional()).describe(
|
|
4875
5012
|
"Questions array for direct specialist write"
|
|
4876
5013
|
)
|
|
4877
5014
|
},
|
|
@@ -4913,22 +5050,22 @@ function registerPipelineTools(server2) {
|
|
|
4913
5050
|
server2.tool(
|
|
4914
5051
|
"stackwright_pro_build_specialist_prompt",
|
|
4915
5052
|
`Assemble execution prompt from answers + upstream artifacts. Foreman passes verbatim. ${DESC}`,
|
|
4916
|
-
{ phase:
|
|
5053
|
+
{ phase: import_zod14.z.string().describe('Phase to build prompt for, e.g. "pages"') },
|
|
4917
5054
|
async ({ phase }) => res(handleBuildSpecialistPrompt({ phase }))
|
|
4918
5055
|
);
|
|
4919
5056
|
server2.tool(
|
|
4920
5057
|
"stackwright_pro_validate_artifact",
|
|
4921
5058
|
`Validate and write artifact to .stackwright/artifacts/. Returns retryPrompt on failure. ${DESC}`,
|
|
4922
5059
|
{
|
|
4923
|
-
phase:
|
|
4924
|
-
responseText:
|
|
4925
|
-
artifact: jsonCoerce(
|
|
5060
|
+
phase: import_zod14.z.string().describe('Phase that produced this artifact, e.g. "designer"'),
|
|
5061
|
+
responseText: import_zod14.z.string().optional().describe("Raw response text from the specialist otter (Foreman-mediated path, legacy)"),
|
|
5062
|
+
artifact: jsonCoerce(import_zod14.z.record(import_zod14.z.string(), import_zod14.z.unknown()).optional()).describe(
|
|
4926
5063
|
"Artifact object to validate and write directly (specialist direct path \u2014 skips off-script detection and JSON parsing)"
|
|
4927
5064
|
),
|
|
4928
|
-
integrationName:
|
|
5065
|
+
integrationName: import_zod14.z.string().optional().describe(
|
|
4929
5066
|
'When phase="api": write to api-config-<integrationName>.json instead of api-config.json. Enables concurrent per-spec fan-out without collision (swp-530y).'
|
|
4930
5067
|
),
|
|
4931
|
-
workflowName:
|
|
5068
|
+
workflowName: import_zod14.z.string().optional().describe(
|
|
4932
5069
|
`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.`
|
|
4933
5070
|
)
|
|
4934
5071
|
},
|
|
@@ -4957,7 +5094,7 @@ function registerPipelineTools(server2) {
|
|
|
4957
5094
|
"stackwright_pro_emit_event",
|
|
4958
5095
|
`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}`,
|
|
4959
5096
|
{
|
|
4960
|
-
type:
|
|
5097
|
+
type: import_zod14.z.enum([
|
|
4961
5098
|
"phase_start",
|
|
4962
5099
|
"phase_complete",
|
|
4963
5100
|
"phase_ready",
|
|
@@ -4966,20 +5103,20 @@ function registerPipelineTools(server2) {
|
|
|
4966
5103
|
]).describe("Event type to emit"),
|
|
4967
5104
|
// phase_ready: emitted in dataflow mode (swp-ioc7) when a phase enters the ready set
|
|
4968
5105
|
// (deps satisfied, not inFlight, not yet complete) — BEFORE invoking the specialist.
|
|
4969
|
-
phase:
|
|
4970
|
-
targetOtter:
|
|
4971
|
-
success: boolCoerce(
|
|
5106
|
+
phase: import_zod14.z.string().optional().describe("Current phase name"),
|
|
5107
|
+
targetOtter: import_zod14.z.string().optional().describe("For agent_invoke_* events: which otter is being invoked"),
|
|
5108
|
+
success: boolCoerce(import_zod14.z.boolean().optional()).describe(
|
|
4972
5109
|
'For agent_invoke_complete: did the invocation succeed? (boolean; string "true"/"false" also accepted for caller tolerance)'
|
|
4973
5110
|
),
|
|
4974
|
-
otter:
|
|
4975
|
-
durationSec:
|
|
5111
|
+
otter: import_zod14.z.string().optional().describe('Which otter is emitting (defaults to "foreman")'),
|
|
5112
|
+
durationSec: import_zod14.z.number().optional().describe("Duration in seconds (for *_complete events)")
|
|
4976
5113
|
},
|
|
4977
5114
|
async ({ type, phase, targetOtter, success, otter, durationSec }) => res(handleEmitEvent({ type, phase, targetOtter, success, otter, durationSec }))
|
|
4978
5115
|
);
|
|
4979
5116
|
}
|
|
4980
5117
|
|
|
4981
5118
|
// src/tools/safe-write.ts
|
|
4982
|
-
var
|
|
5119
|
+
var import_zod15 = require("zod");
|
|
4983
5120
|
var import_fs9 = require("fs");
|
|
4984
5121
|
var import_path9 = require("path");
|
|
4985
5122
|
var import_telemetry2 = require("@stackwright-pro/telemetry");
|
|
@@ -5475,10 +5612,10 @@ function registerSafeWriteTools(server2) {
|
|
|
5475
5612
|
"stackwright_pro_safe_write",
|
|
5476
5613
|
DESC,
|
|
5477
5614
|
{
|
|
5478
|
-
callerOtter:
|
|
5479
|
-
filePath:
|
|
5480
|
-
content:
|
|
5481
|
-
createDirectories: boolCoerce(
|
|
5615
|
+
callerOtter: import_zod15.z.string().describe('The otter agent name requesting the write, e.g. "stackwright-pro-page-otter"'),
|
|
5616
|
+
filePath: import_zod15.z.string().describe('Relative path from project root, e.g. "pages/dashboard/content.yml"'),
|
|
5617
|
+
content: import_zod15.z.string().describe("File content to write"),
|
|
5618
|
+
createDirectories: boolCoerce(import_zod15.z.boolean().optional().default(true)).describe(
|
|
5482
5619
|
"Create parent directories if they don't exist. Default: true"
|
|
5483
5620
|
)
|
|
5484
5621
|
},
|
|
@@ -5495,9 +5632,12 @@ function registerSafeWriteTools(server2) {
|
|
|
5495
5632
|
}
|
|
5496
5633
|
|
|
5497
5634
|
// src/tools/auth.ts
|
|
5498
|
-
var
|
|
5635
|
+
var import_zod16 = require("zod");
|
|
5499
5636
|
var import_fs10 = require("fs");
|
|
5500
5637
|
var import_path10 = require("path");
|
|
5638
|
+
function normalizeProviderSlug(slug) {
|
|
5639
|
+
return slug.replace(/-/g, "_");
|
|
5640
|
+
}
|
|
5501
5641
|
function buildHierarchy(roles) {
|
|
5502
5642
|
const h = {};
|
|
5503
5643
|
for (let i = 0; i < roles.length - 1; i++) {
|
|
@@ -5752,13 +5892,12 @@ ${hierarchyToYaml(hierarchy, " ")}`;
|
|
|
5752
5892
|
const ocspEndpoint = params.cacOcspEndpoint ?? "https://ocsp.disa.mil";
|
|
5753
5893
|
const certHeader = params.cacCertHeader ?? "X-SSL-Client-Cert";
|
|
5754
5894
|
return `# stackwright.auth.yml \u2014 generated by Auth Otter
|
|
5755
|
-
|
|
5756
|
-
${
|
|
5757
|
-
|
|
5758
|
-
|
|
5759
|
-
|
|
5760
|
-
|
|
5761
|
-
certHeader: ${certHeader}
|
|
5895
|
+
type: pki
|
|
5896
|
+
${useProxy ? "proxy" : "middleware"}: ./${useProxy ? "proxy" : "middleware"}.ts
|
|
5897
|
+
caBundle: \${CAC_CA_BUNDLE}
|
|
5898
|
+
edipiLookup: ${edipiLookup}
|
|
5899
|
+
ocspEndpoint: \${CAC_OCSP_ENDPOINT}
|
|
5900
|
+
certHeader: ${certHeader}
|
|
5762
5901
|
${rbacSection}
|
|
5763
5902
|
protectedRoutes:
|
|
5764
5903
|
${routeLines}
|
|
@@ -5769,14 +5908,13 @@ ${auditSection}
|
|
|
5769
5908
|
const scopes2 = params.oidcScopes ?? "openid profile email";
|
|
5770
5909
|
const roleClaim = params.oidcRoleClaim ?? "roles";
|
|
5771
5910
|
return `# stackwright.auth.yml \u2014 generated by Auth Otter
|
|
5772
|
-
|
|
5911
|
+
type: oidc
|
|
5773
5912
|
${providerLine}${useProxy ? "proxy" : "middleware"}: ./${useProxy ? "proxy" : "middleware"}.ts
|
|
5774
|
-
|
|
5775
|
-
|
|
5776
|
-
|
|
5777
|
-
|
|
5778
|
-
|
|
5779
|
-
roleClaim: ${roleClaim}
|
|
5913
|
+
discoveryUrl: \${OIDC_DISCOVERY_URL}
|
|
5914
|
+
clientId: \${OIDC_CLIENT_ID}
|
|
5915
|
+
clientSecret: \${OIDC_CLIENT_SECRET}
|
|
5916
|
+
scopes: ${scopes2}
|
|
5917
|
+
roleClaim: ${roleClaim}
|
|
5780
5918
|
${rbacSection}
|
|
5781
5919
|
protectedRoutes:
|
|
5782
5920
|
${routeLines}
|
|
@@ -5785,14 +5923,13 @@ ${auditSection}
|
|
|
5785
5923
|
}
|
|
5786
5924
|
const scopes = params.oauth2Scopes ?? "read write";
|
|
5787
5925
|
return `# stackwright.auth.yml \u2014 generated by Auth Otter
|
|
5788
|
-
|
|
5926
|
+
type: oauth2
|
|
5789
5927
|
${providerLine}${useProxy ? "proxy" : "middleware"}: ./${useProxy ? "proxy" : "middleware"}.ts
|
|
5790
|
-
|
|
5791
|
-
|
|
5792
|
-
|
|
5793
|
-
|
|
5794
|
-
|
|
5795
|
-
scopes: ${scopes}
|
|
5928
|
+
authorizationUrl: \${OAUTH2_AUTH_URL}
|
|
5929
|
+
tokenUrl: \${OAUTH2_TOKEN_URL}
|
|
5930
|
+
clientId: \${OAUTH2_CLIENT_ID}
|
|
5931
|
+
clientSecret: \${OAUTH2_CLIENT_SECRET}
|
|
5932
|
+
scopes: ${scopes}
|
|
5796
5933
|
${rbacSection}
|
|
5797
5934
|
protectedRoutes:
|
|
5798
5935
|
${routeLines}
|
|
@@ -5999,14 +6136,13 @@ ${hierarchyToYaml(hierarchy, " ")}`;
|
|
|
5999
6136
|
const ocspEndpoint = params.cacOcspEndpoint ?? "https://ocsp.disa.mil";
|
|
6000
6137
|
const certHeader = params.cacCertHeader ?? "X-SSL-Client-Cert";
|
|
6001
6138
|
return `# stackwright.auth.yml \u2014 generated by Auth Otter
|
|
6002
|
-
|
|
6139
|
+
type: pki
|
|
6003
6140
|
devOnly: true
|
|
6004
|
-
${
|
|
6005
|
-
|
|
6006
|
-
|
|
6007
|
-
|
|
6008
|
-
|
|
6009
|
-
certHeader: ${certHeader}
|
|
6141
|
+
${useProxy ? "proxy" : "middleware"}: ./${useProxy ? "proxy" : "middleware"}.ts
|
|
6142
|
+
caBundle: ${caBundle}
|
|
6143
|
+
edipiLookup: ${edipiLookup}
|
|
6144
|
+
ocspEndpoint: ${ocspEndpoint}
|
|
6145
|
+
certHeader: ${certHeader}
|
|
6010
6146
|
${rbacSection}
|
|
6011
6147
|
protectedRoutes:
|
|
6012
6148
|
${routeLines}
|
|
@@ -6017,15 +6153,14 @@ ${auditSection}
|
|
|
6017
6153
|
const scopes2 = params.oidcScopes ?? "openid profile email";
|
|
6018
6154
|
const roleClaim = params.oidcRoleClaim ?? "roles";
|
|
6019
6155
|
return `# stackwright.auth.yml \u2014 generated by Auth Otter
|
|
6020
|
-
|
|
6156
|
+
type: oidc
|
|
6021
6157
|
devOnly: true
|
|
6022
6158
|
${providerLine}${useProxy ? "proxy" : "middleware"}: ./${useProxy ? "proxy" : "middleware"}.ts
|
|
6023
|
-
oidc
|
|
6024
|
-
|
|
6025
|
-
|
|
6026
|
-
|
|
6027
|
-
|
|
6028
|
-
roleClaim: ${roleClaim}
|
|
6159
|
+
discoveryUrl: https://dev-mock-oidc/.well-known/openid-configuration
|
|
6160
|
+
clientId: dev-mock-client
|
|
6161
|
+
clientSecret: dev-mock-secret
|
|
6162
|
+
scopes: ${scopes2}
|
|
6163
|
+
roleClaim: ${roleClaim}
|
|
6029
6164
|
${rbacSection}
|
|
6030
6165
|
protectedRoutes:
|
|
6031
6166
|
${routeLines}
|
|
@@ -6034,15 +6169,14 @@ ${auditSection}
|
|
|
6034
6169
|
}
|
|
6035
6170
|
const scopes = params.oauth2Scopes ?? "read write";
|
|
6036
6171
|
return `# stackwright.auth.yml \u2014 generated by Auth Otter
|
|
6037
|
-
|
|
6172
|
+
type: oauth2
|
|
6038
6173
|
devOnly: true
|
|
6039
6174
|
${providerLine}${useProxy ? "proxy" : "middleware"}: ./${useProxy ? "proxy" : "middleware"}.ts
|
|
6040
|
-
oauth2
|
|
6041
|
-
|
|
6042
|
-
|
|
6043
|
-
|
|
6044
|
-
|
|
6045
|
-
scopes: ${scopes}
|
|
6175
|
+
authorizationUrl: https://dev-mock-oauth2/authorize
|
|
6176
|
+
tokenUrl: https://dev-mock-oauth2/token
|
|
6177
|
+
clientId: dev-mock-client
|
|
6178
|
+
clientSecret: dev-mock-secret
|
|
6179
|
+
scopes: ${scopes}
|
|
6046
6180
|
${rbacSection}
|
|
6047
6181
|
protectedRoutes:
|
|
6048
6182
|
${routeLines}
|
|
@@ -6112,6 +6246,10 @@ function updatePackageJsonScripts(existingJson, roles, mockUsers) {
|
|
|
6112
6246
|
return JSON.stringify(pkg, null, 2) + "\n";
|
|
6113
6247
|
}
|
|
6114
6248
|
async function configureAuthHandler(params, cwd) {
|
|
6249
|
+
params = {
|
|
6250
|
+
...params,
|
|
6251
|
+
provider: params.provider != null ? normalizeProviderSlug(params.provider) : void 0
|
|
6252
|
+
};
|
|
6115
6253
|
const {
|
|
6116
6254
|
method,
|
|
6117
6255
|
provider,
|
|
@@ -6363,45 +6501,46 @@ function registerAuthTools(server2) {
|
|
|
6363
6501
|
"stackwright_pro_configure_auth",
|
|
6364
6502
|
"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.",
|
|
6365
6503
|
{
|
|
6366
|
-
method:
|
|
6367
|
-
|
|
6504
|
+
method: import_zod16.z.enum(["cac", "oidc", "oauth2", "none"]),
|
|
6505
|
+
// Both hyphen and underscore accepted at the tool surface; normalized to underscore downstream.
|
|
6506
|
+
provider: import_zod16.z.enum(["azure-ad", "azure_ad", "okta", "ping", "cognito", "custom"]).optional(),
|
|
6368
6507
|
// CAC
|
|
6369
|
-
cacCaBundle:
|
|
6370
|
-
cacEdipiLookup:
|
|
6371
|
-
cacOcspEndpoint:
|
|
6372
|
-
cacCertHeader:
|
|
6508
|
+
cacCaBundle: import_zod16.z.string().optional(),
|
|
6509
|
+
cacEdipiLookup: import_zod16.z.string().optional(),
|
|
6510
|
+
cacOcspEndpoint: import_zod16.z.string().optional(),
|
|
6511
|
+
cacCertHeader: import_zod16.z.string().optional(),
|
|
6373
6512
|
// OIDC
|
|
6374
|
-
oidcDiscoveryUrl:
|
|
6375
|
-
oidcClientId:
|
|
6376
|
-
oidcClientSecret:
|
|
6377
|
-
oidcScopes:
|
|
6378
|
-
oidcRoleClaim:
|
|
6513
|
+
oidcDiscoveryUrl: import_zod16.z.string().optional(),
|
|
6514
|
+
oidcClientId: import_zod16.z.string().optional(),
|
|
6515
|
+
oidcClientSecret: import_zod16.z.string().optional(),
|
|
6516
|
+
oidcScopes: import_zod16.z.string().optional(),
|
|
6517
|
+
oidcRoleClaim: import_zod16.z.string().optional(),
|
|
6379
6518
|
// OAuth2
|
|
6380
|
-
oauth2AuthUrl:
|
|
6381
|
-
oauth2TokenUrl:
|
|
6382
|
-
oauth2ClientId:
|
|
6383
|
-
oauth2ClientSecret:
|
|
6384
|
-
oauth2Scopes:
|
|
6519
|
+
oauth2AuthUrl: import_zod16.z.string().optional(),
|
|
6520
|
+
oauth2TokenUrl: import_zod16.z.string().optional(),
|
|
6521
|
+
oauth2ClientId: import_zod16.z.string().optional(),
|
|
6522
|
+
oauth2ClientSecret: import_zod16.z.string().optional(),
|
|
6523
|
+
oauth2Scopes: import_zod16.z.string().optional(),
|
|
6385
6524
|
// RBAC
|
|
6386
|
-
rbacRoles: jsonCoerce(
|
|
6387
|
-
rbacDefaultRole:
|
|
6525
|
+
rbacRoles: jsonCoerce(import_zod16.z.array(import_zod16.z.string()).optional()),
|
|
6526
|
+
rbacDefaultRole: import_zod16.z.string().optional(),
|
|
6388
6527
|
// Audit
|
|
6389
|
-
auditEnabled: boolCoerce(
|
|
6390
|
-
auditRetentionDays: numCoerce(
|
|
6528
|
+
auditEnabled: boolCoerce(import_zod16.z.boolean().optional()),
|
|
6529
|
+
auditRetentionDays: numCoerce(import_zod16.z.number().int().positive().optional()),
|
|
6391
6530
|
// Routes — accepts bare strings (backward-compat) or per-route objects (swp-owu0)
|
|
6392
6531
|
protectedRoutes: jsonCoerce(
|
|
6393
|
-
|
|
6394
|
-
|
|
6395
|
-
|
|
6396
|
-
|
|
6532
|
+
import_zod16.z.array(
|
|
6533
|
+
import_zod16.z.union([
|
|
6534
|
+
import_zod16.z.string(),
|
|
6535
|
+
import_zod16.z.object({ pattern: import_zod16.z.string(), requiredRole: import_zod16.z.string().optional() })
|
|
6397
6536
|
])
|
|
6398
6537
|
).optional()
|
|
6399
6538
|
),
|
|
6400
6539
|
// Injection for tests
|
|
6401
|
-
_cwd:
|
|
6402
|
-
devOnly: boolCoerce(
|
|
6403
|
-
mockUsers: jsonCoerce(
|
|
6404
|
-
nextMajorVersion: numCoerce(
|
|
6540
|
+
_cwd: import_zod16.z.string().optional(),
|
|
6541
|
+
devOnly: boolCoerce(import_zod16.z.boolean().optional()),
|
|
6542
|
+
mockUsers: jsonCoerce(import_zod16.z.array(import_zod16.z.object({ name: import_zod16.z.string(), email: import_zod16.z.string() })).optional()),
|
|
6543
|
+
nextMajorVersion: numCoerce(import_zod16.z.number().int().positive().optional())
|
|
6405
6544
|
},
|
|
6406
6545
|
async (params) => {
|
|
6407
6546
|
const cwd = params._cwd ?? process.cwd();
|
|
@@ -6421,7 +6560,7 @@ var _checksums = /* @__PURE__ */ new Map([
|
|
|
6421
6560
|
],
|
|
6422
6561
|
[
|
|
6423
6562
|
"stackwright-pro-auth-otter.json",
|
|
6424
|
-
"
|
|
6563
|
+
"eee511fa214203ce88d51996c6b1b483b6ad3a0ae474cc7be5d380fdbbc43bb1"
|
|
6425
6564
|
],
|
|
6426
6565
|
[
|
|
6427
6566
|
"stackwright-pro-dashboard-otter.json",
|
|
@@ -6441,7 +6580,7 @@ var _checksums = /* @__PURE__ */ new Map([
|
|
|
6441
6580
|
],
|
|
6442
6581
|
[
|
|
6443
6582
|
"stackwright-pro-foreman-otter.json",
|
|
6444
|
-
"
|
|
6583
|
+
"65aa3273274b2b1859d432c3d1166c4a73971861036bf18c35acd8a5357fcf26"
|
|
6445
6584
|
],
|
|
6446
6585
|
[
|
|
6447
6586
|
"stackwright-pro-form-wizard-otter.json",
|
|
@@ -6457,7 +6596,7 @@ var _checksums = /* @__PURE__ */ new Map([
|
|
|
6457
6596
|
],
|
|
6458
6597
|
[
|
|
6459
6598
|
"stackwright-pro-polish-otter.json",
|
|
6460
|
-
"
|
|
6599
|
+
"4b8223d89af7f92b9051fee7bb29fc4b1ee2a5a9ab87e8e67a6d8be6122fa029"
|
|
6461
6600
|
],
|
|
6462
6601
|
[
|
|
6463
6602
|
"stackwright-pro-qa-otter.json",
|
|
@@ -6690,7 +6829,7 @@ function registerIntegrityTools(server2) {
|
|
|
6690
6829
|
}
|
|
6691
6830
|
|
|
6692
6831
|
// src/tools/domain.ts
|
|
6693
|
-
var
|
|
6832
|
+
var import_zod17 = require("zod");
|
|
6694
6833
|
var import_fs12 = require("fs");
|
|
6695
6834
|
var import_path12 = require("path");
|
|
6696
6835
|
function handleListCollections(input) {
|
|
@@ -7076,7 +7215,7 @@ function registerDomainTools(server2) {
|
|
|
7076
7215
|
"stackwright_pro_resolve_data_strategy",
|
|
7077
7216
|
"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.",
|
|
7078
7217
|
{
|
|
7079
|
-
strategy:
|
|
7218
|
+
strategy: import_zod17.z.string().describe(
|
|
7080
7219
|
'The data-1 answer value: "pulse-fast", "isr-fast", "isr-standard", or "isr-slow"'
|
|
7081
7220
|
)
|
|
7082
7221
|
},
|
|
@@ -7086,7 +7225,7 @@ function registerDomainTools(server2) {
|
|
|
7086
7225
|
"stackwright_pro_validate_workflow",
|
|
7087
7226
|
"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.",
|
|
7088
7227
|
{
|
|
7089
|
-
workflow: jsonCoerce(
|
|
7228
|
+
workflow: jsonCoerce(import_zod17.z.record(import_zod17.z.string(), import_zod17.z.unknown()).optional()).describe(
|
|
7090
7229
|
"Parsed workflow object. If omitted, reads from .stackwright/artifacts/workflow-config.json"
|
|
7091
7230
|
)
|
|
7092
7231
|
},
|
|
@@ -7095,7 +7234,7 @@ function registerDomainTools(server2) {
|
|
|
7095
7234
|
}
|
|
7096
7235
|
|
|
7097
7236
|
// src/tools/type-schemas.ts
|
|
7098
|
-
var
|
|
7237
|
+
var import_zod18 = require("zod");
|
|
7099
7238
|
function buildTypeSchemaSummary() {
|
|
7100
7239
|
return {
|
|
7101
7240
|
version: "1.0",
|
|
@@ -7172,7 +7311,7 @@ function registerTypeSchemasTool(server2) {
|
|
|
7172
7311
|
"stackwright_pro_get_type_schemas",
|
|
7173
7312
|
"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.",
|
|
7174
7313
|
{
|
|
7175
|
-
format:
|
|
7314
|
+
format: import_zod18.z.enum(["full", "domains-only"]).optional().default("full").describe("full = complete summary with all fields; domains-only = just domain names")
|
|
7176
7315
|
},
|
|
7177
7316
|
async ({ format }) => {
|
|
7178
7317
|
const summary = buildTypeSchemaSummary();
|
|
@@ -7188,7 +7327,7 @@ function registerTypeSchemasTool(server2) {
|
|
|
7188
7327
|
var fs2 = __toESM(require("fs"));
|
|
7189
7328
|
var os = __toESM(require("os"));
|
|
7190
7329
|
var path3 = __toESM(require("path"));
|
|
7191
|
-
var
|
|
7330
|
+
var import_zod19 = require("zod");
|
|
7192
7331
|
var import_js_yaml3 = require("js-yaml");
|
|
7193
7332
|
var import_cli = require("@stackwright/cli");
|
|
7194
7333
|
var import_types4 = require("@stackwright-pro/types");
|
|
@@ -7300,10 +7439,10 @@ function registerProPageTools(server2) {
|
|
|
7300
7439
|
"stackwright_pro_write_page",
|
|
7301
7440
|
"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.",
|
|
7302
7441
|
{
|
|
7303
|
-
projectRoot:
|
|
7304
|
-
slug:
|
|
7305
|
-
content:
|
|
7306
|
-
locale:
|
|
7442
|
+
projectRoot: import_zod19.z.string().describe("Absolute path to the Stackwright project root"),
|
|
7443
|
+
slug: import_zod19.z.string().describe('Page slug (e.g. "dashboard/main" or "/dashboard/main")'),
|
|
7444
|
+
content: import_zod19.z.string().describe("Full YAML content for the page (content.yml contents)"),
|
|
7445
|
+
locale: import_zod19.z.string().optional().describe(
|
|
7307
7446
|
'BCP 47 locale tag (e.g. "fr", "de"). If provided, writes content.<locale>.yml instead of content.yml.'
|
|
7308
7447
|
)
|
|
7309
7448
|
},
|
|
@@ -7553,7 +7692,7 @@ function registerScaffoldCleanupTools(server2) {
|
|
|
7553
7692
|
}
|
|
7554
7693
|
|
|
7555
7694
|
// src/tools/contrast.ts
|
|
7556
|
-
var
|
|
7695
|
+
var import_zod20 = require("zod");
|
|
7557
7696
|
function linearizeChannel(c255) {
|
|
7558
7697
|
const c = c255 / 255;
|
|
7559
7698
|
return c <= 0.04045 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
|
|
@@ -7725,8 +7864,8 @@ function registerContrastTools(server2) {
|
|
|
7725
7864
|
"stackwright_pro_check_contrast",
|
|
7726
7865
|
'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%").',
|
|
7727
7866
|
{
|
|
7728
|
-
fg:
|
|
7729
|
-
bg:
|
|
7867
|
+
fg: import_zod20.z.string().describe("Foreground (text) color \u2014 hex or HSL"),
|
|
7868
|
+
bg: import_zod20.z.string().describe("Background color \u2014 hex or HSL")
|
|
7730
7869
|
},
|
|
7731
7870
|
async ({ fg, bg }) => {
|
|
7732
7871
|
let result;
|
|
@@ -7756,8 +7895,8 @@ function registerContrastTools(server2) {
|
|
|
7756
7895
|
"stackwright_pro_derive_accessible_palette",
|
|
7757
7896
|
'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%").',
|
|
7758
7897
|
{
|
|
7759
|
-
seed:
|
|
7760
|
-
targetRatio: numCoerce(
|
|
7898
|
+
seed: import_zod20.z.string().describe("Background (seed) color \u2014 hex or HSL"),
|
|
7899
|
+
targetRatio: numCoerce(import_zod20.z.number().default(4.5)).describe(
|
|
7761
7900
|
"Minimum required contrast ratio (default 4.5 for WCAG AA)"
|
|
7762
7901
|
)
|
|
7763
7902
|
},
|
|
@@ -7792,7 +7931,7 @@ function registerContrastTools(server2) {
|
|
|
7792
7931
|
}
|
|
7793
7932
|
|
|
7794
7933
|
// src/tools/compile.ts
|
|
7795
|
-
var
|
|
7934
|
+
var import_zod21 = require("zod");
|
|
7796
7935
|
var import_fs14 = __toESM(require("fs"));
|
|
7797
7936
|
var import_path14 = __toESM(require("path"));
|
|
7798
7937
|
var import_server = require("@stackwright-pro/pulse/server");
|
|
@@ -7838,7 +7977,7 @@ async function tryOssCompile(fn, ctx, extra) {
|
|
|
7838
7977
|
}
|
|
7839
7978
|
}
|
|
7840
7979
|
function registerCompileTools(server2) {
|
|
7841
|
-
const projectRootArg =
|
|
7980
|
+
const projectRootArg = import_zod21.z.string().optional().describe("Absolute path to project root (defaults to cwd)");
|
|
7842
7981
|
server2.tool(
|
|
7843
7982
|
"stackwright_pro_compile_collections",
|
|
7844
7983
|
"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.",
|
|
@@ -8014,7 +8153,7 @@ ${results.join("\n")}`;
|
|
|
8014
8153
|
"stackwright_pro_compile_page",
|
|
8015
8154
|
"Compile a single page by slug. Delegates to compilePage from @stackwright/build-scripts installed in the project.",
|
|
8016
8155
|
{
|
|
8017
|
-
slug:
|
|
8156
|
+
slug: import_zod21.z.string().describe('Page slug (relative path under pages/, e.g. "dashboard")'),
|
|
8018
8157
|
projectRoot: projectRootArg
|
|
8019
8158
|
},
|
|
8020
8159
|
async ({ slug, projectRoot }) => {
|
|
@@ -8034,7 +8173,7 @@ ${results.join("\n")}`;
|
|
|
8034
8173
|
}
|
|
8035
8174
|
|
|
8036
8175
|
// src/tools/strip-legacy-integrations.ts
|
|
8037
|
-
var
|
|
8176
|
+
var import_zod22 = require("zod");
|
|
8038
8177
|
var import_fs15 = require("fs");
|
|
8039
8178
|
var import_path15 = require("path");
|
|
8040
8179
|
function handleStripLegacyIntegrations(input) {
|
|
@@ -8097,7 +8236,7 @@ function registerStripLegacyIntegrationsTool(server2) {
|
|
|
8097
8236
|
"stackwright_pro_strip_legacy_integrations",
|
|
8098
8237
|
"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.",
|
|
8099
8238
|
{
|
|
8100
|
-
projectRoot:
|
|
8239
|
+
projectRoot: import_zod22.z.string().describe("Absolute path to the project root directory")
|
|
8101
8240
|
},
|
|
8102
8241
|
async ({ projectRoot }) => {
|
|
8103
8242
|
const result = handleStripLegacyIntegrations({ projectRoot });
|
|
@@ -8109,7 +8248,7 @@ function registerStripLegacyIntegrationsTool(server2) {
|
|
|
8109
8248
|
}
|
|
8110
8249
|
|
|
8111
8250
|
// src/tools/emitters.ts
|
|
8112
|
-
var
|
|
8251
|
+
var import_zod23 = require("zod");
|
|
8113
8252
|
var import_fs16 = require("fs");
|
|
8114
8253
|
var import_path16 = require("path");
|
|
8115
8254
|
var import_js_yaml4 = __toESM(require("js-yaml"));
|
|
@@ -8168,7 +8307,7 @@ Call this tool, then write both files with stackwright_pro_safe_write:
|
|
|
8168
8307
|
|
|
8169
8308
|
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}`,
|
|
8170
8309
|
{
|
|
8171
|
-
cwd:
|
|
8310
|
+
cwd: import_zod23.z.string().describe(
|
|
8172
8311
|
"Absolute path to the project root containing stackwright.integrations.yml and optionally services/*.yml"
|
|
8173
8312
|
)
|
|
8174
8313
|
},
|
|
@@ -8215,8 +8354,8 @@ mapProvider options:
|
|
|
8215
8354
|
|
|
8216
8355
|
This is the second concrete instance of the swp-zf9y deterministic emitter pattern. Refs: swp-57ku, swp-2m89, swp-zf9y, drawer 957. ${PROVIDERS_DESC}`,
|
|
8217
8356
|
{
|
|
8218
|
-
cwd:
|
|
8219
|
-
mapProvider:
|
|
8357
|
+
cwd: import_zod23.z.string().describe("Absolute path to the project root containing stackwright.integrations.yml"),
|
|
8358
|
+
mapProvider: import_zod23.z.enum(["maplibre", "cesium", "none"]).optional().describe(
|
|
8220
8359
|
"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."
|
|
8221
8360
|
)
|
|
8222
8361
|
},
|
|
@@ -8257,7 +8396,7 @@ Workflow:
|
|
|
8257
8396
|
|
|
8258
8397
|
This is the third concrete instance of the swp-zf9y deterministic emitter pattern. Refs: swp-phkh, swp-zf9y. ${PORTS_DESC}`,
|
|
8259
8398
|
{
|
|
8260
|
-
cwd:
|
|
8399
|
+
cwd: import_zod23.z.string().describe("Absolute path to the project root containing stackwright.integrations.yml")
|
|
8261
8400
|
},
|
|
8262
8401
|
async ({ cwd }) => {
|
|
8263
8402
|
const integrations = readIntegrations(cwd);
|
|
@@ -8286,7 +8425,7 @@ This is the third concrete instance of the swp-zf9y deterministic emitter patter
|
|
|
8286
8425
|
}
|
|
8287
8426
|
|
|
8288
8427
|
// src/tools/list-specs.ts
|
|
8289
|
-
var
|
|
8428
|
+
var import_zod24 = require("zod");
|
|
8290
8429
|
var import_fs17 = require("fs");
|
|
8291
8430
|
var import_path17 = require("path");
|
|
8292
8431
|
var STRIP_SUFFIXES = ["-openapi", "-asyncapi", "-api", "-spec"];
|
|
@@ -8351,7 +8490,7 @@ function registerListSpecsTool(server2) {
|
|
|
8351
8490
|
"stackwright_pro_list_specs",
|
|
8352
8491
|
"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.",
|
|
8353
8492
|
{
|
|
8354
|
-
projectRoot:
|
|
8493
|
+
projectRoot: import_zod24.z.string().describe("Absolute path to the project root directory")
|
|
8355
8494
|
},
|
|
8356
8495
|
async ({ projectRoot }) => {
|
|
8357
8496
|
const result = handleListSpecs({ projectRoot });
|
|
@@ -8363,7 +8502,7 @@ function registerListSpecsTool(server2) {
|
|
|
8363
8502
|
}
|
|
8364
8503
|
|
|
8365
8504
|
// src/tools/consolidate-integrations.ts
|
|
8366
|
-
var
|
|
8505
|
+
var import_zod25 = require("zod");
|
|
8367
8506
|
var import_fs18 = require("fs");
|
|
8368
8507
|
var import_proper_lockfile2 = require("proper-lockfile");
|
|
8369
8508
|
var import_path18 = require("path");
|
|
@@ -8484,7 +8623,7 @@ function registerConsolidateIntegrationsTool(server2) {
|
|
|
8484
8623
|
"no per-spec artifacts are found."
|
|
8485
8624
|
].join(" "),
|
|
8486
8625
|
{
|
|
8487
|
-
projectRoot:
|
|
8626
|
+
projectRoot: import_zod25.z.string().describe("Absolute path to the project root directory")
|
|
8488
8627
|
},
|
|
8489
8628
|
async ({ projectRoot }) => {
|
|
8490
8629
|
try {
|
|
@@ -8542,7 +8681,7 @@ var package_default = {
|
|
|
8542
8681
|
"test:coverage": "vitest run --coverage"
|
|
8543
8682
|
},
|
|
8544
8683
|
name: "@stackwright-pro/mcp",
|
|
8545
|
-
version: "0.2.0-alpha.
|
|
8684
|
+
version: "0.2.0-alpha.112",
|
|
8546
8685
|
description: "MCP tools for Stackwright Pro - Data Explorer, Security, ISR, and Dashboard generation",
|
|
8547
8686
|
license: "SEE LICENSE IN LICENSE",
|
|
8548
8687
|
main: "./dist/server.js",
|
|
@@ -8598,6 +8737,7 @@ registerOrchestrationTools(server);
|
|
|
8598
8737
|
registerPipelineTools(server);
|
|
8599
8738
|
registerSafeWriteTools(server);
|
|
8600
8739
|
registerAuthTools(server);
|
|
8740
|
+
registerReadAuthManifestsTool(server);
|
|
8601
8741
|
registerIntegrityTools(server);
|
|
8602
8742
|
registerArtifactSigningTools(server);
|
|
8603
8743
|
registerDomainTools(server);
|