@stackwright-pro/mcp 0.2.0-alpha.101 → 0.2.0-alpha.103
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 +5 -5
- package/dist/integrity.js.map +1 -1
- package/dist/integrity.mjs +5 -5
- package/dist/integrity.mjs.map +1 -1
- package/dist/pipeline-constants.js.map +1 -1
- package/dist/pipeline-constants.mjs.map +1 -1
- package/dist/server.js +249 -30
- package/dist/server.js.map +1 -1
- package/dist/server.mjs +248 -29
- package/dist/server.mjs.map +1 -1
- package/package.json +5 -4
package/dist/server.mjs
CHANGED
|
@@ -556,7 +556,7 @@ function registerDashboardTools(server2) {
|
|
|
556
556
|
yamlLines.push(` header: Status`);
|
|
557
557
|
yamlLines.push(` type: badge`);
|
|
558
558
|
}
|
|
559
|
-
const
|
|
559
|
+
const yaml2 = yamlLines.join("\n");
|
|
560
560
|
return {
|
|
561
561
|
content: [
|
|
562
562
|
{
|
|
@@ -566,7 +566,7 @@ function registerDashboardTools(server2) {
|
|
|
566
566
|
Layout: ${layout}
|
|
567
567
|
|
|
568
568
|
\`\`\`yaml
|
|
569
|
-
${
|
|
569
|
+
${yaml2}
|
|
570
570
|
\`\`\`
|
|
571
571
|
|
|
572
572
|
\u{1F4A1} Add this to pages/dashboard/content.yml and validate with stackwright_validate_pages.`
|
|
@@ -647,7 +647,7 @@ ${yaml}
|
|
|
647
647
|
yamlLines.push(" action: navigate");
|
|
648
648
|
yamlLines.push(` href: "/${entity}"`);
|
|
649
649
|
yamlLines.push(" style: secondary");
|
|
650
|
-
const
|
|
650
|
+
const yaml2 = yamlLines.join("\n");
|
|
651
651
|
return {
|
|
652
652
|
content: [
|
|
653
653
|
{
|
|
@@ -655,7 +655,7 @@ ${yaml}
|
|
|
655
655
|
text: `\u{1F4C4} Generated Detail Page for: ${entity}
|
|
656
656
|
|
|
657
657
|
\`\`\`yaml
|
|
658
|
-
${
|
|
658
|
+
${yaml2}
|
|
659
659
|
\`\`\`
|
|
660
660
|
|
|
661
661
|
\u{1F4A1} Add this to pages/${entity}/[${slugField}]/content.yml and validate.`
|
|
@@ -2455,7 +2455,7 @@ function enrichErrors(issues, synonyms) {
|
|
|
2455
2455
|
});
|
|
2456
2456
|
}
|
|
2457
2457
|
function handleValidateYamlFragment(input) {
|
|
2458
|
-
const { schemaName, yaml } = input;
|
|
2458
|
+
const { schemaName, yaml: yaml2 } = input;
|
|
2459
2459
|
if (!SUPPORTED_SCHEMA_NAMES.includes(schemaName)) {
|
|
2460
2460
|
return {
|
|
2461
2461
|
valid: false,
|
|
@@ -2465,7 +2465,7 @@ function handleValidateYamlFragment(input) {
|
|
|
2465
2465
|
const name = schemaName;
|
|
2466
2466
|
let parsed;
|
|
2467
2467
|
try {
|
|
2468
|
-
parsed = yamlLoad(
|
|
2468
|
+
parsed = yamlLoad(yaml2);
|
|
2469
2469
|
} catch (err) {
|
|
2470
2470
|
return {
|
|
2471
2471
|
valid: false,
|
|
@@ -2491,8 +2491,8 @@ function registerValidateYamlFragmentTool(server2) {
|
|
|
2491
2491
|
),
|
|
2492
2492
|
yaml: z11.string().describe("YAML string to validate (can also be JSON \u2014 js-yaml parses both)")
|
|
2493
2493
|
},
|
|
2494
|
-
async ({ schemaName, yaml }) => {
|
|
2495
|
-
const result = handleValidateYamlFragment({ schemaName, yaml });
|
|
2494
|
+
async ({ schemaName, yaml: yaml2 }) => {
|
|
2495
|
+
const result = handleValidateYamlFragment({ schemaName, yaml: yaml2 });
|
|
2496
2496
|
return {
|
|
2497
2497
|
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
2498
2498
|
};
|
|
@@ -2967,7 +2967,8 @@ function defaultPhaseStatus() {
|
|
|
2967
2967
|
answered: false,
|
|
2968
2968
|
executed: false,
|
|
2969
2969
|
artifactWritten: false,
|
|
2970
|
-
retryCount: 0
|
|
2970
|
+
retryCount: 0,
|
|
2971
|
+
inFlight: false
|
|
2971
2972
|
};
|
|
2972
2973
|
}
|
|
2973
2974
|
function createDefaultState() {
|
|
@@ -3084,7 +3085,13 @@ function handleSetPipelineState(input) {
|
|
|
3084
3085
|
isError: true
|
|
3085
3086
|
};
|
|
3086
3087
|
}
|
|
3087
|
-
const VALID_FIELDS = [
|
|
3088
|
+
const VALID_FIELDS = [
|
|
3089
|
+
"questionsCollected",
|
|
3090
|
+
"answered",
|
|
3091
|
+
"executed",
|
|
3092
|
+
"artifactWritten",
|
|
3093
|
+
"inFlight"
|
|
3094
|
+
];
|
|
3088
3095
|
if (input.field && !VALID_FIELDS.includes(input.field)) {
|
|
3089
3096
|
return {
|
|
3090
3097
|
text: JSON.stringify({
|
|
@@ -4143,6 +4150,14 @@ function handleEmitEvent(input) {
|
|
|
4143
4150
|
};
|
|
4144
4151
|
}
|
|
4145
4152
|
emitted = emitFn({ type: "phase_start", phase: input.phase, otter: caller });
|
|
4153
|
+
} else if (input.type === "phase_ready") {
|
|
4154
|
+
if (!input.phase) {
|
|
4155
|
+
return {
|
|
4156
|
+
text: JSON.stringify({ emitted: false, reason: "phase required for phase_ready" }),
|
|
4157
|
+
isError: false
|
|
4158
|
+
};
|
|
4159
|
+
}
|
|
4160
|
+
emitted = emitFn({ type: "phase_ready", phase: input.phase, otter: caller });
|
|
4146
4161
|
} else if (input.type === "phase_complete") {
|
|
4147
4162
|
if (!input.phase) {
|
|
4148
4163
|
return {
|
|
@@ -4199,7 +4214,8 @@ function registerPipelineTools(server2) {
|
|
|
4199
4214
|
`Atomic read\u2192modify\u2192write pipeline state. ${DESC}`,
|
|
4200
4215
|
{
|
|
4201
4216
|
phase: z13.string().optional().describe('Phase to update, e.g. "designer"'),
|
|
4202
|
-
field: z13.enum(["questionsCollected", "answered", "executed", "artifactWritten"]).optional().describe("Boolean field to set"),
|
|
4217
|
+
field: z13.enum(["questionsCollected", "answered", "executed", "artifactWritten", "inFlight"]).optional().describe("Boolean field to set"),
|
|
4218
|
+
// inFlight: set true BEFORE specialist invoke (dataflow mode, swp-ioc7); false after.
|
|
4203
4219
|
value: boolCoerce(z13.boolean().optional()).describe(
|
|
4204
4220
|
'Value for the field \u2014 must be a JSON boolean (true/false), NOT the string "true"/"false"'
|
|
4205
4221
|
),
|
|
@@ -4211,7 +4227,13 @@ function registerPipelineTools(server2) {
|
|
|
4211
4227
|
z13.array(
|
|
4212
4228
|
z13.object({
|
|
4213
4229
|
phase: z13.string(),
|
|
4214
|
-
field: z13.enum([
|
|
4230
|
+
field: z13.enum([
|
|
4231
|
+
"questionsCollected",
|
|
4232
|
+
"answered",
|
|
4233
|
+
"executed",
|
|
4234
|
+
"artifactWritten",
|
|
4235
|
+
"inFlight"
|
|
4236
|
+
]),
|
|
4215
4237
|
value: z13.boolean()
|
|
4216
4238
|
})
|
|
4217
4239
|
).optional()
|
|
@@ -4335,7 +4357,15 @@ function registerPipelineTools(server2) {
|
|
|
4335
4357
|
"stackwright_pro_emit_event",
|
|
4336
4358
|
`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}`,
|
|
4337
4359
|
{
|
|
4338
|
-
type: z13.enum([
|
|
4360
|
+
type: z13.enum([
|
|
4361
|
+
"phase_start",
|
|
4362
|
+
"phase_complete",
|
|
4363
|
+
"phase_ready",
|
|
4364
|
+
"agent_invoke_start",
|
|
4365
|
+
"agent_invoke_complete"
|
|
4366
|
+
]).describe("Event type to emit"),
|
|
4367
|
+
// phase_ready: emitted in dataflow mode (swp-ioc7) when a phase enters the ready set
|
|
4368
|
+
// (deps satisfied, not inFlight, not yet complete) — BEFORE invoking the specialist.
|
|
4339
4369
|
phase: z13.string().optional().describe("Current phase name"),
|
|
4340
4370
|
targetOtter: z13.string().optional().describe("For agent_invoke_* events: which otter is being invoked"),
|
|
4341
4371
|
success: boolCoerce(z13.boolean().optional()).describe(
|
|
@@ -4446,7 +4476,17 @@ var OTTER_WRITE_ALLOWLISTS = {
|
|
|
4446
4476
|
{ prefix: "pages/", suffix: "/content.yml", description: "Landing page content" },
|
|
4447
4477
|
{ prefix: "pages/", suffix: "/content.yaml", description: "Landing page content" },
|
|
4448
4478
|
{ prefix: ".stackwright/artifacts/", suffix: ".json", description: "Polish artifact" },
|
|
4449
|
-
{ prefix: "README.md", suffix: "", description: "Project README rewrite" }
|
|
4479
|
+
{ prefix: "README.md", suffix: "", description: "Project README rewrite" },
|
|
4480
|
+
{
|
|
4481
|
+
prefix: ".env.local",
|
|
4482
|
+
suffix: "",
|
|
4483
|
+
description: ".env.local runtime config \u2014 emitter output from stackwright_pro_emit_env_local (swp-8qdd)"
|
|
4484
|
+
},
|
|
4485
|
+
{
|
|
4486
|
+
prefix: ".env.local.example",
|
|
4487
|
+
suffix: "",
|
|
4488
|
+
description: ".env.local.example template \u2014 emitter output from stackwright_pro_emit_env_local (swp-8qdd)"
|
|
4489
|
+
}
|
|
4450
4490
|
],
|
|
4451
4491
|
// QA otter writes ONLY to the qa/ directory and the qa-findings artifact.
|
|
4452
4492
|
// It never writes .tsx, .ts, .yml, or .json outside these paths.
|
|
@@ -5761,7 +5801,7 @@ import { join as join8, basename } from "path";
|
|
|
5761
5801
|
var _checksums = /* @__PURE__ */ new Map([
|
|
5762
5802
|
[
|
|
5763
5803
|
"stackwright-pro-api-otter.json",
|
|
5764
|
-
"
|
|
5804
|
+
"a5ff25531c330289af89e433e696ba1ffef8f7ea09985a559cf915592c9734ad"
|
|
5765
5805
|
],
|
|
5766
5806
|
[
|
|
5767
5807
|
"stackwright-pro-auth-otter.json",
|
|
@@ -5769,7 +5809,7 @@ var _checksums = /* @__PURE__ */ new Map([
|
|
|
5769
5809
|
],
|
|
5770
5810
|
[
|
|
5771
5811
|
"stackwright-pro-dashboard-otter.json",
|
|
5772
|
-
"
|
|
5812
|
+
"f8d594b14e05efea30cf253052d7c7df3e8c4174d739be4cd33f9c96cecdc451"
|
|
5773
5813
|
],
|
|
5774
5814
|
[
|
|
5775
5815
|
"stackwright-pro-data-otter.json",
|
|
@@ -5785,7 +5825,7 @@ var _checksums = /* @__PURE__ */ new Map([
|
|
|
5785
5825
|
],
|
|
5786
5826
|
[
|
|
5787
5827
|
"stackwright-pro-foreman-otter.json",
|
|
5788
|
-
"
|
|
5828
|
+
"c23436769a9db06fa6f9d312b4fdd8b2cef6646461020eeaf227303350073593"
|
|
5789
5829
|
],
|
|
5790
5830
|
[
|
|
5791
5831
|
"stackwright-pro-form-wizard-otter.json",
|
|
@@ -5801,7 +5841,7 @@ var _checksums = /* @__PURE__ */ new Map([
|
|
|
5801
5841
|
],
|
|
5802
5842
|
[
|
|
5803
5843
|
"stackwright-pro-polish-otter.json",
|
|
5804
|
-
"
|
|
5844
|
+
"fd8f8963266c6179eebf8eac4f656e8274aa3a721e5296abdbde5b00ad8a2297"
|
|
5805
5845
|
],
|
|
5806
5846
|
[
|
|
5807
5847
|
"stackwright-pro-qa-otter.json",
|
|
@@ -5809,7 +5849,7 @@ var _checksums = /* @__PURE__ */ new Map([
|
|
|
5809
5849
|
],
|
|
5810
5850
|
[
|
|
5811
5851
|
"stackwright-pro-scaffold-otter.json",
|
|
5812
|
-
"
|
|
5852
|
+
"92930c732547c90a19e89ee0e25b5f037b7366f770941f0a01e148ff240a1b6d"
|
|
5813
5853
|
],
|
|
5814
5854
|
[
|
|
5815
5855
|
"stackwright-pro-theme-otter.json",
|
|
@@ -7461,10 +7501,187 @@ function registerStripLegacyIntegrationsTool(server2) {
|
|
|
7461
7501
|
);
|
|
7462
7502
|
}
|
|
7463
7503
|
|
|
7464
|
-
// src/tools/
|
|
7504
|
+
// src/tools/emitters.ts
|
|
7465
7505
|
import { z as z22 } from "zod";
|
|
7466
|
-
import {
|
|
7467
|
-
import { join as join13
|
|
7506
|
+
import { readFileSync as readFileSync12, existsSync as existsSync12, readdirSync as readdirSync5 } from "fs";
|
|
7507
|
+
import { join as join13 } from "path";
|
|
7508
|
+
import yaml from "js-yaml";
|
|
7509
|
+
import { emitEnvLocal, emitProvidersFile, emitMockPorts } from "@stackwright-pro/emitters";
|
|
7510
|
+
function readIntegrations(cwd) {
|
|
7511
|
+
const filePath = join13(cwd, "stackwright.integrations.yml");
|
|
7512
|
+
if (!existsSync12(filePath)) return [];
|
|
7513
|
+
try {
|
|
7514
|
+
const raw = yaml.load(readFileSync12(filePath, "utf-8"));
|
|
7515
|
+
if (!raw?.integrations || !Array.isArray(raw.integrations)) return [];
|
|
7516
|
+
return raw.integrations.filter((i) => typeof i.name === "string").map((i) => ({
|
|
7517
|
+
name: i.name,
|
|
7518
|
+
auth: i.auth ? { type: i.auth.type, header: i.auth.header, envVar: i.auth.envVar } : void 0
|
|
7519
|
+
}));
|
|
7520
|
+
} catch {
|
|
7521
|
+
return [];
|
|
7522
|
+
}
|
|
7523
|
+
}
|
|
7524
|
+
function readServiceTokenRefs(cwd) {
|
|
7525
|
+
const servicesDir = join13(cwd, "services");
|
|
7526
|
+
if (!existsSync12(servicesDir)) return [];
|
|
7527
|
+
try {
|
|
7528
|
+
const files = readdirSync5(servicesDir).filter((f) => f.endsWith(".yml") || f.endsWith(".yaml"));
|
|
7529
|
+
const refs = [];
|
|
7530
|
+
for (const file of files) {
|
|
7531
|
+
try {
|
|
7532
|
+
const raw = yaml.load(
|
|
7533
|
+
readFileSync12(join13(servicesDir, file), "utf-8")
|
|
7534
|
+
);
|
|
7535
|
+
if (raw?.tokenEnv && typeof raw.tokenEnv === "string") {
|
|
7536
|
+
refs.push({
|
|
7537
|
+
name: raw.name ?? file.replace(/\.ya?ml$/, ""),
|
|
7538
|
+
tokenEnv: raw.tokenEnv
|
|
7539
|
+
});
|
|
7540
|
+
}
|
|
7541
|
+
} catch {
|
|
7542
|
+
}
|
|
7543
|
+
}
|
|
7544
|
+
return refs;
|
|
7545
|
+
} catch {
|
|
7546
|
+
return [];
|
|
7547
|
+
}
|
|
7548
|
+
}
|
|
7549
|
+
var ENV_LOCAL_DESC = "Returns { envLocal, envLocalExample } as JSON. The otter writes both files via stackwright_pro_safe_write.";
|
|
7550
|
+
var PROVIDERS_DESC = "Returns { providersFile } as JSON. The otter writes the file via stackwright_pro_safe_write.";
|
|
7551
|
+
var PORTS_DESC = "Returns { ports } as JSON \u2014 map of integration name \u2192 port number.";
|
|
7552
|
+
function registerEmitterTools(server2) {
|
|
7553
|
+
server2.tool(
|
|
7554
|
+
"stackwright_pro_emit_env_local",
|
|
7555
|
+
`Emit .env.local + .env.local.example contents from stackwright.integrations.yml and services/*.yml. Deterministic emitter \u2014 same project config produces byte-identical output.
|
|
7556
|
+
|
|
7557
|
+
Call this tool, then write both files with stackwright_pro_safe_write:
|
|
7558
|
+
1. stackwright_pro_emit_env_local({ cwd }) \u2192 { envLocal, envLocalExample }
|
|
7559
|
+
2. stackwright_pro_safe_write({ filePath: '.env.local', content: envLocal, ... })
|
|
7560
|
+
3. stackwright_pro_safe_write({ filePath: '.env.local.example', content: envLocalExample, ... })
|
|
7561
|
+
|
|
7562
|
+
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}`,
|
|
7563
|
+
{
|
|
7564
|
+
cwd: z22.string().describe(
|
|
7565
|
+
"Absolute path to the project root containing stackwright.integrations.yml and optionally services/*.yml"
|
|
7566
|
+
)
|
|
7567
|
+
},
|
|
7568
|
+
async ({ cwd }) => {
|
|
7569
|
+
const integrations = readIntegrations(cwd);
|
|
7570
|
+
const services = readServiceTokenRefs(cwd);
|
|
7571
|
+
const output = emitEnvLocal({ integrations, services });
|
|
7572
|
+
return {
|
|
7573
|
+
content: [
|
|
7574
|
+
{
|
|
7575
|
+
type: "text",
|
|
7576
|
+
text: JSON.stringify(
|
|
7577
|
+
{
|
|
7578
|
+
envLocal: output.envLocal,
|
|
7579
|
+
envLocalExample: output.envLocalExample,
|
|
7580
|
+
meta: {
|
|
7581
|
+
integrationsRead: integrations.length,
|
|
7582
|
+
serviceTokenRefsRead: services.length,
|
|
7583
|
+
envVarsEmitted: (output.envLocal.match(/^NEXT_PUBLIC_[A-Z0-9_]+=.+$/m) ? output.envLocal.match(/^NEXT_PUBLIC_[A-Z0-9_]+=.+$/gm) ?? [] : []).length
|
|
7584
|
+
}
|
|
7585
|
+
},
|
|
7586
|
+
null,
|
|
7587
|
+
2
|
|
7588
|
+
)
|
|
7589
|
+
}
|
|
7590
|
+
]
|
|
7591
|
+
};
|
|
7592
|
+
}
|
|
7593
|
+
);
|
|
7594
|
+
server2.tool(
|
|
7595
|
+
"stackwright_pro_emit_providers_file",
|
|
7596
|
+
`Emit app/_components/providers.tsx from stackwright.integrations.yml. Deterministic emitter \u2014 uses LITERAL env access per integration so Next.js can inline NEXT_PUBLIC_* vars at build time. Also registers the map provider (default: Cesium for Pro).
|
|
7597
|
+
|
|
7598
|
+
\u26A0\uFE0F CRITICAL: DO NOT compose providers.tsx by hand. Computed env access (process.env[varName]) returns undefined in browser bundles for NEXT_PUBLIC_* vars \u2014 this silently drops all auth headers and causes 401s on every integration.
|
|
7599
|
+
|
|
7600
|
+
Workflow:
|
|
7601
|
+
1. stackwright_pro_emit_providers_file({ cwd, mapProvider: 'cesium' }) \u2192 { providersFile }
|
|
7602
|
+
2. stackwright_pro_safe_write({ filePath: 'app/_components/providers.tsx', content: providersFile, ... })
|
|
7603
|
+
|
|
7604
|
+
mapProvider options:
|
|
7605
|
+
- 'cesium' (default for Pro): 3D globe + terrain, @stackwright-pro/cesium + cesium peer dep
|
|
7606
|
+
- 'maplibre': free-tier 2D maps, no API key \u2014 OSS-style 2D dashboards only (opt-out)
|
|
7607
|
+
- 'none': skip map registration (ONLY if no pages use map content_items)
|
|
7608
|
+
|
|
7609
|
+
This is the second concrete instance of the swp-zf9y deterministic emitter pattern. Refs: swp-57ku, swp-2m89, swp-zf9y, drawer 957. ${PROVIDERS_DESC}`,
|
|
7610
|
+
{
|
|
7611
|
+
cwd: z22.string().describe("Absolute path to the project root containing stackwright.integrations.yml"),
|
|
7612
|
+
mapProvider: z22.enum(["maplibre", "cesium", "none"]).optional().describe(
|
|
7613
|
+
"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."
|
|
7614
|
+
)
|
|
7615
|
+
},
|
|
7616
|
+
async ({ cwd, mapProvider }) => {
|
|
7617
|
+
const integrations = readIntegrations(cwd);
|
|
7618
|
+
const providersFile = emitProvidersFile({ integrations, mapProvider });
|
|
7619
|
+
return {
|
|
7620
|
+
content: [
|
|
7621
|
+
{
|
|
7622
|
+
type: "text",
|
|
7623
|
+
text: JSON.stringify(
|
|
7624
|
+
{
|
|
7625
|
+
providersFile,
|
|
7626
|
+
meta: {
|
|
7627
|
+
integrationsRead: integrations.length,
|
|
7628
|
+
integrationsWithAuth: integrations.filter((i) => i.auth?.envVar).length,
|
|
7629
|
+
mapProvider: mapProvider ?? "cesium"
|
|
7630
|
+
}
|
|
7631
|
+
},
|
|
7632
|
+
null,
|
|
7633
|
+
2
|
|
7634
|
+
)
|
|
7635
|
+
}
|
|
7636
|
+
]
|
|
7637
|
+
};
|
|
7638
|
+
}
|
|
7639
|
+
);
|
|
7640
|
+
server2.tool(
|
|
7641
|
+
"stackwright_pro_emit_mock_ports",
|
|
7642
|
+
`Emit mock backend port assignments from stackwright.integrations.yml. Deterministic emitter \u2014 assigns consecutive ports starting at 4011 to each integration in declaration order. Skipped integrations (skipMockPort=true) are omitted and do not consume a port number.
|
|
7643
|
+
|
|
7644
|
+
\u26A0\uFE0F DO NOT pick mockUrl port numbers yourself. Port collisions occur when different models pick different defaults (Opus always picked 4010 for all integrations in run-4).
|
|
7645
|
+
|
|
7646
|
+
Workflow:
|
|
7647
|
+
1. stackwright_pro_emit_mock_ports({ cwd }) \u2192 { ports }
|
|
7648
|
+
2. For each integration, set mockUrl to http://localhost:<ports[name]>
|
|
7649
|
+
3. Write stackwright.integrations.yml via stackwright_pro_safe_write
|
|
7650
|
+
|
|
7651
|
+
This is the third concrete instance of the swp-zf9y deterministic emitter pattern. Refs: swp-phkh, swp-zf9y. ${PORTS_DESC}`,
|
|
7652
|
+
{
|
|
7653
|
+
cwd: z22.string().describe("Absolute path to the project root containing stackwright.integrations.yml")
|
|
7654
|
+
},
|
|
7655
|
+
async ({ cwd }) => {
|
|
7656
|
+
const integrations = readIntegrations(cwd);
|
|
7657
|
+
const { ports } = emitMockPorts({ integrations });
|
|
7658
|
+
return {
|
|
7659
|
+
content: [
|
|
7660
|
+
{
|
|
7661
|
+
type: "text",
|
|
7662
|
+
text: JSON.stringify(
|
|
7663
|
+
{
|
|
7664
|
+
ports,
|
|
7665
|
+
meta: {
|
|
7666
|
+
integrationsRead: integrations.length,
|
|
7667
|
+
portsAssigned: Object.keys(ports).length,
|
|
7668
|
+
portRange: Object.keys(ports).length > 0 ? `${Math.min(...Object.values(ports))}\u2013${Math.max(...Object.values(ports))}` : "none"
|
|
7669
|
+
}
|
|
7670
|
+
},
|
|
7671
|
+
null,
|
|
7672
|
+
2
|
|
7673
|
+
)
|
|
7674
|
+
}
|
|
7675
|
+
]
|
|
7676
|
+
};
|
|
7677
|
+
}
|
|
7678
|
+
);
|
|
7679
|
+
}
|
|
7680
|
+
|
|
7681
|
+
// src/tools/list-specs.ts
|
|
7682
|
+
import { z as z23 } from "zod";
|
|
7683
|
+
import { readdirSync as readdirSync6, readFileSync as readFileSync13, statSync, existsSync as existsSync13 } from "fs";
|
|
7684
|
+
import { join as join14, extname, basename as basename2 } from "path";
|
|
7468
7685
|
var STRIP_SUFFIXES = ["-openapi", "-asyncapi", "-api", "-spec"];
|
|
7469
7686
|
var ALLOWED_EXTS = /* @__PURE__ */ new Set([".yaml", ".yml", ".json"]);
|
|
7470
7687
|
function deriveIntegrationName(fileName) {
|
|
@@ -7486,18 +7703,18 @@ function detectFormat(snippet) {
|
|
|
7486
7703
|
}
|
|
7487
7704
|
function handleListSpecs(input) {
|
|
7488
7705
|
const { projectRoot } = input;
|
|
7489
|
-
const specsDir =
|
|
7706
|
+
const specsDir = join14(projectRoot, "specs");
|
|
7490
7707
|
const empty = { projectRoot, specs: [], totalCount: 0 };
|
|
7491
|
-
if (!
|
|
7708
|
+
if (!existsSync13(specsDir)) return empty;
|
|
7492
7709
|
let entries;
|
|
7493
7710
|
try {
|
|
7494
|
-
entries =
|
|
7711
|
+
entries = readdirSync6(specsDir);
|
|
7495
7712
|
} catch {
|
|
7496
7713
|
return empty;
|
|
7497
7714
|
}
|
|
7498
7715
|
const specs = [];
|
|
7499
7716
|
for (const entry of entries) {
|
|
7500
|
-
const fullPath =
|
|
7717
|
+
const fullPath = join14(specsDir, entry);
|
|
7501
7718
|
let stat;
|
|
7502
7719
|
try {
|
|
7503
7720
|
stat = statSync(fullPath);
|
|
@@ -7508,7 +7725,7 @@ function handleListSpecs(input) {
|
|
|
7508
7725
|
if (!ALLOWED_EXTS.has(extname(entry).toLowerCase())) continue;
|
|
7509
7726
|
let snippet = "";
|
|
7510
7727
|
try {
|
|
7511
|
-
snippet =
|
|
7728
|
+
snippet = readFileSync13(fullPath, "utf-8").slice(0, 2048);
|
|
7512
7729
|
} catch {
|
|
7513
7730
|
}
|
|
7514
7731
|
specs.push({
|
|
@@ -7527,7 +7744,7 @@ function registerListSpecsTool(server2) {
|
|
|
7527
7744
|
"stackwright_pro_list_specs",
|
|
7528
7745
|
"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.",
|
|
7529
7746
|
{
|
|
7530
|
-
projectRoot:
|
|
7747
|
+
projectRoot: z23.string().describe("Absolute path to the project root directory")
|
|
7531
7748
|
},
|
|
7532
7749
|
async ({ projectRoot }) => {
|
|
7533
7750
|
const result = handleListSpecs({ projectRoot });
|
|
@@ -7544,6 +7761,7 @@ var package_default = {
|
|
|
7544
7761
|
"@modelcontextprotocol/sdk": "^1.10.0",
|
|
7545
7762
|
"@stackwright/cli": "^0.9.0",
|
|
7546
7763
|
"@stackwright-pro/auth-nextjs": "workspace:*",
|
|
7764
|
+
"@stackwright-pro/emitters": "workspace:*",
|
|
7547
7765
|
"@stackwright-pro/cli-data-explorer": "workspace:*",
|
|
7548
7766
|
"@stackwright-pro/openapi": "workspace:*",
|
|
7549
7767
|
"@stackwright-pro/pulse": "workspace:*",
|
|
@@ -7571,7 +7789,7 @@ var package_default = {
|
|
|
7571
7789
|
"test:coverage": "vitest run --coverage"
|
|
7572
7790
|
},
|
|
7573
7791
|
name: "@stackwright-pro/mcp",
|
|
7574
|
-
version: "0.2.0-alpha.
|
|
7792
|
+
version: "0.2.0-alpha.103",
|
|
7575
7793
|
description: "MCP tools for Stackwright Pro - Data Explorer, Security, ISR, and Dashboard generation",
|
|
7576
7794
|
license: "SEE LICENSE IN LICENSE",
|
|
7577
7795
|
main: "./dist/server.js",
|
|
@@ -7651,6 +7869,7 @@ registerScaffoldCleanupTools(server);
|
|
|
7651
7869
|
registerContrastTools(server);
|
|
7652
7870
|
registerCompileTools(server);
|
|
7653
7871
|
registerStripLegacyIntegrationsTool(server);
|
|
7872
|
+
registerEmitterTools(server);
|
|
7654
7873
|
registerListSpecsTool(server);
|
|
7655
7874
|
registerContentTypeTools(server);
|
|
7656
7875
|
registerPageTools(server);
|