@stackwright-pro/mcp 0.2.0-alpha.13 → 0.2.0-alpha.15
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 +1 -1
- package/dist/integrity.js.map +1 -1
- package/dist/integrity.mjs +1 -1
- package/dist/integrity.mjs.map +1 -1
- package/dist/server.js +196 -151
- package/dist/server.js.map +1 -1
- package/dist/server.mjs +196 -151
- package/dist/server.mjs.map +1 -1
- package/package.json +1 -1
package/dist/server.js
CHANGED
|
@@ -27,15 +27,44 @@ var import_mcp = require("@modelcontextprotocol/sdk/server/mcp.js");
|
|
|
27
27
|
var import_stdio = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
28
28
|
|
|
29
29
|
// src/tools/data-explorer.ts
|
|
30
|
-
var
|
|
30
|
+
var import_zod2 = require("zod");
|
|
31
31
|
var import_cli_data_explorer = require("@stackwright-pro/cli-data-explorer");
|
|
32
|
+
|
|
33
|
+
// src/coerce.ts
|
|
34
|
+
var import_zod = require("zod");
|
|
35
|
+
function jsonCoerce(schema) {
|
|
36
|
+
return import_zod.z.preprocess((v) => {
|
|
37
|
+
if (typeof v === "string") {
|
|
38
|
+
try {
|
|
39
|
+
return JSON.parse(v);
|
|
40
|
+
} catch {
|
|
41
|
+
return v;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return v;
|
|
45
|
+
}, schema);
|
|
46
|
+
}
|
|
47
|
+
function boolCoerce(schema) {
|
|
48
|
+
return import_zod.z.preprocess((v) => v === "true" ? true : v === "false" ? false : v, schema);
|
|
49
|
+
}
|
|
50
|
+
function numCoerce(schema) {
|
|
51
|
+
return import_zod.z.preprocess((v) => {
|
|
52
|
+
if (typeof v === "string" && v.trim() !== "") {
|
|
53
|
+
const n = Number(v);
|
|
54
|
+
if (!Number.isNaN(n)) return n;
|
|
55
|
+
}
|
|
56
|
+
return v;
|
|
57
|
+
}, schema);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// src/tools/data-explorer.ts
|
|
32
61
|
function registerDataExplorerTools(server2) {
|
|
33
62
|
server2.tool(
|
|
34
63
|
"stackwright_pro_list_entities",
|
|
35
64
|
"List all available API entities from OpenAPI specs or generated Zod schemas. Use this to discover what entities are available before generating endpoint filters. Returns entity names, endpoints, and field counts. Part of the Pro Otter Raft for building API-integrated Stackwright applications.",
|
|
36
65
|
{
|
|
37
|
-
specPath:
|
|
38
|
-
projectRoot:
|
|
66
|
+
specPath: import_zod2.z.string().optional().describe("Path to OpenAPI spec file (YAML or JSON)"),
|
|
67
|
+
projectRoot: import_zod2.z.string().optional().describe("Project root directory (auto-detected if omitted)")
|
|
39
68
|
},
|
|
40
69
|
async ({ specPath, projectRoot }) => {
|
|
41
70
|
const result = (0, import_cli_data_explorer.listEntities)({
|
|
@@ -83,9 +112,13 @@ function registerDataExplorerTools(server2) {
|
|
|
83
112
|
"stackwright_pro_generate_filter",
|
|
84
113
|
"Generate endpoint filter configuration from selected entities. Creates include/exclude patterns for stackwright.yml OpenAPI integration. Use this after stackwright_pro_list_entities to select which API endpoints the application needs. Only selected endpoints will generate client code, reducing bundle size and improving security.",
|
|
85
114
|
{
|
|
86
|
-
selectedEntities:
|
|
87
|
-
|
|
88
|
-
|
|
115
|
+
selectedEntities: jsonCoerce(import_zod2.z.array(import_zod2.z.string())).describe(
|
|
116
|
+
'Entity slugs to include (e.g., ["equipment", "supplies"])'
|
|
117
|
+
),
|
|
118
|
+
excludePatterns: jsonCoerce(import_zod2.z.array(import_zod2.z.string()).optional()).describe(
|
|
119
|
+
'Glob patterns to exclude (e.g., ["/admin/**", "/reports/**"])'
|
|
120
|
+
),
|
|
121
|
+
projectRoot: import_zod2.z.string().optional().describe("Project root directory")
|
|
89
122
|
},
|
|
90
123
|
async ({ selectedEntities, excludePatterns, projectRoot }) => {
|
|
91
124
|
const result = (0, import_cli_data_explorer.generateFilter)({
|
|
@@ -141,7 +174,7 @@ function registerDataExplorerTools(server2) {
|
|
|
141
174
|
}
|
|
142
175
|
|
|
143
176
|
// src/tools/security.ts
|
|
144
|
-
var
|
|
177
|
+
var import_zod3 = require("zod");
|
|
145
178
|
var import_crypto = require("crypto");
|
|
146
179
|
var import_fs = __toESM(require("fs"));
|
|
147
180
|
var import_path = __toESM(require("path"));
|
|
@@ -150,8 +183,8 @@ function registerSecurityTools(server2) {
|
|
|
150
183
|
"stackwright_pro_validate_spec",
|
|
151
184
|
"Validate an OpenAPI spec against the enterprise approved-specs configuration. Checks if the spec URL is on the allowlist and verifies SHA-256 hash integrity. Use this in enterprise environments where only pre-approved API specs are allowed. Fails build if spec is not approved or has been modified.",
|
|
152
185
|
{
|
|
153
|
-
specPath:
|
|
154
|
-
configPath:
|
|
186
|
+
specPath: import_zod3.z.string().describe("URL or file path to the OpenAPI spec to validate"),
|
|
187
|
+
configPath: import_zod3.z.string().optional().describe("Path to stackwright.yml with prebuild.security config")
|
|
155
188
|
},
|
|
156
189
|
async ({ specPath, configPath }) => {
|
|
157
190
|
let securityEnabled = false;
|
|
@@ -259,9 +292,9 @@ Status: Valid (${allowlist.length} specs on allowlist)`
|
|
|
259
292
|
"stackwright_pro_add_approved_spec",
|
|
260
293
|
"Add an OpenAPI spec to the approved-specs allowlist in stackwright.yml. Computes the SHA-256 hash of the spec and adds it to the security configuration. Use this when onboarding a new API in enterprise environments.",
|
|
261
294
|
{
|
|
262
|
-
name:
|
|
263
|
-
url:
|
|
264
|
-
configPath:
|
|
295
|
+
name: import_zod3.z.string().describe("Human-readable name for the spec"),
|
|
296
|
+
url: import_zod3.z.string().describe("URL or file path to the OpenAPI spec"),
|
|
297
|
+
configPath: import_zod3.z.string().optional().describe("Path to stackwright.yml")
|
|
265
298
|
},
|
|
266
299
|
async ({ name, url, configPath }) => {
|
|
267
300
|
const configFile = configPath || import_path.default.join(process.cwd(), "stackwright.yml");
|
|
@@ -315,7 +348,7 @@ SHA-256 computed: ${sha256}`
|
|
|
315
348
|
"stackwright_pro_list_approved_specs",
|
|
316
349
|
"List all specs currently on the approved-specs allowlist. Shows spec names, URLs, and hash prefixes. Use this to audit what APIs are approved in the project.",
|
|
317
350
|
{
|
|
318
|
-
configPath:
|
|
351
|
+
configPath: import_zod3.z.string().optional().describe("Path to stackwright.yml")
|
|
319
352
|
},
|
|
320
353
|
async ({ configPath }) => {
|
|
321
354
|
const configFile = configPath || import_path.default.join(process.cwd(), "stackwright.yml");
|
|
@@ -384,16 +417,18 @@ SHA-256 computed: ${sha256}`
|
|
|
384
417
|
}
|
|
385
418
|
|
|
386
419
|
// src/tools/isr.ts
|
|
387
|
-
var
|
|
420
|
+
var import_zod4 = require("zod");
|
|
388
421
|
function registerIsrTools(server2) {
|
|
389
422
|
server2.tool(
|
|
390
423
|
"stackwright_pro_configure_isr",
|
|
391
424
|
"Configure Incremental Static Regeneration (ISR) for an API-backed collection. ISR allows API data to be cached and refreshed on a schedule, providing real-time data with the performance of static generation. Use this after stackwright_pro_generate_filter to set revalidation intervals.",
|
|
392
425
|
{
|
|
393
|
-
collection:
|
|
394
|
-
revalidateSeconds:
|
|
395
|
-
|
|
396
|
-
|
|
426
|
+
collection: import_zod4.z.string().describe('Collection name (e.g., "equipment", "supplies")'),
|
|
427
|
+
revalidateSeconds: numCoerce(import_zod4.z.number().optional()).describe(
|
|
428
|
+
"Revalidation interval in seconds (default: 60)"
|
|
429
|
+
),
|
|
430
|
+
fallback: import_zod4.z.enum(["blocking", "true", "false"]).optional().describe("Fallback behavior for new pages"),
|
|
431
|
+
configPath: import_zod4.z.string().optional().describe("Path to stackwright.yml")
|
|
397
432
|
},
|
|
398
433
|
async ({ collection, revalidateSeconds = 60, fallback = "blocking", configPath }) => {
|
|
399
434
|
const revalidate = revalidateSeconds;
|
|
@@ -436,14 +471,16 @@ ${yamlSnippet}
|
|
|
436
471
|
"stackwright_pro_configure_isr_batch",
|
|
437
472
|
"Configure ISR for multiple collections at once. More efficient than calling stackwright_pro_configure_isr multiple times. Provide different revalidation intervals based on data freshness requirements.",
|
|
438
473
|
{
|
|
439
|
-
collections:
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
474
|
+
collections: jsonCoerce(
|
|
475
|
+
import_zod4.z.array(
|
|
476
|
+
import_zod4.z.object({
|
|
477
|
+
name: import_zod4.z.string().describe("Collection name"),
|
|
478
|
+
revalidateSeconds: numCoerce(import_zod4.z.number().optional()).describe("Revalidation interval")
|
|
479
|
+
})
|
|
480
|
+
)
|
|
444
481
|
).describe("Array of collection configurations"),
|
|
445
|
-
defaultFallback:
|
|
446
|
-
configPath:
|
|
482
|
+
defaultFallback: import_zod4.z.enum(["blocking", "true", "false"]).optional().describe("Default fallback behavior"),
|
|
483
|
+
configPath: import_zod4.z.string().optional().describe("Path to stackwright.yml")
|
|
447
484
|
},
|
|
448
485
|
async ({ collections, defaultFallback = "blocking", configPath }) => {
|
|
449
486
|
const lines = [`\u2699\uFE0F Batch ISR Configuration:
|
|
@@ -471,17 +508,17 @@ Fallback: ${defaultFallback}`);
|
|
|
471
508
|
}
|
|
472
509
|
|
|
473
510
|
// src/tools/dashboard.ts
|
|
474
|
-
var
|
|
511
|
+
var import_zod5 = require("zod");
|
|
475
512
|
var import_cli_data_explorer2 = require("@stackwright-pro/cli-data-explorer");
|
|
476
513
|
function registerDashboardTools(server2) {
|
|
477
514
|
server2.tool(
|
|
478
515
|
"stackwright_pro_generate_dashboard",
|
|
479
516
|
"Generate a dashboard page configuration for displaying API data. Creates YAML content for a Stackwright page with grid, metric_card, data_table, and collection_list content types. Use this after stackwright_pro_generate_filter to create pages for your API collections.",
|
|
480
517
|
{
|
|
481
|
-
entities:
|
|
482
|
-
layout:
|
|
483
|
-
pageTitle:
|
|
484
|
-
specPath:
|
|
518
|
+
entities: jsonCoerce(import_zod5.z.array(import_zod5.z.string())).describe("Entity slugs to include in dashboard"),
|
|
519
|
+
layout: import_zod5.z.enum(["grid", "table", "mixed"]).optional().describe("Dashboard layout style"),
|
|
520
|
+
pageTitle: import_zod5.z.string().optional().describe("Page title"),
|
|
521
|
+
specPath: import_zod5.z.string().optional().describe("Path to OpenAPI spec for entity details")
|
|
485
522
|
},
|
|
486
523
|
async ({ entities, layout = "mixed", pageTitle, specPath }) => {
|
|
487
524
|
let entityDetails = [];
|
|
@@ -567,9 +604,9 @@ ${yaml}
|
|
|
567
604
|
"stackwright_pro_generate_detail_page",
|
|
568
605
|
"Generate a detail view page for a single API entity. Creates YAML content for displaying all fields of an individual record. Use this to create detail pages that complement collection listing pages.",
|
|
569
606
|
{
|
|
570
|
-
entity:
|
|
571
|
-
slugField:
|
|
572
|
-
specPath:
|
|
607
|
+
entity: import_zod5.z.string().describe('Entity slug (e.g., "equipment")'),
|
|
608
|
+
slugField: import_zod5.z.string().optional().describe('Field to use as URL slug (default: "id")'),
|
|
609
|
+
specPath: import_zod5.z.string().optional().describe("Path to OpenAPI spec for field details")
|
|
573
610
|
},
|
|
574
611
|
async ({ entity, slugField = "id", specPath }) => {
|
|
575
612
|
let fields = [];
|
|
@@ -645,7 +682,7 @@ ${yaml}
|
|
|
645
682
|
}
|
|
646
683
|
|
|
647
684
|
// src/tools/clarification.ts
|
|
648
|
-
var
|
|
685
|
+
var import_zod6 = require("zod");
|
|
649
686
|
var CONTRADICTION_PATTERNS = [
|
|
650
687
|
{
|
|
651
688
|
keywords: ["minimal", "clean", "simple"],
|
|
@@ -733,12 +770,14 @@ function registerClarificationTools(server2) {
|
|
|
733
770
|
"stackwright_pro_clarify",
|
|
734
771
|
"Ask the user for clarification when a specialist otter encounters ambiguity. This is for MID-EXECUTION questions, NOT upfront question collection (use the Question Manifest Protocol for that). Returns a structured response for the foreman to present to the user via ask_user_question (closed_choice) or directly (open_text).",
|
|
735
772
|
{
|
|
736
|
-
context:
|
|
737
|
-
question_type:
|
|
738
|
-
question:
|
|
739
|
-
choices:
|
|
740
|
-
|
|
741
|
-
|
|
773
|
+
context: import_zod6.z.string().optional().describe("Context about what the otter is trying to do"),
|
|
774
|
+
question_type: import_zod6.z.enum(["closed_choice", "open_text"]).describe("Type of question being asked"),
|
|
775
|
+
question: import_zod6.z.string().describe("The clarification question to ask the user"),
|
|
776
|
+
choices: jsonCoerce(import_zod6.z.array(import_zod6.z.string()).optional()).describe(
|
|
777
|
+
"Options for closed_choice questions"
|
|
778
|
+
),
|
|
779
|
+
priority: import_zod6.z.enum(["blocking", "preferred", "optional"]).optional().default("preferred").describe("How critical is this clarification? Default: preferred"),
|
|
780
|
+
target_field: import_zod6.z.string().optional().describe("What field/config does this clarify?")
|
|
742
781
|
},
|
|
743
782
|
async ({ context, question_type, question, choices, priority, target_field }) => {
|
|
744
783
|
const result = handleClarify({
|
|
@@ -767,8 +806,10 @@ function registerClarificationTools(server2) {
|
|
|
767
806
|
"stackwright_pro_detect_conflict",
|
|
768
807
|
"Detect when a user's stated preference conflicts with their selected choices. Uses keyword heuristics against known contradiction patterns (minimal vs vibrant, dark vs light, etc). Returns conflict details and resolution options.",
|
|
769
808
|
{
|
|
770
|
-
stated_preference:
|
|
771
|
-
selected_values:
|
|
809
|
+
stated_preference: import_zod6.z.string().describe("What the user said they wanted"),
|
|
810
|
+
selected_values: jsonCoerce(import_zod6.z.record(import_zod6.z.string(), import_zod6.z.string())).describe(
|
|
811
|
+
"What the user actually selected (field \u2192 value)"
|
|
812
|
+
)
|
|
772
813
|
},
|
|
773
814
|
async ({ stated_preference, selected_values }) => {
|
|
774
815
|
const result = handleDetectConflict({ stated_preference, selected_values });
|
|
@@ -813,7 +854,7 @@ ${result.resolution_options?.map((o) => ` \u2022 ${o}`).join("\n")}
|
|
|
813
854
|
}
|
|
814
855
|
|
|
815
856
|
// src/tools/packages.ts
|
|
816
|
-
var
|
|
857
|
+
var import_zod7 = require("zod");
|
|
817
858
|
var import_fs2 = require("fs");
|
|
818
859
|
var import_child_process = require("child_process");
|
|
819
860
|
var import_path2 = __toESM(require("path"));
|
|
@@ -834,24 +875,22 @@ function registerPackageTools(server2) {
|
|
|
834
875
|
"Ensures pro packages are present in a project's package.json. Safe to call multiple times \u2014 never overwrites existing version pins. Use this to bootstrap dependencies before specialist otters run. Pass includeBaseline: true to automatically include all required @stackwright-pro/* baseline dependencies. Safe to call on existing projects \u2014 never overwrites pinned versions.",
|
|
835
876
|
{
|
|
836
877
|
// FIX 3 (B-new-1): Zod v4 requires two-arg z.record(keySchema, valueSchema)
|
|
837
|
-
packages:
|
|
878
|
+
packages: import_zod7.z.record(import_zod7.z.string(), import_zod7.z.string()).optional().default({}).describe(
|
|
838
879
|
'Dependencies to add. Record<packageName, version>. e.g. { "@stackwright-pro/auth": "latest" }. Omit or pass {} when using includeBaseline: true.'
|
|
839
880
|
),
|
|
840
|
-
devPackages:
|
|
841
|
-
|
|
842
|
-
|
|
881
|
+
devPackages: jsonCoerce(import_zod7.z.record(import_zod7.z.string(), import_zod7.z.string()).optional()).describe(
|
|
882
|
+
"devDependencies to add. Same format as packages."
|
|
883
|
+
),
|
|
884
|
+
scripts: jsonCoerce(import_zod7.z.record(import_zod7.z.string(), import_zod7.z.string()).optional()).describe(
|
|
885
|
+
"npm scripts to add. Only adds if key does not already exist."
|
|
886
|
+
),
|
|
887
|
+
targetDir: import_zod7.z.string().optional().describe(
|
|
843
888
|
"Project directory containing package.json. Defaults to process.cwd(). Must be an absolute path within the current working directory."
|
|
844
889
|
),
|
|
845
|
-
runInstall:
|
|
846
|
-
(v) => v === "true" ? true : v === "false" ? false : v,
|
|
847
|
-
import_zod6.z.boolean().optional().default(true)
|
|
848
|
-
).describe(
|
|
890
|
+
runInstall: boolCoerce(import_zod7.z.boolean().optional().default(true)).describe(
|
|
849
891
|
"Run pnpm install after writing package.json. Defaults to true. Pass boolean true/false."
|
|
850
892
|
),
|
|
851
|
-
includeBaseline:
|
|
852
|
-
(v) => v === "true" ? true : v === "false" ? false : v,
|
|
853
|
-
import_zod6.z.boolean().optional().default(false)
|
|
854
|
-
).describe(
|
|
893
|
+
includeBaseline: boolCoerce(import_zod7.z.boolean().optional().default(false)).describe(
|
|
855
894
|
"When true, automatically merges BASELINE_DEPS and BASELINE_DEV_DEPS before applying packages/devPackages args. Safe to call on existing projects \u2014 never overwrites pinned versions. Pass boolean true/false."
|
|
856
895
|
)
|
|
857
896
|
},
|
|
@@ -1010,11 +1049,11 @@ function setupPackages(opts) {
|
|
|
1010
1049
|
}
|
|
1011
1050
|
}
|
|
1012
1051
|
const raw = (0, import_fs2.readFileSync)(realPackageJsonPath, "utf8");
|
|
1013
|
-
const PackageJsonSchema =
|
|
1052
|
+
const PackageJsonSchema = import_zod7.z.object({
|
|
1014
1053
|
// Zod v4: z.record(keySchema, valueSchema) — two-arg form required
|
|
1015
|
-
dependencies:
|
|
1016
|
-
devDependencies:
|
|
1017
|
-
scripts:
|
|
1054
|
+
dependencies: import_zod7.z.record(import_zod7.z.string(), import_zod7.z.string()).optional(),
|
|
1055
|
+
devDependencies: import_zod7.z.record(import_zod7.z.string(), import_zod7.z.string()).optional(),
|
|
1056
|
+
scripts: import_zod7.z.record(import_zod7.z.string(), import_zod7.z.string()).optional()
|
|
1018
1057
|
}).passthrough();
|
|
1019
1058
|
const schemaResult = PackageJsonSchema.safeParse(JSON.parse(raw));
|
|
1020
1059
|
if (!schemaResult.success) {
|
|
@@ -1097,7 +1136,7 @@ function setupPackages(opts) {
|
|
|
1097
1136
|
// src/tools/questions.ts
|
|
1098
1137
|
var import_promises = require("fs/promises");
|
|
1099
1138
|
var import_node_path = require("path");
|
|
1100
|
-
var
|
|
1139
|
+
var import_zod8 = require("zod");
|
|
1101
1140
|
|
|
1102
1141
|
// src/question-adapter.ts
|
|
1103
1142
|
function truncate(str, maxLength) {
|
|
@@ -1283,22 +1322,22 @@ function answersToManifestFormat(answers, questions) {
|
|
|
1283
1322
|
}
|
|
1284
1323
|
|
|
1285
1324
|
// src/tools/questions.ts
|
|
1286
|
-
var ManifestQuestionSchema =
|
|
1287
|
-
id:
|
|
1288
|
-
question:
|
|
1289
|
-
type:
|
|
1290
|
-
required:
|
|
1291
|
-
options:
|
|
1292
|
-
|
|
1293
|
-
label:
|
|
1294
|
-
value:
|
|
1325
|
+
var ManifestQuestionSchema = import_zod8.z.object({
|
|
1326
|
+
id: import_zod8.z.string(),
|
|
1327
|
+
question: import_zod8.z.string(),
|
|
1328
|
+
type: import_zod8.z.enum(["text", "select", "multi-select", "confirm"]),
|
|
1329
|
+
required: import_zod8.z.boolean().optional(),
|
|
1330
|
+
options: import_zod8.z.array(
|
|
1331
|
+
import_zod8.z.object({
|
|
1332
|
+
label: import_zod8.z.string(),
|
|
1333
|
+
value: import_zod8.z.string()
|
|
1295
1334
|
})
|
|
1296
1335
|
).optional(),
|
|
1297
|
-
default:
|
|
1298
|
-
help:
|
|
1299
|
-
dependsOn:
|
|
1300
|
-
questionId:
|
|
1301
|
-
value:
|
|
1336
|
+
default: import_zod8.z.union([import_zod8.z.string(), import_zod8.z.boolean(), import_zod8.z.array(import_zod8.z.string())]).optional(),
|
|
1337
|
+
help: import_zod8.z.string().optional(),
|
|
1338
|
+
dependsOn: import_zod8.z.object({
|
|
1339
|
+
questionId: import_zod8.z.string(),
|
|
1340
|
+
value: import_zod8.z.union([import_zod8.z.string(), import_zod8.z.array(import_zod8.z.string())])
|
|
1302
1341
|
}).optional()
|
|
1303
1342
|
});
|
|
1304
1343
|
function registerQuestionTools(server2) {
|
|
@@ -1306,11 +1345,13 @@ function registerQuestionTools(server2) {
|
|
|
1306
1345
|
"stackwright_pro_present_phase_questions",
|
|
1307
1346
|
"Adapt manifest-format questions from a specialist otter and present them to the user via ask_user_question. Pass only the phase name \u2014 this tool reads questions from .stackwright/question-manifest.json automatically. The questions parameter is optional and only needed if the manifest has not been written yet. Use this instead of calling ask_user_question directly \u2014 it handles label truncation (50-char limit), header generation, confirm/text defaults, and correct array formatting automatically. IMPORTANT: This is the ONLY approved way to prepare questions before calling ask_user_question. Never call ask_user_question with raw manifest questions. Never retry ask_user_question validation errors by calling it directly \u2014 always re-call this tool.",
|
|
1308
1347
|
{
|
|
1309
|
-
phase:
|
|
1310
|
-
questions:
|
|
1348
|
+
phase: import_zod8.z.string().describe('Phase name for display context, e.g. "designer", "api", "auth"'),
|
|
1349
|
+
questions: jsonCoerce(import_zod8.z.array(ManifestQuestionSchema).optional()).describe(
|
|
1311
1350
|
"Questions in Question Manifest format. If omitted, questions are read from .stackwright/question-manifest.json using the phase name."
|
|
1312
1351
|
),
|
|
1313
|
-
answers:
|
|
1352
|
+
answers: jsonCoerce(
|
|
1353
|
+
import_zod8.z.record(import_zod8.z.string(), import_zod8.z.union([import_zod8.z.string(), import_zod8.z.array(import_zod8.z.string()), import_zod8.z.boolean()])).optional()
|
|
1354
|
+
).describe("Previously collected answers used to resolve dependsOn conditions")
|
|
1314
1355
|
},
|
|
1315
1356
|
async ({ phase, questions, answers }) => {
|
|
1316
1357
|
let resolvedQuestions;
|
|
@@ -1395,7 +1436,7 @@ function registerQuestionTools(server2) {
|
|
|
1395
1436
|
}
|
|
1396
1437
|
|
|
1397
1438
|
// src/tools/orchestration.ts
|
|
1398
|
-
var
|
|
1439
|
+
var import_zod9 = require("zod");
|
|
1399
1440
|
var import_fs3 = require("fs");
|
|
1400
1441
|
var import_path3 = require("path");
|
|
1401
1442
|
var OTTER_NAME_TO_PHASE = [
|
|
@@ -1568,8 +1609,8 @@ function registerOrchestrationTools(server2) {
|
|
|
1568
1609
|
"stackwright_pro_parse_otter_response",
|
|
1569
1610
|
"Parse and validate a specialist otter's QUESTION_COLLECTION_MODE JSON response. Handles JSON extraction from LLM responses (strips markdown, fixes single quotes, trailing commas). Detects the phase from the otter name. Use this immediately after invoke_agent() to get a validated manifest phase object.",
|
|
1570
1611
|
{
|
|
1571
|
-
otterName:
|
|
1572
|
-
responseText:
|
|
1612
|
+
otterName: import_zod9.z.string().describe('The agent name, e.g. "stackwright-pro-api-otter"'),
|
|
1613
|
+
responseText: import_zod9.z.string().describe("Raw text response from the otter's QUESTION_COLLECTION_MODE invocation")
|
|
1573
1614
|
},
|
|
1574
1615
|
async ({ otterName, responseText }) => {
|
|
1575
1616
|
const { result, isError } = handleParseOtterResponse({ otterName, responseText });
|
|
@@ -1583,16 +1624,18 @@ function registerOrchestrationTools(server2) {
|
|
|
1583
1624
|
"stackwright_pro_save_manifest",
|
|
1584
1625
|
"Write the question manifest to .stackwright/question-manifest.json. Call this after collecting and parsing questions from all otters via stackwright_pro_parse_otter_response.",
|
|
1585
1626
|
{
|
|
1586
|
-
phases:
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1627
|
+
phases: jsonCoerce(
|
|
1628
|
+
import_zod9.z.array(
|
|
1629
|
+
import_zod9.z.object({
|
|
1630
|
+
phase: import_zod9.z.string(),
|
|
1631
|
+
otter: import_zod9.z.string(),
|
|
1632
|
+
questions: import_zod9.z.array(import_zod9.z.any()),
|
|
1633
|
+
requiredPackages: import_zod9.z.object({
|
|
1634
|
+
dependencies: import_zod9.z.record(import_zod9.z.string(), import_zod9.z.string()).optional(),
|
|
1635
|
+
devPackages: import_zod9.z.record(import_zod9.z.string(), import_zod9.z.string()).optional()
|
|
1636
|
+
}).optional()
|
|
1637
|
+
})
|
|
1638
|
+
)
|
|
1596
1639
|
).describe("Array of parsed phase objects from stackwright_pro_parse_otter_response")
|
|
1597
1640
|
},
|
|
1598
1641
|
async ({ phases }) => {
|
|
@@ -1607,15 +1650,21 @@ function registerOrchestrationTools(server2) {
|
|
|
1607
1650
|
"stackwright_pro_save_phase_answers",
|
|
1608
1651
|
"Save user answers for a phase to .stackwright/answers/{phase}.json. Pass rawAnswers directly from ask_user_question and the original manifest questions for label-to-value reverse mapping.",
|
|
1609
1652
|
{
|
|
1610
|
-
phase:
|
|
1611
|
-
rawAnswers:
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1653
|
+
phase: import_zod9.z.string().describe('Phase name, e.g. "designer"'),
|
|
1654
|
+
rawAnswers: jsonCoerce(
|
|
1655
|
+
import_zod9.z.array(
|
|
1656
|
+
import_zod9.z.object({
|
|
1657
|
+
question_header: import_zod9.z.string(),
|
|
1658
|
+
selected_options: import_zod9.z.array(import_zod9.z.string()),
|
|
1659
|
+
other_text: import_zod9.z.string().nullable().optional()
|
|
1660
|
+
})
|
|
1661
|
+
)
|
|
1662
|
+
).describe(
|
|
1663
|
+
"Answers as returned by ask_user_question \u2014 pass the native array, not a JSON string"
|
|
1664
|
+
),
|
|
1665
|
+
questions: jsonCoerce(import_zod9.z.array(import_zod9.z.any()).optional()).describe(
|
|
1666
|
+
"Original manifest questions for label\u2192value reverse-mapping \u2014 pass the native array, not a JSON string"
|
|
1667
|
+
)
|
|
1619
1668
|
},
|
|
1620
1669
|
async ({ phase, rawAnswers, questions }) => {
|
|
1621
1670
|
const { text, isError } = handleSavePhaseAnswers({
|
|
@@ -1633,7 +1682,7 @@ function registerOrchestrationTools(server2) {
|
|
|
1633
1682
|
"stackwright_pro_read_phase_answers",
|
|
1634
1683
|
"Read saved answers for a phase from .stackwright/answers/{phase}.json. Returns { missing: true } when no answers exist yet \u2014 use this to skip phases safely in the execution loop.",
|
|
1635
1684
|
{
|
|
1636
|
-
phase:
|
|
1685
|
+
phase: import_zod9.z.string().describe('Phase name, e.g. "designer"')
|
|
1637
1686
|
},
|
|
1638
1687
|
async ({ phase }) => {
|
|
1639
1688
|
const { text, isError } = handleReadPhaseAnswers({ phase });
|
|
@@ -1647,7 +1696,7 @@ function registerOrchestrationTools(server2) {
|
|
|
1647
1696
|
"stackwright_pro_get_otter_name",
|
|
1648
1697
|
"Get the agent name for a phase (e.g. 'designer' \u2192 'stackwright-pro-designer-otter'). Use this in the execution loop to invoke the correct specialist otter without hardcoding names in the prompt.",
|
|
1649
1698
|
{
|
|
1650
|
-
phase:
|
|
1699
|
+
phase: import_zod9.z.string().describe('Phase name, e.g. "designer", "api", "pages"')
|
|
1651
1700
|
},
|
|
1652
1701
|
async ({ phase }) => {
|
|
1653
1702
|
const { text, isError } = handleGetOtterName({ phase });
|
|
@@ -1660,7 +1709,7 @@ function registerOrchestrationTools(server2) {
|
|
|
1660
1709
|
}
|
|
1661
1710
|
|
|
1662
1711
|
// src/tools/pipeline.ts
|
|
1663
|
-
var
|
|
1712
|
+
var import_zod10 = require("zod");
|
|
1664
1713
|
var import_fs4 = require("fs");
|
|
1665
1714
|
var import_path4 = require("path");
|
|
1666
1715
|
var PHASE_ORDER = [
|
|
@@ -2134,19 +2183,15 @@ function registerPipelineTools(server2) {
|
|
|
2134
2183
|
"stackwright_pro_set_pipeline_state",
|
|
2135
2184
|
`Atomic read\u2192modify\u2192write pipeline state. ${DESC}`,
|
|
2136
2185
|
{
|
|
2137
|
-
phase:
|
|
2138
|
-
field:
|
|
2139
|
-
value:
|
|
2140
|
-
(v) => v === "true" ? true : v === "false" ? false : v,
|
|
2141
|
-
import_zod9.z.boolean().optional()
|
|
2142
|
-
).describe(
|
|
2186
|
+
phase: import_zod10.z.string().optional().describe('Phase to update, e.g. "designer"'),
|
|
2187
|
+
field: import_zod10.z.enum(["questionsCollected", "answered", "executed", "artifactWritten"]).optional().describe("Boolean field to set"),
|
|
2188
|
+
value: boolCoerce(import_zod10.z.boolean().optional()).describe(
|
|
2143
2189
|
'Value for the field \u2014 must be a JSON boolean (true/false), NOT the string "true"/"false"'
|
|
2144
2190
|
),
|
|
2145
|
-
status:
|
|
2146
|
-
incrementRetry:
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
).describe("Bump retryCount by 1 \u2014 must be a JSON boolean")
|
|
2191
|
+
status: import_zod10.z.enum(["setup", "questions", "execution", "done"]).optional().describe("Top-level status override"),
|
|
2192
|
+
incrementRetry: boolCoerce(import_zod10.z.boolean().optional()).describe(
|
|
2193
|
+
"Bump retryCount by 1 \u2014 must be a JSON boolean"
|
|
2194
|
+
)
|
|
2150
2195
|
},
|
|
2151
2196
|
async (args) => res(
|
|
2152
2197
|
handleSetPipelineState({
|
|
@@ -2174,30 +2219,30 @@ function registerPipelineTools(server2) {
|
|
|
2174
2219
|
"stackwright_pro_write_phase_questions",
|
|
2175
2220
|
`Parse otter question-collection response \u2192 .stackwright/questions/{phase}.json. ${DESC}`,
|
|
2176
2221
|
{
|
|
2177
|
-
phase:
|
|
2178
|
-
responseText:
|
|
2222
|
+
phase: import_zod10.z.string().describe('Phase name, e.g. "designer"'),
|
|
2223
|
+
responseText: import_zod10.z.string().describe("Raw LLM response from QUESTION_COLLECTION_MODE")
|
|
2179
2224
|
},
|
|
2180
2225
|
async ({ phase, responseText }) => res(handleWritePhaseQuestions({ phase, responseText }))
|
|
2181
2226
|
);
|
|
2182
2227
|
server2.tool(
|
|
2183
2228
|
"stackwright_pro_build_specialist_prompt",
|
|
2184
2229
|
`Assemble execution prompt from answers + upstream artifacts. Foreman passes verbatim. ${DESC}`,
|
|
2185
|
-
{ phase:
|
|
2230
|
+
{ phase: import_zod10.z.string().describe('Phase to build prompt for, e.g. "pages"') },
|
|
2186
2231
|
async ({ phase }) => res(handleBuildSpecialistPrompt({ phase }))
|
|
2187
2232
|
);
|
|
2188
2233
|
server2.tool(
|
|
2189
2234
|
"stackwright_pro_validate_artifact",
|
|
2190
2235
|
`Validate specialist response + write artifact to .stackwright/artifacts/. Returns retryPrompt on failure. ${DESC}`,
|
|
2191
2236
|
{
|
|
2192
|
-
phase:
|
|
2193
|
-
responseText:
|
|
2237
|
+
phase: import_zod10.z.string().describe('Phase that produced this artifact, e.g. "designer"'),
|
|
2238
|
+
responseText: import_zod10.z.string().describe("Raw response text from the specialist otter")
|
|
2194
2239
|
},
|
|
2195
2240
|
async ({ phase, responseText }) => res(handleValidateArtifact({ phase, responseText }))
|
|
2196
2241
|
);
|
|
2197
2242
|
}
|
|
2198
2243
|
|
|
2199
2244
|
// src/tools/safe-write.ts
|
|
2200
|
-
var
|
|
2245
|
+
var import_zod11 = require("zod");
|
|
2201
2246
|
var import_fs5 = require("fs");
|
|
2202
2247
|
var import_path5 = require("path");
|
|
2203
2248
|
var OTTER_WRITE_ALLOWLISTS = {
|
|
@@ -2429,10 +2474,10 @@ function registerSafeWriteTools(server2) {
|
|
|
2429
2474
|
"stackwright_pro_safe_write",
|
|
2430
2475
|
DESC,
|
|
2431
2476
|
{
|
|
2432
|
-
callerOtter:
|
|
2433
|
-
filePath:
|
|
2434
|
-
content:
|
|
2435
|
-
createDirectories:
|
|
2477
|
+
callerOtter: import_zod11.z.string().describe('The otter agent name requesting the write, e.g. "stackwright-pro-page-otter"'),
|
|
2478
|
+
filePath: import_zod11.z.string().describe('Relative path from project root, e.g. "pages/dashboard/content.yml"'),
|
|
2479
|
+
content: import_zod11.z.string().describe("File content to write"),
|
|
2480
|
+
createDirectories: import_zod11.z.boolean().optional().describe("Create parent directories if they don't exist. Default: true")
|
|
2436
2481
|
},
|
|
2437
2482
|
async ({ callerOtter, filePath, content, createDirectories }) => {
|
|
2438
2483
|
const result = handleSafeWrite({
|
|
@@ -2447,7 +2492,7 @@ function registerSafeWriteTools(server2) {
|
|
|
2447
2492
|
}
|
|
2448
2493
|
|
|
2449
2494
|
// src/tools/auth.ts
|
|
2450
|
-
var
|
|
2495
|
+
var import_zod12 = require("zod");
|
|
2451
2496
|
var import_fs6 = require("fs");
|
|
2452
2497
|
var import_path6 = require("path");
|
|
2453
2498
|
function buildHierarchy(roles) {
|
|
@@ -2802,35 +2847,35 @@ function registerAuthTools(server2) {
|
|
|
2802
2847
|
"stackwright_pro_configure_auth",
|
|
2803
2848
|
"Generate authentication middleware and configuration for a Next.js Stackwright application. Writes `middleware.ts` from a secure template, appends/updates the `auth:` section in `stackwright.yml`, 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.",
|
|
2804
2849
|
{
|
|
2805
|
-
method:
|
|
2806
|
-
provider:
|
|
2850
|
+
method: import_zod12.z.enum(["cac", "oidc", "oauth2", "none"]),
|
|
2851
|
+
provider: import_zod12.z.enum(["azure-ad", "okta", "ping", "cognito", "custom"]).optional(),
|
|
2807
2852
|
// CAC
|
|
2808
|
-
cacCaBundle:
|
|
2809
|
-
cacEdipiLookup:
|
|
2810
|
-
cacOcspEndpoint:
|
|
2811
|
-
cacCertHeader:
|
|
2853
|
+
cacCaBundle: import_zod12.z.string().optional(),
|
|
2854
|
+
cacEdipiLookup: import_zod12.z.string().optional(),
|
|
2855
|
+
cacOcspEndpoint: import_zod12.z.string().optional(),
|
|
2856
|
+
cacCertHeader: import_zod12.z.string().optional(),
|
|
2812
2857
|
// OIDC
|
|
2813
|
-
oidcDiscoveryUrl:
|
|
2814
|
-
oidcClientId:
|
|
2815
|
-
oidcClientSecret:
|
|
2816
|
-
oidcScopes:
|
|
2817
|
-
oidcRoleClaim:
|
|
2858
|
+
oidcDiscoveryUrl: import_zod12.z.string().optional(),
|
|
2859
|
+
oidcClientId: import_zod12.z.string().optional(),
|
|
2860
|
+
oidcClientSecret: import_zod12.z.string().optional(),
|
|
2861
|
+
oidcScopes: import_zod12.z.string().optional(),
|
|
2862
|
+
oidcRoleClaim: import_zod12.z.string().optional(),
|
|
2818
2863
|
// OAuth2
|
|
2819
|
-
oauth2AuthUrl:
|
|
2820
|
-
oauth2TokenUrl:
|
|
2821
|
-
oauth2ClientId:
|
|
2822
|
-
oauth2ClientSecret:
|
|
2823
|
-
oauth2Scopes:
|
|
2864
|
+
oauth2AuthUrl: import_zod12.z.string().optional(),
|
|
2865
|
+
oauth2TokenUrl: import_zod12.z.string().optional(),
|
|
2866
|
+
oauth2ClientId: import_zod12.z.string().optional(),
|
|
2867
|
+
oauth2ClientSecret: import_zod12.z.string().optional(),
|
|
2868
|
+
oauth2Scopes: import_zod12.z.string().optional(),
|
|
2824
2869
|
// RBAC
|
|
2825
|
-
rbacRoles:
|
|
2826
|
-
rbacDefaultRole:
|
|
2870
|
+
rbacRoles: jsonCoerce(import_zod12.z.array(import_zod12.z.string()).optional()),
|
|
2871
|
+
rbacDefaultRole: import_zod12.z.string().optional(),
|
|
2827
2872
|
// Audit
|
|
2828
|
-
auditEnabled:
|
|
2829
|
-
auditRetentionDays:
|
|
2873
|
+
auditEnabled: boolCoerce(import_zod12.z.boolean().optional()),
|
|
2874
|
+
auditRetentionDays: numCoerce(import_zod12.z.number().int().positive().optional()),
|
|
2830
2875
|
// Routes
|
|
2831
|
-
protectedRoutes:
|
|
2876
|
+
protectedRoutes: jsonCoerce(import_zod12.z.array(import_zod12.z.string()).optional()),
|
|
2832
2877
|
// Injection for tests
|
|
2833
|
-
_cwd:
|
|
2878
|
+
_cwd: import_zod12.z.string().optional()
|
|
2834
2879
|
},
|
|
2835
2880
|
async (params) => {
|
|
2836
2881
|
const cwd = params._cwd ?? process.cwd();
|
|
@@ -2874,7 +2919,7 @@ var _checksums = /* @__PURE__ */ new Map([
|
|
|
2874
2919
|
],
|
|
2875
2920
|
[
|
|
2876
2921
|
"stackwright-pro-theme-otter.json",
|
|
2877
|
-
"
|
|
2922
|
+
"1f182326f1acd3d4091a38c7012085cbb4945893e95be4ca3de72318ad092767"
|
|
2878
2923
|
],
|
|
2879
2924
|
[
|
|
2880
2925
|
"stackwright-pro-workflow-otter.json",
|
|
@@ -3058,7 +3103,7 @@ function registerIntegrityTools(server2) {
|
|
|
3058
3103
|
}
|
|
3059
3104
|
|
|
3060
3105
|
// src/tools/domain.ts
|
|
3061
|
-
var
|
|
3106
|
+
var import_zod13 = require("zod");
|
|
3062
3107
|
var import_fs8 = require("fs");
|
|
3063
3108
|
var import_path8 = require("path");
|
|
3064
3109
|
function handleListCollections(input) {
|
|
@@ -3444,7 +3489,7 @@ function registerDomainTools(server2) {
|
|
|
3444
3489
|
"stackwright_pro_resolve_data_strategy",
|
|
3445
3490
|
"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.",
|
|
3446
3491
|
{
|
|
3447
|
-
strategy:
|
|
3492
|
+
strategy: import_zod13.z.string().describe(
|
|
3448
3493
|
'The data-1 answer value: "pulse-fast", "isr-fast", "isr-standard", or "isr-slow"'
|
|
3449
3494
|
)
|
|
3450
3495
|
},
|
|
@@ -3454,7 +3499,7 @@ function registerDomainTools(server2) {
|
|
|
3454
3499
|
"stackwright_pro_validate_workflow",
|
|
3455
3500
|
"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.",
|
|
3456
3501
|
{
|
|
3457
|
-
workflow:
|
|
3502
|
+
workflow: jsonCoerce(import_zod13.z.record(import_zod13.z.string(), import_zod13.z.unknown()).optional()).describe(
|
|
3458
3503
|
"Parsed workflow object. If omitted, reads from .stackwright/artifacts/workflow-config.json"
|
|
3459
3504
|
)
|
|
3460
3505
|
},
|
|
@@ -3484,7 +3529,7 @@ var package_default = {
|
|
|
3484
3529
|
"test:coverage": "vitest run --coverage"
|
|
3485
3530
|
},
|
|
3486
3531
|
name: "@stackwright-pro/mcp",
|
|
3487
|
-
version: "0.2.0-alpha.
|
|
3532
|
+
version: "0.2.0-alpha.15",
|
|
3488
3533
|
description: "MCP tools for Stackwright Pro - Data Explorer, Security, ISR, and Dashboard generation",
|
|
3489
3534
|
license: "PROPRIETARY",
|
|
3490
3535
|
main: "./dist/server.js",
|