@stackwright-pro/mcp 0.2.0-alpha.111 → 0.2.0-alpha.113
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 +8 -4
- package/dist/integrity.js.map +1 -1
- package/dist/integrity.mjs +8 -4
- package/dist/integrity.mjs.map +1 -1
- package/dist/pipeline-constants.d.mts +5 -3
- package/dist/pipeline-constants.d.ts +5 -3
- package/dist/pipeline-constants.js +47 -1
- package/dist/pipeline-constants.js.map +1 -1
- package/dist/pipeline-constants.mjs +47 -1
- package/dist/pipeline-constants.mjs.map +1 -1
- package/dist/server.js +349 -67
- package/dist/server.js.map +1 -1
- package/dist/server.mjs +340 -58
- package/dist/server.mjs.map +1 -1
- package/package.json +8 -8
package/dist/server.js
CHANGED
|
@@ -580,7 +580,7 @@ function registerDashboardTools(server2) {
|
|
|
580
580
|
yamlLines.push(` header: Status`);
|
|
581
581
|
yamlLines.push(` type: badge`);
|
|
582
582
|
}
|
|
583
|
-
const
|
|
583
|
+
const yaml4 = yamlLines.join("\n");
|
|
584
584
|
return {
|
|
585
585
|
content: [
|
|
586
586
|
{
|
|
@@ -590,7 +590,7 @@ function registerDashboardTools(server2) {
|
|
|
590
590
|
Layout: ${layout}
|
|
591
591
|
|
|
592
592
|
\`\`\`yaml
|
|
593
|
-
${
|
|
593
|
+
${yaml4}
|
|
594
594
|
\`\`\`
|
|
595
595
|
|
|
596
596
|
\u{1F4A1} Add this to pages/dashboard/content.yml and validate with stackwright_validate_pages.`
|
|
@@ -671,7 +671,7 @@ ${yaml3}
|
|
|
671
671
|
yamlLines.push(" action: navigate");
|
|
672
672
|
yamlLines.push(` href: "/${entity}"`);
|
|
673
673
|
yamlLines.push(" style: secondary");
|
|
674
|
-
const
|
|
674
|
+
const yaml4 = yamlLines.join("\n");
|
|
675
675
|
return {
|
|
676
676
|
content: [
|
|
677
677
|
{
|
|
@@ -679,7 +679,7 @@ ${yaml3}
|
|
|
679
679
|
text: `\u{1F4C4} Generated Detail Page for: ${entity}
|
|
680
680
|
|
|
681
681
|
\`\`\`yaml
|
|
682
|
-
${
|
|
682
|
+
${yaml4}
|
|
683
683
|
\`\`\`
|
|
684
684
|
|
|
685
685
|
\u{1F4A1} Add this to pages/${entity}/[${slugField}]/content.yml and validate.`
|
|
@@ -2834,21 +2834,40 @@ function readAllManifestPages(artifactsDir) {
|
|
|
2834
2834
|
return allPages;
|
|
2835
2835
|
}
|
|
2836
2836
|
for (const entry of entries) {
|
|
2837
|
-
if (
|
|
2838
|
-
|
|
2839
|
-
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
|
|
2843
|
-
|
|
2837
|
+
if (entry.endsWith("-manifest.json")) {
|
|
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
|
+
continue;
|
|
2854
|
+
}
|
|
2855
|
+
if (entry === "workflow-config.json" || entry.startsWith("workflow-config-")) {
|
|
2856
|
+
const filePath = (0, import_path6.join)(artifactsDir, entry);
|
|
2857
|
+
try {
|
|
2858
|
+
const raw = JSON.parse((0, import_fs6.readFileSync)(filePath, "utf-8"));
|
|
2859
|
+
const route = raw.workflow?.route;
|
|
2860
|
+
if (typeof route !== "string" || !route) continue;
|
|
2861
|
+
const slug = route.startsWith("/") ? route.slice(1) : route;
|
|
2844
2862
|
allPages.push({
|
|
2845
|
-
slug
|
|
2846
|
-
authRequired:
|
|
2847
|
-
requiredRoles:
|
|
2863
|
+
slug,
|
|
2864
|
+
authRequired: true,
|
|
2865
|
+
requiredRoles: void 0,
|
|
2848
2866
|
source: entry
|
|
2849
2867
|
});
|
|
2868
|
+
} catch {
|
|
2850
2869
|
}
|
|
2851
|
-
|
|
2870
|
+
continue;
|
|
2852
2871
|
}
|
|
2853
2872
|
}
|
|
2854
2873
|
return allPages;
|
|
@@ -2856,7 +2875,7 @@ function readAllManifestPages(artifactsDir) {
|
|
|
2856
2875
|
function registerReadAuthManifestsTool(server2) {
|
|
2857
2876
|
server2.tool(
|
|
2858
2877
|
"stackwright_pro_read_auth_manifests",
|
|
2859
|
-
"Read ALL
|
|
2878
|
+
"Read ALL route-producing artifacts from the pipeline artifacts directory: *-manifest.json files (pages, dashboard, geo, form-wizard) AND workflow-config.json / workflow-config-*.json (different shape: workflow.route). Deterministically derives protectedRoutes and uncoveredSlugs. Uses the both-forms invariant (swp-n7kk): every authRequired route registers BOTH /{slug} (exact) AND /{slug}/:path* (sub-path). Workflow routes appear in uncoveredSlugs (no requiredRoles declared) for auth-reconcile to resolve via cross-cutting rules from auth-config.json. Extended by swp-hng0 to cover all four manifest types (was: pages+dashboard only).",
|
|
2860
2879
|
{
|
|
2861
2880
|
rbacRoles: import_zod11.z.array(import_zod11.z.string()).describe(
|
|
2862
2881
|
'RBAC role hierarchy in descending privilege order, e.g. ["ESF8_COORDINATOR", "HOSPITAL_EM", "OBSERVER"]. Used to compute the lowestRole for each authRequired page.'
|
|
@@ -2990,7 +3009,7 @@ function enrichErrors(issues, synonyms) {
|
|
|
2990
3009
|
});
|
|
2991
3010
|
}
|
|
2992
3011
|
function handleValidateYamlFragment(input) {
|
|
2993
|
-
const { schemaName, yaml:
|
|
3012
|
+
const { schemaName, yaml: yaml4 } = input;
|
|
2994
3013
|
if (!SUPPORTED_SCHEMA_NAMES.includes(schemaName)) {
|
|
2995
3014
|
return {
|
|
2996
3015
|
valid: false,
|
|
@@ -3000,7 +3019,7 @@ function handleValidateYamlFragment(input) {
|
|
|
3000
3019
|
const name = schemaName;
|
|
3001
3020
|
let parsed;
|
|
3002
3021
|
try {
|
|
3003
|
-
parsed = (0, import_js_yaml2.load)(
|
|
3022
|
+
parsed = (0, import_js_yaml2.load)(yaml4);
|
|
3004
3023
|
} catch (err) {
|
|
3005
3024
|
return {
|
|
3006
3025
|
valid: false,
|
|
@@ -3026,8 +3045,8 @@ function registerValidateYamlFragmentTool(server2) {
|
|
|
3026
3045
|
),
|
|
3027
3046
|
yaml: import_zod12.z.string().describe("YAML string to validate (can also be JSON \u2014 js-yaml parses both)")
|
|
3028
3047
|
},
|
|
3029
|
-
async ({ schemaName, yaml:
|
|
3030
|
-
const result = handleValidateYamlFragment({ schemaName, yaml:
|
|
3048
|
+
async ({ schemaName, yaml: yaml4 }) => {
|
|
3049
|
+
const result = handleValidateYamlFragment({ schemaName, yaml: yaml4 });
|
|
3031
3050
|
return {
|
|
3032
3051
|
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
3033
3052
|
};
|
|
@@ -3240,6 +3259,9 @@ var MANIFEST_NAME_TO_PHASE = {
|
|
|
3240
3259
|
"stackwright-pro-dashboard-otter": "dashboard",
|
|
3241
3260
|
"stackwright-pro-form-wizard-otter": "workflow",
|
|
3242
3261
|
"stackwright-pro-geo-otter": "geo",
|
|
3262
|
+
// auth-reconcile runs AFTER pages+dashboard+geo+workflow (wave 6)
|
|
3263
|
+
// Reads auth-config.json + all four manifests; emits auth-reconcile-config.json + stackwright.auth.yml
|
|
3264
|
+
"stackwright-pro-auth-reconcile-otter": "auth-reconcile",
|
|
3243
3265
|
"stackwright-pro-polish-otter": "polish",
|
|
3244
3266
|
"stackwright-services-otter": "services",
|
|
3245
3267
|
"stackwright-pro-qa-otter": "qa"
|
|
@@ -3455,13 +3477,19 @@ var PHASE_ORDER = [
|
|
|
3455
3477
|
"api",
|
|
3456
3478
|
"data",
|
|
3457
3479
|
"auth",
|
|
3458
|
-
// moved earlier
|
|
3480
|
+
// wave 2 — moved earlier, only depends on design-language.json (designer)
|
|
3459
3481
|
"geo",
|
|
3460
3482
|
"workflow",
|
|
3461
3483
|
"services",
|
|
3462
3484
|
"pages",
|
|
3463
3485
|
"dashboard",
|
|
3486
|
+
// auth-reconcile: wave 6 — post-manifest reconciliation
|
|
3487
|
+
// Reads auth-config.json + pages/dashboard/geo/workflow manifests;
|
|
3488
|
+
// emits auth-reconcile-config.json + stackwright.auth.yml (Gate 4 single source of truth)
|
|
3489
|
+
"auth-reconcile",
|
|
3490
|
+
// wave 7: polish — depends on auth-reconcile (replaces auth-config.json direct dep)
|
|
3464
3491
|
"polish",
|
|
3492
|
+
// wave 8: qa — terminal QA gate, depends on polish + transitively everything
|
|
3465
3493
|
"qa"
|
|
3466
3494
|
];
|
|
3467
3495
|
var PHASE_ARTIFACT = {
|
|
@@ -3475,6 +3503,7 @@ var PHASE_ARTIFACT = {
|
|
|
3475
3503
|
dashboard: "dashboard-manifest.json",
|
|
3476
3504
|
workflow: "workflow-config.json",
|
|
3477
3505
|
services: "services-config.json",
|
|
3506
|
+
"auth-reconcile": "auth-reconcile-config.json",
|
|
3478
3507
|
polish: "polish-manifest.json",
|
|
3479
3508
|
geo: "geo-manifest.json",
|
|
3480
3509
|
qa: "qa-findings.json"
|
|
@@ -3489,16 +3518,36 @@ var PHASE_TO_OTTER2 = {
|
|
|
3489
3518
|
pages: "stackwright-pro-page-otter",
|
|
3490
3519
|
dashboard: "stackwright-pro-dashboard-otter",
|
|
3491
3520
|
workflow: "stackwright-pro-form-wizard-otter",
|
|
3521
|
+
"auth-reconcile": "stackwright-pro-auth-reconcile-otter",
|
|
3492
3522
|
services: "stackwright-services-otter",
|
|
3493
3523
|
polish: "stackwright-pro-polish-otter",
|
|
3494
3524
|
geo: "stackwright-pro-geo-otter",
|
|
3495
3525
|
qa: "stackwright-pro-qa-otter"
|
|
3496
3526
|
};
|
|
3527
|
+
var AUTO_EXECUTE_PHASES = /* @__PURE__ */ new Set(["auth-reconcile"]);
|
|
3528
|
+
var PhaseStatusSchema = import_zod14.z.object({
|
|
3529
|
+
status: import_zod14.z.enum(["pending", "running", "completed", "skipped", "failed"]).default("pending"),
|
|
3530
|
+
questionsCollected: import_zod14.z.boolean().default(false),
|
|
3531
|
+
answered: import_zod14.z.boolean().default(false),
|
|
3532
|
+
executed: import_zod14.z.boolean().default(false),
|
|
3533
|
+
artifactWritten: import_zod14.z.boolean().default(false),
|
|
3534
|
+
retryCount: import_zod14.z.number().default(0),
|
|
3535
|
+
inFlight: import_zod14.z.boolean().default(false)
|
|
3536
|
+
});
|
|
3537
|
+
var PipelineStateSchema = import_zod14.z.object({
|
|
3538
|
+
version: import_zod14.z.literal("1.0"),
|
|
3539
|
+
currentPhase: import_zod14.z.string(),
|
|
3540
|
+
status: import_zod14.z.enum(["setup", "questions", "execution", "done"]),
|
|
3541
|
+
phases: import_zod14.z.record(import_zod14.z.string(), PhaseStatusSchema),
|
|
3542
|
+
startedAt: import_zod14.z.string(),
|
|
3543
|
+
updatedAt: import_zod14.z.string()
|
|
3544
|
+
});
|
|
3497
3545
|
function isValidPhase2(phase) {
|
|
3498
3546
|
return PHASE_ORDER.includes(phase);
|
|
3499
3547
|
}
|
|
3500
3548
|
function defaultPhaseStatus() {
|
|
3501
3549
|
return {
|
|
3550
|
+
status: "pending",
|
|
3502
3551
|
questionsCollected: false,
|
|
3503
3552
|
answered: false,
|
|
3504
3553
|
executed: false,
|
|
@@ -3529,10 +3578,9 @@ function readState(cwd) {
|
|
|
3529
3578
|
const p = statePath(cwd);
|
|
3530
3579
|
if (!(0, import_fs8.existsSync)(p)) return createDefaultState();
|
|
3531
3580
|
const raw = JSON.parse(safeReadSync(p));
|
|
3532
|
-
|
|
3533
|
-
|
|
3534
|
-
|
|
3535
|
-
return raw;
|
|
3581
|
+
const result = PipelineStateSchema.safeParse(raw);
|
|
3582
|
+
if (!result.success) return createDefaultState();
|
|
3583
|
+
return result.data;
|
|
3536
3584
|
}
|
|
3537
3585
|
function safeWriteSync(filePath, content) {
|
|
3538
3586
|
if ((0, import_fs8.existsSync)(filePath)) {
|
|
@@ -3621,13 +3669,16 @@ function handleSetPipelineState(input) {
|
|
|
3621
3669
|
isError: true
|
|
3622
3670
|
};
|
|
3623
3671
|
}
|
|
3624
|
-
|
|
3625
|
-
|
|
3626
|
-
|
|
3627
|
-
|
|
3628
|
-
|
|
3629
|
-
|
|
3630
|
-
|
|
3672
|
+
if (input.field === "artifactWritten") {
|
|
3673
|
+
return {
|
|
3674
|
+
text: JSON.stringify({
|
|
3675
|
+
error: true,
|
|
3676
|
+
message: "Cannot set 'artifactWritten' directly. Use stackwright_pro_validate_artifact instead \u2014 it verifies the file exists on disk before flagging."
|
|
3677
|
+
}),
|
|
3678
|
+
isError: true
|
|
3679
|
+
};
|
|
3680
|
+
}
|
|
3681
|
+
const VALID_FIELDS = ["questionsCollected", "answered", "executed", "inFlight"];
|
|
3631
3682
|
if (input.field && !VALID_FIELDS.includes(input.field)) {
|
|
3632
3683
|
return {
|
|
3633
3684
|
text: JSON.stringify({
|
|
@@ -3648,6 +3699,15 @@ function handleSetPipelineState(input) {
|
|
|
3648
3699
|
isError: true
|
|
3649
3700
|
};
|
|
3650
3701
|
}
|
|
3702
|
+
if (update.field === "artifactWritten") {
|
|
3703
|
+
return {
|
|
3704
|
+
text: JSON.stringify({
|
|
3705
|
+
error: true,
|
|
3706
|
+
message: "Cannot set 'artifactWritten' directly. Use stackwright_pro_validate_artifact instead \u2014 it verifies the file exists on disk before flagging."
|
|
3707
|
+
}),
|
|
3708
|
+
isError: true
|
|
3709
|
+
};
|
|
3710
|
+
}
|
|
3651
3711
|
if (!VALID_FIELDS.includes(update.field)) {
|
|
3652
3712
|
return {
|
|
3653
3713
|
text: JSON.stringify({
|
|
@@ -3673,6 +3733,9 @@ function handleSetPipelineState(input) {
|
|
|
3673
3733
|
if (input.field && input.value !== void 0) {
|
|
3674
3734
|
phaseState[input.field] = input.value;
|
|
3675
3735
|
}
|
|
3736
|
+
if (input.phaseStatus !== void 0) {
|
|
3737
|
+
phaseState.status = input.phaseStatus;
|
|
3738
|
+
}
|
|
3676
3739
|
if (input.incrementRetry) {
|
|
3677
3740
|
phaseState.retryCount += 1;
|
|
3678
3741
|
}
|
|
@@ -3699,16 +3762,6 @@ function handleSetPipelineState(input) {
|
|
|
3699
3762
|
},
|
|
3700
3763
|
{ cwd }
|
|
3701
3764
|
);
|
|
3702
|
-
if (input.field === "artifactWritten" && input.value === true && input.phase) {
|
|
3703
|
-
(0, import_telemetry.emit)({ type: "phase_complete", phase: input.phase }, { cwd });
|
|
3704
|
-
}
|
|
3705
|
-
if (input.updates) {
|
|
3706
|
-
for (const update of input.updates) {
|
|
3707
|
-
if (update.field === "artifactWritten" && update.value === true) {
|
|
3708
|
-
(0, import_telemetry.emit)({ type: "phase_complete", phase: update.phase }, { cwd });
|
|
3709
|
-
}
|
|
3710
|
-
}
|
|
3711
|
-
}
|
|
3712
3765
|
} catch {
|
|
3713
3766
|
}
|
|
3714
3767
|
return { text: JSON.stringify(state), isError: false };
|
|
@@ -3728,6 +3781,9 @@ function handleCheckExecutionReady(_cwd, phase) {
|
|
|
3728
3781
|
isError: true
|
|
3729
3782
|
};
|
|
3730
3783
|
}
|
|
3784
|
+
if (AUTO_EXECUTE_PHASES.has(phase)) {
|
|
3785
|
+
return { text: JSON.stringify({ ready: true, phase, autoExecute: true }), isError: false };
|
|
3786
|
+
}
|
|
3731
3787
|
const answerFile = (0, import_path8.join)(cwd, ".stackwright", "answers", `${phase}.json`);
|
|
3732
3788
|
if (!(0, import_fs8.existsSync)(answerFile)) {
|
|
3733
3789
|
return {
|
|
@@ -3757,6 +3813,10 @@ function handleCheckExecutionReady(_cwd, phase) {
|
|
|
3757
3813
|
const answeredPhases = [];
|
|
3758
3814
|
const missingPhases = [];
|
|
3759
3815
|
for (const phase2 of PHASE_ORDER) {
|
|
3816
|
+
if (AUTO_EXECUTE_PHASES.has(phase2)) {
|
|
3817
|
+
answeredPhases.push(phase2);
|
|
3818
|
+
continue;
|
|
3819
|
+
}
|
|
3760
3820
|
const answerFile = (0, import_path8.join)(answersDir, `${phase2}.json`);
|
|
3761
3821
|
if ((0, import_fs8.existsSync)(answerFile)) {
|
|
3762
3822
|
try {
|
|
@@ -4085,6 +4145,8 @@ var PHASE_REQUIRED_KEYS = {
|
|
|
4085
4145
|
dashboard: ["version", "generatedBy"],
|
|
4086
4146
|
workflow: ["version", "generatedBy"],
|
|
4087
4147
|
services: ["version", "generatedBy", "flows"],
|
|
4148
|
+
// auth-reconcile: must have version, generatedBy, and merged protectedRoutes
|
|
4149
|
+
"auth-reconcile": ["version", "generatedBy", "protectedRoutes"],
|
|
4088
4150
|
polish: ["version", "generatedBy"],
|
|
4089
4151
|
geo: ["version", "generatedBy", "geoCollections"],
|
|
4090
4152
|
// qa: skipped=true path only needs version+generatedBy+skipped;
|
|
@@ -4364,6 +4426,28 @@ var PHASE_ARTIFACT_SCHEMA = {
|
|
|
4364
4426
|
null,
|
|
4365
4427
|
2
|
|
4366
4428
|
),
|
|
4429
|
+
"auth-reconcile": JSON.stringify(
|
|
4430
|
+
{
|
|
4431
|
+
version: "1.0",
|
|
4432
|
+
generatedBy: "stackwright-pro-auth-reconcile-otter",
|
|
4433
|
+
authType: "<oidc|saml|cac|oauth2>",
|
|
4434
|
+
rbacRoles: ["<HIGHEST_ROLE>", "<MID_ROLE>", "<LOWEST_ROLE>"],
|
|
4435
|
+
rbacDefaultRole: "<LOWEST_ROLE>",
|
|
4436
|
+
protectedRoutes: [
|
|
4437
|
+
{ pattern: "/dashboard", requiredRole: "<role>" },
|
|
4438
|
+
{ pattern: "/dashboard/:path*", requiredRole: "<role>" }
|
|
4439
|
+
],
|
|
4440
|
+
uncoveredSlugs: [],
|
|
4441
|
+
manifestsRead: ["pages-manifest.json", "dashboard-manifest.json", "geo-manifest.json"],
|
|
4442
|
+
summary: {
|
|
4443
|
+
totalRoutes: 2,
|
|
4444
|
+
manifestDerived: 2,
|
|
4445
|
+
crossCutting: 0
|
|
4446
|
+
}
|
|
4447
|
+
},
|
|
4448
|
+
null,
|
|
4449
|
+
2
|
|
4450
|
+
),
|
|
4367
4451
|
polish: JSON.stringify(
|
|
4368
4452
|
{
|
|
4369
4453
|
version: "1.0",
|
|
@@ -4787,6 +4871,7 @@ function _validateArtifactInner(input) {
|
|
|
4787
4871
|
if (!state.phases[phase]) state.phases[phase] = defaultPhaseStatus();
|
|
4788
4872
|
const ps = state.phases[phase];
|
|
4789
4873
|
ps.artifactWritten = true;
|
|
4874
|
+
ps.status = "completed";
|
|
4790
4875
|
});
|
|
4791
4876
|
const topKeys = Object.keys(artifact).slice(0, 5).join(", ");
|
|
4792
4877
|
const result = {
|
|
@@ -4814,6 +4899,7 @@ function handleValidateArtifact(input) {
|
|
|
4814
4899
|
const parsed = JSON.parse(result.text);
|
|
4815
4900
|
if (parsed.valid === true && parsed.artifactPath) {
|
|
4816
4901
|
(0, import_telemetry.emit)({ type: "file_write", path: parsed.artifactPath, phase }, { cwd });
|
|
4902
|
+
(0, import_telemetry.emit)({ type: "phase_complete", phase }, { cwd });
|
|
4817
4903
|
}
|
|
4818
4904
|
(0, import_telemetry.emit)(
|
|
4819
4905
|
{
|
|
@@ -4914,12 +5000,19 @@ function registerPipelineTools(server2) {
|
|
|
4914
5000
|
`Atomic read\u2192modify\u2192write pipeline state. ${DESC}`,
|
|
4915
5001
|
{
|
|
4916
5002
|
phase: import_zod14.z.string().optional().describe('Phase to update, e.g. "designer"'),
|
|
4917
|
-
field: import_zod14.z.enum(["questionsCollected", "answered", "executed", "
|
|
5003
|
+
field: import_zod14.z.enum(["questionsCollected", "answered", "executed", "inFlight"]).optional().describe(
|
|
5004
|
+
"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)."
|
|
5005
|
+
),
|
|
4918
5006
|
// inFlight: set true BEFORE specialist invoke (dataflow mode, swp-ioc7); false after.
|
|
4919
5007
|
value: boolCoerce(import_zod14.z.boolean().optional()).describe(
|
|
4920
5008
|
'Value for the field \u2014 must be a JSON boolean (true/false), NOT the string "true"/"false"'
|
|
4921
5009
|
),
|
|
4922
|
-
|
|
5010
|
+
// phaseStatus: per-phase execution enum — DISTINCT from top-level `status` (pipeline flow).
|
|
5011
|
+
// Named `phaseStatus` to avoid ambiguity. Sets PhaseStatus.status on the given phase.
|
|
5012
|
+
phaseStatus: import_zod14.z.enum(["pending", "running", "completed", "skipped", "failed"]).optional().describe(
|
|
5013
|
+
"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."
|
|
5014
|
+
),
|
|
5015
|
+
status: import_zod14.z.enum(["setup", "questions", "execution", "done"]).optional().describe("Top-level pipeline flow status override \u2014 distinct from phaseStatus"),
|
|
4923
5016
|
incrementRetry: boolCoerce(import_zod14.z.boolean().optional()).describe(
|
|
4924
5017
|
"Bump retryCount by 1 \u2014 must be a JSON boolean"
|
|
4925
5018
|
),
|
|
@@ -4931,8 +5024,8 @@ function registerPipelineTools(server2) {
|
|
|
4931
5024
|
"questionsCollected",
|
|
4932
5025
|
"answered",
|
|
4933
5026
|
"executed",
|
|
4934
|
-
"artifactWritten",
|
|
4935
5027
|
"inFlight"
|
|
5028
|
+
// artifactWritten intentionally absent — use validate_artifact (swp-og9c)
|
|
4936
5029
|
]),
|
|
4937
5030
|
value: import_zod14.z.boolean()
|
|
4938
5031
|
})
|
|
@@ -4944,6 +5037,7 @@ function registerPipelineTools(server2) {
|
|
|
4944
5037
|
...args.phase != null ? { phase: args.phase } : {},
|
|
4945
5038
|
...args.field != null ? { field: args.field } : {},
|
|
4946
5039
|
...args.value != null ? { value: args.value } : {},
|
|
5040
|
+
...args.phaseStatus != null ? { phaseStatus: args.phaseStatus } : {},
|
|
4947
5041
|
...args.status != null ? { status: args.status } : {},
|
|
4948
5042
|
...args.incrementRetry != null ? { incrementRetry: args.incrementRetry } : {},
|
|
4949
5043
|
...args.updates != null ? { updates: args.updates } : {}
|
|
@@ -5105,6 +5199,20 @@ var OTTER_WRITE_ALLOWLISTS = {
|
|
|
5105
5199
|
description: "Stackwright config (themeName + customTheme writeback)"
|
|
5106
5200
|
}
|
|
5107
5201
|
],
|
|
5202
|
+
// swp-hng0: auth-reconcile otter — reads all manifests, re-emits auth-reconcile-config.json
|
|
5203
|
+
// AND overwrites stackwright.auth.yml (Gate 4: single source of truth after reconciliation)
|
|
5204
|
+
"stackwright-pro-auth-reconcile-otter": [
|
|
5205
|
+
{
|
|
5206
|
+
prefix: ".stackwright/artifacts/",
|
|
5207
|
+
suffix: ".json",
|
|
5208
|
+
description: "Auth reconcile artifact (auth-reconcile-config.json)"
|
|
5209
|
+
},
|
|
5210
|
+
{
|
|
5211
|
+
prefix: "stackwright.auth.",
|
|
5212
|
+
suffix: ".yml",
|
|
5213
|
+
description: "Canonical auth sidecar (stackwright.auth.yml \u2014 Gate 4 rewrite)"
|
|
5214
|
+
}
|
|
5215
|
+
],
|
|
5108
5216
|
"stackwright-pro-auth-otter": [
|
|
5109
5217
|
{ prefix: ".stackwright/artifacts/", suffix: ".json", description: "Auth config artifact" },
|
|
5110
5218
|
{
|
|
@@ -6528,7 +6636,11 @@ var _checksums = /* @__PURE__ */ new Map([
|
|
|
6528
6636
|
],
|
|
6529
6637
|
[
|
|
6530
6638
|
"stackwright-pro-auth-otter.json",
|
|
6531
|
-
"
|
|
6639
|
+
"c9302132ac4180c70dd452814eb4aa4fb9a1d6a9683f6e01ffce509a6001c6cf"
|
|
6640
|
+
],
|
|
6641
|
+
[
|
|
6642
|
+
"stackwright-pro-auth-reconcile-otter.json",
|
|
6643
|
+
"7ffd67d51568c7b2a1eb2ea0ac2b2a8041eb9ddd9c1eb5b95744e55ba049b385"
|
|
6532
6644
|
],
|
|
6533
6645
|
[
|
|
6534
6646
|
"stackwright-pro-dashboard-otter.json",
|
|
@@ -6536,7 +6648,7 @@ var _checksums = /* @__PURE__ */ new Map([
|
|
|
6536
6648
|
],
|
|
6537
6649
|
[
|
|
6538
6650
|
"stackwright-pro-data-otter.json",
|
|
6539
|
-
"
|
|
6651
|
+
"7d1de846488d84eebf8798aef4d75f4f4d250c1ae070ce1200ead3bb8a545eaf"
|
|
6540
6652
|
],
|
|
6541
6653
|
[
|
|
6542
6654
|
"stackwright-pro-designer-otter.json",
|
|
@@ -6548,7 +6660,7 @@ var _checksums = /* @__PURE__ */ new Map([
|
|
|
6548
6660
|
],
|
|
6549
6661
|
[
|
|
6550
6662
|
"stackwright-pro-foreman-otter.json",
|
|
6551
|
-
"
|
|
6663
|
+
"65aa3273274b2b1859d432c3d1166c4a73971861036bf18c35acd8a5357fcf26"
|
|
6552
6664
|
],
|
|
6553
6665
|
[
|
|
6554
6666
|
"stackwright-pro-form-wizard-otter.json",
|
|
@@ -6564,7 +6676,7 @@ var _checksums = /* @__PURE__ */ new Map([
|
|
|
6564
6676
|
],
|
|
6565
6677
|
[
|
|
6566
6678
|
"stackwright-pro-polish-otter.json",
|
|
6567
|
-
"
|
|
6679
|
+
"3ae1252a60727ebca67e33a807d5061cafb88de52f3b98a9d4641f9db725a6ed"
|
|
6568
6680
|
],
|
|
6569
6681
|
[
|
|
6570
6682
|
"stackwright-pro-qa-otter.json",
|
|
@@ -8469,16 +8581,185 @@ function registerListSpecsTool(server2) {
|
|
|
8469
8581
|
);
|
|
8470
8582
|
}
|
|
8471
8583
|
|
|
8472
|
-
// src/tools/
|
|
8584
|
+
// src/tools/describe-endpoint.ts
|
|
8473
8585
|
var import_zod25 = require("zod");
|
|
8474
8586
|
var import_fs18 = require("fs");
|
|
8475
|
-
var import_proper_lockfile2 = require("proper-lockfile");
|
|
8476
8587
|
var import_path18 = require("path");
|
|
8477
8588
|
var import_js_yaml5 = __toESM(require("js-yaml"));
|
|
8589
|
+
function resolveRef(root, ref) {
|
|
8590
|
+
if (!ref.startsWith("#/")) {
|
|
8591
|
+
throw new Error(`[describe_endpoint] External $refs not supported: "${ref}"`);
|
|
8592
|
+
}
|
|
8593
|
+
const parts = ref.slice(2).split("/");
|
|
8594
|
+
let current = root;
|
|
8595
|
+
for (const part of parts) {
|
|
8596
|
+
const key = part.replace(/~1/g, "/").replace(/~0/g, "~");
|
|
8597
|
+
if (current == null || typeof current !== "object") {
|
|
8598
|
+
throw new Error(
|
|
8599
|
+
`[describe_endpoint] $ref "${ref}" cannot be resolved \u2014 segment "${key}" not found`
|
|
8600
|
+
);
|
|
8601
|
+
}
|
|
8602
|
+
current = current[key];
|
|
8603
|
+
}
|
|
8604
|
+
if (current == null || typeof current !== "object") {
|
|
8605
|
+
throw new Error(`[describe_endpoint] $ref "${ref}" resolved to a non-object value`);
|
|
8606
|
+
}
|
|
8607
|
+
return current;
|
|
8608
|
+
}
|
|
8609
|
+
function deref(root, obj) {
|
|
8610
|
+
if (obj == null || typeof obj !== "object") return {};
|
|
8611
|
+
const o = obj;
|
|
8612
|
+
if (typeof o["$ref"] === "string") {
|
|
8613
|
+
const resolved = resolveRef(root, o["$ref"]);
|
|
8614
|
+
return deref(root, resolved);
|
|
8615
|
+
}
|
|
8616
|
+
return o;
|
|
8617
|
+
}
|
|
8618
|
+
function loadSpec(specPath) {
|
|
8619
|
+
const raw = (0, import_fs18.readFileSync)(specPath, "utf-8");
|
|
8620
|
+
const ext = (0, import_path18.extname)(specPath).toLowerCase();
|
|
8621
|
+
if (ext === ".json") {
|
|
8622
|
+
return JSON.parse(raw);
|
|
8623
|
+
}
|
|
8624
|
+
const parsed = import_js_yaml5.default.load(raw);
|
|
8625
|
+
if (parsed == null || typeof parsed !== "object") {
|
|
8626
|
+
throw new Error(`[describe_endpoint] Spec file "${specPath}" did not parse to an object`);
|
|
8627
|
+
}
|
|
8628
|
+
return parsed;
|
|
8629
|
+
}
|
|
8630
|
+
function extractParams(root, pathItem, operation) {
|
|
8631
|
+
const pathLevelRaw = Array.isArray(pathItem["parameters"]) ? pathItem["parameters"] : [];
|
|
8632
|
+
const opLevelRaw = Array.isArray(operation["parameters"]) ? operation["parameters"] : [];
|
|
8633
|
+
const merged = /* @__PURE__ */ new Map();
|
|
8634
|
+
for (const raw of [...pathLevelRaw, ...opLevelRaw]) {
|
|
8635
|
+
const param = deref(root, raw);
|
|
8636
|
+
const name = String(param["name"] ?? "");
|
|
8637
|
+
const inVal = String(param["in"] ?? "");
|
|
8638
|
+
if (name && inVal) {
|
|
8639
|
+
merged.set(`${name}:${inVal}`, param);
|
|
8640
|
+
}
|
|
8641
|
+
}
|
|
8642
|
+
const pathParams = [];
|
|
8643
|
+
const queryParams = [];
|
|
8644
|
+
for (const param of merged.values()) {
|
|
8645
|
+
const inVal = String(param["in"] ?? "");
|
|
8646
|
+
const name = String(param["name"] ?? "");
|
|
8647
|
+
const schema = deref(root, param["schema"] ?? {});
|
|
8648
|
+
if (inVal === "path") {
|
|
8649
|
+
pathParams.push({ name, in: "path", required: true, schema });
|
|
8650
|
+
} else if (inVal === "query") {
|
|
8651
|
+
const required = param["required"] === true;
|
|
8652
|
+
queryParams.push({ name, in: "query", required, schema });
|
|
8653
|
+
}
|
|
8654
|
+
}
|
|
8655
|
+
return { pathParams, queryParams };
|
|
8656
|
+
}
|
|
8657
|
+
function extractSecurity(root, globalSecurity, operationSecurity) {
|
|
8658
|
+
const securityRequirements = operationSecurity !== void 0 ? operationSecurity : globalSecurity;
|
|
8659
|
+
if (securityRequirements.length === 0) return [];
|
|
8660
|
+
const schemes = root["components"]?.["securitySchemes"];
|
|
8661
|
+
if (!schemes || typeof schemes !== "object") return [];
|
|
8662
|
+
const result = [];
|
|
8663
|
+
const seen = /* @__PURE__ */ new Set();
|
|
8664
|
+
for (const req of securityRequirements) {
|
|
8665
|
+
if (!req || typeof req !== "object") continue;
|
|
8666
|
+
for (const schemeName of Object.keys(req)) {
|
|
8667
|
+
if (seen.has(schemeName)) continue;
|
|
8668
|
+
seen.add(schemeName);
|
|
8669
|
+
const schemeRaw = schemes[schemeName];
|
|
8670
|
+
if (!schemeRaw) continue;
|
|
8671
|
+
const scheme = deref(root, schemeRaw);
|
|
8672
|
+
const type = String(scheme["type"] ?? "unknown");
|
|
8673
|
+
if (type === "apiKey") {
|
|
8674
|
+
const inVal = String(scheme["in"] ?? "header");
|
|
8675
|
+
const paramName = String(scheme["name"] ?? schemeName);
|
|
8676
|
+
result.push({ name: schemeName, type, in: inVal, paramName });
|
|
8677
|
+
} else if (type === "http") {
|
|
8678
|
+
const httpScheme = String(scheme["scheme"] ?? "bearer").toLowerCase();
|
|
8679
|
+
result.push({ name: schemeName, type, in: "bearer", paramName: "Authorization" });
|
|
8680
|
+
void httpScheme;
|
|
8681
|
+
} else if (type === "oauth2") {
|
|
8682
|
+
result.push({ name: schemeName, type, in: "bearer", paramName: "Authorization" });
|
|
8683
|
+
} else if (type === "openIdConnect") {
|
|
8684
|
+
result.push({ name: schemeName, type, in: "bearer", paramName: "Authorization" });
|
|
8685
|
+
} else {
|
|
8686
|
+
result.push({ name: schemeName, type, in: "unknown", paramName: schemeName });
|
|
8687
|
+
}
|
|
8688
|
+
}
|
|
8689
|
+
}
|
|
8690
|
+
return result;
|
|
8691
|
+
}
|
|
8692
|
+
function handleDescribeEndpoint(input) {
|
|
8693
|
+
const { specPath, path: path5, method } = input;
|
|
8694
|
+
const normalizedMethod = method.toLowerCase();
|
|
8695
|
+
const root = loadSpec(specPath);
|
|
8696
|
+
const globalSecurity = Array.isArray(root["security"]) ? root["security"] : [];
|
|
8697
|
+
const paths = root["paths"];
|
|
8698
|
+
if (!paths) {
|
|
8699
|
+
return { pathParams: [], queryParams: [], security: [] };
|
|
8700
|
+
}
|
|
8701
|
+
const pathItem = deref(root, paths[path5]);
|
|
8702
|
+
if (!pathItem || Object.keys(pathItem).length === 0) {
|
|
8703
|
+
throw new Error(`[describe_endpoint] Path "${path5}" not found in spec "${specPath}"`);
|
|
8704
|
+
}
|
|
8705
|
+
const operation = deref(root, pathItem[normalizedMethod]);
|
|
8706
|
+
if (!operation || Object.keys(operation).length === 0) {
|
|
8707
|
+
throw new Error(
|
|
8708
|
+
`[describe_endpoint] Method "${method.toUpperCase()}" not found at path "${path5}" in spec "${specPath}"`
|
|
8709
|
+
);
|
|
8710
|
+
}
|
|
8711
|
+
const { pathParams, queryParams } = extractParams(root, pathItem, operation);
|
|
8712
|
+
const operationSecurity = Array.isArray(operation["security"]) ? operation["security"] : void 0;
|
|
8713
|
+
const security = extractSecurity(root, globalSecurity, operationSecurity);
|
|
8714
|
+
return { pathParams, queryParams, security };
|
|
8715
|
+
}
|
|
8716
|
+
function registerDescribeEndpointTool(server2) {
|
|
8717
|
+
server2.tool(
|
|
8718
|
+
"stackwright_pro_describe_endpoint",
|
|
8719
|
+
[
|
|
8720
|
+
"Inspect an OpenAPI 3.0/3.1 spec and return resolved parameter and security details for a",
|
|
8721
|
+
"specific operation. Deterministic \u2014 no LLM. Handles $ref resolution within the spec document.",
|
|
8722
|
+
"",
|
|
8723
|
+
"Returns:",
|
|
8724
|
+
" pathParams \u2014 path parameters [{name, in, required, schema}]",
|
|
8725
|
+
" queryParams \u2014 query parameters [{name, in, required, schema}]",
|
|
8726
|
+
" security \u2014 applicable security schemes [{name, type, in, paramName}]",
|
|
8727
|
+
"",
|
|
8728
|
+
"Used by the data-otter to populate params: entries in stackwright.collections.yml",
|
|
8729
|
+
"from required query params and resolved auth query params (swp-8r8i + swp-1l6l)."
|
|
8730
|
+
].join("\n"),
|
|
8731
|
+
{
|
|
8732
|
+
specPath: import_zod25.z.string().describe("Absolute path to the OpenAPI spec file (.yaml, .yml, or .json)"),
|
|
8733
|
+
path: import_zod25.z.string().describe('The API path to inspect (e.g. "/stations/{stationId}/observations")'),
|
|
8734
|
+
method: import_zod25.z.string().describe('HTTP method (case-insensitive: "get", "post", "put", etc.)')
|
|
8735
|
+
},
|
|
8736
|
+
async ({ specPath, path: path5, method }) => {
|
|
8737
|
+
try {
|
|
8738
|
+
const result = handleDescribeEndpoint({ specPath, path: path5, method });
|
|
8739
|
+
return {
|
|
8740
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
8741
|
+
};
|
|
8742
|
+
} catch (err) {
|
|
8743
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
8744
|
+
return {
|
|
8745
|
+
content: [{ type: "text", text: JSON.stringify({ error: message }) }],
|
|
8746
|
+
isError: true
|
|
8747
|
+
};
|
|
8748
|
+
}
|
|
8749
|
+
}
|
|
8750
|
+
);
|
|
8751
|
+
}
|
|
8752
|
+
|
|
8753
|
+
// src/tools/consolidate-integrations.ts
|
|
8754
|
+
var import_zod26 = require("zod");
|
|
8755
|
+
var import_fs19 = require("fs");
|
|
8756
|
+
var import_proper_lockfile2 = require("proper-lockfile");
|
|
8757
|
+
var import_path19 = require("path");
|
|
8758
|
+
var import_js_yaml6 = __toESM(require("js-yaml"));
|
|
8478
8759
|
var BASE_MOCK_PORT = 4011;
|
|
8479
8760
|
var STRIP_SUFFIXES2 = ["-openapi", "-asyncapi", "-api", "-spec"];
|
|
8480
8761
|
function deriveNameFromFilename(filename) {
|
|
8481
|
-
const base = (0,
|
|
8762
|
+
const base = (0, import_path19.basename)(filename, ".json").replace(/^api-config-/, "");
|
|
8482
8763
|
for (const suffix of STRIP_SUFFIXES2) {
|
|
8483
8764
|
if (base.endsWith(suffix)) return base.slice(0, -suffix.length);
|
|
8484
8765
|
}
|
|
@@ -8486,13 +8767,13 @@ function deriveNameFromFilename(filename) {
|
|
|
8486
8767
|
}
|
|
8487
8768
|
function handleConsolidateIntegrations(input) {
|
|
8488
8769
|
const { projectRoot } = input;
|
|
8489
|
-
const artifactsDir = (0,
|
|
8490
|
-
if (!(0,
|
|
8770
|
+
const artifactsDir = (0, import_path19.join)(projectRoot, ".stackwright", "artifacts");
|
|
8771
|
+
if (!(0, import_fs19.existsSync)(artifactsDir)) {
|
|
8491
8772
|
return { written: false, integrationCount: 0, reason: "no per-spec artifacts found" };
|
|
8492
8773
|
}
|
|
8493
8774
|
let entries;
|
|
8494
8775
|
try {
|
|
8495
|
-
entries = (0,
|
|
8776
|
+
entries = (0, import_fs19.readdirSync)(artifactsDir).filter(
|
|
8496
8777
|
(f) => f.startsWith("api-config-") && f.endsWith(".json") && f !== "api-config.json"
|
|
8497
8778
|
);
|
|
8498
8779
|
} catch {
|
|
@@ -8507,7 +8788,7 @@ function handleConsolidateIntegrations(input) {
|
|
|
8507
8788
|
entries.forEach((filename, index) => {
|
|
8508
8789
|
let artifact = {};
|
|
8509
8790
|
try {
|
|
8510
|
-
const raw = (0,
|
|
8791
|
+
const raw = (0, import_fs19.readFileSync)((0, import_path19.join)(artifactsDir, filename), "utf-8");
|
|
8511
8792
|
artifact = JSON.parse(raw);
|
|
8512
8793
|
} catch {
|
|
8513
8794
|
}
|
|
@@ -8540,20 +8821,20 @@ function handleConsolidateIntegrations(input) {
|
|
|
8540
8821
|
});
|
|
8541
8822
|
const integrations = Array.from(integrationsByName.values());
|
|
8542
8823
|
const dedupedCount = entries.length - skippedIntegrationsList.length - integrations.length;
|
|
8543
|
-
const integrationsYmlPath = (0,
|
|
8824
|
+
const integrationsYmlPath = (0, import_path19.join)(projectRoot, "stackwright.integrations.yml");
|
|
8544
8825
|
let existing = {};
|
|
8545
|
-
if ((0,
|
|
8826
|
+
if ((0, import_fs19.existsSync)(integrationsYmlPath)) {
|
|
8546
8827
|
try {
|
|
8547
|
-
const raw = (0,
|
|
8548
|
-
existing =
|
|
8828
|
+
const raw = (0, import_fs19.readFileSync)(integrationsYmlPath, "utf-8");
|
|
8829
|
+
existing = import_js_yaml6.default.load(raw) ?? {};
|
|
8549
8830
|
} catch {
|
|
8550
8831
|
existing = {};
|
|
8551
8832
|
}
|
|
8552
8833
|
}
|
|
8553
8834
|
const merged = { ...existing, integrations };
|
|
8554
|
-
(0,
|
|
8555
|
-
if (!(0,
|
|
8556
|
-
(0,
|
|
8835
|
+
(0, import_fs19.mkdirSync)((0, import_path19.join)(projectRoot), { recursive: true });
|
|
8836
|
+
if (!(0, import_fs19.existsSync)(integrationsYmlPath)) {
|
|
8837
|
+
(0, import_fs19.writeFileSync)(integrationsYmlPath, "", "utf-8");
|
|
8557
8838
|
}
|
|
8558
8839
|
const release = (0, import_proper_lockfile2.lockSync)(integrationsYmlPath, {
|
|
8559
8840
|
realpath: false,
|
|
@@ -8562,8 +8843,8 @@ function handleConsolidateIntegrations(input) {
|
|
|
8562
8843
|
try {
|
|
8563
8844
|
const header = `# stackwright.integrations.yml \u2014 Auto-generated by stackwright_pro_consolidate_integrations
|
|
8564
8845
|
`;
|
|
8565
|
-
const body =
|
|
8566
|
-
(0,
|
|
8846
|
+
const body = import_js_yaml6.default.dump(merged, { lineWidth: 120, noRefs: true });
|
|
8847
|
+
(0, import_fs19.writeFileSync)(integrationsYmlPath, header + body, "utf-8");
|
|
8567
8848
|
} finally {
|
|
8568
8849
|
release();
|
|
8569
8850
|
}
|
|
@@ -8591,7 +8872,7 @@ function registerConsolidateIntegrationsTool(server2) {
|
|
|
8591
8872
|
"no per-spec artifacts are found."
|
|
8592
8873
|
].join(" "),
|
|
8593
8874
|
{
|
|
8594
|
-
projectRoot:
|
|
8875
|
+
projectRoot: import_zod26.z.string().describe("Absolute path to the project root directory")
|
|
8595
8876
|
},
|
|
8596
8877
|
async ({ projectRoot }) => {
|
|
8597
8878
|
try {
|
|
@@ -8649,7 +8930,7 @@ var package_default = {
|
|
|
8649
8930
|
"test:coverage": "vitest run --coverage"
|
|
8650
8931
|
},
|
|
8651
8932
|
name: "@stackwright-pro/mcp",
|
|
8652
|
-
version: "0.2.0-alpha.
|
|
8933
|
+
version: "0.2.0-alpha.113",
|
|
8653
8934
|
description: "MCP tools for Stackwright Pro - Data Explorer, Security, ISR, and Dashboard generation",
|
|
8654
8935
|
license: "SEE LICENSE IN LICENSE",
|
|
8655
8936
|
main: "./dist/server.js",
|
|
@@ -8719,6 +9000,7 @@ registerCompileTools(server);
|
|
|
8719
9000
|
registerStripLegacyIntegrationsTool(server);
|
|
8720
9001
|
registerEmitterTools(server);
|
|
8721
9002
|
registerListSpecsTool(server);
|
|
9003
|
+
registerDescribeEndpointTool(server);
|
|
8722
9004
|
registerConsolidateIntegrationsTool(server);
|
|
8723
9005
|
(0, import_register.registerContentTypeTools)(server);
|
|
8724
9006
|
(0, import_register.registerPageTools)(server);
|