@stackwright-pro/mcp 0.2.0-alpha.100 → 0.2.0-alpha.102
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 +4 -4
- package/dist/integrity.js.map +1 -1
- package/dist/integrity.mjs +4 -4
- 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 +240 -89
- package/dist/server.js.map +1 -1
- package/dist/server.mjs +239 -88
- package/dist/server.mjs.map +1 -1
- package/package.json +5 -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 yaml2 = 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
|
+
${yaml2}
|
|
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 @@ ${yaml}
|
|
|
671
671
|
yamlLines.push(" action: navigate");
|
|
672
672
|
yamlLines.push(` href: "/${entity}"`);
|
|
673
673
|
yamlLines.push(" style: secondary");
|
|
674
|
-
const
|
|
674
|
+
const yaml2 = yamlLines.join("\n");
|
|
675
675
|
return {
|
|
676
676
|
content: [
|
|
677
677
|
{
|
|
@@ -679,7 +679,7 @@ ${yaml}
|
|
|
679
679
|
text: `\u{1F4C4} Generated Detail Page for: ${entity}
|
|
680
680
|
|
|
681
681
|
\`\`\`yaml
|
|
682
|
-
${
|
|
682
|
+
${yaml2}
|
|
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 } = input;
|
|
2454
|
+
const { schemaName, yaml: yaml2 } = 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)(yaml2);
|
|
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: yaml2 }) => {
|
|
2491
|
+
const result = handleValidateYamlFragment({ schemaName, yaml: yaml2 });
|
|
2492
2492
|
return {
|
|
2493
2493
|
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
2494
2494
|
};
|
|
@@ -2963,7 +2963,8 @@ function defaultPhaseStatus() {
|
|
|
2963
2963
|
answered: false,
|
|
2964
2964
|
executed: false,
|
|
2965
2965
|
artifactWritten: false,
|
|
2966
|
-
retryCount: 0
|
|
2966
|
+
retryCount: 0,
|
|
2967
|
+
inFlight: false
|
|
2967
2968
|
};
|
|
2968
2969
|
}
|
|
2969
2970
|
function createDefaultState() {
|
|
@@ -3080,7 +3081,13 @@ function handleSetPipelineState(input) {
|
|
|
3080
3081
|
isError: true
|
|
3081
3082
|
};
|
|
3082
3083
|
}
|
|
3083
|
-
const VALID_FIELDS = [
|
|
3084
|
+
const VALID_FIELDS = [
|
|
3085
|
+
"questionsCollected",
|
|
3086
|
+
"answered",
|
|
3087
|
+
"executed",
|
|
3088
|
+
"artifactWritten",
|
|
3089
|
+
"inFlight"
|
|
3090
|
+
];
|
|
3084
3091
|
if (input.field && !VALID_FIELDS.includes(input.field)) {
|
|
3085
3092
|
return {
|
|
3086
3093
|
text: JSON.stringify({
|
|
@@ -4117,24 +4124,94 @@ function handleValidateArtifact(input) {
|
|
|
4117
4124
|
}
|
|
4118
4125
|
return result;
|
|
4119
4126
|
}
|
|
4127
|
+
function handleEmitEvent(input) {
|
|
4128
|
+
const emitFn = input._emit ?? import_telemetry.emit;
|
|
4129
|
+
try {
|
|
4130
|
+
const caller = input.otter ?? "foreman";
|
|
4131
|
+
if (caller !== "foreman") {
|
|
4132
|
+
return {
|
|
4133
|
+
text: JSON.stringify({
|
|
4134
|
+
emitted: false,
|
|
4135
|
+
reason: `AUTHORIZATION: only the foreman otter may emit lifecycle events. Specialist otters should signal completion via their response text and the artifact write \u2014 not by emitting phase events. Caller was "${caller}". This is informational, not a failure.`
|
|
4136
|
+
}),
|
|
4137
|
+
isError: false
|
|
4138
|
+
};
|
|
4139
|
+
}
|
|
4140
|
+
let emitted = false;
|
|
4141
|
+
if (input.type === "phase_start") {
|
|
4142
|
+
if (!input.phase) {
|
|
4143
|
+
return {
|
|
4144
|
+
text: JSON.stringify({ emitted: false, reason: "phase required for phase_start" }),
|
|
4145
|
+
isError: false
|
|
4146
|
+
};
|
|
4147
|
+
}
|
|
4148
|
+
emitted = emitFn({ type: "phase_start", phase: input.phase, otter: caller });
|
|
4149
|
+
} else if (input.type === "phase_ready") {
|
|
4150
|
+
if (!input.phase) {
|
|
4151
|
+
return {
|
|
4152
|
+
text: JSON.stringify({ emitted: false, reason: "phase required for phase_ready" }),
|
|
4153
|
+
isError: false
|
|
4154
|
+
};
|
|
4155
|
+
}
|
|
4156
|
+
emitted = emitFn({ type: "phase_ready", phase: input.phase, otter: caller });
|
|
4157
|
+
} else if (input.type === "phase_complete") {
|
|
4158
|
+
if (!input.phase) {
|
|
4159
|
+
return {
|
|
4160
|
+
text: JSON.stringify({ emitted: false, reason: "phase required for phase_complete" }),
|
|
4161
|
+
isError: false
|
|
4162
|
+
};
|
|
4163
|
+
}
|
|
4164
|
+
emitted = emitFn({
|
|
4165
|
+
type: "phase_complete",
|
|
4166
|
+
phase: input.phase,
|
|
4167
|
+
otter: caller,
|
|
4168
|
+
...input.durationSec != null ? { durationSec: input.durationSec } : {}
|
|
4169
|
+
});
|
|
4170
|
+
} else if (input.type === "agent_invoke_start") {
|
|
4171
|
+
emitted = emitFn({
|
|
4172
|
+
type: "agent_invoke_start",
|
|
4173
|
+
targetOtter: input.targetOtter ?? "",
|
|
4174
|
+
phase: input.phase,
|
|
4175
|
+
otter: caller
|
|
4176
|
+
});
|
|
4177
|
+
} else if (input.type === "agent_invoke_complete") {
|
|
4178
|
+
emitted = emitFn({
|
|
4179
|
+
type: "agent_invoke_complete",
|
|
4180
|
+
targetOtter: input.targetOtter ?? "",
|
|
4181
|
+
success: input.success ?? true,
|
|
4182
|
+
phase: input.phase,
|
|
4183
|
+
otter: caller,
|
|
4184
|
+
...input.durationSec != null ? { durationSec: input.durationSec } : {}
|
|
4185
|
+
});
|
|
4186
|
+
}
|
|
4187
|
+
return { text: JSON.stringify({ emitted }), isError: false };
|
|
4188
|
+
} catch (err) {
|
|
4189
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
4190
|
+
return {
|
|
4191
|
+
text: JSON.stringify({ emitted: false, reason: `telemetry error (non-fatal): ${reason}` }),
|
|
4192
|
+
isError: false
|
|
4193
|
+
};
|
|
4194
|
+
}
|
|
4195
|
+
}
|
|
4120
4196
|
function registerPipelineTools(server2) {
|
|
4121
|
-
const
|
|
4197
|
+
const DESC2 = "Writes state to .stackwright/ \u2014 the filesystem is the state machine.";
|
|
4122
4198
|
const res = (r) => ({
|
|
4123
4199
|
content: [{ type: "text", text: r.text }],
|
|
4124
4200
|
isError: r.isError
|
|
4125
4201
|
});
|
|
4126
4202
|
server2.tool(
|
|
4127
4203
|
"stackwright_pro_get_pipeline_state",
|
|
4128
|
-
`Read pipeline state from .stackwright/pipeline-state.json. ${
|
|
4204
|
+
`Read pipeline state from .stackwright/pipeline-state.json. ${DESC2}`,
|
|
4129
4205
|
{},
|
|
4130
4206
|
async () => res(handleGetPipelineState())
|
|
4131
4207
|
);
|
|
4132
4208
|
server2.tool(
|
|
4133
4209
|
"stackwright_pro_set_pipeline_state",
|
|
4134
|
-
`Atomic read\u2192modify\u2192write pipeline state. ${
|
|
4210
|
+
`Atomic read\u2192modify\u2192write pipeline state. ${DESC2}`,
|
|
4135
4211
|
{
|
|
4136
4212
|
phase: import_zod13.z.string().optional().describe('Phase to update, e.g. "designer"'),
|
|
4137
|
-
field: import_zod13.z.enum(["questionsCollected", "answered", "executed", "artifactWritten"]).optional().describe("Boolean field to set"),
|
|
4213
|
+
field: import_zod13.z.enum(["questionsCollected", "answered", "executed", "artifactWritten", "inFlight"]).optional().describe("Boolean field to set"),
|
|
4214
|
+
// inFlight: set true BEFORE specialist invoke (dataflow mode, swp-ioc7); false after.
|
|
4138
4215
|
value: boolCoerce(import_zod13.z.boolean().optional()).describe(
|
|
4139
4216
|
'Value for the field \u2014 must be a JSON boolean (true/false), NOT the string "true"/"false"'
|
|
4140
4217
|
),
|
|
@@ -4146,7 +4223,13 @@ function registerPipelineTools(server2) {
|
|
|
4146
4223
|
import_zod13.z.array(
|
|
4147
4224
|
import_zod13.z.object({
|
|
4148
4225
|
phase: import_zod13.z.string(),
|
|
4149
|
-
field: import_zod13.z.enum([
|
|
4226
|
+
field: import_zod13.z.enum([
|
|
4227
|
+
"questionsCollected",
|
|
4228
|
+
"answered",
|
|
4229
|
+
"executed",
|
|
4230
|
+
"artifactWritten",
|
|
4231
|
+
"inFlight"
|
|
4232
|
+
]),
|
|
4150
4233
|
value: import_zod13.z.boolean()
|
|
4151
4234
|
})
|
|
4152
4235
|
).optional()
|
|
@@ -4165,7 +4248,7 @@ function registerPipelineTools(server2) {
|
|
|
4165
4248
|
);
|
|
4166
4249
|
server2.tool(
|
|
4167
4250
|
"stackwright_pro_check_execution_ready",
|
|
4168
|
-
`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. ${DESC2}`,
|
|
4169
4252
|
{
|
|
4170
4253
|
phase: import_zod13.z.string().optional().describe("If provided, check only this phase's readiness. Omit to check all phases.")
|
|
4171
4254
|
},
|
|
@@ -4173,19 +4256,19 @@ function registerPipelineTools(server2) {
|
|
|
4173
4256
|
);
|
|
4174
4257
|
server2.tool(
|
|
4175
4258
|
"stackwright_pro_get_ready_phases",
|
|
4176
|
-
`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. ${DESC2}`,
|
|
4177
4260
|
{},
|
|
4178
4261
|
async () => res(handleGetReadyPhases())
|
|
4179
4262
|
);
|
|
4180
4263
|
server2.tool(
|
|
4181
4264
|
"stackwright_pro_list_artifacts",
|
|
4182
|
-
`List phase artifacts in .stackwright/artifacts/ with completedCount/totalCount. ${
|
|
4265
|
+
`List phase artifacts in .stackwright/artifacts/ with completedCount/totalCount. ${DESC2}`,
|
|
4183
4266
|
{},
|
|
4184
4267
|
async () => res(handleListArtifacts())
|
|
4185
4268
|
);
|
|
4186
4269
|
server2.tool(
|
|
4187
4270
|
"stackwright_pro_write_phase_questions",
|
|
4188
|
-
`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. ${DESC2}`,
|
|
4189
4272
|
{
|
|
4190
4273
|
phase: import_zod13.z.string().optional().describe('Phase name, e.g. "designer" (required for direct write)'),
|
|
4191
4274
|
responseText: import_zod13.z.string().optional().describe("Raw LLM response from QUESTION_COLLECTION_MODE"),
|
|
@@ -4230,13 +4313,13 @@ function registerPipelineTools(server2) {
|
|
|
4230
4313
|
);
|
|
4231
4314
|
server2.tool(
|
|
4232
4315
|
"stackwright_pro_build_specialist_prompt",
|
|
4233
|
-
`Assemble execution prompt from answers + upstream artifacts. Foreman passes verbatim. ${
|
|
4316
|
+
`Assemble execution prompt from answers + upstream artifacts. Foreman passes verbatim. ${DESC2}`,
|
|
4234
4317
|
{ phase: import_zod13.z.string().describe('Phase to build prompt for, e.g. "pages"') },
|
|
4235
4318
|
async ({ phase }) => res(handleBuildSpecialistPrompt({ phase }))
|
|
4236
4319
|
);
|
|
4237
4320
|
server2.tool(
|
|
4238
4321
|
"stackwright_pro_validate_artifact",
|
|
4239
|
-
`Validate and write artifact to .stackwright/artifacts/. Returns retryPrompt on failure. ${
|
|
4322
|
+
`Validate and write artifact to .stackwright/artifacts/. Returns retryPrompt on failure. ${DESC2}`,
|
|
4240
4323
|
{
|
|
4241
4324
|
phase: import_zod13.z.string().describe('Phase that produced this artifact, e.g. "designer"'),
|
|
4242
4325
|
responseText: import_zod13.z.string().optional().describe("Raw response text from the specialist otter (Foreman-mediated path, legacy)"),
|
|
@@ -4268,60 +4351,26 @@ function registerPipelineTools(server2) {
|
|
|
4268
4351
|
);
|
|
4269
4352
|
server2.tool(
|
|
4270
4353
|
"stackwright_pro_emit_event",
|
|
4271
|
-
`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. ${DESC2}`,
|
|
4272
4355
|
{
|
|
4273
|
-
type: import_zod13.z.enum([
|
|
4356
|
+
type: import_zod13.z.enum([
|
|
4357
|
+
"phase_start",
|
|
4358
|
+
"phase_complete",
|
|
4359
|
+
"phase_ready",
|
|
4360
|
+
"agent_invoke_start",
|
|
4361
|
+
"agent_invoke_complete"
|
|
4362
|
+
]).describe("Event type to emit"),
|
|
4363
|
+
// phase_ready: emitted in dataflow mode (swp-ioc7) when a phase enters the ready set
|
|
4364
|
+
// (deps satisfied, not inFlight, not yet complete) — BEFORE invoking the specialist.
|
|
4274
4365
|
phase: import_zod13.z.string().optional().describe("Current phase name"),
|
|
4275
4366
|
targetOtter: import_zod13.z.string().optional().describe("For agent_invoke_* events: which otter is being invoked"),
|
|
4276
|
-
success: import_zod13.z.boolean().optional().describe(
|
|
4367
|
+
success: boolCoerce(import_zod13.z.boolean().optional()).describe(
|
|
4368
|
+
'For agent_invoke_complete: did the invocation succeed? (boolean; string "true"/"false" also accepted for caller tolerance)'
|
|
4369
|
+
),
|
|
4277
4370
|
otter: import_zod13.z.string().optional().describe('Which otter is emitting (defaults to "foreman")'),
|
|
4278
4371
|
durationSec: import_zod13.z.number().optional().describe("Duration in seconds (for *_complete events)")
|
|
4279
4372
|
},
|
|
4280
|
-
async ({ type, phase, targetOtter, success, otter, durationSec }) => {
|
|
4281
|
-
let emitted = false;
|
|
4282
|
-
try {
|
|
4283
|
-
if (type === "phase_start") {
|
|
4284
|
-
if (!phase) {
|
|
4285
|
-
return res({
|
|
4286
|
-
text: JSON.stringify({ emitted: false, reason: "phase required for phase_start" }),
|
|
4287
|
-
isError: false
|
|
4288
|
-
});
|
|
4289
|
-
}
|
|
4290
|
-
emitted = (0, import_telemetry.emit)({ type: "phase_start", phase, otter: otter ?? "foreman" });
|
|
4291
|
-
} else if (type === "phase_complete") {
|
|
4292
|
-
if (!phase) {
|
|
4293
|
-
return res({
|
|
4294
|
-
text: JSON.stringify({ emitted: false, reason: "phase required for phase_complete" }),
|
|
4295
|
-
isError: false
|
|
4296
|
-
});
|
|
4297
|
-
}
|
|
4298
|
-
emitted = (0, import_telemetry.emit)({
|
|
4299
|
-
type: "phase_complete",
|
|
4300
|
-
phase,
|
|
4301
|
-
otter: otter ?? "foreman",
|
|
4302
|
-
...durationSec != null ? { durationSec } : {}
|
|
4303
|
-
});
|
|
4304
|
-
} else if (type === "agent_invoke_start") {
|
|
4305
|
-
emitted = (0, import_telemetry.emit)({
|
|
4306
|
-
type: "agent_invoke_start",
|
|
4307
|
-
targetOtter: targetOtter ?? "",
|
|
4308
|
-
phase,
|
|
4309
|
-
otter: otter ?? "foreman"
|
|
4310
|
-
});
|
|
4311
|
-
} else if (type === "agent_invoke_complete") {
|
|
4312
|
-
emitted = (0, import_telemetry.emit)({
|
|
4313
|
-
type: "agent_invoke_complete",
|
|
4314
|
-
targetOtter: targetOtter ?? "",
|
|
4315
|
-
success: success ?? true,
|
|
4316
|
-
phase,
|
|
4317
|
-
otter: otter ?? "foreman",
|
|
4318
|
-
...durationSec != null ? { durationSec } : {}
|
|
4319
|
-
});
|
|
4320
|
-
}
|
|
4321
|
-
} catch {
|
|
4322
|
-
}
|
|
4323
|
-
return res({ text: JSON.stringify({ emitted }), isError: false });
|
|
4324
|
-
}
|
|
4373
|
+
async ({ type, phase, targetOtter, success, otter, durationSec }) => res(handleEmitEvent({ type, phase, targetOtter, success, otter, durationSec }))
|
|
4325
4374
|
);
|
|
4326
4375
|
}
|
|
4327
4376
|
|
|
@@ -4423,7 +4472,17 @@ var OTTER_WRITE_ALLOWLISTS = {
|
|
|
4423
4472
|
{ prefix: "pages/", suffix: "/content.yml", description: "Landing page content" },
|
|
4424
4473
|
{ prefix: "pages/", suffix: "/content.yaml", description: "Landing page content" },
|
|
4425
4474
|
{ prefix: ".stackwright/artifacts/", suffix: ".json", description: "Polish artifact" },
|
|
4426
|
-
{ prefix: "README.md", suffix: "", description: "Project README rewrite" }
|
|
4475
|
+
{ prefix: "README.md", suffix: "", description: "Project README rewrite" },
|
|
4476
|
+
{
|
|
4477
|
+
prefix: ".env.local",
|
|
4478
|
+
suffix: "",
|
|
4479
|
+
description: ".env.local runtime config \u2014 emitter output from stackwright_pro_emit_env_local (swp-8qdd)"
|
|
4480
|
+
},
|
|
4481
|
+
{
|
|
4482
|
+
prefix: ".env.local.example",
|
|
4483
|
+
suffix: "",
|
|
4484
|
+
description: ".env.local.example template \u2014 emitter output from stackwright_pro_emit_env_local (swp-8qdd)"
|
|
4485
|
+
}
|
|
4427
4486
|
],
|
|
4428
4487
|
// QA otter writes ONLY to the qa/ directory and the qa-findings artifact.
|
|
4429
4488
|
// It never writes .tsx, .ts, .yml, or .json outside these paths.
|
|
@@ -4791,10 +4850,10 @@ function handleSafeWrite(input) {
|
|
|
4791
4850
|
return result;
|
|
4792
4851
|
}
|
|
4793
4852
|
function registerSafeWriteTools(server2) {
|
|
4794
|
-
const
|
|
4853
|
+
const DESC2 = "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.";
|
|
4795
4854
|
server2.tool(
|
|
4796
4855
|
"stackwright_pro_safe_write",
|
|
4797
|
-
|
|
4856
|
+
DESC2,
|
|
4798
4857
|
{
|
|
4799
4858
|
callerOtter: import_zod14.z.string().describe('The otter agent name requesting the write, e.g. "stackwright-pro-page-otter"'),
|
|
4800
4859
|
filePath: import_zod14.z.string().describe('Relative path from project root, e.g. "pages/dashboard/content.yml"'),
|
|
@@ -5762,7 +5821,7 @@ var _checksums = /* @__PURE__ */ new Map([
|
|
|
5762
5821
|
],
|
|
5763
5822
|
[
|
|
5764
5823
|
"stackwright-pro-foreman-otter.json",
|
|
5765
|
-
"
|
|
5824
|
+
"c23436769a9db06fa6f9d312b4fdd8b2cef6646461020eeaf227303350073593"
|
|
5766
5825
|
],
|
|
5767
5826
|
[
|
|
5768
5827
|
"stackwright-pro-form-wizard-otter.json",
|
|
@@ -5778,7 +5837,7 @@ var _checksums = /* @__PURE__ */ new Map([
|
|
|
5778
5837
|
],
|
|
5779
5838
|
[
|
|
5780
5839
|
"stackwright-pro-polish-otter.json",
|
|
5781
|
-
"
|
|
5840
|
+
"fd8f8963266c6179eebf8eac4f656e8274aa3a721e5296abdbde5b00ad8a2297"
|
|
5782
5841
|
],
|
|
5783
5842
|
[
|
|
5784
5843
|
"stackwright-pro-qa-otter.json",
|
|
@@ -5786,7 +5845,7 @@ var _checksums = /* @__PURE__ */ new Map([
|
|
|
5786
5845
|
],
|
|
5787
5846
|
[
|
|
5788
5847
|
"stackwright-pro-scaffold-otter.json",
|
|
5789
|
-
"
|
|
5848
|
+
"c2ae10733d8bd66bd965b29a77193b0abf0ea6765cd02886df1413bf598e0588"
|
|
5790
5849
|
],
|
|
5791
5850
|
[
|
|
5792
5851
|
"stackwright-pro-theme-otter.json",
|
|
@@ -5794,7 +5853,7 @@ var _checksums = /* @__PURE__ */ new Map([
|
|
|
5794
5853
|
],
|
|
5795
5854
|
[
|
|
5796
5855
|
"stackwright-services-otter.json",
|
|
5797
|
-
"
|
|
5856
|
+
"2a50ceb3fad166251d0ad8709a34a32118645713e0e34628165d16dced1d5c93"
|
|
5798
5857
|
]
|
|
5799
5858
|
]);
|
|
5800
5859
|
Object.freeze(_checksums);
|
|
@@ -6858,10 +6917,10 @@ function handleCleanupScaffold(_cwd) {
|
|
|
6858
6917
|
};
|
|
6859
6918
|
}
|
|
6860
6919
|
function registerScaffoldCleanupTools(server2) {
|
|
6861
|
-
const
|
|
6920
|
+
const DESC2 = "Deterministic scaffold remnant cleanup \u2014 removes stale OSS scaffold files after raft run.";
|
|
6862
6921
|
server2.tool(
|
|
6863
6922
|
"stackwright_pro_cleanup_scaffold",
|
|
6864
|
-
`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. ${DESC2}`,
|
|
6865
6924
|
{},
|
|
6866
6925
|
async () => {
|
|
6867
6926
|
const r = handleCleanupScaffold();
|
|
@@ -7429,14 +7488,104 @@ function registerStripLegacyIntegrationsTool(server2) {
|
|
|
7429
7488
|
);
|
|
7430
7489
|
}
|
|
7431
7490
|
|
|
7432
|
-
// src/tools/
|
|
7491
|
+
// src/tools/emitters.ts
|
|
7433
7492
|
var import_zod22 = require("zod");
|
|
7434
7493
|
var import_fs14 = require("fs");
|
|
7435
7494
|
var import_path14 = require("path");
|
|
7495
|
+
var import_js_yaml3 = __toESM(require("js-yaml"));
|
|
7496
|
+
var import_emitters = require("@stackwright-pro/emitters");
|
|
7497
|
+
function readIntegrations(cwd) {
|
|
7498
|
+
const filePath = (0, import_path14.join)(cwd, "stackwright.integrations.yml");
|
|
7499
|
+
if (!(0, import_fs14.existsSync)(filePath)) return [];
|
|
7500
|
+
try {
|
|
7501
|
+
const raw = import_js_yaml3.default.load((0, import_fs14.readFileSync)(filePath, "utf-8"));
|
|
7502
|
+
if (!raw?.integrations || !Array.isArray(raw.integrations)) return [];
|
|
7503
|
+
return raw.integrations.filter((i) => typeof i.name === "string").map((i) => ({
|
|
7504
|
+
name: i.name,
|
|
7505
|
+
auth: i.auth ? { type: i.auth.type, header: i.auth.header, envVar: i.auth.envVar } : void 0
|
|
7506
|
+
}));
|
|
7507
|
+
} catch {
|
|
7508
|
+
return [];
|
|
7509
|
+
}
|
|
7510
|
+
}
|
|
7511
|
+
function readServiceTokenRefs(cwd) {
|
|
7512
|
+
const servicesDir = (0, import_path14.join)(cwd, "services");
|
|
7513
|
+
if (!(0, import_fs14.existsSync)(servicesDir)) return [];
|
|
7514
|
+
try {
|
|
7515
|
+
const files = (0, import_fs14.readdirSync)(servicesDir).filter((f) => f.endsWith(".yml") || f.endsWith(".yaml"));
|
|
7516
|
+
const refs = [];
|
|
7517
|
+
for (const file of files) {
|
|
7518
|
+
try {
|
|
7519
|
+
const raw = import_js_yaml3.default.load(
|
|
7520
|
+
(0, import_fs14.readFileSync)((0, import_path14.join)(servicesDir, file), "utf-8")
|
|
7521
|
+
);
|
|
7522
|
+
if (raw?.tokenEnv && typeof raw.tokenEnv === "string") {
|
|
7523
|
+
refs.push({
|
|
7524
|
+
name: raw.name ?? file.replace(/\.ya?ml$/, ""),
|
|
7525
|
+
tokenEnv: raw.tokenEnv
|
|
7526
|
+
});
|
|
7527
|
+
}
|
|
7528
|
+
} catch {
|
|
7529
|
+
}
|
|
7530
|
+
}
|
|
7531
|
+
return refs;
|
|
7532
|
+
} catch {
|
|
7533
|
+
return [];
|
|
7534
|
+
}
|
|
7535
|
+
}
|
|
7536
|
+
var DESC = "Returns { envLocal, envLocalExample } as JSON. The otter writes both files via stackwright_pro_safe_write.";
|
|
7537
|
+
function registerEmitterTools(server2) {
|
|
7538
|
+
server2.tool(
|
|
7539
|
+
"stackwright_pro_emit_env_local",
|
|
7540
|
+
`Emit .env.local + .env.local.example contents from stackwright.integrations.yml and services/*.yml. Deterministic emitter \u2014 same project config produces byte-identical output.
|
|
7541
|
+
|
|
7542
|
+
Call this tool, then write both files with stackwright_pro_safe_write:
|
|
7543
|
+
1. stackwright_pro_emit_env_local({ cwd }) \u2192 { envLocal, envLocalExample }
|
|
7544
|
+
2. stackwright_pro_safe_write({ filePath: '.env.local', content: envLocal, ... })
|
|
7545
|
+
3. stackwright_pro_safe_write({ filePath: '.env.local.example', content: envLocalExample, ... })
|
|
7546
|
+
|
|
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. ${DESC}`,
|
|
7548
|
+
{
|
|
7549
|
+
cwd: import_zod22.z.string().describe(
|
|
7550
|
+
"Absolute path to the project root containing stackwright.integrations.yml and optionally services/*.yml"
|
|
7551
|
+
)
|
|
7552
|
+
},
|
|
7553
|
+
async ({ cwd }) => {
|
|
7554
|
+
const integrations = readIntegrations(cwd);
|
|
7555
|
+
const services = readServiceTokenRefs(cwd);
|
|
7556
|
+
const output = (0, import_emitters.emitEnvLocal)({ integrations, services });
|
|
7557
|
+
return {
|
|
7558
|
+
content: [
|
|
7559
|
+
{
|
|
7560
|
+
type: "text",
|
|
7561
|
+
text: JSON.stringify(
|
|
7562
|
+
{
|
|
7563
|
+
envLocal: output.envLocal,
|
|
7564
|
+
envLocalExample: output.envLocalExample,
|
|
7565
|
+
meta: {
|
|
7566
|
+
integrationsRead: integrations.length,
|
|
7567
|
+
serviceTokenRefsRead: services.length,
|
|
7568
|
+
envVarsEmitted: (output.envLocal.match(/^NEXT_PUBLIC_[A-Z0-9_]+=.+$/m) ? output.envLocal.match(/^NEXT_PUBLIC_[A-Z0-9_]+=.+$/gm) ?? [] : []).length
|
|
7569
|
+
}
|
|
7570
|
+
},
|
|
7571
|
+
null,
|
|
7572
|
+
2
|
|
7573
|
+
)
|
|
7574
|
+
}
|
|
7575
|
+
]
|
|
7576
|
+
};
|
|
7577
|
+
}
|
|
7578
|
+
);
|
|
7579
|
+
}
|
|
7580
|
+
|
|
7581
|
+
// src/tools/list-specs.ts
|
|
7582
|
+
var import_zod23 = require("zod");
|
|
7583
|
+
var import_fs15 = require("fs");
|
|
7584
|
+
var import_path15 = require("path");
|
|
7436
7585
|
var STRIP_SUFFIXES = ["-openapi", "-asyncapi", "-api", "-spec"];
|
|
7437
7586
|
var ALLOWED_EXTS = /* @__PURE__ */ new Set([".yaml", ".yml", ".json"]);
|
|
7438
7587
|
function deriveIntegrationName(fileName) {
|
|
7439
|
-
let name = (0,
|
|
7588
|
+
let name = (0, import_path15.basename)(fileName, (0, import_path15.extname)(fileName));
|
|
7440
7589
|
for (const suffix of STRIP_SUFFIXES) {
|
|
7441
7590
|
if (name.endsWith(suffix)) {
|
|
7442
7591
|
name = name.slice(0, -suffix.length);
|
|
@@ -7454,29 +7603,29 @@ function detectFormat(snippet) {
|
|
|
7454
7603
|
}
|
|
7455
7604
|
function handleListSpecs(input) {
|
|
7456
7605
|
const { projectRoot } = input;
|
|
7457
|
-
const specsDir = (0,
|
|
7606
|
+
const specsDir = (0, import_path15.join)(projectRoot, "specs");
|
|
7458
7607
|
const empty = { projectRoot, specs: [], totalCount: 0 };
|
|
7459
|
-
if (!(0,
|
|
7608
|
+
if (!(0, import_fs15.existsSync)(specsDir)) return empty;
|
|
7460
7609
|
let entries;
|
|
7461
7610
|
try {
|
|
7462
|
-
entries = (0,
|
|
7611
|
+
entries = (0, import_fs15.readdirSync)(specsDir);
|
|
7463
7612
|
} catch {
|
|
7464
7613
|
return empty;
|
|
7465
7614
|
}
|
|
7466
7615
|
const specs = [];
|
|
7467
7616
|
for (const entry of entries) {
|
|
7468
|
-
const fullPath = (0,
|
|
7617
|
+
const fullPath = (0, import_path15.join)(specsDir, entry);
|
|
7469
7618
|
let stat;
|
|
7470
7619
|
try {
|
|
7471
|
-
stat = (0,
|
|
7620
|
+
stat = (0, import_fs15.statSync)(fullPath);
|
|
7472
7621
|
} catch {
|
|
7473
7622
|
continue;
|
|
7474
7623
|
}
|
|
7475
7624
|
if (!stat.isFile()) continue;
|
|
7476
|
-
if (!ALLOWED_EXTS.has((0,
|
|
7625
|
+
if (!ALLOWED_EXTS.has((0, import_path15.extname)(entry).toLowerCase())) continue;
|
|
7477
7626
|
let snippet = "";
|
|
7478
7627
|
try {
|
|
7479
|
-
snippet = (0,
|
|
7628
|
+
snippet = (0, import_fs15.readFileSync)(fullPath, "utf-8").slice(0, 2048);
|
|
7480
7629
|
} catch {
|
|
7481
7630
|
}
|
|
7482
7631
|
specs.push({
|
|
@@ -7495,7 +7644,7 @@ function registerListSpecsTool(server2) {
|
|
|
7495
7644
|
"stackwright_pro_list_specs",
|
|
7496
7645
|
"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.",
|
|
7497
7646
|
{
|
|
7498
|
-
projectRoot:
|
|
7647
|
+
projectRoot: import_zod23.z.string().describe("Absolute path to the project root directory")
|
|
7499
7648
|
},
|
|
7500
7649
|
async ({ projectRoot }) => {
|
|
7501
7650
|
const result = handleListSpecs({ projectRoot });
|
|
@@ -7512,6 +7661,7 @@ var package_default = {
|
|
|
7512
7661
|
"@modelcontextprotocol/sdk": "^1.10.0",
|
|
7513
7662
|
"@stackwright/cli": "^0.9.0",
|
|
7514
7663
|
"@stackwright-pro/auth-nextjs": "workspace:*",
|
|
7664
|
+
"@stackwright-pro/emitters": "workspace:*",
|
|
7515
7665
|
"@stackwright-pro/cli-data-explorer": "workspace:*",
|
|
7516
7666
|
"@stackwright-pro/openapi": "workspace:*",
|
|
7517
7667
|
"@stackwright-pro/pulse": "workspace:*",
|
|
@@ -7539,7 +7689,7 @@ var package_default = {
|
|
|
7539
7689
|
"test:coverage": "vitest run --coverage"
|
|
7540
7690
|
},
|
|
7541
7691
|
name: "@stackwright-pro/mcp",
|
|
7542
|
-
version: "0.2.0-alpha.
|
|
7692
|
+
version: "0.2.0-alpha.102",
|
|
7543
7693
|
description: "MCP tools for Stackwright Pro - Data Explorer, Security, ISR, and Dashboard generation",
|
|
7544
7694
|
license: "SEE LICENSE IN LICENSE",
|
|
7545
7695
|
main: "./dist/server.js",
|
|
@@ -7606,6 +7756,7 @@ registerScaffoldCleanupTools(server);
|
|
|
7606
7756
|
registerContrastTools(server);
|
|
7607
7757
|
registerCompileTools(server);
|
|
7608
7758
|
registerStripLegacyIntegrationsTool(server);
|
|
7759
|
+
registerEmitterTools(server);
|
|
7609
7760
|
registerListSpecsTool(server);
|
|
7610
7761
|
(0, import_register.registerContentTypeTools)(server);
|
|
7611
7762
|
(0, import_register.registerPageTools)(server);
|