@thehammer/schema-mcp-server 1.0.9 → 1.0.11
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 +32 -0
- package/dist/api-client.js +35 -44
- package/dist/index.js +30 -11
- package/package.json +1 -1
package/dist/api-client.d.ts
CHANGED
|
@@ -38,6 +38,31 @@ 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
|
+
* NON-BLOCKING. A single HTTP round-trip. The agent NEVER waits inside MCP —
|
|
45
|
+
* blocking hides dispatch failures behind timeouts and ties up the agent when
|
|
46
|
+
* it could be doing other productive work.
|
|
47
|
+
*
|
|
48
|
+
* Returns one of:
|
|
49
|
+
* - `passed` — all items green (cache hit or fresh review)
|
|
50
|
+
* - `failed` — items need fixes; response includes each item's `analysis`
|
|
51
|
+
* - `running` — a reviewer is dispatched (or already in flight); call again later
|
|
52
|
+
* - `error` — a prior reviewer dispatch failed at this iteration; manual
|
|
53
|
+
* intervention needed. Do NOT retry on this category; surface to the user
|
|
54
|
+
* via an annotation.
|
|
55
|
+
*
|
|
56
|
+
* Recommended pattern:
|
|
57
|
+
* 1. Call `quality_gate(A)` — reviewer is launched by the backend on the
|
|
58
|
+
* first running-with-pending-items response
|
|
59
|
+
* 2. Do other productive work (work on other categories, read annotations,
|
|
60
|
+
* preview templates, call `quality_gate(B)` in parallel)
|
|
61
|
+
* 3. Call `quality_gate(A)` again later to poll. The backend is idempotent:
|
|
62
|
+
* won't launch a second reviewer while the first is running.
|
|
63
|
+
* 4. When the agent has no other productive work, it still polls — each poll
|
|
64
|
+
* is cheap, short, and carries minimal context.
|
|
65
|
+
*/
|
|
41
66
|
export declare function callQualityGate(category: string, message?: string): Promise<ApiResponse>;
|
|
42
67
|
/**
|
|
43
68
|
* Orchestrator finalization — mandatory last action before exit.
|
|
@@ -50,4 +75,11 @@ export declare function callQualityGate(category: string, message?: string): Pro
|
|
|
50
75
|
*/
|
|
51
76
|
export declare function completeDispatch(message?: string): Promise<ApiResponse>;
|
|
52
77
|
export declare function postProgress(progressMessage: string, phase?: string): Promise<ApiResponse>;
|
|
78
|
+
/**
|
|
79
|
+
* Fail-fast termination — agent calls this the moment anything deviates from the
|
|
80
|
+
* prompt's described behavior (missing tool, unexpected response, sub-agent not found,
|
|
81
|
+
* API error the prompt doesn't cover, etc.). Never use shell, tinker, or other creative
|
|
82
|
+
* workarounds — abort and let the operator diagnose.
|
|
83
|
+
*/
|
|
84
|
+
export declare function abortDispatch(reason: string, details?: string, phase?: string): Promise<ApiResponse>;
|
|
53
85
|
export { SCHEMA_ID };
|
package/dist/api-client.js
CHANGED
|
@@ -180,55 +180,33 @@ 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
|
-
* BLOCKING
|
|
184
|
-
*
|
|
185
|
-
*
|
|
186
|
-
* one call per category — no polling loop in agent context, no wasted context
|
|
187
|
-
* on intermediate `running` responses.
|
|
183
|
+
* NON-BLOCKING. A single HTTP round-trip. The agent NEVER waits inside MCP —
|
|
184
|
+
* blocking hides dispatch failures behind timeouts and ties up the agent when
|
|
185
|
+
* it could be doing other productive work.
|
|
188
186
|
*
|
|
189
187
|
* Returns one of:
|
|
190
|
-
* - `passed`
|
|
191
|
-
* - `failed`
|
|
192
|
-
* - `
|
|
193
|
-
*
|
|
188
|
+
* - `passed` — all items green (cache hit or fresh review)
|
|
189
|
+
* - `failed` — items need fixes; response includes each item's `analysis`
|
|
190
|
+
* - `running` — a reviewer is dispatched (or already in flight); call again later
|
|
191
|
+
* - `error` — a prior reviewer dispatch failed at this iteration; manual
|
|
192
|
+
* intervention needed. Do NOT retry on this category; surface to the user
|
|
193
|
+
* via an annotation.
|
|
194
194
|
*
|
|
195
|
-
*
|
|
196
|
-
*
|
|
197
|
-
*
|
|
195
|
+
* Recommended pattern:
|
|
196
|
+
* 1. Call `quality_gate(A)` — reviewer is launched by the backend on the
|
|
197
|
+
* first running-with-pending-items response
|
|
198
|
+
* 2. Do other productive work (work on other categories, read annotations,
|
|
199
|
+
* preview templates, call `quality_gate(B)` in parallel)
|
|
200
|
+
* 3. Call `quality_gate(A)` again later to poll. The backend is idempotent:
|
|
201
|
+
* won't launch a second reviewer while the first is running.
|
|
202
|
+
* 4. When the agent has no other productive work, it still polls — each poll
|
|
203
|
+
* is cheap, short, and carries minimal context.
|
|
198
204
|
*/
|
|
199
|
-
const QUALITY_GATE_POLL_INTERVAL_MS = 3_000;
|
|
200
|
-
const QUALITY_GATE_MAX_POLL_MS = 15 * 60 * 1_000; // 15 minutes
|
|
201
205
|
export async function callQualityGate(category, message) {
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
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
|
-
}
|
|
206
|
+
return apiRequest("POST", mcpPath("quality-gate"), {
|
|
207
|
+
category,
|
|
208
|
+
message,
|
|
209
|
+
});
|
|
232
210
|
}
|
|
233
211
|
/**
|
|
234
212
|
* Orchestrator finalization — mandatory last action before exit.
|
|
@@ -250,4 +228,17 @@ export async function postProgress(progressMessage, phase) {
|
|
|
250
228
|
phase,
|
|
251
229
|
});
|
|
252
230
|
}
|
|
231
|
+
/**
|
|
232
|
+
* Fail-fast termination — agent calls this the moment anything deviates from the
|
|
233
|
+
* prompt's described behavior (missing tool, unexpected response, sub-agent not found,
|
|
234
|
+
* API error the prompt doesn't cover, etc.). Never use shell, tinker, or other creative
|
|
235
|
+
* workarounds — abort and let the operator diagnose.
|
|
236
|
+
*/
|
|
237
|
+
export async function abortDispatch(reason, details, phase) {
|
|
238
|
+
return apiRequest("POST", mcpPath("abort"), {
|
|
239
|
+
reason,
|
|
240
|
+
details,
|
|
241
|
+
phase,
|
|
242
|
+
});
|
|
243
|
+
}
|
|
253
244
|
export { SCHEMA_ID };
|
package/dist/index.js
CHANGED
|
@@ -52,6 +52,10 @@ const COMMON_TOOLS = [
|
|
|
52
52
|
"template_preview",
|
|
53
53
|
"template_preview_html",
|
|
54
54
|
"quality_gate_list",
|
|
55
|
+
// Fail-fast termination — always available regardless of role. The agent calls
|
|
56
|
+
// this the moment anything deviates from the prompt's described behavior instead
|
|
57
|
+
// of inventing creative workarounds via shell commands or source-code exploration.
|
|
58
|
+
"abort",
|
|
55
59
|
];
|
|
56
60
|
const ROLE_TOOLS = {
|
|
57
61
|
orchestrator: new Set([
|
|
@@ -226,6 +230,23 @@ if (shouldRegister("post_progress"))
|
|
|
226
230
|
const result = await api.postProgress(message, phase);
|
|
227
231
|
return jsonResult(result);
|
|
228
232
|
});
|
|
233
|
+
if (shouldRegister("abort"))
|
|
234
|
+
server.tool("abort", "FAIL-FAST TERMINATION. Call this the moment anything deviates from the prompt's described behavior: a required tool is missing, a tool returns an unexpected error, a sub-agent can't be invoked, an API call fails in a way the prompt doesn't cover, or anything else the prompt says should work is broken. Do NOT try to work around problems with shell commands, source-code exploration, or creative solutions. Abort, explain what failed, and exit immediately. After calling abort, your response ends — no further tool calls.", {
|
|
235
|
+
reason: z
|
|
236
|
+
.string()
|
|
237
|
+
.describe("Short description of what failed (one sentence). Example: 'mcp__schema__template_patch returned tool_not_found' or 'template-builder sub-agent is not available'."),
|
|
238
|
+
details: z
|
|
239
|
+
.string()
|
|
240
|
+
.optional()
|
|
241
|
+
.describe("Full error details, stack trace, tool response, or context that would help the operator diagnose the failure."),
|
|
242
|
+
phase: z
|
|
243
|
+
.string()
|
|
244
|
+
.optional()
|
|
245
|
+
.describe("Phase you were in when the failure occurred (e.g., 'planning', 'delegating', 'template_patch')."),
|
|
246
|
+
}, async ({ reason, details, phase }) => {
|
|
247
|
+
const result = await api.abortDispatch(reason, details, phase);
|
|
248
|
+
return jsonResult(result);
|
|
249
|
+
});
|
|
229
250
|
// ============================================================================
|
|
230
251
|
// Schema Tools
|
|
231
252
|
// ============================================================================
|
|
@@ -681,20 +702,18 @@ if (shouldRegister("quality_gate_submit_review"))
|
|
|
681
702
|
return jsonResult(result);
|
|
682
703
|
});
|
|
683
704
|
if (shouldRegister("quality_gate"))
|
|
684
|
-
server.tool("quality_gate", "
|
|
685
|
-
"BLOCKING —
|
|
686
|
-
"
|
|
687
|
-
"
|
|
688
|
-
"
|
|
705
|
+
server.tool("quality_gate", "Dispatch or poll the quality gate for a single category (schema, directive, or template). " +
|
|
706
|
+
"NON-BLOCKING — the call returns immediately. Response statuses: " +
|
|
707
|
+
"'passed' means all items in the category are green (safe to move on); " +
|
|
708
|
+
"'running' means a reviewer was dispatched (or one is already in flight) — do other " +
|
|
709
|
+
"productive work, then call this tool again later to check status; " +
|
|
689
710
|
"'failed' means items need fixes — read each item's `analysis`, apply fixes via " +
|
|
690
711
|
"mutation tools (which auto-invalidate the category), then call this tool again; " +
|
|
691
712
|
"'error' means the reviewer dispatch itself failed — surface the error to the user " +
|
|
692
|
-
"and stop (do NOT retry
|
|
693
|
-
"
|
|
694
|
-
"
|
|
695
|
-
"
|
|
696
|
-
"(e.g. schema + directive in parallel). Do NOT call this tool twice for the same " +
|
|
697
|
-
"category before the first call returns.", {
|
|
713
|
+
"via an annotation and stop on that category (do NOT retry). " +
|
|
714
|
+
"You may call this for multiple categories in parallel. The backend is idempotent — " +
|
|
715
|
+
"calling while a reviewer is running returns 'running' without launching a duplicate. " +
|
|
716
|
+
"When you have no other productive work, continue polling — each call is cheap.", {
|
|
698
717
|
category: z
|
|
699
718
|
.enum(["schema", "directive", "template"])
|
|
700
719
|
.describe("The quality gate category to check. Must be one of: schema, directive, template."),
|