@stackwright-pro/mcp 0.2.0-alpha.102 → 0.2.0-alpha.104
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/server.js +253 -31
- package/dist/server.js.map +1 -1
- package/dist/server.mjs +254 -32
- package/dist/server.mjs.map +1 -1
- package/package.json +4 -4
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 yaml3 = 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
|
+
${yaml3}
|
|
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 @@ ${yaml2}
|
|
|
671
671
|
yamlLines.push(" action: navigate");
|
|
672
672
|
yamlLines.push(` href: "/${entity}"`);
|
|
673
673
|
yamlLines.push(" style: secondary");
|
|
674
|
-
const
|
|
674
|
+
const yaml3 = yamlLines.join("\n");
|
|
675
675
|
return {
|
|
676
676
|
content: [
|
|
677
677
|
{
|
|
@@ -679,7 +679,7 @@ ${yaml2}
|
|
|
679
679
|
text: `\u{1F4C4} Generated Detail Page for: ${entity}
|
|
680
680
|
|
|
681
681
|
\`\`\`yaml
|
|
682
|
-
${
|
|
682
|
+
${yaml3}
|
|
683
683
|
\`\`\`
|
|
684
684
|
|
|
685
685
|
\u{1F4A1} Add this to pages/${entity}/[${slugField}]/content.yml and validate.`
|
|
@@ -2451,7 +2451,7 @@ function enrichErrors(issues, synonyms) {
|
|
|
2451
2451
|
});
|
|
2452
2452
|
}
|
|
2453
2453
|
function handleValidateYamlFragment(input) {
|
|
2454
|
-
const { schemaName, yaml:
|
|
2454
|
+
const { schemaName, yaml: yaml3 } = input;
|
|
2455
2455
|
if (!SUPPORTED_SCHEMA_NAMES.includes(schemaName)) {
|
|
2456
2456
|
return {
|
|
2457
2457
|
valid: false,
|
|
@@ -2461,7 +2461,7 @@ function handleValidateYamlFragment(input) {
|
|
|
2461
2461
|
const name = schemaName;
|
|
2462
2462
|
let parsed;
|
|
2463
2463
|
try {
|
|
2464
|
-
parsed = (0, import_js_yaml.load)(
|
|
2464
|
+
parsed = (0, import_js_yaml.load)(yaml3);
|
|
2465
2465
|
} catch (err) {
|
|
2466
2466
|
return {
|
|
2467
2467
|
valid: false,
|
|
@@ -2487,8 +2487,8 @@ function registerValidateYamlFragmentTool(server2) {
|
|
|
2487
2487
|
),
|
|
2488
2488
|
yaml: import_zod11.z.string().describe("YAML string to validate (can also be JSON \u2014 js-yaml parses both)")
|
|
2489
2489
|
},
|
|
2490
|
-
async ({ schemaName, yaml:
|
|
2491
|
-
const result = handleValidateYamlFragment({ schemaName, yaml:
|
|
2490
|
+
async ({ schemaName, yaml: yaml3 }) => {
|
|
2491
|
+
const result = handleValidateYamlFragment({ schemaName, yaml: yaml3 });
|
|
2492
2492
|
return {
|
|
2493
2493
|
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
2494
2494
|
};
|
|
@@ -4194,20 +4194,20 @@ function handleEmitEvent(input) {
|
|
|
4194
4194
|
}
|
|
4195
4195
|
}
|
|
4196
4196
|
function registerPipelineTools(server2) {
|
|
4197
|
-
const
|
|
4197
|
+
const DESC = "Writes state to .stackwright/ \u2014 the filesystem is the state machine.";
|
|
4198
4198
|
const res = (r) => ({
|
|
4199
4199
|
content: [{ type: "text", text: r.text }],
|
|
4200
4200
|
isError: r.isError
|
|
4201
4201
|
});
|
|
4202
4202
|
server2.tool(
|
|
4203
4203
|
"stackwright_pro_get_pipeline_state",
|
|
4204
|
-
`Read pipeline state from .stackwright/pipeline-state.json. ${
|
|
4204
|
+
`Read pipeline state from .stackwright/pipeline-state.json. ${DESC}`,
|
|
4205
4205
|
{},
|
|
4206
4206
|
async () => res(handleGetPipelineState())
|
|
4207
4207
|
);
|
|
4208
4208
|
server2.tool(
|
|
4209
4209
|
"stackwright_pro_set_pipeline_state",
|
|
4210
|
-
`Atomic read\u2192modify\u2192write pipeline state. ${
|
|
4210
|
+
`Atomic read\u2192modify\u2192write pipeline state. ${DESC}`,
|
|
4211
4211
|
{
|
|
4212
4212
|
phase: import_zod13.z.string().optional().describe('Phase to update, e.g. "designer"'),
|
|
4213
4213
|
field: import_zod13.z.enum(["questionsCollected", "answered", "executed", "artifactWritten", "inFlight"]).optional().describe("Boolean field to set"),
|
|
@@ -4248,7 +4248,7 @@ function registerPipelineTools(server2) {
|
|
|
4248
4248
|
);
|
|
4249
4249
|
server2.tool(
|
|
4250
4250
|
"stackwright_pro_check_execution_ready",
|
|
4251
|
-
`Check all phases have answer files in .stackwright/answers/. If phase is provided, check only that phase. ${
|
|
4251
|
+
`Check all phases have answer files in .stackwright/answers/. If phase is provided, check only that phase. ${DESC}`,
|
|
4252
4252
|
{
|
|
4253
4253
|
phase: import_zod13.z.string().optional().describe("If provided, check only this phase's readiness. Omit to check all phases.")
|
|
4254
4254
|
},
|
|
@@ -4256,19 +4256,19 @@ function registerPipelineTools(server2) {
|
|
|
4256
4256
|
);
|
|
4257
4257
|
server2.tool(
|
|
4258
4258
|
"stackwright_pro_get_ready_phases",
|
|
4259
|
-
`Return phases whose dependencies are all satisfied (executed=true). Use to determine which phases can run next \u2014 enables wave-based execution. ${
|
|
4259
|
+
`Return phases whose dependencies are all satisfied (executed=true). Use to determine which phases can run next \u2014 enables wave-based execution. ${DESC}`,
|
|
4260
4260
|
{},
|
|
4261
4261
|
async () => res(handleGetReadyPhases())
|
|
4262
4262
|
);
|
|
4263
4263
|
server2.tool(
|
|
4264
4264
|
"stackwright_pro_list_artifacts",
|
|
4265
|
-
`List phase artifacts in .stackwright/artifacts/ with completedCount/totalCount. ${
|
|
4265
|
+
`List phase artifacts in .stackwright/artifacts/ with completedCount/totalCount. ${DESC}`,
|
|
4266
4266
|
{},
|
|
4267
4267
|
async () => res(handleListArtifacts())
|
|
4268
4268
|
);
|
|
4269
4269
|
server2.tool(
|
|
4270
4270
|
"stackwright_pro_write_phase_questions",
|
|
4271
|
-
`Parse otter question-collection response \u2192 .stackwright/questions/{phase}.json. Specialists may also call this directly with a parsed questions array. ${
|
|
4271
|
+
`Parse otter question-collection response \u2192 .stackwright/questions/{phase}.json. Specialists may also call this directly with a parsed questions array. ${DESC}`,
|
|
4272
4272
|
{
|
|
4273
4273
|
phase: import_zod13.z.string().optional().describe('Phase name, e.g. "designer" (required for direct write)'),
|
|
4274
4274
|
responseText: import_zod13.z.string().optional().describe("Raw LLM response from QUESTION_COLLECTION_MODE"),
|
|
@@ -4313,13 +4313,13 @@ function registerPipelineTools(server2) {
|
|
|
4313
4313
|
);
|
|
4314
4314
|
server2.tool(
|
|
4315
4315
|
"stackwright_pro_build_specialist_prompt",
|
|
4316
|
-
`Assemble execution prompt from answers + upstream artifacts. Foreman passes verbatim. ${
|
|
4316
|
+
`Assemble execution prompt from answers + upstream artifacts. Foreman passes verbatim. ${DESC}`,
|
|
4317
4317
|
{ phase: import_zod13.z.string().describe('Phase to build prompt for, e.g. "pages"') },
|
|
4318
4318
|
async ({ phase }) => res(handleBuildSpecialistPrompt({ phase }))
|
|
4319
4319
|
);
|
|
4320
4320
|
server2.tool(
|
|
4321
4321
|
"stackwright_pro_validate_artifact",
|
|
4322
|
-
`Validate and write artifact to .stackwright/artifacts/. Returns retryPrompt on failure. ${
|
|
4322
|
+
`Validate and write artifact to .stackwright/artifacts/. Returns retryPrompt on failure. ${DESC}`,
|
|
4323
4323
|
{
|
|
4324
4324
|
phase: import_zod13.z.string().describe('Phase that produced this artifact, e.g. "designer"'),
|
|
4325
4325
|
responseText: import_zod13.z.string().optional().describe("Raw response text from the specialist otter (Foreman-mediated path, legacy)"),
|
|
@@ -4351,7 +4351,7 @@ function registerPipelineTools(server2) {
|
|
|
4351
4351
|
);
|
|
4352
4352
|
server2.tool(
|
|
4353
4353
|
"stackwright_pro_emit_event",
|
|
4354
|
-
`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. ${
|
|
4354
|
+
`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}`,
|
|
4355
4355
|
{
|
|
4356
4356
|
type: import_zod13.z.enum([
|
|
4357
4357
|
"phase_start",
|
|
@@ -4850,10 +4850,10 @@ function handleSafeWrite(input) {
|
|
|
4850
4850
|
return result;
|
|
4851
4851
|
}
|
|
4852
4852
|
function registerSafeWriteTools(server2) {
|
|
4853
|
-
const
|
|
4853
|
+
const DESC = "Controlled file-write chokepoint. Every write from specialist otters goes through this tool with per-otter path allowlists. The LLM cannot write to arbitrary filesystem paths.";
|
|
4854
4854
|
server2.tool(
|
|
4855
4855
|
"stackwright_pro_safe_write",
|
|
4856
|
-
|
|
4856
|
+
DESC,
|
|
4857
4857
|
{
|
|
4858
4858
|
callerOtter: import_zod14.z.string().describe('The otter agent name requesting the write, e.g. "stackwright-pro-page-otter"'),
|
|
4859
4859
|
filePath: import_zod14.z.string().describe('Relative path from project root, e.g. "pages/dashboard/content.yml"'),
|
|
@@ -5797,7 +5797,7 @@ var import_path9 = require("path");
|
|
|
5797
5797
|
var _checksums = /* @__PURE__ */ new Map([
|
|
5798
5798
|
[
|
|
5799
5799
|
"stackwright-pro-api-otter.json",
|
|
5800
|
-
"
|
|
5800
|
+
"023352bac8303d86b33559719dc3f8d06d3a5a1458719eb74e1dc76019cf9d2f"
|
|
5801
5801
|
],
|
|
5802
5802
|
[
|
|
5803
5803
|
"stackwright-pro-auth-otter.json",
|
|
@@ -5805,7 +5805,7 @@ var _checksums = /* @__PURE__ */ new Map([
|
|
|
5805
5805
|
],
|
|
5806
5806
|
[
|
|
5807
5807
|
"stackwright-pro-dashboard-otter.json",
|
|
5808
|
-
"
|
|
5808
|
+
"f8d594b14e05efea30cf253052d7c7df3e8c4174d739be4cd33f9c96cecdc451"
|
|
5809
5809
|
],
|
|
5810
5810
|
[
|
|
5811
5811
|
"stackwright-pro-data-otter.json",
|
|
@@ -5821,7 +5821,7 @@ var _checksums = /* @__PURE__ */ new Map([
|
|
|
5821
5821
|
],
|
|
5822
5822
|
[
|
|
5823
5823
|
"stackwright-pro-foreman-otter.json",
|
|
5824
|
-
"
|
|
5824
|
+
"9d68b7b20af7a8a1668e2a693b4a2b05cf37acce1e9f6298a0966c97a3417e9f"
|
|
5825
5825
|
],
|
|
5826
5826
|
[
|
|
5827
5827
|
"stackwright-pro-form-wizard-otter.json",
|
|
@@ -5845,11 +5845,11 @@ var _checksums = /* @__PURE__ */ new Map([
|
|
|
5845
5845
|
],
|
|
5846
5846
|
[
|
|
5847
5847
|
"stackwright-pro-scaffold-otter.json",
|
|
5848
|
-
"
|
|
5848
|
+
"92930c732547c90a19e89ee0e25b5f037b7366f770941f0a01e148ff240a1b6d"
|
|
5849
5849
|
],
|
|
5850
5850
|
[
|
|
5851
5851
|
"stackwright-pro-theme-otter.json",
|
|
5852
|
-
"
|
|
5852
|
+
"01d16d0597d475db60362e3b8020035e140817d197c36f4307a48b95f4b28b60"
|
|
5853
5853
|
],
|
|
5854
5854
|
[
|
|
5855
5855
|
"stackwright-services-otter.json",
|
|
@@ -6917,10 +6917,10 @@ function handleCleanupScaffold(_cwd) {
|
|
|
6917
6917
|
};
|
|
6918
6918
|
}
|
|
6919
6919
|
function registerScaffoldCleanupTools(server2) {
|
|
6920
|
-
const
|
|
6920
|
+
const DESC = "Deterministic scaffold remnant cleanup \u2014 removes stale OSS scaffold files after raft run.";
|
|
6921
6921
|
server2.tool(
|
|
6922
6922
|
"stackwright_pro_cleanup_scaffold",
|
|
6923
|
-
`Remove/rewrite stale scaffold files (blog posts, hardcoded not-found page) after the raft pipeline completes. ${
|
|
6923
|
+
`Remove/rewrite stale scaffold files (blog posts, hardcoded not-found page) after the raft pipeline completes. ${DESC}`,
|
|
6924
6924
|
{},
|
|
6925
6925
|
async () => {
|
|
6926
6926
|
const r = handleCleanupScaffold();
|
|
@@ -7533,7 +7533,9 @@ function readServiceTokenRefs(cwd) {
|
|
|
7533
7533
|
return [];
|
|
7534
7534
|
}
|
|
7535
7535
|
}
|
|
7536
|
-
var
|
|
7536
|
+
var ENV_LOCAL_DESC = "Returns { envLocal, envLocalExample } as JSON. The otter writes both files via stackwright_pro_safe_write.";
|
|
7537
|
+
var PROVIDERS_DESC = "Returns { providersFile } as JSON. The otter writes the file via stackwright_pro_safe_write.";
|
|
7538
|
+
var PORTS_DESC = "Returns { ports } as JSON \u2014 map of integration name \u2192 port number.";
|
|
7537
7539
|
function registerEmitterTools(server2) {
|
|
7538
7540
|
server2.tool(
|
|
7539
7541
|
"stackwright_pro_emit_env_local",
|
|
@@ -7544,7 +7546,7 @@ Call this tool, then write both files with stackwright_pro_safe_write:
|
|
|
7544
7546
|
2. stackwright_pro_safe_write({ filePath: '.env.local', content: envLocal, ... })
|
|
7545
7547
|
3. stackwright_pro_safe_write({ filePath: '.env.local.example', content: envLocalExample, ... })
|
|
7546
7548
|
|
|
7547
|
-
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. ${
|
|
7549
|
+
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}`,
|
|
7548
7550
|
{
|
|
7549
7551
|
cwd: import_zod22.z.string().describe(
|
|
7550
7552
|
"Absolute path to the project root containing stackwright.integrations.yml and optionally services/*.yml"
|
|
@@ -7576,6 +7578,91 @@ Do NOT compose the contents by hand. This emitter is the source of truth. If an
|
|
|
7576
7578
|
};
|
|
7577
7579
|
}
|
|
7578
7580
|
);
|
|
7581
|
+
server2.tool(
|
|
7582
|
+
"stackwright_pro_emit_providers_file",
|
|
7583
|
+
`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).
|
|
7584
|
+
|
|
7585
|
+
\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.
|
|
7586
|
+
|
|
7587
|
+
Workflow:
|
|
7588
|
+
1. stackwright_pro_emit_providers_file({ cwd, mapProvider: 'cesium' }) \u2192 { providersFile }
|
|
7589
|
+
2. stackwright_pro_safe_write({ filePath: 'app/_components/providers.tsx', content: providersFile, ... })
|
|
7590
|
+
|
|
7591
|
+
mapProvider options:
|
|
7592
|
+
- 'cesium' (default for Pro): 3D globe + terrain, @stackwright-pro/cesium + cesium peer dep
|
|
7593
|
+
- 'maplibre': free-tier 2D maps, no API key \u2014 OSS-style 2D dashboards only (opt-out)
|
|
7594
|
+
- 'none': skip map registration (ONLY if no pages use map content_items)
|
|
7595
|
+
|
|
7596
|
+
This is the second concrete instance of the swp-zf9y deterministic emitter pattern. Refs: swp-57ku, swp-2m89, swp-zf9y, drawer 957. ${PROVIDERS_DESC}`,
|
|
7597
|
+
{
|
|
7598
|
+
cwd: import_zod22.z.string().describe("Absolute path to the project root containing stackwright.integrations.yml"),
|
|
7599
|
+
mapProvider: import_zod22.z.enum(["maplibre", "cesium", "none"]).optional().describe(
|
|
7600
|
+
"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."
|
|
7601
|
+
)
|
|
7602
|
+
},
|
|
7603
|
+
async ({ cwd, mapProvider }) => {
|
|
7604
|
+
const integrations = readIntegrations(cwd);
|
|
7605
|
+
const providersFile = (0, import_emitters.emitProvidersFile)({ integrations, mapProvider });
|
|
7606
|
+
return {
|
|
7607
|
+
content: [
|
|
7608
|
+
{
|
|
7609
|
+
type: "text",
|
|
7610
|
+
text: JSON.stringify(
|
|
7611
|
+
{
|
|
7612
|
+
providersFile,
|
|
7613
|
+
meta: {
|
|
7614
|
+
integrationsRead: integrations.length,
|
|
7615
|
+
integrationsWithAuth: integrations.filter((i) => i.auth?.envVar).length,
|
|
7616
|
+
mapProvider: mapProvider ?? "cesium"
|
|
7617
|
+
}
|
|
7618
|
+
},
|
|
7619
|
+
null,
|
|
7620
|
+
2
|
|
7621
|
+
)
|
|
7622
|
+
}
|
|
7623
|
+
]
|
|
7624
|
+
};
|
|
7625
|
+
}
|
|
7626
|
+
);
|
|
7627
|
+
server2.tool(
|
|
7628
|
+
"stackwright_pro_emit_mock_ports",
|
|
7629
|
+
`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.
|
|
7630
|
+
|
|
7631
|
+
\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).
|
|
7632
|
+
|
|
7633
|
+
Workflow:
|
|
7634
|
+
1. stackwright_pro_emit_mock_ports({ cwd }) \u2192 { ports }
|
|
7635
|
+
2. For each integration, set mockUrl to http://localhost:<ports[name]>
|
|
7636
|
+
3. Write stackwright.integrations.yml via stackwright_pro_safe_write
|
|
7637
|
+
|
|
7638
|
+
This is the third concrete instance of the swp-zf9y deterministic emitter pattern. Refs: swp-phkh, swp-zf9y. ${PORTS_DESC}`,
|
|
7639
|
+
{
|
|
7640
|
+
cwd: import_zod22.z.string().describe("Absolute path to the project root containing stackwright.integrations.yml")
|
|
7641
|
+
},
|
|
7642
|
+
async ({ cwd }) => {
|
|
7643
|
+
const integrations = readIntegrations(cwd);
|
|
7644
|
+
const { ports } = (0, import_emitters.emitMockPorts)({ integrations });
|
|
7645
|
+
return {
|
|
7646
|
+
content: [
|
|
7647
|
+
{
|
|
7648
|
+
type: "text",
|
|
7649
|
+
text: JSON.stringify(
|
|
7650
|
+
{
|
|
7651
|
+
ports,
|
|
7652
|
+
meta: {
|
|
7653
|
+
integrationsRead: integrations.length,
|
|
7654
|
+
portsAssigned: Object.keys(ports).length,
|
|
7655
|
+
portRange: Object.keys(ports).length > 0 ? `${Math.min(...Object.values(ports))}\u2013${Math.max(...Object.values(ports))}` : "none"
|
|
7656
|
+
}
|
|
7657
|
+
},
|
|
7658
|
+
null,
|
|
7659
|
+
2
|
|
7660
|
+
)
|
|
7661
|
+
}
|
|
7662
|
+
]
|
|
7663
|
+
};
|
|
7664
|
+
}
|
|
7665
|
+
);
|
|
7579
7666
|
}
|
|
7580
7667
|
|
|
7581
7668
|
// src/tools/list-specs.ts
|
|
@@ -7655,6 +7742,140 @@ function registerListSpecsTool(server2) {
|
|
|
7655
7742
|
);
|
|
7656
7743
|
}
|
|
7657
7744
|
|
|
7745
|
+
// src/tools/consolidate-integrations.ts
|
|
7746
|
+
var import_zod24 = require("zod");
|
|
7747
|
+
var import_fs16 = require("fs");
|
|
7748
|
+
var import_proper_lockfile2 = require("proper-lockfile");
|
|
7749
|
+
var import_path16 = require("path");
|
|
7750
|
+
var import_js_yaml4 = __toESM(require("js-yaml"));
|
|
7751
|
+
var BASE_MOCK_PORT = 4011;
|
|
7752
|
+
var STRIP_SUFFIXES2 = ["-openapi", "-asyncapi", "-api", "-spec"];
|
|
7753
|
+
function deriveNameFromFilename(filename) {
|
|
7754
|
+
const base = (0, import_path16.basename)(filename, ".json").replace(/^api-config-/, "");
|
|
7755
|
+
for (const suffix of STRIP_SUFFIXES2) {
|
|
7756
|
+
if (base.endsWith(suffix)) return base.slice(0, -suffix.length);
|
|
7757
|
+
}
|
|
7758
|
+
return base;
|
|
7759
|
+
}
|
|
7760
|
+
function handleConsolidateIntegrations(input) {
|
|
7761
|
+
const { projectRoot } = input;
|
|
7762
|
+
const artifactsDir = (0, import_path16.join)(projectRoot, ".stackwright", "artifacts");
|
|
7763
|
+
if (!(0, import_fs16.existsSync)(artifactsDir)) {
|
|
7764
|
+
return { written: false, integrationCount: 0, reason: "no per-spec artifacts found" };
|
|
7765
|
+
}
|
|
7766
|
+
let entries;
|
|
7767
|
+
try {
|
|
7768
|
+
entries = (0, import_fs16.readdirSync)(artifactsDir).filter(
|
|
7769
|
+
(f) => f.startsWith("api-config-") && f.endsWith(".json") && f !== "api-config.json"
|
|
7770
|
+
);
|
|
7771
|
+
} catch {
|
|
7772
|
+
return { written: false, integrationCount: 0, reason: "could not read artifacts directory" };
|
|
7773
|
+
}
|
|
7774
|
+
if (entries.length === 0) {
|
|
7775
|
+
return { written: false, integrationCount: 0, reason: "no per-spec artifacts found" };
|
|
7776
|
+
}
|
|
7777
|
+
entries.sort();
|
|
7778
|
+
const integrationsByName = /* @__PURE__ */ new Map();
|
|
7779
|
+
entries.forEach((filename, index) => {
|
|
7780
|
+
let artifact = {};
|
|
7781
|
+
try {
|
|
7782
|
+
const raw = (0, import_fs16.readFileSync)((0, import_path16.join)(artifactsDir, filename), "utf-8");
|
|
7783
|
+
artifact = JSON.parse(raw);
|
|
7784
|
+
} catch {
|
|
7785
|
+
}
|
|
7786
|
+
const name = artifact.integrationName ?? deriveNameFromFilename(filename);
|
|
7787
|
+
const spec = artifact.integrationSpec ?? artifact.specPath ?? `./specs/${name}.yaml`;
|
|
7788
|
+
const mockUrl = artifact.mockUrl ?? `http://localhost:${BASE_MOCK_PORT + index}`;
|
|
7789
|
+
const baseUrl = artifact.baseUrl ?? "";
|
|
7790
|
+
const auth = artifact.auth ?? { type: "none" };
|
|
7791
|
+
const isAsyncApi = artifact.skipped?.some((s) => s.format === "asyncapi") ?? false;
|
|
7792
|
+
const integrationType = artifact.integrationFormat ?? (isAsyncApi ? "asyncapi" : "openapi");
|
|
7793
|
+
const entry = {
|
|
7794
|
+
type: integrationType,
|
|
7795
|
+
name,
|
|
7796
|
+
spec,
|
|
7797
|
+
mockUrl,
|
|
7798
|
+
baseUrl,
|
|
7799
|
+
auth
|
|
7800
|
+
};
|
|
7801
|
+
if (artifact.integrationEndpoints) {
|
|
7802
|
+
entry.endpoints = artifact.integrationEndpoints;
|
|
7803
|
+
}
|
|
7804
|
+
integrationsByName.set(name, entry);
|
|
7805
|
+
});
|
|
7806
|
+
const integrations = Array.from(integrationsByName.values());
|
|
7807
|
+
const dedupedCount = entries.length - integrations.length;
|
|
7808
|
+
const integrationsYmlPath = (0, import_path16.join)(projectRoot, "stackwright.integrations.yml");
|
|
7809
|
+
let existing = {};
|
|
7810
|
+
if ((0, import_fs16.existsSync)(integrationsYmlPath)) {
|
|
7811
|
+
try {
|
|
7812
|
+
const raw = (0, import_fs16.readFileSync)(integrationsYmlPath, "utf-8");
|
|
7813
|
+
existing = import_js_yaml4.default.load(raw) ?? {};
|
|
7814
|
+
} catch {
|
|
7815
|
+
existing = {};
|
|
7816
|
+
}
|
|
7817
|
+
}
|
|
7818
|
+
const merged = { ...existing, integrations };
|
|
7819
|
+
(0, import_fs16.mkdirSync)((0, import_path16.join)(projectRoot), { recursive: true });
|
|
7820
|
+
if (!(0, import_fs16.existsSync)(integrationsYmlPath)) {
|
|
7821
|
+
(0, import_fs16.writeFileSync)(integrationsYmlPath, "", "utf-8");
|
|
7822
|
+
}
|
|
7823
|
+
const release = (0, import_proper_lockfile2.lockSync)(integrationsYmlPath, {
|
|
7824
|
+
realpath: false,
|
|
7825
|
+
stale: 1e4
|
|
7826
|
+
});
|
|
7827
|
+
try {
|
|
7828
|
+
const header = `# stackwright.integrations.yml \u2014 Auto-generated by stackwright_pro_consolidate_integrations
|
|
7829
|
+
`;
|
|
7830
|
+
const body = import_js_yaml4.default.dump(merged, { lineWidth: 120, noRefs: true });
|
|
7831
|
+
(0, import_fs16.writeFileSync)(integrationsYmlPath, header + body, "utf-8");
|
|
7832
|
+
} finally {
|
|
7833
|
+
release();
|
|
7834
|
+
}
|
|
7835
|
+
return {
|
|
7836
|
+
written: true,
|
|
7837
|
+
integrationCount: integrations.length,
|
|
7838
|
+
path: "stackwright.integrations.yml",
|
|
7839
|
+
...dedupedCount > 0 ? { dedupedCount } : {}
|
|
7840
|
+
};
|
|
7841
|
+
}
|
|
7842
|
+
function registerConsolidateIntegrationsTool(server2) {
|
|
7843
|
+
server2.tool(
|
|
7844
|
+
"stackwright_pro_consolidate_integrations",
|
|
7845
|
+
[
|
|
7846
|
+
"Assemble stackwright.integrations.yml from per-spec api-config-*.json artifacts.",
|
|
7847
|
+
"Called by the foreman AFTER all parallel api-otter invocations complete (swp-3l9j).",
|
|
7848
|
+
"Reads .stackwright/artifacts/api-config-{name}.json for each spec, deduplicates by",
|
|
7849
|
+
"integration name (last-write-wins), preserves any non-integrations top-level keys in",
|
|
7850
|
+
"an existing stackwright.integrations.yml, and writes the merged result atomically.",
|
|
7851
|
+
"Returns { written, integrationCount, path } on success or { written: false, reason } if",
|
|
7852
|
+
"no per-spec artifacts are found."
|
|
7853
|
+
].join(" "),
|
|
7854
|
+
{
|
|
7855
|
+
projectRoot: import_zod24.z.string().describe("Absolute path to the project root directory")
|
|
7856
|
+
},
|
|
7857
|
+
async ({ projectRoot }) => {
|
|
7858
|
+
try {
|
|
7859
|
+
const result = handleConsolidateIntegrations({ projectRoot });
|
|
7860
|
+
return {
|
|
7861
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
7862
|
+
};
|
|
7863
|
+
} catch (err) {
|
|
7864
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
7865
|
+
return {
|
|
7866
|
+
content: [
|
|
7867
|
+
{
|
|
7868
|
+
type: "text",
|
|
7869
|
+
text: JSON.stringify({ written: false, error: message })
|
|
7870
|
+
}
|
|
7871
|
+
],
|
|
7872
|
+
isError: true
|
|
7873
|
+
};
|
|
7874
|
+
}
|
|
7875
|
+
}
|
|
7876
|
+
);
|
|
7877
|
+
}
|
|
7878
|
+
|
|
7658
7879
|
// package.json
|
|
7659
7880
|
var package_default = {
|
|
7660
7881
|
dependencies: {
|
|
@@ -7667,7 +7888,7 @@ var package_default = {
|
|
|
7667
7888
|
"@stackwright-pro/pulse": "workspace:*",
|
|
7668
7889
|
"@stackwright-pro/telemetry": "workspace:*",
|
|
7669
7890
|
"@stackwright-pro/types": "workspace:*",
|
|
7670
|
-
"@stackwright/mcp": "0.6.0-alpha.
|
|
7891
|
+
"@stackwright/mcp": "0.6.0-alpha.2",
|
|
7671
7892
|
"@types/js-yaml": "^4.0.9",
|
|
7672
7893
|
"js-yaml": "^4.2.0",
|
|
7673
7894
|
"proper-lockfile": "^4.1.2",
|
|
@@ -7689,7 +7910,7 @@ var package_default = {
|
|
|
7689
7910
|
"test:coverage": "vitest run --coverage"
|
|
7690
7911
|
},
|
|
7691
7912
|
name: "@stackwright-pro/mcp",
|
|
7692
|
-
version: "0.2.0-alpha.
|
|
7913
|
+
version: "0.2.0-alpha.104",
|
|
7693
7914
|
description: "MCP tools for Stackwright Pro - Data Explorer, Security, ISR, and Dashboard generation",
|
|
7694
7915
|
license: "SEE LICENSE IN LICENSE",
|
|
7695
7916
|
main: "./dist/server.js",
|
|
@@ -7758,6 +7979,7 @@ registerCompileTools(server);
|
|
|
7758
7979
|
registerStripLegacyIntegrationsTool(server);
|
|
7759
7980
|
registerEmitterTools(server);
|
|
7760
7981
|
registerListSpecsTool(server);
|
|
7982
|
+
registerConsolidateIntegrationsTool(server);
|
|
7761
7983
|
(0, import_register.registerContentTypeTools)(server);
|
|
7762
7984
|
(0, import_register.registerPageTools)(server);
|
|
7763
7985
|
(0, import_register.registerSiteTools)(server);
|