@thehammer/schema-mcp-server 1.0.8 → 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.
@@ -38,14 +38,6 @@ 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
- /**
42
- * Check (or kick off) quality gate review for a single category.
43
- *
44
- * Returns one of: passed (cache hit), running (reviewer dispatched or in flight),
45
- * failed (items need fixes with analysis). The orchestrator uses this as its
46
- * primary quality-gate entry point — call once per category when 100% done with
47
- * that category's work.
48
- */
49
41
  export declare function callQualityGate(category: string, message?: string): Promise<ApiResponse>;
50
42
  /**
51
43
  * Orchestrator finalization — mandatory last action before exit.
@@ -180,16 +180,55 @@ export async function submitQualityGateReview(itemId, status, analysis, message)
180
180
  /**
181
181
  * Check (or kick off) quality gate review for a single category.
182
182
  *
183
- * Returns one of: passed (cache hit), running (reviewer dispatched or in flight),
184
- * failed (items need fixes with analysis). The orchestrator uses this as its
185
- * primary quality-gate entry point call once per category when 100% done with
186
- * that category's work.
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.
187
198
  */
199
+ const QUALITY_GATE_POLL_INTERVAL_MS = 3_000;
200
+ const QUALITY_GATE_MAX_POLL_MS = 15 * 60 * 1_000; // 15 minutes
188
201
  export async function callQualityGate(category, message) {
189
- return apiRequest("POST", mcpPath("quality-gate"), {
190
- category,
191
- message,
192
- });
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
+ }
193
232
  }
194
233
  /**
195
234
  * Orchestrator finalization — mandatory last action before exit.
package/dist/index.js CHANGED
@@ -682,13 +682,19 @@ if (shouldRegister("quality_gate_submit_review"))
682
682
  });
683
683
  if (shouldRegister("quality_gate"))
684
684
  server.tool("quality_gate", "Run the quality gate for a single category (schema, directive, or template). " +
685
- "Call this when you are 100% done with that category's work it either returns cached " +
686
- "results instantly or dispatches a reviewer. Response statuses: " +
687
- "'passed' means all items in the category are green (safe to move on); " +
688
- "'running' means a reviewer is in flight do other useful work and call again later; " +
689
- "'failed' means items need fixes — read each item's `analysis`, apply fixes via mutation " +
690
- "tools (which auto-invalidate the category), then re-call this tool. " +
691
- "You may call this for different categories in parallel while sub-agents are running.", {
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.", {
692
698
  category: z
693
699
  .enum(["schema", "directive", "template"])
694
700
  .describe("The quality gate category to check. Must be one of: schema, directive, template."),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thehammer/schema-mcp-server",
3
- "version": "1.0.8",
3
+ "version": "1.0.9",
4
4
  "description": "MCP server for Schema Builder - translates Claude Code tool calls into Laravel API requests",
5
5
  "license": "MIT",
6
6
  "repository": {