@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,288 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* M3-05 (DRO-261) — genie's 5-step atomic write-sequence orchestrator.
|
|
3
|
+
*
|
|
4
|
+
* `runAtomicSync` sequences one sync commit as five ordered, stop-on-first-
|
|
5
|
+
* failure steps. The atomic write sequence is load-bearing and unchanged in
|
|
6
|
+
* shape:
|
|
7
|
+
*
|
|
8
|
+
* 1. Write the `.genie/recompile` sentinel FIRST, to fence the manifest/copy
|
|
9
|
+
* machinery — a consumer that sees the sentinel knows a sync is mid-flight
|
|
10
|
+
* and the tree may be inconsistent until the anchor lands.
|
|
11
|
+
* 2. Apply every content write, chunked into batches of ≤ 256 per
|
|
12
|
+
* `write_files` call (the M1-08 `MAX_FILES_PER_CALL` ceiling — a 257-file
|
|
13
|
+
* call would be rejected as `TooManyFilesError`).
|
|
14
|
+
* 3. Apply every delete via one `delete_files` call. A path that is
|
|
15
|
+
* authorized-but-absent is NOT a failure (M1-09 AC5 returns it in
|
|
16
|
+
* `notFoundPaths`) — only a real error (out-of-plan path, unlink failure)
|
|
17
|
+
* trips stop-on-first-failure.
|
|
18
|
+
* 4. RE-ARM the sentinel (write it again), so it still fences the tree after
|
|
19
|
+
* the writes/deletes landed and right up until the anchor is committed.
|
|
20
|
+
* 5. Write `.genie/sync.json` LAST, via M3-06's {@link writeAnchor}. It is the
|
|
21
|
+
* completion proof: its presence means every prior step succeeded.
|
|
22
|
+
*
|
|
23
|
+
* ── Why the anchor is last (AC7) ─────────────────────────────────────────────
|
|
24
|
+
* A mid-plan failure (steps 1–4) returns before step 5, so `.genie/sync.json`
|
|
25
|
+
* is never written for an incomplete sync. The NEXT sync sees "sentinel present,
|
|
26
|
+
* anchor absent" ({@link detectResumeStep} → 2) and knows the tree is a
|
|
27
|
+
* half-write to repair from step 2 — rather than trusting a stale anchor that
|
|
28
|
+
* would mask the incomplete state. This is the whole reason the write order is
|
|
29
|
+
* load-bearing.
|
|
30
|
+
*
|
|
31
|
+
* ── Native surface (CLAUDE.md hard rule 1) ───────────────────────────────────
|
|
32
|
+
* `.genie/recompile` and `.genie/sync.json` are genie-NATIVE artifacts. They are
|
|
33
|
+
* written fs-native to `projectRoot` (NOT through the plan-gated `write_files`
|
|
34
|
+
* verb — they would never match a user plan's `writes` globs, and they are
|
|
35
|
+
* genie's own bookkeeping, not user content). They must NOT be renamed to the
|
|
36
|
+
* Anthropic `_ds_recompile` / `_ds_sync.json` interop shapes; an interop bridge
|
|
37
|
+
* that maps them is a separate, opt-in concern.
|
|
38
|
+
*
|
|
39
|
+
* ── Composition (Kiln's plan, DRO-696) ───────────────────────────────────────
|
|
40
|
+
* Steps 2–3 call the in-process `writeFiles` / `deleteFiles` CORE functions
|
|
41
|
+
* directly (not over the MCP transport) — the same way `conjure_screen.ts`
|
|
42
|
+
* composes tool-layer logic — so the orchestrator reuses their full plan-gating,
|
|
43
|
+
* atomicity, and rollback contracts without re-implementing any of it.
|
|
44
|
+
*/
|
|
45
|
+
import { mkdir, readFile, stat, writeFile } from "node:fs/promises";
|
|
46
|
+
import { join } from "node:path";
|
|
47
|
+
import { performance } from "node:perf_hooks";
|
|
48
|
+
import { deleteFiles } from "../tools/delete_files.js";
|
|
49
|
+
import { MAX_FILES_PER_CALL, writeFiles } from "../tools/write_files.js";
|
|
50
|
+
import { readAnchor, writeAnchor } from "./anchor.js";
|
|
51
|
+
// ─── Native sentinel (AC2) ───────────────────────────────────────────────────
|
|
52
|
+
/** Kit-root-relative path of genie's recompile fence sentinel (native surface). */
|
|
53
|
+
export const RECOMPILE_SENTINEL_PATH = ".genie/recompile";
|
|
54
|
+
/**
|
|
55
|
+
* The exact sentinel body (AC2). genie's native `{"by":"genie"}` marker — NOT
|
|
56
|
+
* the Anthropic `_ds_recompile` interop shape (CLAUDE.md hard rule 1). Kept as
|
|
57
|
+
* a compact single-line literal so a byte-for-byte assertion is trivial and the
|
|
58
|
+
* re-arm in step 4 reproduces it exactly.
|
|
59
|
+
*/
|
|
60
|
+
export const RECOMPILE_SENTINEL_BODY = '{"by":"genie"}';
|
|
61
|
+
// ─── runAtomicSync (AC1–AC7, AC9) ────────────────────────────────────────────
|
|
62
|
+
/**
|
|
63
|
+
* Run the 5-step atomic sync sequence. Stops on the first failing step (AC7),
|
|
64
|
+
* leaving `.genie/sync.json` unwritten so the next sync's diff repairs the
|
|
65
|
+
* half-write; a not-found delete inside step 3 is NOT a failure (AC4). Every
|
|
66
|
+
* attempted step emits a {@link StepEvent} (AC9).
|
|
67
|
+
*/
|
|
68
|
+
export async function runAtomicSync(deps, args) {
|
|
69
|
+
const { store, projectRoot } = deps;
|
|
70
|
+
const events = [];
|
|
71
|
+
try {
|
|
72
|
+
// Step 1 — fence the tree with the recompile sentinel FIRST (AC2).
|
|
73
|
+
await runStep(1, events, () => writeSentinel(projectRoot));
|
|
74
|
+
// Step 2 — content writes, chunked ≤ 256/call (AC3).
|
|
75
|
+
await runStep(2, events, () => runWrites(store, args.planId, args.writes));
|
|
76
|
+
// Step 3 — deletes (AC4); a not-found delete does not throw (M1-09 AC5).
|
|
77
|
+
await runStep(3, events, () => runDeletes(store, args.planId, args.deletes));
|
|
78
|
+
// Step 4 — re-arm the sentinel so it fences right up to the anchor (AC5).
|
|
79
|
+
await runStep(4, events, () => writeSentinel(projectRoot));
|
|
80
|
+
// Step 5 — write `.genie/sync.json` LAST as the completion proof (AC6).
|
|
81
|
+
await runStep(5, events, () => writeFinalAnchor(projectRoot, args));
|
|
82
|
+
return { ok: true, events };
|
|
83
|
+
}
|
|
84
|
+
catch (error) {
|
|
85
|
+
// The failing step pushed its own `ok: false` event before rethrowing, so
|
|
86
|
+
// the last event's step IS the failed step (AC7). `?? 1` is unreachable
|
|
87
|
+
// (a throw always follows at least one pushed event) but keeps the type
|
|
88
|
+
// total without a non-null assertion.
|
|
89
|
+
const failedStep = events[events.length - 1]?.step ?? 1;
|
|
90
|
+
return {
|
|
91
|
+
ok: false,
|
|
92
|
+
failedStep,
|
|
93
|
+
error: error instanceof Error ? error : new Error(String(error)),
|
|
94
|
+
events,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
// ─── detectResumeStep (AC8) ──────────────────────────────────────────────────
|
|
99
|
+
/**
|
|
100
|
+
* Inspect a kit root and report where the NEXT sync should resume from (AC8):
|
|
101
|
+
*
|
|
102
|
+
* - `2` — sentinel present, anchor ABSENT: a prior sync fenced the tree
|
|
103
|
+
* (step 1) then crashed before the anchor landed (steps 2–4). The
|
|
104
|
+
* tree is a half-write; resume from step 2 to re-apply
|
|
105
|
+
* writes/deletes and re-arm before writing the anchor.
|
|
106
|
+
* - `1` — sentinel AND anchor both absent: a fresh, never-synced kit.
|
|
107
|
+
* Start a normal sync from step 1.
|
|
108
|
+
* - `null` — the anchor is present (a prior sync completed cleanly): there is
|
|
109
|
+
* no partial-write to resume; the next sync is a NEW plan from step
|
|
110
|
+
* 1 with fresh inputs, not a resume.
|
|
111
|
+
*
|
|
112
|
+
* Never mutates the tree. Propagates {@link readAnchor}'s `AnchorParseError`
|
|
113
|
+
* for a corrupt-but-present anchor — a corrupt anchor is a real operability
|
|
114
|
+
* problem, not a "nothing to resume" signal (same reasoning `readAnchor` itself
|
|
115
|
+
* applies). Likewise propagates any non-"missing" error from the sentinel
|
|
116
|
+
* `stat` (e.g. `EACCES` on `.genie/`) rather than treating it as "sentinel
|
|
117
|
+
* absent" — see {@link pathExists}.
|
|
118
|
+
*/
|
|
119
|
+
export async function detectResumeStep(projectRoot) {
|
|
120
|
+
const sentinelPresent = await pathExists(join(projectRoot, RECOMPILE_SENTINEL_PATH));
|
|
121
|
+
const anchor = await readAnchor(projectRoot); // null when absent (AC8 of M3-06)
|
|
122
|
+
if (anchor !== null)
|
|
123
|
+
return null; // clean — last sync completed
|
|
124
|
+
return sentinelPresent ? 2 : 1; // half-write → step 2; fresh → step 1
|
|
125
|
+
}
|
|
126
|
+
// ─── Step bodies ─────────────────────────────────────────────────────────────
|
|
127
|
+
/**
|
|
128
|
+
* Write (or re-arm) the native recompile sentinel fs-directly under
|
|
129
|
+
* `projectRoot`. Idempotent — steps 1 and 4 both call it and the second write
|
|
130
|
+
* simply reproduces the same bytes. Not plan-gated: `.genie/recompile` is
|
|
131
|
+
* genie's own bookkeeping, never user content.
|
|
132
|
+
*/
|
|
133
|
+
async function writeSentinel(projectRoot) {
|
|
134
|
+
await mkdir(join(projectRoot, ".genie"), { recursive: true });
|
|
135
|
+
await writeFile(join(projectRoot, RECOMPILE_SENTINEL_PATH), RECOMPILE_SENTINEL_BODY, "utf-8");
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Step 2 — apply all content writes, chunked into ≤ `MAX_FILES_PER_CALL`
|
|
139
|
+
* batches, one plan-gated `writeFiles` call each (AC3). An empty `writes` array
|
|
140
|
+
* yields zero batches → zero calls → a clean no-op (the step still emits its
|
|
141
|
+
* event). A `WriteFailedError` / `PathOutsidePlanError` from any batch
|
|
142
|
+
* propagates and fails the step.
|
|
143
|
+
*/
|
|
144
|
+
async function runWrites(store, planId, writes) {
|
|
145
|
+
for (const batch of chunk(writes, MAX_FILES_PER_CALL)) {
|
|
146
|
+
await writeFiles(store, { planId, files: batch });
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Step 3 — apply all deletes in one plan-gated `delete_files` call (AC4).
|
|
151
|
+
*
|
|
152
|
+
* Skipped entirely when there is nothing to delete: `delete_files`' args schema
|
|
153
|
+
* requires `paths` to be non-empty (`.min(1)`), so calling it with `[]` would
|
|
154
|
+
* be an `InvalidArguments` error rather than a no-op. A not-found path is
|
|
155
|
+
* handled INSIDE `deleteFiles` (returned in `notFoundPaths`, never thrown), so
|
|
156
|
+
* it does not fail this step (AC7's not-found exception). Only a real error
|
|
157
|
+
* (out-of-plan path, unlink failure) propagates.
|
|
158
|
+
*/
|
|
159
|
+
async function runDeletes(store, planId, deletes) {
|
|
160
|
+
if (deletes.length === 0)
|
|
161
|
+
return;
|
|
162
|
+
await deleteFiles(store, { planId, paths: deletes });
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Step 5 — assemble M3-06's `PlanResult` from the sync inputs and write
|
|
166
|
+
* `.genie/sync.json` LAST via {@link writeAnchor} (AC6). `writeAnchor` hashes
|
|
167
|
+
* only source/render-extension paths and does its own temp-file + rename commit,
|
|
168
|
+
* so this step is the atomic completion proof.
|
|
169
|
+
*/
|
|
170
|
+
async function writeFinalAnchor(projectRoot, args) {
|
|
171
|
+
const planResult = {
|
|
172
|
+
writes: await resolveAnchorWrites(projectRoot, args.writes),
|
|
173
|
+
verified: args.verified ?? [],
|
|
174
|
+
};
|
|
175
|
+
await writeAnchor(projectRoot, planResult);
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Resolve each {@link WriteInput} to the `{ path, content }` shape
|
|
179
|
+
* `writeAnchor` hashes.
|
|
180
|
+
*
|
|
181
|
+
* ── Committed bytes, not the plan's local source (Copilot review) ───────────
|
|
182
|
+
* Inline `data` resolves for free — utf-8 decodes to the string, base64 to a
|
|
183
|
+
* `Buffer` — the exact bytes already handed to `writeFiles` in step 2, no disk
|
|
184
|
+
* read at all.
|
|
185
|
+
*
|
|
186
|
+
* A `localPath` write is different: step 2 STREAMS it straight from the
|
|
187
|
+
* plan's `localDir` into the kit tree (`store/local.ts`'s `streamCopy`, via
|
|
188
|
+
* `createReadStream` — never buffered here, by design, so a large upload
|
|
189
|
+
* never fully loads into memory). This function used to re-read that SAME
|
|
190
|
+
* `localDir` source file a second time, during step 5, to compute its hash —
|
|
191
|
+
* a TOCTOU hazard, since the plan's `localDir` is a directory the CALLER
|
|
192
|
+
* controls and may keep writing to for the lifetime of a sync, so the bytes
|
|
193
|
+
* step 5 would hash could silently diverge from the bytes step 2 actually
|
|
194
|
+
* streamed into the kit. It also contradicted `sync/anchor.ts`'s own
|
|
195
|
+
* contract that hashes must come from "the exact bytes that landed, not
|
|
196
|
+
* re-read from disk after the fact."
|
|
197
|
+
*
|
|
198
|
+
* The fix: read the file back from `projectRoot` — the KIT destination step
|
|
199
|
+
* 2 just committed it to (`join(projectRoot, write.path)`) — never from the
|
|
200
|
+
* plan's `localDir` source. `projectRoot` is guaranteed (by `SyncDeps`'s own
|
|
201
|
+
* contract, see above) to be the exact directory `store.writeFiles` resolved
|
|
202
|
+
* the write to, so this hashes precisely the bytes the kit tree now holds —
|
|
203
|
+
* the same tree `writeAnchor` is meant to vouch for — rather than a second,
|
|
204
|
+
* independently-timed read of a directory outside genie's control.
|
|
205
|
+
*
|
|
206
|
+
* A write with neither `data` nor `localPath` is unreachable here (step 2's
|
|
207
|
+
* `write_files` would have rejected it, and step 5 only runs once step 2
|
|
208
|
+
* passed); it is defensively hashed as empty rather than throwing.
|
|
209
|
+
*/
|
|
210
|
+
async function resolveAnchorWrites(projectRoot, writes) {
|
|
211
|
+
const resolved = [];
|
|
212
|
+
for (const write of writes) {
|
|
213
|
+
let content;
|
|
214
|
+
if (write.data !== undefined) {
|
|
215
|
+
content = write.encoding === "base64" ? Buffer.from(write.data, "base64") : write.data;
|
|
216
|
+
}
|
|
217
|
+
else if (write.localPath !== undefined) {
|
|
218
|
+
content = await readFile(join(projectRoot, write.path));
|
|
219
|
+
}
|
|
220
|
+
else {
|
|
221
|
+
content = "";
|
|
222
|
+
}
|
|
223
|
+
resolved.push({ path: write.path, content });
|
|
224
|
+
}
|
|
225
|
+
return resolved;
|
|
226
|
+
}
|
|
227
|
+
// ─── Helpers ─────────────────────────────────────────────────────────────────
|
|
228
|
+
/**
|
|
229
|
+
* Time one step, push its {@link StepEvent}, and either return the step's value
|
|
230
|
+
* or re-throw after recording the failure (AC9). The re-throw is what
|
|
231
|
+
* `runAtomicSync`'s outer catch turns into the stop-on-first-failure result — so
|
|
232
|
+
* the failing step's event is always recorded before the sequence unwinds.
|
|
233
|
+
*/
|
|
234
|
+
async function runStep(step, events, fn) {
|
|
235
|
+
const start = performance.now();
|
|
236
|
+
try {
|
|
237
|
+
const value = await fn();
|
|
238
|
+
events.push({ step, ok: true, ms: performance.now() - start });
|
|
239
|
+
return value;
|
|
240
|
+
}
|
|
241
|
+
catch (error) {
|
|
242
|
+
events.push({ step, ok: false, ms: performance.now() - start });
|
|
243
|
+
throw error;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
/** Split `items` into consecutive slices of at most `size` (AC3 chunking). */
|
|
247
|
+
function chunk(items, size) {
|
|
248
|
+
const batches = [];
|
|
249
|
+
for (let index = 0; index < items.length; index += size) {
|
|
250
|
+
batches.push(items.slice(index, index + size));
|
|
251
|
+
}
|
|
252
|
+
return batches;
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* True if `path` exists (any node type); false if it (or a parent directory
|
|
256
|
+
* component) genuinely does not exist. Any OTHER `stat` failure — EACCES,
|
|
257
|
+
* EPERM, a transient I/O error — propagates rather than being misread as
|
|
258
|
+
* "absent" (Copilot review on this PR): silently mapping every error to
|
|
259
|
+
* `false` could make {@link detectResumeStep} report "fresh, start from step
|
|
260
|
+
* 1" for a sentinel that is actually present-but-unreadable, masking a real
|
|
261
|
+
* operability problem instead of surfacing it. Mirrors `./anchor.ts`'s
|
|
262
|
+
* `readAnchor` (and `store/local.ts`'s identical helper), which apply the
|
|
263
|
+
* same ENOENT/ENOTDIR-only rule for the same reason.
|
|
264
|
+
*/
|
|
265
|
+
async function pathExists(path) {
|
|
266
|
+
try {
|
|
267
|
+
await stat(path);
|
|
268
|
+
return true;
|
|
269
|
+
}
|
|
270
|
+
catch (error) {
|
|
271
|
+
if (isMissingPathError(error))
|
|
272
|
+
return false;
|
|
273
|
+
throw error;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* ENOENT (missing file) and ENOTDIR (a parent path component is a file, not a
|
|
278
|
+
* directory) both mean "not there". Duplicated locally rather than imported
|
|
279
|
+
* from `./anchor.ts` / `store/local.ts` — each of those already carries its
|
|
280
|
+
* own copy of this exact one-liner, matching this repo's established
|
|
281
|
+
* per-module-owns-its-guard convention for this helper.
|
|
282
|
+
*/
|
|
283
|
+
function isMissingPathError(error) {
|
|
284
|
+
return (error instanceof Error &&
|
|
285
|
+
"code" in error &&
|
|
286
|
+
(error.code === "ENOENT" || error.code === "ENOTDIR"));
|
|
287
|
+
}
|
|
288
|
+
//# sourceMappingURL=orchestrator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"orchestrator.js","sourceRoot":"","sources":["../../src/sync/orchestrator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP tool: bind_kit (M1-20).
|
|
3
|
+
*
|
|
4
|
+
* Attaches a UI kit to a project and optionally marks it the default for
|
|
5
|
+
* screen generation (M1-21, `conjure_screen`, resolves against this).
|
|
6
|
+
*
|
|
7
|
+
* Input: { projectId: string, kitId: string, default?: boolean }
|
|
8
|
+
* Output: ProjectSummary (same shape `list_projects`/`get_project` return)
|
|
9
|
+
*/
|
|
10
|
+
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
11
|
+
import type { BindKitArgs, ProjectSummary } from "./create_project.js";
|
|
12
|
+
export declare const BIND_KIT_TOOL_NAME = "mcp__genie__bind_kit";
|
|
13
|
+
/**
|
|
14
|
+
* Narrow port `bind_kit` depends on — anything that can bind a kit to a
|
|
15
|
+
* project and return its updated summary. `ProjectStore` (from
|
|
16
|
+
* `create_project.ts`) satisfies this structurally, matching the
|
|
17
|
+
* `ProjectGetStore`/`ProjectListStore` pattern already used by sibling tools.
|
|
18
|
+
*/
|
|
19
|
+
export interface ProjectBindKitStore {
|
|
20
|
+
bindKit(args: BindKitArgs): Promise<ProjectSummary>;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Validate args and bind the kit. Exported standalone (bypassing the MCP
|
|
24
|
+
* transport) so programmatic/direct callers get the same validation
|
|
25
|
+
* defense-in-depth as `get_project`'s `getProject()` and `get_kit`'s `getKit()`.
|
|
26
|
+
*/
|
|
27
|
+
export declare function bindKit(store: ProjectBindKitStore, args: unknown): Promise<ProjectSummary>;
|
|
28
|
+
export declare function registerBindKitTool(server: McpServer, store: ProjectBindKitStore): void;
|
|
29
|
+
//# sourceMappingURL=bind_kit.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bind_kit.d.ts","sourceRoot":"","sources":["../../src/tools/bind_kit.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAGzE,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAGvE,eAAO,MAAM,kBAAkB,yBAAyB,CAAC;AAwBzD;;;;;GAKG;AACH,MAAM,WAAW,mBAAmB;IAClC,OAAO,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;CACrD;AAED;;;;GAIG;AACH,wBAAsB,OAAO,CAAC,KAAK,EAAE,mBAAmB,EAAE,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,cAAc,CAAC,CAGhG;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,mBAAmB,GAAG,IAAI,CA8CvF"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { PROJECT_ID_PATTERN, ProjectStoreError, projectSummaryShape } from "./create_project.js";
|
|
3
|
+
import { KIT_ID_PATTERN } from "./get_kit.js";
|
|
4
|
+
export const BIND_KIT_TOOL_NAME = "mcp__genie__bind_kit";
|
|
5
|
+
const projectIdSchema = z
|
|
6
|
+
.string()
|
|
7
|
+
.regex(PROJECT_ID_PATTERN, "projectId must be a 3-64 character slug containing only lowercase letters, numbers, and hyphens.");
|
|
8
|
+
const kitIdSchema = z
|
|
9
|
+
.string()
|
|
10
|
+
.regex(KIT_ID_PATTERN, "kitId must be a 3-64 character slug containing only lowercase letters, numbers, and hyphens.");
|
|
11
|
+
const bindKitArgsSchema = z
|
|
12
|
+
.object({
|
|
13
|
+
projectId: projectIdSchema,
|
|
14
|
+
kitId: kitIdSchema,
|
|
15
|
+
default: z.boolean().optional(),
|
|
16
|
+
})
|
|
17
|
+
.strict();
|
|
18
|
+
/**
|
|
19
|
+
* Validate args and bind the kit. Exported standalone (bypassing the MCP
|
|
20
|
+
* transport) so programmatic/direct callers get the same validation
|
|
21
|
+
* defense-in-depth as `get_project`'s `getProject()` and `get_kit`'s `getKit()`.
|
|
22
|
+
*/
|
|
23
|
+
export async function bindKit(store, args) {
|
|
24
|
+
const parsed = bindKitArgsSchema.parse(args);
|
|
25
|
+
return store.bindKit(parsed);
|
|
26
|
+
}
|
|
27
|
+
export function registerBindKitTool(server, store) {
|
|
28
|
+
server.registerTool(BIND_KIT_TOOL_NAME, {
|
|
29
|
+
title: "Bind kit",
|
|
30
|
+
description: "Attach a UI kit to a workspace or blueprint project, optionally marking it the " +
|
|
31
|
+
"default kit for screen generation. Binding the same kit twice updates the existing " +
|
|
32
|
+
"binding in place. Setting default: true clears default status from every other " +
|
|
33
|
+
"binding on the project. Typically precedes conjure_screen, which resolves its kit " +
|
|
34
|
+
"from these bindings when no explicit kitId is given.",
|
|
35
|
+
inputSchema: {
|
|
36
|
+
projectId: projectIdSchema,
|
|
37
|
+
kitId: kitIdSchema,
|
|
38
|
+
default: z.boolean().optional(),
|
|
39
|
+
},
|
|
40
|
+
outputSchema: projectSummaryShape,
|
|
41
|
+
}, async (args) => {
|
|
42
|
+
try {
|
|
43
|
+
const result = await bindKit(store, args);
|
|
44
|
+
return {
|
|
45
|
+
content: [{ type: "text", text: JSON.stringify(result) }],
|
|
46
|
+
structuredContent: result,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
if (error instanceof ProjectStoreError) {
|
|
51
|
+
return {
|
|
52
|
+
isError: true,
|
|
53
|
+
content: [
|
|
54
|
+
{
|
|
55
|
+
type: "text",
|
|
56
|
+
text: JSON.stringify({
|
|
57
|
+
code: error.code,
|
|
58
|
+
message: error.message,
|
|
59
|
+
...(error.projectId ? { projectId: error.projectId } : {}),
|
|
60
|
+
...(error.kitId ? { kitId: error.kitId } : {}),
|
|
61
|
+
}),
|
|
62
|
+
},
|
|
63
|
+
],
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
throw error;
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=bind_kit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bind_kit.js","sourceRoot":"","sources":["../../src/tools/bind_kit.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAEjG,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAE9C,MAAM,CAAC,MAAM,kBAAkB,GAAG,sBAAsB,CAAC;AAEzD,MAAM,eAAe,GAAG,CAAC;KACtB,MAAM,EAAE;KACR,KAAK,CACJ,kBAAkB,EAClB,kGAAkG,CACnG,CAAC;AAEJ,MAAM,WAAW,GAAG,CAAC;KAClB,MAAM,EAAE;KACR,KAAK,CACJ,cAAc,EACd,8FAA8F,CAC/F,CAAC;AAEJ,MAAM,iBAAiB,GAAG,CAAC;KACxB,MAAM,CAAC;IACN,SAAS,EAAE,eAAe;IAC1B,KAAK,EAAE,WAAW;IAClB,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;CAChC,CAAC;KACD,MAAM,EAAE,CAAC;AAYZ;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,KAA0B,EAAE,IAAa;IACrE,MAAM,MAAM,GAAG,iBAAiB,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC7C,OAAO,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;AAC/B,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,MAAiB,EAAE,KAA0B;IAC/E,MAAM,CAAC,YAAY,CACjB,kBAAkB,EAClB;QACE,KAAK,EAAE,UAAU;QACjB,WAAW,EACT,iFAAiF;YACjF,qFAAqF;YACrF,iFAAiF;YACjF,oFAAoF;YACpF,sDAAsD;QACxD,WAAW,EAAE;YACX,SAAS,EAAE,eAAe;YAC1B,KAAK,EAAE,WAAW;YAClB,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;SAChC;QACD,YAAY,EAAE,mBAAmB;KAClC,EACD,KAAK,EAAE,IAAI,EAAE,EAAE;QACb,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;YAC1C,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC;gBAClE,iBAAiB,EAAE,MAAM;aAC1B,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,KAAK,YAAY,iBAAiB,EAAE,CAAC;gBACvC,OAAO;oBACL,OAAO,EAAE,IAAI;oBACb,OAAO,EAAE;wBACP;4BACE,IAAI,EAAE,MAAe;4BACrB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;gCACnB,IAAI,EAAE,KAAK,CAAC,IAAI;gCAChB,OAAO,EAAE,KAAK,CAAC,OAAO;gCACtB,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gCAC1D,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;6BAC/C,CAAC;yBACH;qBACF;iBACF,CAAC;YACJ,CAAC;YACD,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { type ValidatedComponent } from "../llm/schema.js";
|
|
4
|
+
import { type LoadedPrompt } from "../llm/prompts.js";
|
|
5
|
+
import { type ChatCompletionFn, type UsageInfo } from "../llm/component-response.js";
|
|
6
|
+
import { type GeneratedFileWithEncoding } from "../llm/generated-files.js";
|
|
7
|
+
import { type Framework } from "../framework/interface.js";
|
|
8
|
+
export type { ChatCompletionFn, UsageInfo } from "../llm/component-response.js";
|
|
9
|
+
export declare const CONJURE_TOOL_NAME = "mcp__genie__conjure";
|
|
10
|
+
/** Target framework for the generated component (AC2/AC3). Re-exported from the
|
|
11
|
+
* M2-08 adapter module so the tool contract and the adapter registry share one
|
|
12
|
+
* source of truth (`framework/interface.ts#FRAMEWORKS`). */
|
|
13
|
+
export declare const CONJURE_FRAMEWORKS: readonly ["react", "vue", "html"];
|
|
14
|
+
export type ConjureFramework = Framework;
|
|
15
|
+
/** Default framework + model routing alias (AC3). `design-default` is resolved
|
|
16
|
+
* to a concrete provider model by the configured endpoint/gateway (M2-05). */
|
|
17
|
+
export declare const DEFAULT_FRAMEWORK: ConjureFramework;
|
|
18
|
+
export declare const DEFAULT_MODEL = "design-default";
|
|
19
|
+
/** `refUrl` bodies larger than this are warned about (AC7) and truncated before
|
|
20
|
+
* inlining, so a giant page can't blow the request's token budget. */
|
|
21
|
+
export declare const REF_URL_WARN_BYTES: number;
|
|
22
|
+
export type AddressLookup = (hostname: string) => Promise<readonly {
|
|
23
|
+
address: string;
|
|
24
|
+
family: number;
|
|
25
|
+
}[]>;
|
|
26
|
+
export declare function isSafeRefUrl(raw: string): boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Public boolean form of {@link resolveSafeAddress} kept for the existing
|
|
29
|
+
* test surface / any external reuse (M6-03 follow-up). A hostname is "safe"
|
|
30
|
+
* if at least one resolved address is not private/loopback/link-local.
|
|
31
|
+
*/
|
|
32
|
+
export declare function isSafeResolvedAddress(hostname: string, lookupAddresses?: AddressLookup): Promise<boolean>;
|
|
33
|
+
/**
|
|
34
|
+
* Fetch a single URL whose hostname has already been resolved to a
|
|
35
|
+
* known-safe `address`/`family` (M6-03 follow-up, TOCTOU fix): rather than
|
|
36
|
+
* re-validating a hostname and then letting the HTTP client perform its own,
|
|
37
|
+
* second, independent DNS resolution at connect time — the exact gap an
|
|
38
|
+
* attacker-controlled DNS name (a "rebinding" host that answers safely to
|
|
39
|
+
* the guard and privately to the real connection) can exploit — this pins
|
|
40
|
+
* the *already-validated* address into the connection via undici's
|
|
41
|
+
* `Agent({ connect: { lookup } })` override, so validation and connection
|
|
42
|
+
* are guaranteed to use the identical address. Redirects are fetched with
|
|
43
|
+
* `redirect: "manual"` and returned to the caller un-followed; the caller
|
|
44
|
+
* (`safeFetchFollowingRedirects`) re-runs full validation (schema-level
|
|
45
|
+
* `isSafeRefUrl` + resolved-address check) on every redirect target before
|
|
46
|
+
* following it, so a public URL cannot use a redirect to smuggle a request to
|
|
47
|
+
* a private target past the guard.
|
|
48
|
+
*/
|
|
49
|
+
export declare function fetchWithPinnedAddress(url: string, address: string, family: 4 | 6, timeoutMs?: number): Promise<ReferenceFetchResponse & {
|
|
50
|
+
bodyTruncated: boolean;
|
|
51
|
+
observedBodyBytes: number;
|
|
52
|
+
}>;
|
|
53
|
+
declare const conjureArgsSchema: z.ZodObject<{
|
|
54
|
+
kitId: z.ZodString;
|
|
55
|
+
kit: z.ZodString;
|
|
56
|
+
prompt: z.ZodString;
|
|
57
|
+
group: z.ZodOptional<z.ZodString>;
|
|
58
|
+
refImageDataUrl: z.ZodOptional<z.ZodString>;
|
|
59
|
+
refUrl: z.ZodOptional<z.ZodString>;
|
|
60
|
+
framework: z.ZodDefault<z.ZodEnum<{
|
|
61
|
+
react: "react";
|
|
62
|
+
vue: "vue";
|
|
63
|
+
html: "html";
|
|
64
|
+
}>>;
|
|
65
|
+
model: z.ZodDefault<z.ZodString>;
|
|
66
|
+
}, z.core.$strict>;
|
|
67
|
+
export type ConjureArgs = z.infer<typeof conjureArgsSchema>;
|
|
68
|
+
/**
|
|
69
|
+
* What `conjure` returns (AC9): the validated component — its name, resolved
|
|
70
|
+
* group, file set, and manifest metadata — plus token `usage` for the caller's
|
|
71
|
+
* accounting. Deliberately does NOT include anything about having *written* the
|
|
72
|
+
* files: generation is pure (AC9).
|
|
73
|
+
*/
|
|
74
|
+
export interface ConjureResult extends Record<string, unknown> {
|
|
75
|
+
componentName: string;
|
|
76
|
+
group: string;
|
|
77
|
+
files: GeneratedFileWithEncoding[];
|
|
78
|
+
manifestEntry: ValidatedComponent["manifestEntry"];
|
|
79
|
+
usage: UsageInfo;
|
|
80
|
+
}
|
|
81
|
+
/** Injectable URL-fetch seam for tests (AC7). When omitted, production uses the
|
|
82
|
+
* DNS-validated, address-pinned Undici path rather than global `fetch`.
|
|
83
|
+
* `headers` is optional so existing test doubles that only stub `{ ok, status, text }`
|
|
84
|
+
* keep compiling; the redirect-following logic treats a missing `headers` on a
|
|
85
|
+
* 3xx response as "no Location to follow" and stops rather than throwing. */
|
|
86
|
+
export interface ReferenceFetchResponse {
|
|
87
|
+
ok: boolean;
|
|
88
|
+
status: number;
|
|
89
|
+
headers?: {
|
|
90
|
+
get(name: string): string | null;
|
|
91
|
+
};
|
|
92
|
+
bodyTruncated?: boolean;
|
|
93
|
+
observedBodyBytes?: number;
|
|
94
|
+
text(): Promise<string>;
|
|
95
|
+
}
|
|
96
|
+
export type FetchFn = (url: string) => Promise<ReferenceFetchResponse>;
|
|
97
|
+
export type PinnedFetchFn = typeof fetchWithPinnedAddress;
|
|
98
|
+
export interface ConjureDeps {
|
|
99
|
+
chat?: ChatCompletionFn;
|
|
100
|
+
fetchImpl?: FetchFn;
|
|
101
|
+
/** Pinned socket seam for deterministic production-path tests. */
|
|
102
|
+
fetchPinnedAddress?: PinnedFetchFn;
|
|
103
|
+
/** DNS seam for deterministic SSRF tests. Production uses `dns.lookup`. */
|
|
104
|
+
lookupAddresses?: AddressLookup;
|
|
105
|
+
/** Overall DNS + redirect/fetch deadline seam. Production defaults to 30 seconds. */
|
|
106
|
+
refUrlTimeoutMs?: number;
|
|
107
|
+
/** Prompt loader override (tests). Defaults to the real versioned loader (AC5). */
|
|
108
|
+
loadSystemPrompt?: () => LoadedPrompt;
|
|
109
|
+
}
|
|
110
|
+
/** Typed failure surfaced to the tool boundary (mapped to an MCP error result).
|
|
111
|
+
* One code: an empty reply is just one way output can be invalid, so it folds
|
|
112
|
+
* into `ERR_LLM_OUTPUT_INVALID` rather than being its own code (Copilot review —
|
|
113
|
+
* keep the public error surface to codes this file actually throws). */
|
|
114
|
+
export declare class ConjureError extends Error {
|
|
115
|
+
readonly code: "ERR_LLM_OUTPUT_INVALID";
|
|
116
|
+
readonly details?: Record<string, unknown> | undefined;
|
|
117
|
+
constructor(code: "ERR_LLM_OUTPUT_INVALID", message: string, details?: Record<string, unknown> | undefined);
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Truncate `text` so its UTF-8 encoding is at most `maxBytes` bytes, cutting on
|
|
121
|
+
* a codepoint boundary (Copilot review: `String.slice` cuts UTF-16 code units,
|
|
122
|
+
* so a non-ASCII page could still blow the byte cap). We encode, slice the byte
|
|
123
|
+
* buffer at the cap, then drop any trailing bytes that form a partial multi-byte
|
|
124
|
+
* sequence so the decoded result carries no U+FFFD replacement char and is
|
|
125
|
+
* guaranteed ≤ `maxBytes`.
|
|
126
|
+
*/
|
|
127
|
+
export declare function truncateUtf8(text: string, maxBytes: number): string;
|
|
128
|
+
/**
|
|
129
|
+
* Generate one component. Pure (AC9): validates + returns, never writes.
|
|
130
|
+
*
|
|
131
|
+
* Flow: resolve args → optionally fetch `refUrl` (AC7) → run the shared
|
|
132
|
+
* request/validate/retry loop (build messages +vision AC6, call the endpoint
|
|
133
|
+
* with the json_schema response_format AC4, validate against COMPONENT_SCHEMA
|
|
134
|
+
* AC8, retry ONCE on failure) → return
|
|
135
|
+
* `{ componentName, group, files, manifestEntry, usage }` (AC9) and log a
|
|
136
|
+
* per-call line (AC10). The loop itself lives in `component-response.ts`, shared
|
|
137
|
+
* with `refine` (M2-04).
|
|
138
|
+
*/
|
|
139
|
+
export declare function conjure(deps: ConjureDeps, args: unknown): Promise<ConjureResult>;
|
|
140
|
+
export declare function registerConjureTool(server: McpServer, deps?: ConjureDeps): void;
|
|
141
|
+
//# sourceMappingURL=conjure.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"conjure.d.ts","sourceRoot":"","sources":["../../src/tools/conjure.ts"],"names":[],"mappings":"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"}
|