@ambitresearch/genie 1.3.1
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/README.md +15 -0
- package/dist/auth/bearer.d.ts +49 -0
- package/dist/auth/bearer.d.ts.map +1 -0
- package/dist/auth/bearer.js +159 -0
- package/dist/auth/bearer.js.map +1 -0
- package/dist/auth/oauth/authorize.d.ts +19 -0
- package/dist/auth/oauth/authorize.d.ts.map +1 -0
- package/dist/auth/oauth/authorize.js +111 -0
- package/dist/auth/oauth/authorize.js.map +1 -0
- package/dist/auth/oauth/config.d.ts +10 -0
- package/dist/auth/oauth/config.d.ts.map +1 -0
- package/dist/auth/oauth/config.js +16 -0
- package/dist/auth/oauth/config.js.map +1 -0
- package/dist/auth/oauth/dcr.d.ts +15 -0
- package/dist/auth/oauth/dcr.d.ts.map +1 -0
- package/dist/auth/oauth/dcr.js +38 -0
- package/dist/auth/oauth/dcr.js.map +1 -0
- package/dist/auth/oauth/jwt.d.ts +13 -0
- package/dist/auth/oauth/jwt.d.ts.map +1 -0
- package/dist/auth/oauth/jwt.js +46 -0
- package/dist/auth/oauth/jwt.js.map +1 -0
- package/dist/auth/oauth/metadata.d.ts +9 -0
- package/dist/auth/oauth/metadata.d.ts.map +1 -0
- package/dist/auth/oauth/metadata.js +19 -0
- package/dist/auth/oauth/metadata.js.map +1 -0
- package/dist/auth/oauth/router.d.ts +32 -0
- package/dist/auth/oauth/router.d.ts.map +1 -0
- package/dist/auth/oauth/router.js +159 -0
- package/dist/auth/oauth/router.js.map +1 -0
- package/dist/auth/oauth/store.d.ts +55 -0
- package/dist/auth/oauth/store.d.ts.map +1 -0
- package/dist/auth/oauth/store.js +63 -0
- package/dist/auth/oauth/store.js.map +1 -0
- package/dist/auth/oauth/token.d.ts +21 -0
- package/dist/auth/oauth/token.d.ts.map +1 -0
- package/dist/auth/oauth/token.js +77 -0
- package/dist/auth/oauth/token.js.map +1 -0
- package/dist/auth/oidc/group-policy.d.ts +43 -0
- package/dist/auth/oidc/group-policy.d.ts.map +1 -0
- package/dist/auth/oidc/group-policy.js +54 -0
- package/dist/auth/oidc/group-policy.js.map +1 -0
- package/dist/auth/oidc/verifier.d.ts +42 -0
- package/dist/auth/oidc/verifier.d.ts.map +1 -0
- package/dist/auth/oidc/verifier.js +145 -0
- package/dist/auth/oidc/verifier.js.map +1 -0
- package/dist/auth/token-cli.d.ts +9 -0
- package/dist/auth/token-cli.d.ts.map +1 -0
- package/dist/auth/token-cli.js +98 -0
- package/dist/auth/token-cli.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +149 -0
- package/dist/cli.js.map +1 -0
- package/dist/config/redact.d.ts +20 -0
- package/dist/config/redact.d.ts.map +1 -0
- package/dist/config/redact.js +77 -0
- package/dist/config/redact.js.map +1 -0
- package/dist/config/secrets.d.ts +100 -0
- package/dist/config/secrets.d.ts.map +1 -0
- package/dist/config/secrets.js +130 -0
- package/dist/config/secrets.js.map +1 -0
- package/dist/framework/html.d.ts +103 -0
- package/dist/framework/html.d.ts.map +1 -0
- package/dist/framework/html.js +271 -0
- package/dist/framework/html.js.map +1 -0
- package/dist/framework/interface.d.ts +130 -0
- package/dist/framework/interface.d.ts.map +1 -0
- package/dist/framework/interface.js +112 -0
- package/dist/framework/interface.js.map +1 -0
- package/dist/framework/react.d.ts +133 -0
- package/dist/framework/react.d.ts.map +1 -0
- package/dist/framework/react.js +243 -0
- package/dist/framework/react.js.map +1 -0
- package/dist/framework/vue.d.ts +99 -0
- package/dist/framework/vue.d.ts.map +1 -0
- package/dist/framework/vue.js +375 -0
- package/dist/framework/vue.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/llm/client.d.ts +81 -0
- package/dist/llm/client.d.ts.map +1 -0
- package/dist/llm/client.js +141 -0
- package/dist/llm/client.js.map +1 -0
- package/dist/llm/component-response.d.ts +111 -0
- package/dist/llm/component-response.d.ts.map +1 -0
- package/dist/llm/component-response.js +167 -0
- package/dist/llm/component-response.js.map +1 -0
- package/dist/llm/generated-files.d.ts +10 -0
- package/dist/llm/generated-files.d.ts.map +1 -0
- package/dist/llm/generated-files.js +26 -0
- package/dist/llm/generated-files.js.map +1 -0
- package/dist/llm/prompts/CHANGELOG.md +70 -0
- package/dist/llm/prompts/generate-component.system.md +99 -0
- package/dist/llm/prompts/refine-component.system.md +112 -0
- package/dist/llm/prompts.d.ts +66 -0
- package/dist/llm/prompts.d.ts.map +1 -0
- package/dist/llm/prompts.js +78 -0
- package/dist/llm/prompts.js.map +1 -0
- package/dist/llm/retry.d.ts +183 -0
- package/dist/llm/retry.d.ts.map +1 -0
- package/dist/llm/retry.js +475 -0
- package/dist/llm/retry.js.map +1 -0
- package/dist/llm/schema.d.ts +129 -0
- package/dist/llm/schema.d.ts.map +1 -0
- package/dist/llm/schema.js +147 -0
- package/dist/llm/schema.js.map +1 -0
- package/dist/llm/validate.d.ts +107 -0
- package/dist/llm/validate.d.ts.map +1 -0
- package/dist/llm/validate.js +174 -0
- package/dist/llm/validate.js.map +1 -0
- package/dist/manifest/compiler.d.ts +112 -0
- package/dist/manifest/compiler.d.ts.map +1 -0
- package/dist/manifest/compiler.js +306 -0
- package/dist/manifest/compiler.js.map +1 -0
- package/dist/manifest/ensure.d.ts +46 -0
- package/dist/manifest/ensure.d.ts.map +1 -0
- package/dist/manifest/ensure.js +49 -0
- package/dist/manifest/ensure.js.map +1 -0
- package/dist/manifest/index.d.ts +13 -0
- package/dist/manifest/index.d.ts.map +1 -0
- package/dist/manifest/index.js +13 -0
- package/dist/manifest/index.js.map +1 -0
- package/dist/middleware/plan-guard.d.ts +167 -0
- package/dist/middleware/plan-guard.d.ts.map +1 -0
- package/dist/middleware/plan-guard.js +190 -0
- package/dist/middleware/plan-guard.js.map +1 -0
- package/dist/plans/index.d.ts +71 -0
- package/dist/plans/index.d.ts.map +1 -0
- package/dist/plans/index.js +252 -0
- package/dist/plans/index.js.map +1 -0
- package/dist/schemas/component.schema.json +114 -0
- package/dist/server.d.ts +96 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +258 -0
- package/dist/server.js.map +1 -0
- package/dist/store/empty-manifest.d.ts +58 -0
- package/dist/store/empty-manifest.d.ts.map +1 -0
- package/dist/store/empty-manifest.js +59 -0
- package/dist/store/empty-manifest.js.map +1 -0
- package/dist/store/git-host.d.ts +120 -0
- package/dist/store/git-host.d.ts.map +1 -0
- package/dist/store/git-host.js +796 -0
- package/dist/store/git-host.js.map +1 -0
- package/dist/store/index.d.ts +5 -0
- package/dist/store/index.d.ts.map +1 -0
- package/dist/store/index.js +4 -0
- package/dist/store/index.js.map +1 -0
- package/dist/store/interface.d.ts +322 -0
- package/dist/store/interface.d.ts.map +1 -0
- package/dist/store/interface.js +100 -0
- package/dist/store/interface.js.map +1 -0
- package/dist/store/kit-files.d.ts +88 -0
- package/dist/store/kit-files.d.ts.map +1 -0
- package/dist/store/kit-files.js +199 -0
- package/dist/store/kit-files.js.map +1 -0
- package/dist/store/local.d.ts +70 -0
- package/dist/store/local.d.ts.map +1 -0
- package/dist/store/local.js +651 -0
- package/dist/store/local.js.map +1 -0
- package/dist/store/manifest.d.ts +44 -0
- package/dist/store/manifest.d.ts.map +1 -0
- package/dist/store/manifest.js +116 -0
- package/dist/store/manifest.js.map +1 -0
- package/dist/store/viewer-assets.d.ts +20 -0
- package/dist/store/viewer-assets.d.ts.map +1 -0
- package/dist/store/viewer-assets.js +118 -0
- package/dist/store/viewer-assets.js.map +1 -0
- package/dist/sync/anchor.d.ts +125 -0
- package/dist/sync/anchor.d.ts.map +1 -0
- package/dist/sync/anchor.js +210 -0
- package/dist/sync/anchor.js.map +1 -0
- package/dist/sync/index.d.ts +15 -0
- package/dist/sync/index.d.ts.map +1 -0
- package/dist/sync/index.js +15 -0
- package/dist/sync/index.js.map +1 -0
- package/dist/sync/orchestrator.d.ts +160 -0
- package/dist/sync/orchestrator.d.ts.map +1 -0
- package/dist/sync/orchestrator.js +288 -0
- package/dist/sync/orchestrator.js.map +1 -0
- package/dist/tools/bind_kit.d.ts +29 -0
- package/dist/tools/bind_kit.d.ts.map +1 -0
- package/dist/tools/bind_kit.js +70 -0
- package/dist/tools/bind_kit.js.map +1 -0
- package/dist/tools/conjure.d.ts +141 -0
- package/dist/tools/conjure.d.ts.map +1 -0
- package/dist/tools/conjure.js +655 -0
- package/dist/tools/conjure.js.map +1 -0
- package/dist/tools/conjure_screen.d.ts +174 -0
- package/dist/tools/conjure_screen.d.ts.map +1 -0
- package/dist/tools/conjure_screen.js +458 -0
- package/dist/tools/conjure_screen.js.map +1 -0
- package/dist/tools/create_kit.d.ts +32 -0
- package/dist/tools/create_kit.d.ts.map +1 -0
- package/dist/tools/create_kit.js +131 -0
- package/dist/tools/create_kit.js.map +1 -0
- package/dist/tools/create_project.d.ts +267 -0
- package/dist/tools/create_project.d.ts.map +1 -0
- package/dist/tools/create_project.js +546 -0
- package/dist/tools/create_project.js.map +1 -0
- package/dist/tools/delete_files.d.ts +93 -0
- package/dist/tools/delete_files.d.ts.map +1 -0
- package/dist/tools/delete_files.js +276 -0
- package/dist/tools/delete_files.js.map +1 -0
- package/dist/tools/delete_project.d.ts +43 -0
- package/dist/tools/delete_project.d.ts.map +1 -0
- package/dist/tools/delete_project.js +118 -0
- package/dist/tools/delete_project.js.map +1 -0
- package/dist/tools/get_kit.d.ts +28 -0
- package/dist/tools/get_kit.d.ts.map +1 -0
- package/dist/tools/get_kit.js +95 -0
- package/dist/tools/get_kit.js.map +1 -0
- package/dist/tools/get_project.d.ts +37 -0
- package/dist/tools/get_project.d.ts.map +1 -0
- package/dist/tools/get_project.js +71 -0
- package/dist/tools/get_project.js.map +1 -0
- package/dist/tools/list_components.d.ts +42 -0
- package/dist/tools/list_components.d.ts.map +1 -0
- package/dist/tools/list_components.js +125 -0
- package/dist/tools/list_components.js.map +1 -0
- package/dist/tools/list_files.d.ts +32 -0
- package/dist/tools/list_files.d.ts.map +1 -0
- package/dist/tools/list_files.js +109 -0
- package/dist/tools/list_files.js.map +1 -0
- package/dist/tools/list_kits.d.ts +14 -0
- package/dist/tools/list_kits.d.ts.map +1 -0
- package/dist/tools/list_kits.js +41 -0
- package/dist/tools/list_kits.js.map +1 -0
- package/dist/tools/list_projects.d.ts +23 -0
- package/dist/tools/list_projects.d.ts.map +1 -0
- package/dist/tools/list_projects.js +66 -0
- package/dist/tools/list_projects.js.map +1 -0
- package/dist/tools/plan.d.ts +16 -0
- package/dist/tools/plan.d.ts.map +1 -0
- package/dist/tools/plan.js +146 -0
- package/dist/tools/plan.js.map +1 -0
- package/dist/tools/preview.d.ts +289 -0
- package/dist/tools/preview.d.ts.map +1 -0
- package/dist/tools/preview.js +672 -0
- package/dist/tools/preview.js.map +1 -0
- package/dist/tools/read_file.d.ts +40 -0
- package/dist/tools/read_file.d.ts.map +1 -0
- package/dist/tools/read_file.js +114 -0
- package/dist/tools/read_file.js.map +1 -0
- package/dist/tools/refine.d.ts +220 -0
- package/dist/tools/refine.d.ts.map +1 -0
- package/dist/tools/refine.js +501 -0
- package/dist/tools/refine.js.map +1 -0
- package/dist/tools/validate.d.ts +74 -0
- package/dist/tools/validate.d.ts.map +1 -0
- package/dist/tools/validate.js +224 -0
- package/dist/tools/validate.js.map +1 -0
- package/dist/tools/write_files.d.ts +158 -0
- package/dist/tools/write_files.d.ts.map +1 -0
- package/dist/tools/write_files.js +541 -0
- package/dist/tools/write_files.js.map +1 -0
- package/dist/transport.d.ts +77 -0
- package/dist/transport.d.ts.map +1 -0
- package/dist/transport.js +448 -0
- package/dist/transport.js.map +1 -0
- package/dist/ui/card-asset-broker.d.ts +42 -0
- package/dist/ui/card-asset-broker.d.ts.map +1 -0
- package/dist/ui/card-asset-broker.js +479 -0
- package/dist/ui/card-asset-broker.js.map +1 -0
- package/dist/ui/grid-resource.d.ts +252 -0
- package/dist/ui/grid-resource.d.ts.map +1 -0
- package/dist/ui/grid-resource.js +680 -0
- package/dist/ui/grid-resource.js.map +1 -0
- package/dist/ui/viewer-static/index.html +95 -0
- package/dist/ui/viewer-static/viewer.css +451 -0
- package/dist/ui/viewer-static/viewer.js +1405 -0
- package/dist/validate/full-scan.d.ts +87 -0
- package/dist/validate/full-scan.d.ts.map +1 -0
- package/dist/validate/full-scan.js +299 -0
- package/dist/validate/full-scan.js.map +1 -0
- package/dist/validate/index.d.ts +15 -0
- package/dist/validate/index.d.ts.map +1 -0
- package/dist/validate/index.js +18 -0
- package/dist/validate/index.js.map +1 -0
- package/dist/validate/marker.d.ts +89 -0
- package/dist/validate/marker.d.ts.map +1 -0
- package/dist/validate/marker.js +87 -0
- package/dist/validate/marker.js.map +1 -0
- package/dist/validate/phash.d.ts +135 -0
- package/dist/validate/phash.d.ts.map +1 -0
- package/dist/validate/phash.js +307 -0
- package/dist/validate/phash.js.map +1 -0
- package/dist/validate/render.d.ts +38 -0
- package/dist/validate/render.d.ts.map +1 -0
- package/dist/validate/render.js +155 -0
- package/dist/validate/render.js.map +1 -0
- package/dist/watch/index.d.ts +12 -0
- package/dist/watch/index.d.ts.map +1 -0
- package/dist/watch/index.js +12 -0
- package/dist/watch/index.js.map +1 -0
- package/dist/watch/watcher.d.ts +65 -0
- package/dist/watch/watcher.d.ts.map +1 -0
- package/dist/watch/watcher.js +238 -0
- package/dist/watch/watcher.js.map +1 -0
- package/package.json +70 -0
|
@@ -0,0 +1,501 @@
|
|
|
1
|
+
import { createTwoFilesPatch } from "diff";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import {} from "../llm/schema.js";
|
|
4
|
+
import { REFINE_COMPONENT_SYSTEM_PROMPT_FILE, loadPrompt, } from "../llm/prompts.js";
|
|
5
|
+
// The shared request/validate/retry harness (M2-03/M2-04) — the same Ajv
|
|
6
|
+
// validate, response_format envelope, retry-feedback wording, and two-attempt
|
|
7
|
+
// loop `conjure` uses (AC6).
|
|
8
|
+
import { appendRetryFeedback, logStderr, runComponentGeneration, } from "../llm/component-response.js";
|
|
9
|
+
// Value import (not type-only): `retry.ts` has no import-time side effects —
|
|
10
|
+
// unlike `client.ts`, it never touches `GENIE_LLM_*` env or constructs
|
|
11
|
+
// anything eagerly at module load — so wrapping `defaultChatCompletion`
|
|
12
|
+
// below in `withRetry` is safe to do statically (same reasoning as
|
|
13
|
+
// `conjure.ts`; DRO-253 / DRO-618: `refine` shares the exact same gap
|
|
14
|
+
// conjure had — `withRetry` existed but no production call site applied it).
|
|
15
|
+
import { withRetry } from "../llm/retry.js";
|
|
16
|
+
import { normalizeGeneratedFiles, validateGeneratedBinaryContent, } from "../llm/generated-files.js";
|
|
17
|
+
import { KIT_ID_PATTERN } from "./get_kit.js";
|
|
18
|
+
export const REFINE_TOOL_NAME = "mcp__genie__refine";
|
|
19
|
+
/** Default model routing alias — the same one `conjure` uses (M2-05). Resolved
|
|
20
|
+
* to a concrete provider model by the configured endpoint/gateway. Defined
|
|
21
|
+
* locally to keep `refine` decoupled from `conjure`'s module. */
|
|
22
|
+
export const DEFAULT_MODEL = "design-default";
|
|
23
|
+
/** PascalCase component-name shape — identical to `COMPONENT_SCHEMA`'s
|
|
24
|
+
* `componentName` pattern, so an id `refine` accepts is one `conjure` could have
|
|
25
|
+
* produced. */
|
|
26
|
+
export const COMPONENT_NAME_PATTERN = /^[A-Z][A-Za-z0-9]{1,63}$/;
|
|
27
|
+
/** Directory prefix every kit component's files live under. */
|
|
28
|
+
const COMPONENTS_ROOT = "components";
|
|
29
|
+
// ── Input schema (AC2) ────────────────────────────────────────────────────────
|
|
30
|
+
//
|
|
31
|
+
// { kitId, componentName, instruction, region?: { x, y, w, h }, model? }
|
|
32
|
+
// (research §3.1). `region` bounds mirror COMPONENT_SCHEMA's viewport limits
|
|
33
|
+
// (≤4096) so a canvas selection can't request an absurd crop; `w`/`h` are ≥1
|
|
34
|
+
// (a zero-area rect is not a selection). `model` defaults like `conjure`.
|
|
35
|
+
const regionSchema = z
|
|
36
|
+
.object({
|
|
37
|
+
x: z.number().int().min(0).max(4096),
|
|
38
|
+
y: z.number().int().min(0).max(4096),
|
|
39
|
+
w: z.number().int().min(1).max(4096),
|
|
40
|
+
h: z.number().int().min(1).max(4096),
|
|
41
|
+
})
|
|
42
|
+
.strict();
|
|
43
|
+
const refineInputShape = {
|
|
44
|
+
kitId: z
|
|
45
|
+
.string()
|
|
46
|
+
.regex(KIT_ID_PATTERN, "kitId must be a 3-64 character slug of lowercase letters, numbers, and hyphens."),
|
|
47
|
+
componentName: z
|
|
48
|
+
.string()
|
|
49
|
+
.regex(COMPONENT_NAME_PATTERN, "componentName must be PascalCase, 2-64 chars (e.g. Button)."),
|
|
50
|
+
instruction: z.string().min(1).max(8192),
|
|
51
|
+
region: regionSchema.optional(),
|
|
52
|
+
model: z.string().min(1).max(128).default(DEFAULT_MODEL),
|
|
53
|
+
};
|
|
54
|
+
const refineArgsSchema = z.object(refineInputShape).strict();
|
|
55
|
+
/** Typed failure surfaced to the tool boundary (mapped to an MCP error result).
|
|
56
|
+
* `ERR_COMPONENT_NOT_FOUND` — no files for `componentName` in the kit (or the
|
|
57
|
+
* kit itself is absent); `ERR_LLM_OUTPUT_INVALID` — the model did not return a
|
|
58
|
+
* schema-valid component after the retry (same code `conjure` throws). */
|
|
59
|
+
export class RefineError extends Error {
|
|
60
|
+
code;
|
|
61
|
+
details;
|
|
62
|
+
constructor(code, message, details) {
|
|
63
|
+
super(message);
|
|
64
|
+
this.code = code;
|
|
65
|
+
this.details = details;
|
|
66
|
+
this.name = "RefineError";
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
// ── Default (production) chat impl: lazy client import (same as conjure) ───────
|
|
70
|
+
/**
|
|
71
|
+
* Default `chat` seam: dynamically imports the M2-01 client on first call, so
|
|
72
|
+
* building the server never eagerly triggers `MissingLLMConfigError` (see module
|
|
73
|
+
* header). A real `refine` call in a properly-configured deployment resolves
|
|
74
|
+
* this to `withRetry(createChatCompletion)` (M2-06, DRO-253) — every
|
|
75
|
+
* production LLM call this tool makes is retry/backoff-wrapped by default,
|
|
76
|
+
* same as `conjure`; callers (and tests, via `deps.chat`) never need to
|
|
77
|
+
* remember to apply the wrapper themselves.
|
|
78
|
+
*
|
|
79
|
+
* `withRetry` is called fresh on every invocation rather than wrapped once at
|
|
80
|
+
* module scope: the module-scope `createChatCompletion` binding doesn't exist
|
|
81
|
+
* until the dynamic import resolves, and re-wrapping a plain async function
|
|
82
|
+
* is cheap (no state beyond reading `GENIE_LLM_RETRY_MAX` from `process.env`
|
|
83
|
+
* per call, matching `conjure.ts`'s identical seam).
|
|
84
|
+
*/
|
|
85
|
+
const defaultChatCompletion = async (input) => {
|
|
86
|
+
const { createChatCompletion } = await import("../llm/client.js");
|
|
87
|
+
return withRetry(createChatCompletion)(input);
|
|
88
|
+
};
|
|
89
|
+
/** Load Playwright at runtime, or `null` if it is not installed. The non-literal
|
|
90
|
+
* specifier keeps `tsc` from resolving the (non-dependency) module at build. */
|
|
91
|
+
async function importPlaywright() {
|
|
92
|
+
const specifier = "playwright";
|
|
93
|
+
try {
|
|
94
|
+
return (await import(specifier));
|
|
95
|
+
}
|
|
96
|
+
catch (error) {
|
|
97
|
+
logStderr({
|
|
98
|
+
event: "refine.region.unavailable",
|
|
99
|
+
reason: "playwright-not-installed",
|
|
100
|
+
error: String(error),
|
|
101
|
+
});
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Default cropper (AC7): render the preview HTML in headless Chromium and
|
|
107
|
+
* screenshot the region rect, returning it as a PNG data URL for vision input.
|
|
108
|
+
* Degrades gracefully — if Playwright is absent, or launch/render/screenshot
|
|
109
|
+
* fails, it logs and returns `{ dataUrl: null }` so `refine` continues without
|
|
110
|
+
* the image rather than failing the whole call over an optional enhancement.
|
|
111
|
+
*/
|
|
112
|
+
export const defaultRegionCropper = {
|
|
113
|
+
async crop({ html, region, viewport }) {
|
|
114
|
+
const pw = await importPlaywright();
|
|
115
|
+
if (!pw)
|
|
116
|
+
return { dataUrl: null };
|
|
117
|
+
let browser;
|
|
118
|
+
try {
|
|
119
|
+
// `--no-sandbox` so it runs in restricted CI/container environments.
|
|
120
|
+
browser = await pw.chromium.launch({ args: ["--no-sandbox"] });
|
|
121
|
+
const page = await browser.newPage({ viewport });
|
|
122
|
+
// `load` (not `networkidle`): an embedded-CSP preview has no network to go
|
|
123
|
+
// idle on (`default-src 'none'`), so waiting for idle would just add the
|
|
124
|
+
// default timeout to every crop.
|
|
125
|
+
await page.setContent(html, { waitUntil: "load" });
|
|
126
|
+
const buf = await page.screenshot({
|
|
127
|
+
clip: { x: region.x, y: region.y, width: region.w, height: region.h },
|
|
128
|
+
});
|
|
129
|
+
return { dataUrl: `data:image/png;base64,${buf.toString("base64")}` };
|
|
130
|
+
}
|
|
131
|
+
catch (error) {
|
|
132
|
+
logStderr({ event: "refine.region.error", error: String(error) });
|
|
133
|
+
return { dataUrl: null };
|
|
134
|
+
}
|
|
135
|
+
finally {
|
|
136
|
+
if (browser)
|
|
137
|
+
await browser.close();
|
|
138
|
+
}
|
|
139
|
+
},
|
|
140
|
+
};
|
|
141
|
+
// ── File discovery (AC3) ──────────────────────────────────────────────────────
|
|
142
|
+
/**
|
|
143
|
+
* Split a kit-relative path into its `components/<group>/<Name>/…` parts, or
|
|
144
|
+
* `null` if it is not a component file. Used to find every file belonging to
|
|
145
|
+
* `componentName` and to read its group off the first match.
|
|
146
|
+
*/
|
|
147
|
+
function parseComponentPath(path) {
|
|
148
|
+
const parts = path.split("/");
|
|
149
|
+
if (parts.length < 4 || parts[0] !== COMPONENTS_ROOT)
|
|
150
|
+
return null;
|
|
151
|
+
return { group: parts[1], name: parts[2], rest: parts.slice(3).join("/") };
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Load every file of `componentName` from the kit (AC3): `listFiles` to discover
|
|
155
|
+
* the set, then `readFile` per file (one call each, as the AC specifies). The
|
|
156
|
+
* group is derived from the matched paths — a component's directory names it.
|
|
157
|
+
* Throws `RefineError("ERR_COMPONENT_NOT_FOUND")` when nothing matches (a missing
|
|
158
|
+
* kit surfaces the same way: no files, nothing to refine).
|
|
159
|
+
*/
|
|
160
|
+
async function loadComponentFiles(kitStore, kitId, componentName) {
|
|
161
|
+
let entries;
|
|
162
|
+
try {
|
|
163
|
+
entries = await kitStore.listFiles(kitId);
|
|
164
|
+
}
|
|
165
|
+
catch (error) {
|
|
166
|
+
// A missing kit (NotFoundError) is just "nothing to refine" — one clear code.
|
|
167
|
+
throw new RefineError("ERR_COMPONENT_NOT_FOUND", `Could not load component "${componentName}" from kit "${kitId}": ${String(error?.message ?? error)}`, { kitId, componentName });
|
|
168
|
+
}
|
|
169
|
+
// Match files whose 3rd path segment is exactly the component name. Sort by
|
|
170
|
+
// path so group derivation and file order are deterministic.
|
|
171
|
+
const matches = entries
|
|
172
|
+
.map((e) => ({ path: e.path, parsed: parseComponentPath(e.path) }))
|
|
173
|
+
.filter((m) => m.parsed !== null && m.parsed.name === componentName)
|
|
174
|
+
.sort((a, b) => a.path.localeCompare(b.path));
|
|
175
|
+
if (matches.length === 0) {
|
|
176
|
+
throw new RefineError("ERR_COMPONENT_NOT_FOUND", `No component named "${componentName}" was found in kit "${kitId}". ` +
|
|
177
|
+
`Expected files under ${COMPONENTS_ROOT}/<group>/${componentName}/.`, { kitId, componentName });
|
|
178
|
+
}
|
|
179
|
+
// A component lives in ONE group; take it from the first match and keep only
|
|
180
|
+
// that group's files (guards the pathological case of two same-named dirs).
|
|
181
|
+
const group = matches[0].parsed.group;
|
|
182
|
+
const inGroup = matches.filter((m) => m.parsed.group === group);
|
|
183
|
+
const files = await Promise.all(inGroup.map(async ({ path }) => {
|
|
184
|
+
const read = await kitStore.readFile(kitId, path);
|
|
185
|
+
return { path, content: read.content, encoding: read.encoding, mimeType: read.mimeType };
|
|
186
|
+
}));
|
|
187
|
+
return { group, files };
|
|
188
|
+
}
|
|
189
|
+
// ── Preview + viewport helpers (AC4/AC7) ──────────────────────────────────────
|
|
190
|
+
/** The `<Name>.html` preview file among the loaded set, if present. */
|
|
191
|
+
function findPreview(files, componentName) {
|
|
192
|
+
const suffix = `/${componentName}/${componentName}.html`;
|
|
193
|
+
return files.find((f) => f.path.endsWith(suffix));
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Choose a render viewport for the crop that (a) is at least the component's
|
|
197
|
+
* natural preview size (read from `meta.json`'s `viewport` when available, so the
|
|
198
|
+
* layout matches how the card really renders) and (b) is big enough to contain
|
|
199
|
+
* the requested region. Falls back to a sensible default when there is no
|
|
200
|
+
* parseable meta.
|
|
201
|
+
*/
|
|
202
|
+
export function deriveRenderViewport(files, region) {
|
|
203
|
+
const DEFAULT = { width: 400, height: 300 };
|
|
204
|
+
const meta = files.find((f) => f.path.endsWith("/meta.json"));
|
|
205
|
+
let base = DEFAULT;
|
|
206
|
+
if (meta) {
|
|
207
|
+
try {
|
|
208
|
+
const parsed = JSON.parse(meta.content);
|
|
209
|
+
const w = parsed.viewport?.width;
|
|
210
|
+
const h = parsed.viewport?.height;
|
|
211
|
+
if (typeof w === "number" && typeof h === "number" && w > 0 && h > 0) {
|
|
212
|
+
base = { width: w, height: h };
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
catch {
|
|
216
|
+
// Non-JSON / unexpected meta → keep the default. Best-effort only.
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
return {
|
|
220
|
+
width: Math.max(base.width, region.x + region.w),
|
|
221
|
+
height: Math.max(base.height, region.y + region.h),
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
// ── Prompt / message assembly (AC4) ───────────────────────────────────────────
|
|
225
|
+
/** True for files we inline verbatim into the prompt. Binary (base64) files are
|
|
226
|
+
* summarized rather than dumped as base64 into the context. */
|
|
227
|
+
function isTextFile(file) {
|
|
228
|
+
return file.encoding !== "base64";
|
|
229
|
+
}
|
|
230
|
+
/** Build the natural-language user instruction block (everything except the
|
|
231
|
+
* optional vision crop image, attached separately). */
|
|
232
|
+
function buildUserText(args, group, files, cropAttached) {
|
|
233
|
+
const lines = [
|
|
234
|
+
"## Instruction",
|
|
235
|
+
args.instruction,
|
|
236
|
+
"",
|
|
237
|
+
"## Component",
|
|
238
|
+
`Name: ${args.componentName}`,
|
|
239
|
+
`Group: ${group}`,
|
|
240
|
+
];
|
|
241
|
+
if (args.region) {
|
|
242
|
+
const { x, y, w, h } = args.region;
|
|
243
|
+
lines.push("", "## Region (canvas selection)", `The instruction targets this rectangle of the preview, in the preview's own ` +
|
|
244
|
+
`pixel coordinates: x=${x}, y=${y}, width=${w}, height=${h}.`);
|
|
245
|
+
lines.push(cropAttached
|
|
246
|
+
? "A cropped screenshot of that region is attached as a reference image — " +
|
|
247
|
+
"focus your edit on the element(s) it shows and leave the rest unchanged."
|
|
248
|
+
: "(A rendered crop of that region could not be produced; identify which " +
|
|
249
|
+
"element sits at those coordinates from the preview markup below.)");
|
|
250
|
+
}
|
|
251
|
+
lines.push("", "## Current files", "Apply only the instruction. Return every file below (updated where the edit " +
|
|
252
|
+
"touches it, unchanged otherwise); do not rename the component or drop files.");
|
|
253
|
+
for (const file of files) {
|
|
254
|
+
lines.push("", `### File: ${file.path} (${file.mimeType})`);
|
|
255
|
+
lines.push(isTextFile(file) ? file.content : `[binary file, ${file.encoding} — omitted]`);
|
|
256
|
+
}
|
|
257
|
+
return lines.join("\n");
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* Assemble the messages for one attempt (AC4). System prompt is message 0; the
|
|
261
|
+
* user message carries the instruction + current files, and — when a region crop
|
|
262
|
+
* was produced — becomes a content-parts array with a vision `image_url` part
|
|
263
|
+
* (the same shape `conjure` uses for its reference image). `retry` appends the
|
|
264
|
+
* shared validation-feedback block on the single retry (AC6).
|
|
265
|
+
*/
|
|
266
|
+
function buildMessages(systemPrompt, args, group, files, cropDataUrl, retry) {
|
|
267
|
+
let userText = buildUserText(args, group, files, cropDataUrl !== null);
|
|
268
|
+
if (retry)
|
|
269
|
+
userText = appendRetryFeedback(userText, retry);
|
|
270
|
+
const userContent = cropDataUrl
|
|
271
|
+
? [
|
|
272
|
+
{ type: "text", text: userText },
|
|
273
|
+
{ type: "image_url", image_url: { url: cropDataUrl } },
|
|
274
|
+
]
|
|
275
|
+
: userText;
|
|
276
|
+
return [
|
|
277
|
+
{ role: "system", content: systemPrompt },
|
|
278
|
+
{ role: "user", content: userContent },
|
|
279
|
+
];
|
|
280
|
+
}
|
|
281
|
+
// ── Unified diff (AC5) ────────────────────────────────────────────────────────
|
|
282
|
+
/**
|
|
283
|
+
* Build a git-style unified diff from the original file set to the updated one,
|
|
284
|
+
* matched by path. Only CHANGED files contribute a hunk (unchanged files are
|
|
285
|
+
* omitted so the diff shows exactly what the refinement did); added/removed
|
|
286
|
+
* files diff against `/dev/null`. Informational only — `files` is authoritative.
|
|
287
|
+
*/
|
|
288
|
+
export function buildUnifiedDiff(originals, updated) {
|
|
289
|
+
const paths = new Set([...originals.keys(), ...updated.keys()]);
|
|
290
|
+
const sorted = [...paths].sort((a, b) => a.localeCompare(b));
|
|
291
|
+
const parts = [];
|
|
292
|
+
for (const path of sorted) {
|
|
293
|
+
const before = originals.get(path) ?? "";
|
|
294
|
+
const after = updated.get(path) ?? "";
|
|
295
|
+
if (before === after)
|
|
296
|
+
continue;
|
|
297
|
+
parts.push(createTwoFilesPatch(originals.has(path) ? `a/${path}` : "/dev/null", updated.has(path) ? `b/${path}` : "/dev/null", before, after));
|
|
298
|
+
}
|
|
299
|
+
return parts.join("\n");
|
|
300
|
+
}
|
|
301
|
+
// ── Core ──────────────────────────────────────────────────────────────────────
|
|
302
|
+
/**
|
|
303
|
+
* Refine one existing component. Flow: load current files (AC3) → optionally
|
|
304
|
+
* render a region crop (AC4/AC7) → run the shared request/validate/retry loop
|
|
305
|
+
* with the diff-mode prompt (AC6) → compute the unified diff (AC5) → return
|
|
306
|
+
* `{ diff, files, … }` and log a per-call line (AC8).
|
|
307
|
+
*/
|
|
308
|
+
export async function refine(deps, args) {
|
|
309
|
+
const parsed = refineArgsSchema.parse(args);
|
|
310
|
+
const chat = deps.chat ?? defaultChatCompletion;
|
|
311
|
+
const cropper = deps.cropper ?? defaultRegionCropper;
|
|
312
|
+
const systemPrompt = (deps.loadSystemPrompt ?? (() => loadPrompt(REFINE_COMPONENT_SYSTEM_PROMPT_FILE)))();
|
|
313
|
+
const startedAt = performance.now();
|
|
314
|
+
const hasRegion = parsed.region !== undefined;
|
|
315
|
+
// AC3 — load the component's current files from the kit.
|
|
316
|
+
const { group, files: originalFiles } = await loadComponentFiles(deps.kitStore, parsed.kitId, parsed.componentName);
|
|
317
|
+
const originalBinaryPaths = new Set(originalFiles.filter((file) => !isTextFile(file)).map((file) => file.path));
|
|
318
|
+
// AC4/AC7 — if a region was given, try to render a crop of it for vision input.
|
|
319
|
+
let cropDataUrl = null;
|
|
320
|
+
if (parsed.region) {
|
|
321
|
+
const preview = findPreview(originalFiles, parsed.componentName);
|
|
322
|
+
if (preview && isTextFile(preview)) {
|
|
323
|
+
const viewport = deriveRenderViewport(originalFiles, parsed.region);
|
|
324
|
+
const { dataUrl } = await cropper.crop({
|
|
325
|
+
html: preview.content,
|
|
326
|
+
region: parsed.region,
|
|
327
|
+
viewport,
|
|
328
|
+
});
|
|
329
|
+
cropDataUrl = dataUrl;
|
|
330
|
+
}
|
|
331
|
+
else {
|
|
332
|
+
// No preview to render — the coordinates still reach the prompt as text.
|
|
333
|
+
logStderr({
|
|
334
|
+
event: "refine.region.no_preview",
|
|
335
|
+
componentName: parsed.componentName,
|
|
336
|
+
kitId: parsed.kitId,
|
|
337
|
+
});
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
// AC6 — shared request/validate/retry-once loop (same as conjure).
|
|
341
|
+
const { outcome, usage, attempts } = await runComponentGeneration({
|
|
342
|
+
chat,
|
|
343
|
+
model: parsed.model,
|
|
344
|
+
validateGeneratedComponent: (component) => validateGeneratedBinaryContent(component, originalBinaryPaths),
|
|
345
|
+
buildMessages: (retry) => buildMessages(systemPrompt.text, parsed, group, originalFiles, cropDataUrl, retry),
|
|
346
|
+
});
|
|
347
|
+
const latencyMs = Math.round(performance.now() - startedAt);
|
|
348
|
+
if (!outcome.ok) {
|
|
349
|
+
logStderr({
|
|
350
|
+
event: "refine",
|
|
351
|
+
ok: false,
|
|
352
|
+
componentName: parsed.componentName,
|
|
353
|
+
hasRegion,
|
|
354
|
+
model: parsed.model,
|
|
355
|
+
promptTokens: usage.promptTokens,
|
|
356
|
+
completionTokens: usage.completionTokens,
|
|
357
|
+
latencyMs,
|
|
358
|
+
promptVersion: systemPrompt.version,
|
|
359
|
+
attempts,
|
|
360
|
+
});
|
|
361
|
+
throw new RefineError("ERR_LLM_OUTPUT_INVALID", `The model did not return a schema-valid component after ${attempts} attempt(s). ` +
|
|
362
|
+
`Last validation error:\n${outcome.reason}`, { attempts, reason: outcome.reason });
|
|
363
|
+
}
|
|
364
|
+
const component = outcome.component;
|
|
365
|
+
// Binary (base64) originals are never sent to the model (they can't be inlined
|
|
366
|
+
// as prompt text — see buildUserText), so the model cannot echo them back. If
|
|
367
|
+
// we returned `component.files` as-is, any binary asset in the component
|
|
368
|
+
// directory would be silently DROPPED from the returned set and the diff would
|
|
369
|
+
// misreport it as deleted (diffed against /dev/null) — a refine round-trip
|
|
370
|
+
// would lose it (Copilot review, PR #127). So carry every original binary file
|
|
371
|
+
// forward into the result, even if the model fabricates the same path. Because
|
|
372
|
+
// that file is byte-identical on both sides, `buildUnifiedDiff`'s
|
|
373
|
+
// `before === after` check omits it automatically.
|
|
374
|
+
//
|
|
375
|
+
// Deliberate consequence (Copilot review, PR #128): because omission of a
|
|
376
|
+
// binary can't be distinguished from "the model never saw it", this carry-
|
|
377
|
+
// forward means `refine` cannot DELETE a binary asset — omission always
|
|
378
|
+
// resurrects it. That is intentional for v1: `refine` is an *edit* verb whose
|
|
379
|
+
// prompt explicitly says "don't drop files", and the kit's own system prompt
|
|
380
|
+
// steers components toward inline SVG / `data:` URIs rather than binary assets
|
|
381
|
+
// in the first place. Removing a binary from a component is the job of the
|
|
382
|
+
// dedicated, plan-gated `delete_files` / `write_files` verbs, not a side effect
|
|
383
|
+
// of a natural-language refine instruction. If a future version needs
|
|
384
|
+
// refine-driven binary deletion, it would take an explicit keep/delete marker
|
|
385
|
+
// protocol (the model returns the path with a sentinel the tool resolves to the
|
|
386
|
+
// original bytes, and true omission then means delete) — out of scope here.
|
|
387
|
+
// A model-supplied entry for an ORIGINAL binary path cannot be trusted: the
|
|
388
|
+
// prompt exposed only a placeholder, never those bytes. Preserve the original
|
|
389
|
+
// until a future explicit binary replacement/delete protocol exists. New
|
|
390
|
+
// binary paths are still allowed when their returned content validates.
|
|
391
|
+
const returnedFiles = normalizeGeneratedFiles(component.files).filter((file) => !originalBinaryPaths.has(file.path));
|
|
392
|
+
const carriedBinaries = originalFiles
|
|
393
|
+
.filter((f) => !isTextFile(f))
|
|
394
|
+
.map((f) => ({
|
|
395
|
+
path: f.path,
|
|
396
|
+
content: f.content,
|
|
397
|
+
mimeType: f.mimeType,
|
|
398
|
+
encoding: "base64",
|
|
399
|
+
}));
|
|
400
|
+
const files = [...returnedFiles, ...carriedBinaries];
|
|
401
|
+
// AC5 — unified diff (informational) from originals → updated, by path. Built
|
|
402
|
+
// from the merged `files` so carried-forward binaries (identical on both sides)
|
|
403
|
+
// are excluded, while genuine text edits still surface.
|
|
404
|
+
const originalsByPath = new Map(originalFiles.map((f) => [f.path, f.content]));
|
|
405
|
+
const updatedByPath = new Map(files.map((f) => [f.path, f.content]));
|
|
406
|
+
const diff = buildUnifiedDiff(originalsByPath, updatedByPath);
|
|
407
|
+
// AC8 — per-call structured log.
|
|
408
|
+
logStderr({
|
|
409
|
+
event: "refine",
|
|
410
|
+
ok: true,
|
|
411
|
+
componentName: component.componentName,
|
|
412
|
+
hasRegion,
|
|
413
|
+
model: parsed.model,
|
|
414
|
+
promptTokens: usage.promptTokens,
|
|
415
|
+
completionTokens: usage.completionTokens,
|
|
416
|
+
latencyMs,
|
|
417
|
+
promptVersion: systemPrompt.version,
|
|
418
|
+
attempts,
|
|
419
|
+
});
|
|
420
|
+
return {
|
|
421
|
+
componentName: component.componentName,
|
|
422
|
+
group: component.group,
|
|
423
|
+
diff,
|
|
424
|
+
files,
|
|
425
|
+
manifestEntry: component.manifestEntry,
|
|
426
|
+
usage,
|
|
427
|
+
};
|
|
428
|
+
}
|
|
429
|
+
// ── MCP registration ──────────────────────────────────────────────────────────
|
|
430
|
+
const refineOutputShape = {
|
|
431
|
+
componentName: z.string(),
|
|
432
|
+
group: z.string(),
|
|
433
|
+
diff: z.string(),
|
|
434
|
+
files: z.array(z
|
|
435
|
+
.object({
|
|
436
|
+
path: z.string(),
|
|
437
|
+
content: z.string(),
|
|
438
|
+
mimeType: z.string(),
|
|
439
|
+
encoding: z.enum(["utf-8", "base64"]),
|
|
440
|
+
})
|
|
441
|
+
.strict()),
|
|
442
|
+
manifestEntry: z
|
|
443
|
+
.object({
|
|
444
|
+
viewport: z.object({ width: z.number(), height: z.number() }).strict(),
|
|
445
|
+
subtitle: z.string().optional(),
|
|
446
|
+
tags: z.array(z.string()).optional(),
|
|
447
|
+
})
|
|
448
|
+
.strict(),
|
|
449
|
+
usage: z
|
|
450
|
+
.object({
|
|
451
|
+
promptTokens: z.number().int().min(0),
|
|
452
|
+
completionTokens: z.number().int().min(0),
|
|
453
|
+
totalTokens: z.number().int().min(0),
|
|
454
|
+
})
|
|
455
|
+
.strict(),
|
|
456
|
+
};
|
|
457
|
+
export function registerRefineTool(server, deps) {
|
|
458
|
+
server.registerTool(REFINE_TOOL_NAME, {
|
|
459
|
+
title: "Refine component",
|
|
460
|
+
description: "Iterate on an existing component in a UI kit. Takes a free-form instruction " +
|
|
461
|
+
'(e.g. "make the border radius softer") and an optional region { x, y, w, h } rect ' +
|
|
462
|
+
'for a canvas-style "fix this element" edit, and returns a unified diff plus the full ' +
|
|
463
|
+
"updated files (the files are the source of truth; the diff is informational). Loads the " +
|
|
464
|
+
"component's current source from the kit, validates the model's reply against " +
|
|
465
|
+
"COMPONENT_SCHEMA (retried once on a validation failure), and — when a region is given — " +
|
|
466
|
+
"attaches a rendered crop of it as a visual reference. Reach for this to adjust a " +
|
|
467
|
+
"component already written to the kit (typically after conjure → write_files → preview); " +
|
|
468
|
+
"`design-default` is the valid gateway routing alias. Persist the returned files via " +
|
|
469
|
+
"plan, mapping each {path, content, mimeType, encoding} to write_files " +
|
|
470
|
+
"{path, data: content, mimeType, encoding}, before previewing.",
|
|
471
|
+
inputSchema: refineInputShape,
|
|
472
|
+
outputSchema: refineOutputShape,
|
|
473
|
+
}, async (args) => {
|
|
474
|
+
try {
|
|
475
|
+
const result = await refine(deps, args);
|
|
476
|
+
return {
|
|
477
|
+
content: [{ type: "text", text: JSON.stringify(result) }],
|
|
478
|
+
structuredContent: result,
|
|
479
|
+
};
|
|
480
|
+
}
|
|
481
|
+
catch (error) {
|
|
482
|
+
if (error instanceof RefineError) {
|
|
483
|
+
return {
|
|
484
|
+
isError: true,
|
|
485
|
+
content: [
|
|
486
|
+
{
|
|
487
|
+
type: "text",
|
|
488
|
+
text: JSON.stringify({
|
|
489
|
+
code: error.code,
|
|
490
|
+
message: error.message,
|
|
491
|
+
...(error.details ? { details: error.details } : {}),
|
|
492
|
+
}),
|
|
493
|
+
},
|
|
494
|
+
],
|
|
495
|
+
};
|
|
496
|
+
}
|
|
497
|
+
throw error;
|
|
498
|
+
}
|
|
499
|
+
});
|
|
500
|
+
}
|
|
501
|
+
//# sourceMappingURL=refine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"refine.js","sourceRoot":"","sources":["../../src/tools/refine.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
|
+
import { Registry } from "prom-client";
|
|
4
|
+
import { type FullScanKitStore, type FullScanResult, type Renderer } from "../validate/index.js";
|
|
5
|
+
/** Input schema for validate (counter-persistence facet). */
|
|
6
|
+
declare const countsSchema: z.ZodObject<{
|
|
7
|
+
total: z.ZodNumber;
|
|
8
|
+
bad: z.ZodNumber;
|
|
9
|
+
thin: z.ZodNumber;
|
|
10
|
+
variantsIdentical: z.ZodNumber;
|
|
11
|
+
iterations: z.ZodNumber;
|
|
12
|
+
}, z.core.$strip>;
|
|
13
|
+
type ValidateCounts = z.infer<typeof countsSchema>;
|
|
14
|
+
/**
|
|
15
|
+
* Prometheus metrics registry and counters.
|
|
16
|
+
* Exposed as a module singleton so M6-01 can register it with the HTTP endpoint.
|
|
17
|
+
*/
|
|
18
|
+
export declare const metricsRegistry: Registry<"text/plain; version=0.0.4; charset=utf-8">;
|
|
19
|
+
/**
|
|
20
|
+
* Persist validation counts to a timestamped JSON report file.
|
|
21
|
+
*
|
|
22
|
+
* @param reportsDir - Directory where reports are stored (.genie/reports)
|
|
23
|
+
* @param kitId - Kit identifier
|
|
24
|
+
* @param counts - Validation counts to persist
|
|
25
|
+
* @returns The path to the created report file
|
|
26
|
+
*/
|
|
27
|
+
export declare function persistReport(reportsDir: string, kitId: string, counts: ValidateCounts): Promise<string>;
|
|
28
|
+
/**
|
|
29
|
+
* Emit Prometheus metrics for the given validation counts.
|
|
30
|
+
*
|
|
31
|
+
* @param kitId - Kit identifier (used as metric label)
|
|
32
|
+
* @param counts - Validation counts to emit
|
|
33
|
+
*/
|
|
34
|
+
export declare function emitMetrics(kitId: string, counts: ValidateCounts): void;
|
|
35
|
+
/**
|
|
36
|
+
* Derive the M1-12 counter shape from a full-scan result (AC8: the full-scan
|
|
37
|
+
* facet persists its run via the SAME `persistReport`/`emitMetrics` path as the
|
|
38
|
+
* counter facet). `iterations` is 1 — a single scan pass — and the four
|
|
39
|
+
* validation dimensions come straight off the scan. `bad` is the scan's own
|
|
40
|
+
* literal sum (`markerMissing + thin + variantsIdentical`).
|
|
41
|
+
*/
|
|
42
|
+
export declare function countsFromScan(result: FullScanResult): ValidateCounts;
|
|
43
|
+
/** Options for {@link registerValidate}. */
|
|
44
|
+
export interface RegisterValidateOptions {
|
|
45
|
+
/** Where the counter facet + full-scan facet persist their JSON reports.
|
|
46
|
+
* Defaults to `GENIE_REPORTS_DIR` / `.genie/reports`. */
|
|
47
|
+
reportsDir?: string;
|
|
48
|
+
/**
|
|
49
|
+
* The kit read-port the full-scan facet walks (`listFiles`/`readFile`). When
|
|
50
|
+
* omitted, the full-scan facet is unavailable and a no-`counts` call returns a
|
|
51
|
+
* typed error — the counter-persistence facet still works standalone (so a
|
|
52
|
+
* deployment that only uses telemetry needs no store wired here). `server.ts`
|
|
53
|
+
* passes the shared `kitStore`.
|
|
54
|
+
*/
|
|
55
|
+
kitStore?: FullScanKitStore;
|
|
56
|
+
/**
|
|
57
|
+
* Factory for the one headless renderer the full-scan facet reuses across a
|
|
58
|
+
* scan (AC7). Defaults to {@link createDefaultRenderer} (lazy Playwright,
|
|
59
|
+
* `null` when unavailable → the scan degrades to marker-only). Injectable so
|
|
60
|
+
* tests supply a stub and never launch a browser.
|
|
61
|
+
*/
|
|
62
|
+
createRenderer?: () => Promise<Renderer | null>;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Register the `mcp__genie__validate` tool on the given MCP server (both
|
|
66
|
+
* facets — see the module header).
|
|
67
|
+
*
|
|
68
|
+
* Backward-compatible call shape: `registerValidate(server, reportsDir?)` still
|
|
69
|
+
* works (the M1-12 wiring), and `registerValidate(server, options)` opts into
|
|
70
|
+
* the full-scan facet by supplying a `kitStore`.
|
|
71
|
+
*/
|
|
72
|
+
export declare function registerValidate(server: McpServer, reportsDirOrOptions?: string | RegisterValidateOptions): void;
|
|
73
|
+
export {};
|
|
74
|
+
//# sourceMappingURL=validate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../src/tools/validate.ts"],"names":[],"mappings":"AA8BA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,EAAW,QAAQ,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAGL,KAAK,gBAAgB,EACrB,KAAK,cAAc,EACnB,KAAK,QAAQ,EACd,MAAM,sBAAsB,CAAC;AAE9B,6DAA6D;AAC7D,QAAA,MAAM,YAAY;;;;;;iBAMhB,CAAC;AAuBH,KAAK,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAC;AAEnD;;;GAGG;AACH,eAAO,MAAM,eAAe,sDAAiB,CAAC;AAqC9C;;;;;;;GAOG;AACH,wBAAsB,aAAa,CACjC,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,cAAc,GACrB,OAAO,CAAC,MAAM,CAAC,CAgBjB;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,cAAc,GAAG,IAAI,CAMvE;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,cAAc,GAAG,cAAc,CAQrE;AAED,4CAA4C;AAC5C,MAAM,WAAW,uBAAuB;IACtC;6DACyD;IACzD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,gBAAgB,CAAC;IAC5B;;;;;OAKG;IACH,cAAc,CAAC,EAAE,MAAM,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC;CACjD;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,SAAS,EACjB,mBAAmB,CAAC,EAAE,MAAM,GAAG,uBAAuB,GACrD,IAAI,CAuFN"}
|