@thehammer/schema-mcp-server 1.0.7 → 1.0.9
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/api-client.d.ts +11 -0
- package/dist/api-client.js +67 -0
- package/dist/index.js +52 -2
- package/package.json +1 -1
package/dist/api-client.d.ts
CHANGED
|
@@ -38,5 +38,16 @@ export declare function getTemplatePreviewHtml(templateId: number, teamObjectId?
|
|
|
38
38
|
export declare function getStyleList(): Promise<ApiResponse>;
|
|
39
39
|
export declare function listQualityGateItems(): Promise<ApiResponse>;
|
|
40
40
|
export declare function submitQualityGateReview(itemId: number, status: string, analysis: string, message?: string): Promise<ApiResponse>;
|
|
41
|
+
export declare function callQualityGate(category: string, message?: string): Promise<ApiResponse>;
|
|
42
|
+
/**
|
|
43
|
+
* Orchestrator finalization — mandatory last action before exit.
|
|
44
|
+
*
|
|
45
|
+
* Returns {ok: true} when every outstanding check has cleared, transitioning the
|
|
46
|
+
* dispatch to completed. Returns {ok: false, outstanding: [...]} when any category
|
|
47
|
+
* is pending, any item failed, any template has validation_errors, or any directive
|
|
48
|
+
* has meta.selector_mismatches / meta.extraction_coverage_errors. In the non-empty
|
|
49
|
+
* case, the dispatch stays running so the agent can fix the issues and re-call.
|
|
50
|
+
*/
|
|
51
|
+
export declare function completeDispatch(message?: string): Promise<ApiResponse>;
|
|
41
52
|
export declare function postProgress(progressMessage: string, phase?: string): Promise<ApiResponse>;
|
|
42
53
|
export { SCHEMA_ID };
|
package/dist/api-client.js
CHANGED
|
@@ -177,6 +177,73 @@ export async function submitQualityGateReview(itemId, status, analysis, message)
|
|
|
177
177
|
message,
|
|
178
178
|
});
|
|
179
179
|
}
|
|
180
|
+
/**
|
|
181
|
+
* Check (or kick off) quality gate review for a single category.
|
|
182
|
+
*
|
|
183
|
+
* BLOCKING BY DESIGN. This call dispatches a reviewer (if one isn't already
|
|
184
|
+
* running) and then polls the backend until the gate for that category reaches
|
|
185
|
+
* a terminal state (`passed`, `failed`, or `error`). The agent sees exactly
|
|
186
|
+
* one call per category — no polling loop in agent context, no wasted context
|
|
187
|
+
* on intermediate `running` responses.
|
|
188
|
+
*
|
|
189
|
+
* Returns one of:
|
|
190
|
+
* - `passed` — all items green (cache hit or fresh review)
|
|
191
|
+
* - `failed` — items need fixes (with `analysis`)
|
|
192
|
+
* - `error` — a prior reviewer dispatch failed at this iteration; manual
|
|
193
|
+
* intervention needed (the agent must surface this to the user)
|
|
194
|
+
*
|
|
195
|
+
* Polling cadence: POLL_INTERVAL_MS between requests, capped at MAX_POLL_MS
|
|
196
|
+
* total wall time. If the cap is reached the function returns a synthetic
|
|
197
|
+
* `timeout` status so the agent doesn't hang forever.
|
|
198
|
+
*/
|
|
199
|
+
const QUALITY_GATE_POLL_INTERVAL_MS = 3_000;
|
|
200
|
+
const QUALITY_GATE_MAX_POLL_MS = 15 * 60 * 1_000; // 15 minutes
|
|
201
|
+
export async function callQualityGate(category, message) {
|
|
202
|
+
const terminal = new Set(["passed", "failed", "error", "timeout"]);
|
|
203
|
+
const deadline = Date.now() + QUALITY_GATE_MAX_POLL_MS;
|
|
204
|
+
let attempt = 0;
|
|
205
|
+
while (true) {
|
|
206
|
+
attempt += 1;
|
|
207
|
+
// Only pass the agent-authored message on the FIRST call — subsequent
|
|
208
|
+
// polls are internal and shouldn't spam the backend logs with duplicates.
|
|
209
|
+
const body = { category };
|
|
210
|
+
if (attempt === 1 && message) {
|
|
211
|
+
body.message = message;
|
|
212
|
+
}
|
|
213
|
+
const result = await apiRequest("POST", mcpPath("quality-gate"), body);
|
|
214
|
+
const status = String(result.status ?? "");
|
|
215
|
+
if (terminal.has(status)) {
|
|
216
|
+
return result;
|
|
217
|
+
}
|
|
218
|
+
if (status !== "running") {
|
|
219
|
+
// Unknown status — surface it verbatim so bugs are loud rather
|
|
220
|
+
// than swallowed by the polling loop.
|
|
221
|
+
return result;
|
|
222
|
+
}
|
|
223
|
+
if (Date.now() >= deadline) {
|
|
224
|
+
return {
|
|
225
|
+
...result,
|
|
226
|
+
status: "timeout",
|
|
227
|
+
message: `quality_gate(${category}) did not reach a terminal state within ${QUALITY_GATE_MAX_POLL_MS / 1000}s. The reviewer dispatch may be stuck — check dispatch status and retry.`,
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
await new Promise((resolve) => setTimeout(resolve, QUALITY_GATE_POLL_INTERVAL_MS));
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Orchestrator finalization — mandatory last action before exit.
|
|
235
|
+
*
|
|
236
|
+
* Returns {ok: true} when every outstanding check has cleared, transitioning the
|
|
237
|
+
* dispatch to completed. Returns {ok: false, outstanding: [...]} when any category
|
|
238
|
+
* is pending, any item failed, any template has validation_errors, or any directive
|
|
239
|
+
* has meta.selector_mismatches / meta.extraction_coverage_errors. In the non-empty
|
|
240
|
+
* case, the dispatch stays running so the agent can fix the issues and re-call.
|
|
241
|
+
*/
|
|
242
|
+
export async function completeDispatch(message) {
|
|
243
|
+
return apiRequest("POST", mcpPath("complete"), {
|
|
244
|
+
message,
|
|
245
|
+
});
|
|
246
|
+
}
|
|
180
247
|
export async function postProgress(progressMessage, phase) {
|
|
181
248
|
return apiRequest("POST", mcpPath("progress"), {
|
|
182
249
|
message: progressMessage,
|
package/dist/index.js
CHANGED
|
@@ -66,6 +66,9 @@ const ROLE_TOOLS = {
|
|
|
66
66
|
"context_workflow_inputs",
|
|
67
67
|
"context_workflow_input_pages",
|
|
68
68
|
"context_chat_history",
|
|
69
|
+
// Agent-driven quality gate lifecycle (orchestrator-only)
|
|
70
|
+
"quality_gate",
|
|
71
|
+
"complete",
|
|
69
72
|
]),
|
|
70
73
|
"schema-builder": new Set([
|
|
71
74
|
...COMMON_TOOLS,
|
|
@@ -530,12 +533,23 @@ if (shouldRegister("template_create"))
|
|
|
530
533
|
return jsonResult(result);
|
|
531
534
|
});
|
|
532
535
|
if (shouldRegister("template_list"))
|
|
533
|
-
server.tool("template_list", "List all template definitions for the current schema"
|
|
536
|
+
server.tool("template_list", "List all template definitions for the current schema. " +
|
|
537
|
+
"Each template includes a `validation_errors` field — when non-null it indicates unresolved " +
|
|
538
|
+
"coherence-check failures (field_warnings, style_warnings, meta_warnings, region_warnings, " +
|
|
539
|
+
"formatter_warnings, required_warnings) from the most recent mutation. Orchestrators do not " +
|
|
540
|
+
"need to poll this — `complete` automatically surfaces template validation errors as " +
|
|
541
|
+
"`template_errors` in its outstanding list.", {}, async () => {
|
|
534
542
|
const result = await api.listTemplates();
|
|
535
543
|
return jsonResult(result);
|
|
536
544
|
});
|
|
537
545
|
if (shouldRegister("template_get"))
|
|
538
|
-
server.tool("template_get", "Get full details of a template definition including template_json"
|
|
546
|
+
server.tool("template_get", "Get full details of a template definition including template_json. " +
|
|
547
|
+
"The response includes a `validation_errors` field — when non-null it indicates unresolved " +
|
|
548
|
+
"coherence-check failures (field_warnings, style_warnings, meta_warnings, region_warnings, " +
|
|
549
|
+
"formatter_warnings, required_warnings). Template-builder sub-agents should inspect this field " +
|
|
550
|
+
"after their own mutations to self-correct before handing work back. Orchestrators do not need " +
|
|
551
|
+
"to poll this — `complete` automatically surfaces template validation errors in its " +
|
|
552
|
+
"outstanding list.", {
|
|
539
553
|
template_id: z.number().describe("ID of the template to fetch"),
|
|
540
554
|
}, async ({ template_id }) => {
|
|
541
555
|
const result = await api.getTemplateDetails(template_id);
|
|
@@ -666,6 +680,42 @@ if (shouldRegister("quality_gate_submit_review"))
|
|
|
666
680
|
const result = await api.submitQualityGateReview(quality_gate_item_id, status, analysis, message);
|
|
667
681
|
return jsonResult(result);
|
|
668
682
|
});
|
|
683
|
+
if (shouldRegister("quality_gate"))
|
|
684
|
+
server.tool("quality_gate", "Run the quality gate for a single category (schema, directive, or template). " +
|
|
685
|
+
"BLOCKING — this call dispatches a reviewer (if one isn't already running) and waits " +
|
|
686
|
+
"until the gate reaches a terminal state. You receive ONE response per call: never " +
|
|
687
|
+
"poll the same category repeatedly. Response statuses: " +
|
|
688
|
+
"'passed' means all items are green (safe to move on); " +
|
|
689
|
+
"'failed' means items need fixes — read each item's `analysis`, apply fixes via " +
|
|
690
|
+
"mutation tools (which auto-invalidate the category), then call this tool again; " +
|
|
691
|
+
"'error' means the reviewer dispatch itself failed — surface the error to the user " +
|
|
692
|
+
"and stop (do NOT retry the same category); " +
|
|
693
|
+
"'timeout' means the call hit its 15-minute wall-time cap — the reviewer may be " +
|
|
694
|
+
"stuck, report it and move on. " +
|
|
695
|
+
"Parallelism is still available via concurrent tool calls for DIFFERENT categories " +
|
|
696
|
+
"(e.g. schema + directive in parallel). Do NOT call this tool twice for the same " +
|
|
697
|
+
"category before the first call returns.", {
|
|
698
|
+
category: z
|
|
699
|
+
.enum(["schema", "directive", "template"])
|
|
700
|
+
.describe("The quality gate category to check. Must be one of: schema, directive, template."),
|
|
701
|
+
message: messageParam,
|
|
702
|
+
}, async ({ category, message }) => {
|
|
703
|
+
const result = await api.callQualityGate(category, message);
|
|
704
|
+
return jsonResult(result);
|
|
705
|
+
});
|
|
706
|
+
if (shouldRegister("complete"))
|
|
707
|
+
server.tool("complete", "MANDATORY final action — call this to finalize your dispatch. Aggregates every known " +
|
|
708
|
+
"failure surface (pending quality gate categories, failed items, template validation " +
|
|
709
|
+
"errors, directive meta errors) and either transitions your dispatch to completed " +
|
|
710
|
+
"when everything is clean (returns {ok: true}) or returns {ok: false, outstanding: [...]} " +
|
|
711
|
+
"listing exactly what still needs fixing. When outstanding is non-empty, work through " +
|
|
712
|
+
"each item and call this tool again. Do NOT exit your session without calling this tool " +
|
|
713
|
+
"successfully — your dispatch will be marked dead by the heartbeat watchdog instead.", {
|
|
714
|
+
message: messageParam,
|
|
715
|
+
}, async ({ message }) => {
|
|
716
|
+
const result = await api.completeDispatch(message);
|
|
717
|
+
return jsonResult(result);
|
|
718
|
+
});
|
|
669
719
|
// ============================================================================
|
|
670
720
|
// Style Library Tools (read-only)
|
|
671
721
|
// ============================================================================
|