@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 @@
|
|
|
1
|
+
{"version":3,"file":"delete_files.d.ts","sourceRoot":"","sources":["../../src/tools/delete_files.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAGH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAItD,eAAO,MAAM,sBAAsB,6BAA6B,CAAC;AACjE,eAAO,MAAM,wBAAwB,QAOA,CAAC;AAEtC;;;;;GAKG;AACH,QAAA,MAAM,qBAAqB;;;kBAKhB,CAAC;AAEZ,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAEpE,MAAM,WAAW,iBAAkB,SAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAChE,iDAAiD;IACjD,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,+DAA+D;IAC/D,aAAa,EAAE,MAAM,EAAE,CAAC;CACzB;AAED,MAAM,MAAM,oBAAoB,GAAG,kBAAkB,GAAG,sBAAsB,GAAG,cAAc,CAAC;AAEhG,iEAAiE;AACjE,qBAAa,gBAAiB,SAAQ,KAAK;IACzC,QAAQ,CAAC,IAAI,EAAE,oBAAoB,CAAC;IACpC,2DAA2D;IAC3D,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;gBAEX,IAAI,EAAE,oBAAoB,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM;CAMvE;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAI/D;AAgCD;;;;;;;GAOG;AACH,wBAAsB,WAAW,CAC/B,KAAK,EAAE,QAAQ,EACf,IAAI,EAAE,eAAe,GACpB,OAAO,CAAC,iBAAiB,CAAC,CA+F5B;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,QAAQ,GAAG,IAAI,CA+EhF"}
|
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP tool: delete_files (M1-09; re-plumbed onto KitStore in M1-14a-1a / DRO-540).
|
|
3
|
+
*
|
|
4
|
+
* The plan-gated companion to `write_files`. Every requested path must be
|
|
5
|
+
* covered by a glob in the plan's `deletes` list (locked at `plan` time) —
|
|
6
|
+
* otherwise the whole call is rejected with `PathOutsidePlanError` and nothing
|
|
7
|
+
* is touched. A path that is authorized but no longer exists is NOT an error:
|
|
8
|
+
* it is recorded in `notFoundPaths` and the call still succeeds. This is the
|
|
9
|
+
* "known-good failure to silently retry past" from the research report — e.g.
|
|
10
|
+
* deleting a floor-card component's `_preview/*.html` that was never generated
|
|
11
|
+
* remotely.
|
|
12
|
+
*
|
|
13
|
+
* Plan-gating stays here (planId → `deletes` globs is a genie concept, not a
|
|
14
|
+
* store concept). The physical removal is delegated to the injected
|
|
15
|
+
* `KitStore.deleteFile`, so the SAME verb deletes from a `LocalFsKitStore` (fs
|
|
16
|
+
* unlink) or a `GitHostKitStore` (contents-API DELETE on the default branch)
|
|
17
|
+
* with identical gating and result shaping.
|
|
18
|
+
*
|
|
19
|
+
* Input: { planId: string, paths: string[] }
|
|
20
|
+
* Output: { deletedPaths: string[], notFoundPaths: string[] }
|
|
21
|
+
*
|
|
22
|
+
* Ordering: paths are deleted longest-first so a file is always removed before
|
|
23
|
+
* any (shorter) prefix that names its containing directory — avoiding a
|
|
24
|
+
* spurious ENOTEMPTY. (Recursive directory delete is out of scope: paths must
|
|
25
|
+
* name files. A directory target surfaces as a hard `DeleteFailed` error.)
|
|
26
|
+
*/
|
|
27
|
+
import { isAbsolute } from "node:path";
|
|
28
|
+
import { z } from "zod";
|
|
29
|
+
import { withPlanGuard } from "../middleware/plan-guard.js";
|
|
30
|
+
import { getPlan, pathMatchesGlobs, PlanNotFoundError } from "../plans/index.js";
|
|
31
|
+
export const DELETE_FILES_TOOL_NAME = "mcp__genie__delete_files";
|
|
32
|
+
export const DELETE_FILES_DESCRIPTION = "Delete kit files authorized by a plan. Every path must match a glob in " +
|
|
33
|
+
"the plan's `deletes`; an out-of-plan path rejects the whole call. A path " +
|
|
34
|
+
"that no longer exists is not an error — it is returned in `notFoundPaths`. " +
|
|
35
|
+
"Paths must name files, not directories. Requires a planId from mcp__genie__plan " +
|
|
36
|
+
"whose `deletes` globs cover every path being removed. After deletion, call " +
|
|
37
|
+
"mcp__genie__preview to recompile the manifest so the grid and list_components " +
|
|
38
|
+
"stop exposing removed components.";
|
|
39
|
+
/**
|
|
40
|
+
* Authoritative argument schema. `.strict()` rejects unknown keys, and the
|
|
41
|
+
* per-item `.min(1)` guards against empty path strings. This is re-parsed
|
|
42
|
+
* inside `deleteFiles` so the same validation holds whether the tool is invoked
|
|
43
|
+
* over MCP or called directly (tests, future in-process callers).
|
|
44
|
+
*/
|
|
45
|
+
const deleteFilesArgsSchema = z
|
|
46
|
+
.object({
|
|
47
|
+
planId: z.string().min(1),
|
|
48
|
+
paths: z.array(z.string().min(1)).min(1),
|
|
49
|
+
})
|
|
50
|
+
.strict();
|
|
51
|
+
/** Structured, client-facing error for the delete_files tool. */
|
|
52
|
+
export class DeleteFilesError extends Error {
|
|
53
|
+
code;
|
|
54
|
+
/** The offending path, when the error is path-specific. */
|
|
55
|
+
path;
|
|
56
|
+
constructor(code, message, path) {
|
|
57
|
+
super(message);
|
|
58
|
+
this.name = "DeleteFilesError";
|
|
59
|
+
this.code = code;
|
|
60
|
+
this.path = path;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Sort paths so deeper/longer paths come first. Deleting a file before the
|
|
65
|
+
* (shorter) path that names its parent directory avoids ENOTEMPTY. Length ties
|
|
66
|
+
* fall back to `localeCompare` for a deterministic order. Pure — never mutates
|
|
67
|
+
* the caller's array.
|
|
68
|
+
*/
|
|
69
|
+
export function sortPathsLongestFirst(paths) {
|
|
70
|
+
return [...paths].sort((a, b) => b.length !== a.length ? b.length - a.length : a.localeCompare(b));
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* True if any `/`- or `\`-separated segment is `.` or `..`.
|
|
74
|
+
*
|
|
75
|
+
* `pathMatchesGlobs` checks the RAW request string, but a store resolves it
|
|
76
|
+
* against the kit root. Those two views can disagree: a dot-segment input like
|
|
77
|
+
* `allowed/../secret.txt` matches a glob such as `allowed/../*.txt` yet resolves
|
|
78
|
+
* to `kitRoot/secret.txt` — a file the plan never meant to authorize. Rejecting
|
|
79
|
+
* any dot-segment BEFORE both the glob check and the store call makes plan
|
|
80
|
+
* gating depend only on the literal authorized path.
|
|
81
|
+
*/
|
|
82
|
+
function hasDotSegment(path) {
|
|
83
|
+
return path.split(/[/\\]/).some((segment) => segment === "." || segment === "..");
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* True if a kitId is path-shaped (contains a separator or a `..`). The tool no
|
|
87
|
+
* longer holds a `kitsRoot`, so it cannot re-derive the on-disk kit root to
|
|
88
|
+
* prove containment; instead it rejects a traversal-shaped kitId outright.
|
|
89
|
+
*
|
|
90
|
+
* `plan` accepts `kitId: z.string().min(1)` with no traversal guard and stores
|
|
91
|
+
* it verbatim, so a plan authored with e.g. `kitId: ".."` could otherwise make
|
|
92
|
+
* a LocalFs store resolve a kit dir OUTSIDE the kits root (defense in depth,
|
|
93
|
+
* mirroring read_file's kitId check). A store guards internally too, but this
|
|
94
|
+
* keeps the whole-call rejection at the atomic pre-flight, before anything is
|
|
95
|
+
* deleted.
|
|
96
|
+
*/
|
|
97
|
+
function isPathShapedKitId(kitId) {
|
|
98
|
+
return kitId.includes("/") || kitId.includes("\\") || kitId.includes("..");
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Delete every `path` in `args.paths` from the plan's kit, subject to the
|
|
102
|
+
* plan's `deletes` allow-list.
|
|
103
|
+
*
|
|
104
|
+
* @param store The injected kit backend (M1-14a-1a / DRO-540). The concrete kit
|
|
105
|
+
* is `plan.kitId`; the physical removal is `store.deleteFile(plan.kitId, path)`
|
|
106
|
+
* — LocalFs unlink or git-host contents-API delete, behind one interface.
|
|
107
|
+
*/
|
|
108
|
+
export async function deleteFiles(store, args) {
|
|
109
|
+
// 1. Validate argument shape (AC2). A malformed planId / empty paths array is
|
|
110
|
+
// an InvalidArguments error, never a silent no-op.
|
|
111
|
+
let parsed;
|
|
112
|
+
try {
|
|
113
|
+
parsed = deleteFilesArgsSchema.parse(args);
|
|
114
|
+
}
|
|
115
|
+
catch (error) {
|
|
116
|
+
if (error instanceof z.ZodError) {
|
|
117
|
+
throw new DeleteFilesError("InvalidArguments", error.issues[0]?.message ??
|
|
118
|
+
"Invalid arguments: expected { planId: string, paths: string[] }.");
|
|
119
|
+
}
|
|
120
|
+
throw error;
|
|
121
|
+
}
|
|
122
|
+
// 2. Resolve the plan. Unknown / expired / malformed-UUID planIds throw
|
|
123
|
+
// PlanNotFoundError (surfaced to the client, not swallowed here).
|
|
124
|
+
const plan = await getPlan(parsed.planId);
|
|
125
|
+
// 2a. Defense in depth: a plan authored with a traversal-shaped kitId (e.g.
|
|
126
|
+
// "..") could make a LocalFs store resolve a kit dir outside the kits
|
|
127
|
+
// root. As the first destructive consumer, reject it before deleting
|
|
128
|
+
// anything (mirrors read_file's kitId guard).
|
|
129
|
+
if (isPathShapedKitId(plan.kitId)) {
|
|
130
|
+
throw new DeleteFilesError("PathOutsidePlanError", `Plan kitId "${plan.kitId}" is not a valid kit identifier.`, plan.kitId);
|
|
131
|
+
}
|
|
132
|
+
// 3. De-duplicate while preserving first-seen order — a path repeated in the
|
|
133
|
+
// request must not appear twice in the result, nor in both result arrays.
|
|
134
|
+
const uniquePaths = [...new Set(parsed.paths)];
|
|
135
|
+
// 4. Atomic pre-flight (AC3). EVERY path must both (a) match a `deletes` glob
|
|
136
|
+
// and (b) stay inside the kit root. If any path fails, throw before
|
|
137
|
+
// deleting anything — so an out-of-plan path can never take an in-plan
|
|
138
|
+
// sibling down with it. The containment check is purely lexical now (the
|
|
139
|
+
// tool holds no kits root): a relative path with no `.`/`..` segment can
|
|
140
|
+
// never escape the kit root, and an absolute path always does.
|
|
141
|
+
for (const path of uniquePaths) {
|
|
142
|
+
// 4a. Normalize-first defense: a `.`/`..` segment lets the raw-string glob
|
|
143
|
+
// check and the resolved delete target disagree (see hasDotSegment).
|
|
144
|
+
if (hasDotSegment(path)) {
|
|
145
|
+
throw new DeleteFilesError("PathOutsidePlanError", `Path "${path}" contains a "." or ".." segment.`, path);
|
|
146
|
+
}
|
|
147
|
+
// 4b. An absolute path escapes any kit root by definition.
|
|
148
|
+
if (isAbsolute(path)) {
|
|
149
|
+
throw new DeleteFilesError("PathOutsidePlanError", `Path "${path}" is absolute and resolves outside the kit root.`, path);
|
|
150
|
+
}
|
|
151
|
+
if (!pathMatchesGlobs(path, plan.deletes)) {
|
|
152
|
+
throw new DeleteFilesError("PathOutsidePlanError", `Path "${path}" is not covered by the plan's deletes.`, path);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
// 5. Delete longest-first (files before their containing directories), via the
|
|
156
|
+
// injected store. `{ existed: false }` is the AC5 silent-retry case; a hard
|
|
157
|
+
// store error (a directory target, permission denied, …) fails the whole
|
|
158
|
+
// call (AC6) rather than being swallowed.
|
|
159
|
+
const deleted = new Set();
|
|
160
|
+
const notFound = new Set();
|
|
161
|
+
for (const path of sortPathsLongestFirst(uniquePaths)) {
|
|
162
|
+
try {
|
|
163
|
+
const { existed } = await store.deleteFile(plan.kitId, path);
|
|
164
|
+
if (existed) {
|
|
165
|
+
deleted.add(path);
|
|
166
|
+
}
|
|
167
|
+
else {
|
|
168
|
+
notFound.add(path); // AC5 — authorized but absent: a non-error.
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
catch (error) {
|
|
172
|
+
const code = error instanceof Error && "code" in error ? String(error.code) : "unknown";
|
|
173
|
+
throw new DeleteFilesError("DeleteFailed", `Failed to delete "${path}": ${code}.`, path);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
// 6. Report in the original (de-duplicated) request order.
|
|
177
|
+
return {
|
|
178
|
+
deletedPaths: uniquePaths.filter((path) => deleted.has(path)),
|
|
179
|
+
notFoundPaths: uniquePaths.filter((path) => notFound.has(path)),
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Register the `mcp__genie__delete_files` tool.
|
|
184
|
+
*
|
|
185
|
+
* AC1: Tool name `mcp__genie__delete_files`.
|
|
186
|
+
* AC2: Input `{ planId: string, paths: string[] }`.
|
|
187
|
+
* AC3: Each path must match a plan `deletes` glob, else PathOutsidePlanError.
|
|
188
|
+
* AC4: Returns `deletedPaths` — what was actually removed.
|
|
189
|
+
* AC5: A missing path is a non-error, recorded in `notFoundPaths`.
|
|
190
|
+
* AC6: Other errors (permission denied, directory target, …) fail the call.
|
|
191
|
+
*
|
|
192
|
+
* Plan-boundary validation (planId presence/existence/expiry, path-vs-
|
|
193
|
+
* `deletes`-glob) runs through the M1-13 plan-guard middleware
|
|
194
|
+
* (`../middleware/plan-guard.ts`) so the write/delete verbs share one
|
|
195
|
+
* identical check. Delete-tool-specific validation (InvalidArguments shape,
|
|
196
|
+
* kitId containment, dot-segment rejection, unlink failure taxonomy) stays
|
|
197
|
+
* in `deleteFiles` itself — the guard is intentionally tool-agnostic about
|
|
198
|
+
* those.
|
|
199
|
+
*/
|
|
200
|
+
export function registerDeleteFilesTool(server, store) {
|
|
201
|
+
server.registerTool(DELETE_FILES_TOOL_NAME, {
|
|
202
|
+
title: "Delete files",
|
|
203
|
+
description: DELETE_FILES_DESCRIPTION,
|
|
204
|
+
inputSchema: {
|
|
205
|
+
planId: z
|
|
206
|
+
.string()
|
|
207
|
+
.describe("The planId returned by mcp__genie__plan whose `deletes` authorize these paths."),
|
|
208
|
+
paths: z
|
|
209
|
+
.array(z.string())
|
|
210
|
+
.describe("Kit-root-relative file paths to delete; each must match a `deletes` glob."),
|
|
211
|
+
},
|
|
212
|
+
// `deletedPaths` is the contract's required field (RFC §9.8); `notFoundPaths`
|
|
213
|
+
// is always populated but declared optional so `required` stays `["deletedPaths"]`.
|
|
214
|
+
outputSchema: {
|
|
215
|
+
deletedPaths: z.array(z.string()),
|
|
216
|
+
notFoundPaths: z.array(z.string()).optional(),
|
|
217
|
+
},
|
|
218
|
+
},
|
|
219
|
+
// M1-13 plan-vs-write guard (DRO-239). The middleware runs BEFORE the
|
|
220
|
+
// delete handler, catching PlanNotFoundError and out-of-plan paths and
|
|
221
|
+
// returning the canonical JSON-RPC `-32602` shape `{ code, message,
|
|
222
|
+
// data: { reason, planId?, path? } }`. The delete-side path-outside-
|
|
223
|
+
// plan branch below is now only reachable for a direct in-process caller
|
|
224
|
+
// (see the "deleteFiles — core behaviour" test suite), which bypasses
|
|
225
|
+
// MCP registration and this middleware with it — kept as defense-in-
|
|
226
|
+
// depth so removing the check from `deleteFiles` doesn't silently open
|
|
227
|
+
// that path for those callers.
|
|
228
|
+
withPlanGuard({ mode: "deletes", pathsKey: "paths" }, async (args) => {
|
|
229
|
+
try {
|
|
230
|
+
const result = await deleteFiles(store, args);
|
|
231
|
+
return {
|
|
232
|
+
content: [{ type: "text", text: JSON.stringify(result) }],
|
|
233
|
+
structuredContent: result,
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
catch (error) {
|
|
237
|
+
if (error instanceof DeleteFilesError) {
|
|
238
|
+
return {
|
|
239
|
+
isError: true,
|
|
240
|
+
content: [
|
|
241
|
+
{
|
|
242
|
+
type: "text",
|
|
243
|
+
text: JSON.stringify({
|
|
244
|
+
error: error.code,
|
|
245
|
+
message: error.message,
|
|
246
|
+
...(error.path !== undefined ? { path: error.path } : {}),
|
|
247
|
+
}),
|
|
248
|
+
},
|
|
249
|
+
],
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
if (error instanceof PlanNotFoundError) {
|
|
253
|
+
// Ordinarily unreachable at the wire level — the M1-13 plan-guard
|
|
254
|
+
// middleware (above) catches PlanNotFoundError first. Kept as
|
|
255
|
+
// belt-and-suspenders for a future refactor that bypasses the
|
|
256
|
+
// guard or a race where a plan expires between the guard's
|
|
257
|
+
// getPlan and the core's getPlan.
|
|
258
|
+
return {
|
|
259
|
+
isError: true,
|
|
260
|
+
content: [
|
|
261
|
+
{
|
|
262
|
+
type: "text",
|
|
263
|
+
text: JSON.stringify({
|
|
264
|
+
error: "PlanNotFoundError",
|
|
265
|
+
message: error.message,
|
|
266
|
+
planId: error.planId,
|
|
267
|
+
}),
|
|
268
|
+
},
|
|
269
|
+
],
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
throw error; // unexpected — bubble up as an MCP internal error
|
|
273
|
+
}
|
|
274
|
+
}));
|
|
275
|
+
}
|
|
276
|
+
//# sourceMappingURL=delete_files.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"delete_files.js","sourceRoot":"","sources":["../../src/tools/delete_files.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { ProjectStore } from "./create_project.js";
|
|
4
|
+
export declare const DELETE_PROJECT_TOOL_NAME = "mcp__genie__delete_project";
|
|
5
|
+
export declare const ERR_PROJECT_READONLY = "ERR_PROJECT_READONLY";
|
|
6
|
+
export declare const ERR_INVALID_PROJECT_ID = "ERR_INVALID_PROJECT_ID";
|
|
7
|
+
declare const deleteProjectArgsSchema: z.ZodObject<{
|
|
8
|
+
projectId: z.ZodString;
|
|
9
|
+
}, z.core.$strict>;
|
|
10
|
+
export type DeleteProjectArgs = z.infer<typeof deleteProjectArgsSchema>;
|
|
11
|
+
export interface DeleteProjectResult extends Record<string, unknown> {
|
|
12
|
+
deletedProjectId: string;
|
|
13
|
+
_meta?: {
|
|
14
|
+
warnings?: string[];
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
export declare class DeleteProjectError extends Error {
|
|
18
|
+
readonly code: string;
|
|
19
|
+
constructor(code: string, message: string);
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Delete a project through the injected `ProjectStore` (M1-14a-1 / DRO-531 —
|
|
23
|
+
* the `delete_project` store-injection re-plumb).
|
|
24
|
+
*
|
|
25
|
+
* Previously this reached into the filesystem directly via a raw `projectsRoot`
|
|
26
|
+
* path + `node:fs`; it now routes through the same `ProjectStore` instance the
|
|
27
|
+
* rest of the project family (`create_project`/`get_project`/`bind_kit`/
|
|
28
|
+
* `conjure_screen`) already uses, so a non-LocalFs backend injected into
|
|
29
|
+
* `createServer` reaches this verb too. Persistence + read-only policy live in
|
|
30
|
+
* `ProjectStore.deleteProject`; this function owns only the tool's arg-shape
|
|
31
|
+
* validation and result/error shaping.
|
|
32
|
+
*
|
|
33
|
+
* Contract (unchanged from the pre-seam tool):
|
|
34
|
+
* - Malformed / traversal `projectId` → `ERR_INVALID_PROJECT_ID`, nothing
|
|
35
|
+
* touched (the Zod schema rejects it before the store is reached).
|
|
36
|
+
* - Missing project → success with an idempotent "already deleted" warning.
|
|
37
|
+
* - Read-only project → `ERR_PROJECT_READONLY`, nothing removed.
|
|
38
|
+
* - Otherwise the project tree is removed and `deletedProjectId` returned.
|
|
39
|
+
*/
|
|
40
|
+
export declare function deleteProject(store: ProjectStore, args: DeleteProjectArgs): Promise<DeleteProjectResult>;
|
|
41
|
+
export declare function registerDeleteProjectTool(server: McpServer, store: ProjectStore): void;
|
|
42
|
+
export {};
|
|
43
|
+
//# sourceMappingURL=delete_project.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"delete_project.d.ts","sourceRoot":"","sources":["../../src/tools/delete_project.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAsB,YAAY,EAAqB,MAAM,qBAAqB,CAAC;AAE1F,eAAO,MAAM,wBAAwB,+BAA+B,CAAC;AAErE,eAAO,MAAM,oBAAoB,yBAAyB,CAAC;AAC3D,eAAO,MAAM,sBAAsB,2BAA2B,CAAC;AAS/D,QAAA,MAAM,uBAAuB;;kBAIlB,CAAC;AAEZ,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAC;AAExE,MAAM,WAAW,mBAAoB,SAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAClE,gBAAgB,EAAE,MAAM,CAAC;IACzB,KAAK,CAAC,EAAE;QACN,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;KACrB,CAAC;CACH;AAED,qBAAa,kBAAmB,SAAQ,KAAK;IAC3C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;gBAEV,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;CAK1C;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,aAAa,CACjC,KAAK,EAAE,YAAY,EACnB,IAAI,EAAE,iBAAiB,GACtB,OAAO,CAAC,mBAAmB,CAAC,CAmC9B;AAED,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,YAAY,GAAG,IAAI,CA8CtF"}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { PROJECT_ID_PATTERN, ProjectStore, ProjectStoreError } from "./create_project.js";
|
|
3
|
+
export const DELETE_PROJECT_TOOL_NAME = "mcp__genie__delete_project";
|
|
4
|
+
export const ERR_PROJECT_READONLY = "ERR_PROJECT_READONLY";
|
|
5
|
+
export const ERR_INVALID_PROJECT_ID = "ERR_INVALID_PROJECT_ID";
|
|
6
|
+
const projectIdSchema = z
|
|
7
|
+
.string()
|
|
8
|
+
.regex(PROJECT_ID_PATTERN, "projectId must be a 3-64 character slug containing only lowercase letters, numbers, and hyphens.");
|
|
9
|
+
const deleteProjectArgsSchema = z
|
|
10
|
+
.object({
|
|
11
|
+
projectId: projectIdSchema,
|
|
12
|
+
})
|
|
13
|
+
.strict();
|
|
14
|
+
export class DeleteProjectError extends Error {
|
|
15
|
+
code;
|
|
16
|
+
constructor(code, message) {
|
|
17
|
+
super(message);
|
|
18
|
+
this.name = "DeleteProjectError";
|
|
19
|
+
this.code = code;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Delete a project through the injected `ProjectStore` (M1-14a-1 / DRO-531 —
|
|
24
|
+
* the `delete_project` store-injection re-plumb).
|
|
25
|
+
*
|
|
26
|
+
* Previously this reached into the filesystem directly via a raw `projectsRoot`
|
|
27
|
+
* path + `node:fs`; it now routes through the same `ProjectStore` instance the
|
|
28
|
+
* rest of the project family (`create_project`/`get_project`/`bind_kit`/
|
|
29
|
+
* `conjure_screen`) already uses, so a non-LocalFs backend injected into
|
|
30
|
+
* `createServer` reaches this verb too. Persistence + read-only policy live in
|
|
31
|
+
* `ProjectStore.deleteProject`; this function owns only the tool's arg-shape
|
|
32
|
+
* validation and result/error shaping.
|
|
33
|
+
*
|
|
34
|
+
* Contract (unchanged from the pre-seam tool):
|
|
35
|
+
* - Malformed / traversal `projectId` → `ERR_INVALID_PROJECT_ID`, nothing
|
|
36
|
+
* touched (the Zod schema rejects it before the store is reached).
|
|
37
|
+
* - Missing project → success with an idempotent "already deleted" warning.
|
|
38
|
+
* - Read-only project → `ERR_PROJECT_READONLY`, nothing removed.
|
|
39
|
+
* - Otherwise the project tree is removed and `deletedProjectId` returned.
|
|
40
|
+
*/
|
|
41
|
+
export async function deleteProject(store, args) {
|
|
42
|
+
let parsed;
|
|
43
|
+
try {
|
|
44
|
+
parsed = deleteProjectArgsSchema.parse(args);
|
|
45
|
+
}
|
|
46
|
+
catch (error) {
|
|
47
|
+
if (error instanceof z.ZodError) {
|
|
48
|
+
const issue = error.issues[0];
|
|
49
|
+
throw new DeleteProjectError(ERR_INVALID_PROJECT_ID, issue?.message ??
|
|
50
|
+
"projectId must be a 3-64 character slug containing only lowercase letters, numbers, and hyphens.");
|
|
51
|
+
}
|
|
52
|
+
throw error;
|
|
53
|
+
}
|
|
54
|
+
try {
|
|
55
|
+
const { existed } = await store.deleteProject(parsed.projectId);
|
|
56
|
+
if (!existed) {
|
|
57
|
+
return {
|
|
58
|
+
deletedProjectId: parsed.projectId,
|
|
59
|
+
_meta: {
|
|
60
|
+
warnings: [`Project "${parsed.projectId}" does not exist or was already deleted.`],
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
return { deletedProjectId: parsed.projectId };
|
|
65
|
+
}
|
|
66
|
+
catch (error) {
|
|
67
|
+
// Translate the store's error taxonomy onto the tool's own so both direct
|
|
68
|
+
// callers and the MCP wrapper below keep branching on `DeleteProjectError`.
|
|
69
|
+
if (error instanceof ProjectStoreError && error.code === ERR_PROJECT_READONLY) {
|
|
70
|
+
throw new DeleteProjectError(ERR_PROJECT_READONLY, error.message);
|
|
71
|
+
}
|
|
72
|
+
throw error;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
export function registerDeleteProjectTool(server, store) {
|
|
76
|
+
server.registerTool(DELETE_PROJECT_TOOL_NAME, {
|
|
77
|
+
title: "Delete project",
|
|
78
|
+
description: "Delete a workspace or blueprint project. Deleting a blueprint does not delete derived workspaces. " +
|
|
79
|
+
"Irreversible — confirm via get_project first if you need to check its bindings or screens before removing it.",
|
|
80
|
+
inputSchema: {
|
|
81
|
+
projectId: projectIdSchema,
|
|
82
|
+
},
|
|
83
|
+
outputSchema: {
|
|
84
|
+
deletedProjectId: z.string(),
|
|
85
|
+
_meta: z
|
|
86
|
+
.object({
|
|
87
|
+
warnings: z.array(z.string()).optional(),
|
|
88
|
+
})
|
|
89
|
+
.optional(),
|
|
90
|
+
},
|
|
91
|
+
}, async (args) => {
|
|
92
|
+
try {
|
|
93
|
+
const result = await deleteProject(store, args);
|
|
94
|
+
return {
|
|
95
|
+
content: [{ type: "text", text: JSON.stringify(result) }],
|
|
96
|
+
structuredContent: result,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
catch (error) {
|
|
100
|
+
if (error instanceof DeleteProjectError) {
|
|
101
|
+
return {
|
|
102
|
+
isError: true,
|
|
103
|
+
content: [
|
|
104
|
+
{
|
|
105
|
+
type: "text",
|
|
106
|
+
text: JSON.stringify({
|
|
107
|
+
code: error.code,
|
|
108
|
+
message: error.message,
|
|
109
|
+
}),
|
|
110
|
+
},
|
|
111
|
+
],
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
throw error;
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
//# sourceMappingURL=delete_project.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"delete_project.js","sourceRoot":"","sources":["../../src/tools/delete_project.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import type { KitStore } from "../store/interface.js";
|
|
4
|
+
export declare const GET_KIT_TOOL_NAME = "mcp__genie__get_kit";
|
|
5
|
+
/** Shape every `kitId` produced by `buildKitId` (create_kit.ts) satisfies: a
|
|
6
|
+
* lowercase slug plus a 6-char hex suffix. Exported so other tools (e.g.
|
|
7
|
+
* `bind_kit`) validate against the exact same pattern instead of redeclaring it. */
|
|
8
|
+
export declare const KIT_ID_PATTERN: RegExp;
|
|
9
|
+
declare const getKitResultSchema: z.ZodObject<{
|
|
10
|
+
id: z.ZodString;
|
|
11
|
+
name: z.ZodString;
|
|
12
|
+
type: z.ZodLiteral<"GENIE_KIT">;
|
|
13
|
+
createdAt: z.ZodString;
|
|
14
|
+
}, z.core.$strict>;
|
|
15
|
+
export type GetKitResult = z.infer<typeof getKitResultSchema>;
|
|
16
|
+
export declare class ProjectNotFoundError extends Error {
|
|
17
|
+
readonly kitId: string;
|
|
18
|
+
constructor(kitId: string);
|
|
19
|
+
}
|
|
20
|
+
export declare class WrongProjectTypeError extends Error {
|
|
21
|
+
readonly kitId: string;
|
|
22
|
+
readonly actualType: string;
|
|
23
|
+
constructor(kitId: string, actualType: string);
|
|
24
|
+
}
|
|
25
|
+
export declare function registerGetKitTool(server: McpServer, store: KitStore): void;
|
|
26
|
+
export declare function getKit(store: KitStore, args: unknown): Promise<GetKitResult>;
|
|
27
|
+
export {};
|
|
28
|
+
//# sourceMappingURL=get_kit.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get_kit.d.ts","sourceRoot":"","sources":["../../src/tools/get_kit.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEzE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAW,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAG/D,eAAO,MAAM,iBAAiB,wBAAwB,CAAC;AAEvD;;oFAEoF;AACpF,eAAO,MAAM,cAAc,QAAsB,CAAC;AAQlD,QAAA,MAAM,kBAAkB;;;;;kBAOb,CAAC;AAEZ,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAE9D,qBAAa,oBAAqB,SAAQ,KAAK;IACjC,QAAQ,CAAC,KAAK,EAAE,MAAM;gBAAb,KAAK,EAAE,MAAM;CAInC;AAED,qBAAa,qBAAsB,SAAQ,KAAK;IAE5C,QAAQ,CAAC,KAAK,EAAE,MAAM;IACtB,QAAQ,CAAC,UAAU,EAAE,MAAM;gBADlB,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,MAAM;CAK9B;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,QAAQ,GAAG,IAAI,CAqC3E;AAED,wBAAsB,MAAM,CAAC,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,YAAY,CAAC,CAoBlF"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { ErrorCode, McpError } from "@modelcontextprotocol/sdk/types.js";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { NotFoundError, KIT_TYPE } from "../store/interface.js";
|
|
4
|
+
export const GET_KIT_TOOL_NAME = "mcp__genie__get_kit";
|
|
5
|
+
/** Shape every `kitId` produced by `buildKitId` (create_kit.ts) satisfies: a
|
|
6
|
+
* lowercase slug plus a 6-char hex suffix. Exported so other tools (e.g.
|
|
7
|
+
* `bind_kit`) validate against the exact same pattern instead of redeclaring it. */
|
|
8
|
+
export const KIT_ID_PATTERN = /^[a-z0-9-]{3,64}$/;
|
|
9
|
+
const getKitArgsSchema = z
|
|
10
|
+
.object({
|
|
11
|
+
kitId: z.string().regex(KIT_ID_PATTERN),
|
|
12
|
+
})
|
|
13
|
+
.strict();
|
|
14
|
+
const getKitResultSchema = z
|
|
15
|
+
.object({
|
|
16
|
+
id: z.string(),
|
|
17
|
+
name: z.string(),
|
|
18
|
+
type: z.literal(KIT_TYPE),
|
|
19
|
+
createdAt: z.string(),
|
|
20
|
+
})
|
|
21
|
+
.strict();
|
|
22
|
+
export class ProjectNotFoundError extends Error {
|
|
23
|
+
kitId;
|
|
24
|
+
constructor(kitId) {
|
|
25
|
+
super(`Project "${kitId}" was not found.`);
|
|
26
|
+
this.kitId = kitId;
|
|
27
|
+
this.name = "ProjectNotFoundError";
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
export class WrongProjectTypeError extends Error {
|
|
31
|
+
kitId;
|
|
32
|
+
actualType;
|
|
33
|
+
constructor(kitId, actualType) {
|
|
34
|
+
super(`Project "${kitId}" is "${actualType}", not "${KIT_TYPE}".`);
|
|
35
|
+
this.kitId = kitId;
|
|
36
|
+
this.actualType = actualType;
|
|
37
|
+
this.name = "WrongProjectTypeError";
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
export function registerGetKitTool(server, store) {
|
|
41
|
+
server.registerTool(GET_KIT_TOOL_NAME, {
|
|
42
|
+
title: "Get kit",
|
|
43
|
+
description: "Return metadata for one writable UI kit and verify the kitId resolves to a GENIE_KIT. " +
|
|
44
|
+
"Useful to confirm a kitId (e.g. from list_kits) is valid and writable before " +
|
|
45
|
+
"generating or binding against it.",
|
|
46
|
+
inputSchema: {
|
|
47
|
+
kitId: z.string().regex(KIT_ID_PATTERN),
|
|
48
|
+
},
|
|
49
|
+
outputSchema: {
|
|
50
|
+
id: z.string(),
|
|
51
|
+
name: z.string(),
|
|
52
|
+
type: z.literal(KIT_TYPE),
|
|
53
|
+
createdAt: z.string(),
|
|
54
|
+
},
|
|
55
|
+
}, async (args) => {
|
|
56
|
+
try {
|
|
57
|
+
const result = await getKit(store, args);
|
|
58
|
+
return {
|
|
59
|
+
content: [{ type: "text", text: JSON.stringify(result) }],
|
|
60
|
+
structuredContent: result,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
catch (error) {
|
|
64
|
+
if (error instanceof ProjectNotFoundError || error instanceof WrongProjectTypeError) {
|
|
65
|
+
throw new McpError(ErrorCode.InvalidParams, error.name, {
|
|
66
|
+
code: error.name,
|
|
67
|
+
message: error.message,
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
throw error;
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
export async function getKit(store, args) {
|
|
75
|
+
const { kitId } = getKitArgsSchema.parse(args);
|
|
76
|
+
let kit;
|
|
77
|
+
try {
|
|
78
|
+
kit = await store.getKit(kitId);
|
|
79
|
+
}
|
|
80
|
+
catch (error) {
|
|
81
|
+
if (error instanceof NotFoundError)
|
|
82
|
+
throw new ProjectNotFoundError(kitId);
|
|
83
|
+
throw error;
|
|
84
|
+
}
|
|
85
|
+
if (kit.type !== KIT_TYPE) {
|
|
86
|
+
throw new WrongProjectTypeError(kitId, kit.type);
|
|
87
|
+
}
|
|
88
|
+
return getKitResultSchema.parse({
|
|
89
|
+
id: kit.id,
|
|
90
|
+
name: kit.name,
|
|
91
|
+
type: KIT_TYPE,
|
|
92
|
+
createdAt: kit.createdAt,
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=get_kit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get_kit.js","sourceRoot":"","sources":["../../src/tools/get_kit.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP tool: get_project (M1-17).
|
|
3
|
+
*
|
|
4
|
+
* Metadata read for a single workspace or blueprint project manifest.
|
|
5
|
+
* Blueprints are returned through the same shape (`kind: "blueprint"`) — there is
|
|
6
|
+
* no special-case tool family for them (AC4).
|
|
7
|
+
*
|
|
8
|
+
* Input: { projectId: string }
|
|
9
|
+
* Output: ProjectSummary & { screens: ProjectScreen[]; sourceBlueprintId?: string }
|
|
10
|
+
*/
|
|
11
|
+
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
12
|
+
import { z } from "zod";
|
|
13
|
+
import type { ProjectDetail } from "./create_project.js";
|
|
14
|
+
export declare const GET_PROJECT_TOOL_NAME = "mcp__genie__get_project";
|
|
15
|
+
/** Error code raised when `projectId` does not resolve to an existing project. */
|
|
16
|
+
export declare const ERR_PROJECT_NOT_FOUND: "ERR_PROJECT_NOT_FOUND";
|
|
17
|
+
declare const getProjectArgsSchema: z.ZodObject<{
|
|
18
|
+
projectId: z.ZodString;
|
|
19
|
+
}, z.core.$strict>;
|
|
20
|
+
export type GetProjectArgs = z.infer<typeof getProjectArgsSchema>;
|
|
21
|
+
/**
|
|
22
|
+
* Narrow port `get_project` depends on — anything that can resolve a single
|
|
23
|
+
* project's full detail. `ProjectStore` (from `create_project.ts`) satisfies this
|
|
24
|
+
* structurally, matching the `ProjectListStore` pattern already used by `list_projects`.
|
|
25
|
+
*/
|
|
26
|
+
export interface ProjectGetStore {
|
|
27
|
+
getProject(projectId: string): Promise<ProjectDetail>;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Validate args and fetch project detail. Exported standalone (bypassing the MCP
|
|
31
|
+
* transport) so programmatic/direct callers get the same validation defense-in-depth
|
|
32
|
+
* as `list_files`' `listFiles()` and `get_kit`'s `getKit()`.
|
|
33
|
+
*/
|
|
34
|
+
export declare function getProject(store: ProjectGetStore, args: unknown): Promise<ProjectDetail>;
|
|
35
|
+
export declare function registerGetProjectTool(server: McpServer, store: ProjectGetStore): void;
|
|
36
|
+
export {};
|
|
37
|
+
//# sourceMappingURL=get_project.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get_project.d.ts","sourceRoot":"","sources":["../../src/tools/get_project.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAOxB,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEzD,eAAO,MAAM,qBAAqB,4BAA4B,CAAC;AAE/D,kFAAkF;AAClF,eAAO,MAAM,qBAAqB,EAAG,uBAAgC,CAAC;AAStE,QAAA,MAAM,oBAAoB;;kBAIf,CAAC;AAEZ,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAYlE;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC9B,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;CACvD;AAED;;;;GAIG;AACH,wBAAsB,UAAU,CAC9B,KAAK,EAAE,eAAe,EACtB,IAAI,EAAE,OAAO,GACZ,OAAO,CAAC,aAAa,CAAC,CAIxB;AAED,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,eAAe,GAAG,IAAI,CA0CtF"}
|