@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":"secrets.d.ts","sourceRoot":"","sources":["../../src/config/secrets.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAMH,gFAAgF;AAChF,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;EAKrB,CAAC;AAEX,wDAAwD;AACxD,MAAM,MAAM,SAAS,GAAG,CAAC,OAAO,kBAAkB,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC;AAEnE,mEAAmE;AACnE,eAAO,MAAM,iBAAiB,KAAK,CAAC;AAIpC;;;;GAIG;AACH,qBAAa,qBAAsB,SAAQ,KAAK;aAClB,QAAQ,EAAE,SAAS,MAAM,EAAE;gBAA3B,QAAQ,EAAE,SAAS,MAAM,EAAE;CAIxD;AAID;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAazE;AAID,wEAAwE;AACxE,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,SAAS,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,kBAAkB;IACjC,2DAA2D;IAC3D,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,yEAAyE;IACzE,IAAI,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACzB;;;OAGG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,iFAAiF;IACjF,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IACpC,oEAAoE;IACpE,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;CAC/C;AAED;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CAAC,OAAO,GAAE,kBAAuB,GAAG,YAAY,EAAE,CA8C5E;AAID;;;;GAIG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,SAAS,YAAY,EAAE,EAC/B,KAAK,GAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAA2C,GACnE,IAAI,CAON"}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Secret loading (M5-03 / DRO-275) — no plaintext secrets at rest.
|
|
3
|
+
*
|
|
4
|
+
* Every secret genie uses is read only from env vars or, when
|
|
5
|
+
* `--secrets-from <path>` is passed (e.g. a mounted Docker/Kubernetes
|
|
6
|
+
* secret), from an owner-only `KEY=VALUE`-per-line file at that path (AC6).
|
|
7
|
+
* Files with group/other permission bits are rejected before reading. Nothing
|
|
8
|
+
* secret is ever hardcoded, and this module never writes a secret value to
|
|
9
|
+
* disk, argv, or a log line.
|
|
10
|
+
*
|
|
11
|
+
* Bootstrap contract (AC2): `loadSecrets()` throws `SecretValidationError`
|
|
12
|
+
* with one message per problem when any *required* secret is:
|
|
13
|
+
* - missing (unset, and absent from a `--secrets-from` file if provided);
|
|
14
|
+
* - shorter than its required minimum length;
|
|
15
|
+
* - present verbatim anywhere in `process.argv` (a value passed as a CLI
|
|
16
|
+
* flag is visible to `ps`/shell history on every other local user, so a
|
|
17
|
+
* secret leaking into argv is treated as fatal, not just discouraged).
|
|
18
|
+
*
|
|
19
|
+
* AC3: `auditLoadedSecrets` logs which secret *names* were loaded (never
|
|
20
|
+
* values) as a single structured line on process.stderr, mirroring the
|
|
21
|
+
* stdout-is-JSON-RPC convention documented in `llm/client.ts`.
|
|
22
|
+
*/
|
|
23
|
+
import { readFileSync, statSync } from "node:fs";
|
|
24
|
+
// ─── Known secrets ───────────────────────────────────────────────────────────
|
|
25
|
+
/** Every secret env var genie recognises, and whether it's required to boot. */
|
|
26
|
+
export const SECRET_DEFINITIONS = [
|
|
27
|
+
{ key: "GENIE_LLM_API_KEY", required: true, minLength: 16 },
|
|
28
|
+
{ key: "OAUTH_HS256_KEY", required: true, minLength: 32 },
|
|
29
|
+
{ key: "GENIE_GIT_TOKEN", required: false, minLength: 0 },
|
|
30
|
+
{ key: "OAUTH_CLIENT_SECRET", required: false, minLength: 0 },
|
|
31
|
+
];
|
|
32
|
+
/** Minimum acceptable length for a required secret value (AC2). */
|
|
33
|
+
export const MIN_SECRET_LENGTH = 16;
|
|
34
|
+
// ─── Errors ──────────────────────────────────────────────────────────────────
|
|
35
|
+
/**
|
|
36
|
+
* Thrown by `loadSecrets` when bootstrap validation fails. Aggregates every
|
|
37
|
+
* problem found (not just the first) so a misconfigured deployment gets the
|
|
38
|
+
* full picture in one failure rather than fixing issues one at a time.
|
|
39
|
+
*/
|
|
40
|
+
export class SecretValidationError extends Error {
|
|
41
|
+
problems;
|
|
42
|
+
constructor(problems) {
|
|
43
|
+
super(`Secret validation failed:\n - ${problems.join("\n - ")}`);
|
|
44
|
+
this.problems = problems;
|
|
45
|
+
this.name = "SecretValidationError";
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
// ─── Secrets-from-file parsing ───────────────────────────────────────────────
|
|
49
|
+
/**
|
|
50
|
+
* Parse a `KEY=VALUE`-per-line secrets file (AC6), e.g. a mounted secret
|
|
51
|
+
* mounted at `/run/secrets/genie`. Blank lines and `#`-prefixed comments are
|
|
52
|
+
* skipped. Values are not trimmed of surrounding quotes — the file is
|
|
53
|
+
* expected to hold raw values, matching Docker/Kubernetes secret conventions
|
|
54
|
+
* (unlike a shell-sourced `.env`, no quoting/escaping is applied).
|
|
55
|
+
*/
|
|
56
|
+
export function parseSecretsFile(contents) {
|
|
57
|
+
const out = {};
|
|
58
|
+
for (const rawLine of contents.split("\n")) {
|
|
59
|
+
const line = rawLine.trim();
|
|
60
|
+
if (line === "" || line.startsWith("#"))
|
|
61
|
+
continue;
|
|
62
|
+
const eq = line.indexOf("=");
|
|
63
|
+
if (eq === -1)
|
|
64
|
+
continue;
|
|
65
|
+
const key = line.slice(0, eq).trim();
|
|
66
|
+
const value = line.slice(eq + 1);
|
|
67
|
+
if (key === "")
|
|
68
|
+
continue;
|
|
69
|
+
out[key] = value;
|
|
70
|
+
}
|
|
71
|
+
return out;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Load and validate every known secret (AC1/AC2). Reads from env only,
|
|
75
|
+
* optionally overlaid by a `--secrets-from` file (AC6). Throws
|
|
76
|
+
* `SecretValidationError` if any *required* secret is missing, too short, or
|
|
77
|
+
* leaked into argv verbatim.
|
|
78
|
+
*
|
|
79
|
+
* Returns only the secrets that were actually present (optional secrets are
|
|
80
|
+
* omitted when unset) so callers can distinguish "not configured" from "".
|
|
81
|
+
*/
|
|
82
|
+
export function loadSecrets(options = {}) {
|
|
83
|
+
const env = options.env ?? process.env;
|
|
84
|
+
const argv = options.argv ?? process.argv;
|
|
85
|
+
const readFile = options.readFile ?? ((path) => readFileSync(path, "utf8"));
|
|
86
|
+
const statFile = options.statFile ?? statSync;
|
|
87
|
+
let fileValues = {};
|
|
88
|
+
if (options.secretsFromPath) {
|
|
89
|
+
const mode = statFile(options.secretsFromPath).mode & 0o777;
|
|
90
|
+
if ((mode & 0o077) !== 0) {
|
|
91
|
+
throw new SecretValidationError([
|
|
92
|
+
`Secrets file ${options.secretsFromPath} must not be readable or writable by group or other users (mode ${mode.toString(8).padStart(3, "0")}).`,
|
|
93
|
+
]);
|
|
94
|
+
}
|
|
95
|
+
fileValues = parseSecretsFile(readFile(options.secretsFromPath));
|
|
96
|
+
}
|
|
97
|
+
const problems = [];
|
|
98
|
+
const loaded = [];
|
|
99
|
+
for (const def of SECRET_DEFINITIONS) {
|
|
100
|
+
const value = fileValues[def.key] ?? env[def.key];
|
|
101
|
+
if (value === undefined || value === "") {
|
|
102
|
+
if (def.required)
|
|
103
|
+
problems.push(`${def.key} is required but not set.`);
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
if (def.required && value.length < def.minLength) {
|
|
107
|
+
problems.push(`${def.key} must be at least ${def.minLength} characters (got ${value.length}).`);
|
|
108
|
+
}
|
|
109
|
+
if (argv.some((arg) => arg.includes(value))) {
|
|
110
|
+
problems.push(`${def.key}'s value was found in process.argv — secrets must never be passed as CLI flags.`);
|
|
111
|
+
}
|
|
112
|
+
loaded.push({ key: def.key, value });
|
|
113
|
+
}
|
|
114
|
+
if (problems.length > 0)
|
|
115
|
+
throw new SecretValidationError(problems);
|
|
116
|
+
return loaded;
|
|
117
|
+
}
|
|
118
|
+
// ─── Startup audit (AC3) ─────────────────────────────────────────────────────
|
|
119
|
+
/**
|
|
120
|
+
* Log which secrets were loaded — key names only, never values — as a single
|
|
121
|
+
* structured line on stderr (stdout is the JSON-RPC stream on the stdio
|
|
122
|
+
* transport; see `llm/client.ts` for the same convention).
|
|
123
|
+
*/
|
|
124
|
+
export function auditLoadedSecrets(loaded, write = (line) => process.stderr.write(line)) {
|
|
125
|
+
write(JSON.stringify({
|
|
126
|
+
event: "secrets.loaded",
|
|
127
|
+
keys: loaded.map((s) => s.key),
|
|
128
|
+
}) + "\n");
|
|
129
|
+
}
|
|
130
|
+
//# sourceMappingURL=secrets.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"secrets.js","sourceRoot":"","sources":["../../src/config/secrets.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `HtmlAdapter` (M2-08 stub → **v2 · DRO-617**) — the vanilla-HTML framework adapter.
|
|
3
|
+
*
|
|
4
|
+
* Lowers a neutral {@link RenderInput} (a self-contained `.html` document /
|
|
5
|
+
* template) into the three target artefacts, mirroring {@link ReactAdapter} /
|
|
6
|
+
* {@link VueAdapter} method-for-method so `conjure` treats every framework the
|
|
7
|
+
* same:
|
|
8
|
+
* - {@link HtmlAdapter.renderSource} → `<Name>.html` (the canonical source)
|
|
9
|
+
* - {@link HtmlAdapter.renderPreview} → `<Name>.preview.js` — a browser-ready
|
|
10
|
+
* **IIFE** exposing the component on `globalThis.GenieComponent` for the M4
|
|
11
|
+
* iframe grid to mount, exactly like the React/Vue previews
|
|
12
|
+
* - {@link HtmlAdapter.extractDts} → `<Name>.d.ts` — a minimal custom-element
|
|
13
|
+
* typing surface (an `HTMLElementTagNameMap` augmentation for any
|
|
14
|
+
* `customElements.define(...)` the source registers), or a valid empty module
|
|
15
|
+
*
|
|
16
|
+
* ── Why vanilla HTML still emits a `.preview.js` IIFE ─────────────────────────
|
|
17
|
+
* The HTML *is* already browser-ready — but the M4-03 iframe grid mounts **every**
|
|
18
|
+
* framework through the identical `window.{@link PREVIEW_GLOBAL_NAME}` handle
|
|
19
|
+
* (`{ default, <Name> }`), so React and Vue cards mount the same way (react.ts /
|
|
20
|
+
* vue.ts). Emitting an HTML card as a raw document instead would fork the grid's
|
|
21
|
+
* mount path per framework. Instead this adapter wraps the markup in the same
|
|
22
|
+
* preview-global contract: the IIFE exposes a descriptor whose `mount(container)`
|
|
23
|
+
* writes the component's markup into the card and *re-executes* any inline
|
|
24
|
+
* `<script>` (browsers do not run scripts inserted via `innerHTML`), so an
|
|
25
|
+
* interactive vanilla-HTML component behaves the same mounted as it would opened
|
|
26
|
+
* directly. This is the issue's "mostly a pass-through + optional JS/CSS inlining":
|
|
27
|
+
* no bundler, no compile — the markup flows through verbatim, only *wrapped* for a
|
|
28
|
+
* uniform mount.
|
|
29
|
+
*
|
|
30
|
+
* ── No preview host globals ───────────────────────────────────────────────────
|
|
31
|
+
* Unlike React (`window.React`) and Vue (`window.Vue`), a vanilla-HTML preview has
|
|
32
|
+
* **no** framework runtime to resolve from a host global — the browser is the
|
|
33
|
+
* runtime. So there is no host-global contract and no esbuild rewrite plugin here;
|
|
34
|
+
* the preview is fully self-contained and evaluates in any window.
|
|
35
|
+
*
|
|
36
|
+
* ── Import-time safety ────────────────────────────────────────────────────────
|
|
37
|
+
* Nothing heavy is imported here at all — the preview is assembled from plain
|
|
38
|
+
* string templating and `extractDts` scans the source with a regex — so resolving
|
|
39
|
+
* an `HtmlAdapter` (which the registry does on first `getAdapter("html")`) is
|
|
40
|
+
* free, and `conjure` can read its `promptDirective` / `defaultViewport` on the
|
|
41
|
+
* generation hot path with zero cost. The React/Vue adapters lazy-`import` esbuild
|
|
42
|
+
* / ts-morph / the SFC compiler for the same "keep resolving cheap" reason; the
|
|
43
|
+
* HTML adapter simply needs none of them.
|
|
44
|
+
*/
|
|
45
|
+
import { type AdapterFile, type FrameworkAdapter, type Framework, type RenderInput, type Viewport } from "./interface.js";
|
|
46
|
+
/**
|
|
47
|
+
* v2 tracking issue this adapter was implemented under (kept exported for
|
|
48
|
+
* provenance and referenced by the conformance suite's URL-shape assertion).
|
|
49
|
+
* Retained now that HTML is no longer a stub so historical links still resolve.
|
|
50
|
+
*/
|
|
51
|
+
export declare const HTML_TRACKING_ISSUE = "https://github.com/ambitresearch/genie/issues/130";
|
|
52
|
+
/**
|
|
53
|
+
* The property name the preview descriptor carries the component's raw markup
|
|
54
|
+
* under. Exported so a test (or the M4 grid) can read the pass-through markup off
|
|
55
|
+
* `window.GenieComponent.default.html` without re-deriving the key.
|
|
56
|
+
*/
|
|
57
|
+
export declare const PREVIEW_HTML_KEY = "html";
|
|
58
|
+
export declare class HtmlAdapter implements FrameworkAdapter {
|
|
59
|
+
readonly framework: Framework;
|
|
60
|
+
/**
|
|
61
|
+
* A comfortable default card for a vanilla-HTML component when the caller has no
|
|
62
|
+
* better viewport. Matches the React/Vue adapters (and the RFC's default preview
|
|
63
|
+
* grid cell, §7.5) so a framework switch never resizes a card by default.
|
|
64
|
+
*/
|
|
65
|
+
readonly defaultViewport: Viewport;
|
|
66
|
+
/**
|
|
67
|
+
* The framework directive `conjure` injects into the generation prompt (AC4):
|
|
68
|
+
* name the target framework and the self-contained vanilla-HTML shape the model
|
|
69
|
+
* should emit. Kept aligned with the original stub's directive so a prompt built
|
|
70
|
+
* before this adapter graduated still reads identically.
|
|
71
|
+
*/
|
|
72
|
+
readonly promptDirective: string;
|
|
73
|
+
/**
|
|
74
|
+
* The canonical source file: `<Name>.html`, carrying the model-authored markup
|
|
75
|
+
* verbatim. `text/html` matches the MIME the kit-file classifier maps `.html` to
|
|
76
|
+
* (`mime-types` resolves `.html` → `text/html`), so an adapter-emitted source and
|
|
77
|
+
* a store-read source report the same type.
|
|
78
|
+
*/
|
|
79
|
+
renderSource(input: RenderInput): AdapterFile;
|
|
80
|
+
/**
|
|
81
|
+
* Wrap the component markup in the browser-ready **IIFE** exposing it on
|
|
82
|
+
* `globalThis.${PREVIEW_GLOBAL_NAME}` (`{ default, <Name> }`), so the M4 grid
|
|
83
|
+
* mounts an HTML card through the identical `window.GenieComponent` handle it
|
|
84
|
+
* uses for React/Vue — see {@link previewIife} for the descriptor + `mount`
|
|
85
|
+
* contract. The markup passes through verbatim (no bundler, no compile); this is
|
|
86
|
+
* `async` only to satisfy the {@link FrameworkAdapter} contract (React/Vue are
|
|
87
|
+
* async because they lazy-load esbuild) — HTML needs no async work, so it
|
|
88
|
+
* resolves immediately.
|
|
89
|
+
*/
|
|
90
|
+
renderPreview(input: RenderInput): Promise<AdapterFile>;
|
|
91
|
+
/**
|
|
92
|
+
* Emit a `.d.ts` typing surface (parity with React/Vue). A vanilla-HTML
|
|
93
|
+
* component exports no component type, so the useful typing is the **custom
|
|
94
|
+
* elements** it registers: {@link customElementTags} scans the source for
|
|
95
|
+
* `customElements.define("x-y", …)` and {@link dtsForCustomElements} augments
|
|
96
|
+
* `HTMLElementTagNameMap` for each. A component that registers none falls back to
|
|
97
|
+
* a valid empty module (`export {};`) — never an empty file — exactly as the
|
|
98
|
+
* React/Vue adapters do for a source with no exported declarations. `async` only
|
|
99
|
+
* to match the contract; the work is synchronous.
|
|
100
|
+
*/
|
|
101
|
+
extractDts(input: RenderInput): Promise<AdapterFile>;
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=html.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"html.d.ts","sourceRoot":"","sources":["../../src/framework/html.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AACH,OAAO,EAEL,KAAK,WAAW,EAChB,KAAK,gBAAgB,EACrB,KAAK,SAAS,EACd,KAAK,WAAW,EAChB,KAAK,QAAQ,EACd,MAAM,gBAAgB,CAAC;AAQxB;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,sDAAsD,CAAC;AAoBvF;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,SAAS,CAAC;AAgIvC,qBAAa,WAAY,YAAW,gBAAgB;IAClD,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAU;IAEvC;;;;OAIG;IACH,QAAQ,CAAC,eAAe,EAAE,QAAQ,CAA+B;IAEjE;;;;;OAKG;IACH,QAAQ,CAAC,eAAe,EAAE,MAAM,CAInB;IAEb;;;;;OAKG;IACH,YAAY,CAAC,KAAK,EAAE,WAAW,GAAG,WAAW;IAQ7C;;;;;;;;;OASG;IACH,aAAa,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC;IAQvD;;;;;;;;;OASG;IACH,UAAU,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC;CAQrD"}
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `HtmlAdapter` (M2-08 stub → **v2 · DRO-617**) — the vanilla-HTML framework adapter.
|
|
3
|
+
*
|
|
4
|
+
* Lowers a neutral {@link RenderInput} (a self-contained `.html` document /
|
|
5
|
+
* template) into the three target artefacts, mirroring {@link ReactAdapter} /
|
|
6
|
+
* {@link VueAdapter} method-for-method so `conjure` treats every framework the
|
|
7
|
+
* same:
|
|
8
|
+
* - {@link HtmlAdapter.renderSource} → `<Name>.html` (the canonical source)
|
|
9
|
+
* - {@link HtmlAdapter.renderPreview} → `<Name>.preview.js` — a browser-ready
|
|
10
|
+
* **IIFE** exposing the component on `globalThis.GenieComponent` for the M4
|
|
11
|
+
* iframe grid to mount, exactly like the React/Vue previews
|
|
12
|
+
* - {@link HtmlAdapter.extractDts} → `<Name>.d.ts` — a minimal custom-element
|
|
13
|
+
* typing surface (an `HTMLElementTagNameMap` augmentation for any
|
|
14
|
+
* `customElements.define(...)` the source registers), or a valid empty module
|
|
15
|
+
*
|
|
16
|
+
* ── Why vanilla HTML still emits a `.preview.js` IIFE ─────────────────────────
|
|
17
|
+
* The HTML *is* already browser-ready — but the M4-03 iframe grid mounts **every**
|
|
18
|
+
* framework through the identical `window.{@link PREVIEW_GLOBAL_NAME}` handle
|
|
19
|
+
* (`{ default, <Name> }`), so React and Vue cards mount the same way (react.ts /
|
|
20
|
+
* vue.ts). Emitting an HTML card as a raw document instead would fork the grid's
|
|
21
|
+
* mount path per framework. Instead this adapter wraps the markup in the same
|
|
22
|
+
* preview-global contract: the IIFE exposes a descriptor whose `mount(container)`
|
|
23
|
+
* writes the component's markup into the card and *re-executes* any inline
|
|
24
|
+
* `<script>` (browsers do not run scripts inserted via `innerHTML`), so an
|
|
25
|
+
* interactive vanilla-HTML component behaves the same mounted as it would opened
|
|
26
|
+
* directly. This is the issue's "mostly a pass-through + optional JS/CSS inlining":
|
|
27
|
+
* no bundler, no compile — the markup flows through verbatim, only *wrapped* for a
|
|
28
|
+
* uniform mount.
|
|
29
|
+
*
|
|
30
|
+
* ── No preview host globals ───────────────────────────────────────────────────
|
|
31
|
+
* Unlike React (`window.React`) and Vue (`window.Vue`), a vanilla-HTML preview has
|
|
32
|
+
* **no** framework runtime to resolve from a host global — the browser is the
|
|
33
|
+
* runtime. So there is no host-global contract and no esbuild rewrite plugin here;
|
|
34
|
+
* the preview is fully self-contained and evaluates in any window.
|
|
35
|
+
*
|
|
36
|
+
* ── Import-time safety ────────────────────────────────────────────────────────
|
|
37
|
+
* Nothing heavy is imported here at all — the preview is assembled from plain
|
|
38
|
+
* string templating and `extractDts` scans the source with a regex — so resolving
|
|
39
|
+
* an `HtmlAdapter` (which the registry does on first `getAdapter("html")`) is
|
|
40
|
+
* free, and `conjure` can read its `promptDirective` / `defaultViewport` on the
|
|
41
|
+
* generation hot path with zero cost. The React/Vue adapters lazy-`import` esbuild
|
|
42
|
+
* / ts-morph / the SFC compiler for the same "keep resolving cheap" reason; the
|
|
43
|
+
* HTML adapter simply needs none of them.
|
|
44
|
+
*/
|
|
45
|
+
import { componentPath, } from "./interface.js";
|
|
46
|
+
// The M4 grid's preview-global name is a cross-framework contract; import the
|
|
47
|
+
// single source of truth from the React adapter rather than redeclaring it, so
|
|
48
|
+
// HTML, Vue and React cards are all mounted through the identical
|
|
49
|
+
// `window.GenieComponent` handle. (react.js has no heavy top-level imports —
|
|
50
|
+
// only `import type` — so this stays free and pulls no esbuild/ts-morph.)
|
|
51
|
+
import { PREVIEW_GLOBAL_NAME } from "./react.js";
|
|
52
|
+
/**
|
|
53
|
+
* v2 tracking issue this adapter was implemented under (kept exported for
|
|
54
|
+
* provenance and referenced by the conformance suite's URL-shape assertion).
|
|
55
|
+
* Retained now that HTML is no longer a stub so historical links still resolve.
|
|
56
|
+
*/
|
|
57
|
+
export const HTML_TRACKING_ISSUE = "https://github.com/ambitresearch/genie/issues/130";
|
|
58
|
+
/**
|
|
59
|
+
* Matches a `customElements.define("tag-name", …)` registration in the source,
|
|
60
|
+
* capturing the custom-element tag (which must contain a hyphen per the HTML
|
|
61
|
+
* spec). Used by {@link HtmlAdapter.extractDts} to surface a typed element map.
|
|
62
|
+
* Tolerant of single/double/back quotes and arbitrary whitespace around `(`.
|
|
63
|
+
*
|
|
64
|
+
* **Case-sensitive by design** (only the `g` flag — no `i`): `customElements.define`
|
|
65
|
+
* is a case-sensitive JS API, so a mixed-case token like `CustomElements.Define` is
|
|
66
|
+
* not a real registration and must not match. More importantly, a valid custom-element
|
|
67
|
+
* name is lowercase per the HTML spec — `define("X-Counter", …)` throws `SyntaxError`
|
|
68
|
+
* at runtime — so an `i` flag would let the tag group accept uppercase names and type
|
|
69
|
+
* an element in `HTMLElementTagNameMap` that can never actually be registered. The
|
|
70
|
+
* literal `customElements`/`define` and every valid tag name are already lowercase,
|
|
71
|
+
* so dropping `i` costs nothing and rejects exactly the tags that can never exist.
|
|
72
|
+
*/
|
|
73
|
+
const CUSTOM_ELEMENT_DEFINE = /customElements\s*\.\s*define\s*\(\s*["'`]([a-z][a-z0-9]*-[a-z0-9-]*)["'`]/g;
|
|
74
|
+
/**
|
|
75
|
+
* The property name the preview descriptor carries the component's raw markup
|
|
76
|
+
* under. Exported so a test (or the M4 grid) can read the pass-through markup off
|
|
77
|
+
* `window.GenieComponent.default.html` without re-deriving the key.
|
|
78
|
+
*/
|
|
79
|
+
export const PREVIEW_HTML_KEY = "html";
|
|
80
|
+
/**
|
|
81
|
+
* Serialize a string into a JS string literal that is also safe to embed inside
|
|
82
|
+
* an HTML `<script>` block. `JSON.stringify` handles quotes/newlines/control
|
|
83
|
+
* chars, and replacing every `<` with the `<` escape means the literal can
|
|
84
|
+
* never contain a `</script>` (or `<script>`, or `<!--`) token an HTML parser
|
|
85
|
+
* would act on. `"<"` evaluates back to `"<"` at JS runtime, so the value
|
|
86
|
+
* the descriptor carries is byte-identical to the source markup.
|
|
87
|
+
*/
|
|
88
|
+
function jsStringForHtmlEmbedding(value) {
|
|
89
|
+
return JSON.stringify(value).replace(/</g, "\\u003c");
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Build the browser-ready preview IIFE body for a vanilla-HTML component. The
|
|
93
|
+
* emitted script assigns `window.GenieComponent = { default: descriptor, <Name>:
|
|
94
|
+
* descriptor }` (the same `{ default, <Name> }` shape React/Vue expose), where the
|
|
95
|
+
* descriptor is:
|
|
96
|
+
*
|
|
97
|
+
* {
|
|
98
|
+
* framework: "html",
|
|
99
|
+
* html: "<the component markup, verbatim>",
|
|
100
|
+
* mount: function (container) { … }
|
|
101
|
+
* }
|
|
102
|
+
*
|
|
103
|
+
* `mount` writes the markup into the target element and then re-executes any
|
|
104
|
+
* inline `<script>` the markup carried — because setting `innerHTML` produces
|
|
105
|
+
* inert `<script>` nodes the browser will not run. Re-creating each `<script>`
|
|
106
|
+
* (copying its attributes + text) makes an interactive vanilla-HTML component work
|
|
107
|
+
* mounted exactly as it would opened directly (the "optional JS … inlining" the
|
|
108
|
+
* issue calls for). It is defensive about a missing DOM (returns without throwing)
|
|
109
|
+
* so evaluating the bundle for static analysis never crashes.
|
|
110
|
+
*
|
|
111
|
+
* The markup is embedded via `JSON.stringify` so any quotes / newlines in the
|
|
112
|
+
* source are safely escaped into a single JS string literal. `JSON.stringify`
|
|
113
|
+
* does **not** escape `<` (or `/`), so a literal `</script>` in the markup would
|
|
114
|
+
* survive verbatim — harmless in a standalone `.js` file, but a script-breakout
|
|
115
|
+
* hazard the instant this preview is inlined into an HTML `<script>` block (which
|
|
116
|
+
* an iframe host page may do). Escaping every `<` to its `<` unicode form
|
|
117
|
+
* closes that hole: `"<"` evaluates back to `<` at runtime (so the mounted
|
|
118
|
+
* markup is byte-identical to the source), yet no HTML parser ever sees a
|
|
119
|
+
* `<script` / `</script` token in the emitted preview. The standard safe-embed
|
|
120
|
+
* technique used by JSON-in-HTML serializers.
|
|
121
|
+
*/
|
|
122
|
+
function previewIife(input) {
|
|
123
|
+
const markup = jsStringForHtmlEmbedding(input.source);
|
|
124
|
+
const componentExport = JSON.stringify(input.componentName);
|
|
125
|
+
return [
|
|
126
|
+
`(function () {`,
|
|
127
|
+
` "use strict";`,
|
|
128
|
+
` var descriptor = {`,
|
|
129
|
+
` framework: "html",`,
|
|
130
|
+
` ${PREVIEW_HTML_KEY}: ${markup},`,
|
|
131
|
+
` mount: function (container) {`,
|
|
132
|
+
` if (!container || typeof document === "undefined") return;`,
|
|
133
|
+
` container.innerHTML = descriptor.${PREVIEW_HTML_KEY};`,
|
|
134
|
+
` // Scripts inserted via innerHTML are inert; re-create each so the`,
|
|
135
|
+
` // browser executes it — this is what makes interactivity work mounted.`,
|
|
136
|
+
` var inert = container.querySelectorAll("script");`,
|
|
137
|
+
` for (var i = 0; i < inert.length; i++) {`,
|
|
138
|
+
` var old = inert[i];`,
|
|
139
|
+
` var next = document.createElement("script");`,
|
|
140
|
+
` for (var a = 0; a < old.attributes.length; a++) {`,
|
|
141
|
+
` var attr = old.attributes[a];`,
|
|
142
|
+
` next.setAttribute(attr.name, attr.value);`,
|
|
143
|
+
` }`,
|
|
144
|
+
` next.textContent = old.textContent;`,
|
|
145
|
+
` old.parentNode.replaceChild(next, old);`,
|
|
146
|
+
` }`,
|
|
147
|
+
` return container;`,
|
|
148
|
+
` },`,
|
|
149
|
+
` };`,
|
|
150
|
+
` var GC = { default: descriptor };`,
|
|
151
|
+
` GC[${componentExport}] = descriptor;`,
|
|
152
|
+
` if (typeof window !== "undefined") {`,
|
|
153
|
+
` window.${PREVIEW_GLOBAL_NAME} = GC;`,
|
|
154
|
+
` } else if (typeof globalThis !== "undefined") {`,
|
|
155
|
+
` globalThis.${PREVIEW_GLOBAL_NAME} = GC;`,
|
|
156
|
+
` }`,
|
|
157
|
+
`})();`,
|
|
158
|
+
].join("\n");
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Collect the distinct custom-element tag names the source registers via
|
|
162
|
+
* `customElements.define("x-y", …)`, in first-seen order. Empty when the markup
|
|
163
|
+
* defines no custom elements (the common case for a plain HTML component).
|
|
164
|
+
*/
|
|
165
|
+
function customElementTags(source) {
|
|
166
|
+
const tags = [];
|
|
167
|
+
const seen = new Set();
|
|
168
|
+
// `matchAll` needs the /g flag (present on CUSTOM_ELEMENT_DEFINE); re-run from a
|
|
169
|
+
// fresh matcher each call so the shared regex's lastIndex never leaks state.
|
|
170
|
+
for (const match of source.matchAll(CUSTOM_ELEMENT_DEFINE)) {
|
|
171
|
+
const tag = match[1];
|
|
172
|
+
if (tag && !seen.has(tag)) {
|
|
173
|
+
seen.add(tag);
|
|
174
|
+
tags.push(tag);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
return tags;
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Build the `.d.ts` typing surface for an HTML component. Vanilla HTML has no
|
|
181
|
+
* exported component type the way a `.tsx`/`.vue` source does, so the only stable
|
|
182
|
+
* typing worth surfacing is the **custom elements** the markup registers: each
|
|
183
|
+
* `customElements.define("x-y", …)` is declared as an `HTMLElement` and mapped in
|
|
184
|
+
* `HTMLElementTagNameMap`, so a consuming TypeScript project's
|
|
185
|
+
* `document.createElement("x-y")` / `querySelector("x-y")` are typed. When the
|
|
186
|
+
* source registers none, fall back to a valid empty module (never an empty file),
|
|
187
|
+
* mirroring the React/Vue `export {};` fallback.
|
|
188
|
+
*/
|
|
189
|
+
function dtsForCustomElements(tags) {
|
|
190
|
+
if (tags.length === 0)
|
|
191
|
+
return `export {};\n`;
|
|
192
|
+
const lines = [
|
|
193
|
+
"// Custom elements this HTML component registers via customElements.define().",
|
|
194
|
+
"declare global {",
|
|
195
|
+
" interface HTMLElementTagNameMap {",
|
|
196
|
+
];
|
|
197
|
+
for (const tag of tags) {
|
|
198
|
+
lines.push(` ${JSON.stringify(tag)}: HTMLElement;`);
|
|
199
|
+
}
|
|
200
|
+
lines.push(" }", "}", "export {};", "");
|
|
201
|
+
return lines.join("\n");
|
|
202
|
+
}
|
|
203
|
+
export class HtmlAdapter {
|
|
204
|
+
framework = "html";
|
|
205
|
+
/**
|
|
206
|
+
* A comfortable default card for a vanilla-HTML component when the caller has no
|
|
207
|
+
* better viewport. Matches the React/Vue adapters (and the RFC's default preview
|
|
208
|
+
* grid cell, §7.5) so a framework switch never resizes a card by default.
|
|
209
|
+
*/
|
|
210
|
+
defaultViewport = { width: 400, height: 300 };
|
|
211
|
+
/**
|
|
212
|
+
* The framework directive `conjure` injects into the generation prompt (AC4):
|
|
213
|
+
* name the target framework and the self-contained vanilla-HTML shape the model
|
|
214
|
+
* should emit. Kept aligned with the original stub's directive so a prompt built
|
|
215
|
+
* before this adapter graduated still reads identically.
|
|
216
|
+
*/
|
|
217
|
+
promptDirective = [
|
|
218
|
+
"Target framework: html",
|
|
219
|
+
"Emit a self-contained vanilla HTML component: semantic markup with inline " +
|
|
220
|
+
"<style>, and vanilla JS in a <script> only if interactivity is required.",
|
|
221
|
+
].join("\n");
|
|
222
|
+
/**
|
|
223
|
+
* The canonical source file: `<Name>.html`, carrying the model-authored markup
|
|
224
|
+
* verbatim. `text/html` matches the MIME the kit-file classifier maps `.html` to
|
|
225
|
+
* (`mime-types` resolves `.html` → `text/html`), so an adapter-emitted source and
|
|
226
|
+
* a store-read source report the same type.
|
|
227
|
+
*/
|
|
228
|
+
renderSource(input) {
|
|
229
|
+
return {
|
|
230
|
+
path: componentPath(input, `${input.componentName}.html`),
|
|
231
|
+
content: input.source,
|
|
232
|
+
mimeType: "text/html",
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Wrap the component markup in the browser-ready **IIFE** exposing it on
|
|
237
|
+
* `globalThis.${PREVIEW_GLOBAL_NAME}` (`{ default, <Name> }`), so the M4 grid
|
|
238
|
+
* mounts an HTML card through the identical `window.GenieComponent` handle it
|
|
239
|
+
* uses for React/Vue — see {@link previewIife} for the descriptor + `mount`
|
|
240
|
+
* contract. The markup passes through verbatim (no bundler, no compile); this is
|
|
241
|
+
* `async` only to satisfy the {@link FrameworkAdapter} contract (React/Vue are
|
|
242
|
+
* async because they lazy-load esbuild) — HTML needs no async work, so it
|
|
243
|
+
* resolves immediately.
|
|
244
|
+
*/
|
|
245
|
+
renderPreview(input) {
|
|
246
|
+
return Promise.resolve({
|
|
247
|
+
path: componentPath(input, `${input.componentName}.preview.js`),
|
|
248
|
+
content: previewIife(input),
|
|
249
|
+
mimeType: "text/javascript",
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Emit a `.d.ts` typing surface (parity with React/Vue). A vanilla-HTML
|
|
254
|
+
* component exports no component type, so the useful typing is the **custom
|
|
255
|
+
* elements** it registers: {@link customElementTags} scans the source for
|
|
256
|
+
* `customElements.define("x-y", …)` and {@link dtsForCustomElements} augments
|
|
257
|
+
* `HTMLElementTagNameMap` for each. A component that registers none falls back to
|
|
258
|
+
* a valid empty module (`export {};`) — never an empty file — exactly as the
|
|
259
|
+
* React/Vue adapters do for a source with no exported declarations. `async` only
|
|
260
|
+
* to match the contract; the work is synchronous.
|
|
261
|
+
*/
|
|
262
|
+
extractDts(input) {
|
|
263
|
+
const tags = customElementTags(input.source);
|
|
264
|
+
return Promise.resolve({
|
|
265
|
+
path: componentPath(input, `${input.componentName}.d.ts`),
|
|
266
|
+
content: dtsForCustomElements(tags),
|
|
267
|
+
mimeType: "text/plain",
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
//# sourceMappingURL=html.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"html.js","sourceRoot":"","sources":["../../src/framework/html.ts"],"names":[],"mappings":"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"}
|