@chiralkit/cli 0.1.0-alpha.0

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.
Files changed (198) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +97 -0
  3. package/dist/add.d.ts +4 -0
  4. package/dist/add.js +118 -0
  5. package/dist/add.js.map +1 -0
  6. package/dist/agents/subprocess.d.ts +10 -0
  7. package/dist/agents/subprocess.js +43 -0
  8. package/dist/agents/subprocess.js.map +1 -0
  9. package/dist/automation/index.d.ts +14 -0
  10. package/dist/automation/index.js +129 -0
  11. package/dist/automation/index.js.map +1 -0
  12. package/dist/automation/install.d.ts +19 -0
  13. package/dist/automation/install.js +116 -0
  14. package/dist/automation/install.js.map +1 -0
  15. package/dist/automation/parsers/audit-report.d.ts +2 -0
  16. package/dist/automation/parsers/audit-report.js +42 -0
  17. package/dist/automation/parsers/audit-report.js.map +1 -0
  18. package/dist/automation/parsers/exit-code.d.ts +2 -0
  19. package/dist/automation/parsers/exit-code.js +6 -0
  20. package/dist/automation/parsers/exit-code.js.map +1 -0
  21. package/dist/automation/parsers/index.d.ts +10 -0
  22. package/dist/automation/parsers/index.js +13 -0
  23. package/dist/automation/parsers/index.js.map +1 -0
  24. package/dist/automation/parsers/observer-snapshot.d.ts +2 -0
  25. package/dist/automation/parsers/observer-snapshot.js +30 -0
  26. package/dist/automation/parsers/observer-snapshot.js.map +1 -0
  27. package/dist/automation/parsers/plan-report.d.ts +2 -0
  28. package/dist/automation/parsers/plan-report.js +53 -0
  29. package/dist/automation/parsers/plan-report.js.map +1 -0
  30. package/dist/automation/parsers/refinement-report.d.ts +2 -0
  31. package/dist/automation/parsers/refinement-report.js +149 -0
  32. package/dist/automation/parsers/refinement-report.js.map +1 -0
  33. package/dist/automation/parsers/types.d.ts +7 -0
  34. package/dist/automation/parsers/types.js +2 -0
  35. package/dist/automation/parsers/types.js.map +1 -0
  36. package/dist/automation/run.d.ts +25 -0
  37. package/dist/automation/run.js +68 -0
  38. package/dist/automation/run.js.map +1 -0
  39. package/dist/automation/schema.d.ts +130 -0
  40. package/dist/automation/schema.js +46 -0
  41. package/dist/automation/schema.js.map +1 -0
  42. package/dist/automation/status.d.ts +16 -0
  43. package/dist/automation/status.js +56 -0
  44. package/dist/automation/status.js.map +1 -0
  45. package/dist/automation/verifiers/index.d.ts +7 -0
  46. package/dist/automation/verifiers/index.js +5 -0
  47. package/dist/automation/verifiers/index.js.map +1 -0
  48. package/dist/automation/verifiers/shell.d.ts +5 -0
  49. package/dist/automation/verifiers/shell.js +17 -0
  50. package/dist/automation/verifiers/shell.js.map +1 -0
  51. package/dist/automation/verifiers/types.d.ts +12 -0
  52. package/dist/automation/verifiers/types.js +2 -0
  53. package/dist/automation/verifiers/types.js.map +1 -0
  54. package/dist/backlog/add.d.ts +10 -0
  55. package/dist/backlog/add.js +30 -0
  56. package/dist/backlog/add.js.map +1 -0
  57. package/dist/backlog/index.d.ts +1 -0
  58. package/dist/backlog/index.js +53 -0
  59. package/dist/backlog/index.js.map +1 -0
  60. package/dist/config.d.ts +26 -0
  61. package/dist/config.js +110 -0
  62. package/dist/config.js.map +1 -0
  63. package/dist/detect.d.ts +2 -0
  64. package/dist/detect.js +26 -0
  65. package/dist/detect.js.map +1 -0
  66. package/dist/doctor-invariants.d.ts +6 -0
  67. package/dist/doctor-invariants.js +50 -0
  68. package/dist/doctor-invariants.js.map +1 -0
  69. package/dist/doctor.d.ts +13 -0
  70. package/dist/doctor.js +281 -0
  71. package/dist/doctor.js.map +1 -0
  72. package/dist/generate.d.ts +1 -0
  73. package/dist/generate.js +275 -0
  74. package/dist/generate.js.map +1 -0
  75. package/dist/generator/agent.d.ts +8 -0
  76. package/dist/generator/agent.js +66 -0
  77. package/dist/generator/agent.js.map +1 -0
  78. package/dist/generator/api.d.ts +7 -0
  79. package/dist/generator/api.js +42 -0
  80. package/dist/generator/api.js.map +1 -0
  81. package/dist/generator/config.d.ts +23 -0
  82. package/dist/generator/config.js +121 -0
  83. package/dist/generator/config.js.map +1 -0
  84. package/dist/generator/parse-response.d.ts +5 -0
  85. package/dist/generator/parse-response.js +58 -0
  86. package/dist/generator/parse-response.js.map +1 -0
  87. package/dist/generator/prompt.d.ts +9 -0
  88. package/dist/generator/prompt.js +166 -0
  89. package/dist/generator/prompt.js.map +1 -0
  90. package/dist/generator/request.d.ts +17 -0
  91. package/dist/generator/request.js +15 -0
  92. package/dist/generator/request.js.map +1 -0
  93. package/dist/generators/prompts/stencil.md +45 -0
  94. package/dist/generators/prompts/vue.md +54 -0
  95. package/dist/index.d.ts +2 -0
  96. package/dist/index.js +102 -0
  97. package/dist/index.js.map +1 -0
  98. package/dist/init.d.ts +1 -0
  99. package/dist/init.js +89 -0
  100. package/dist/init.js.map +1 -0
  101. package/dist/installers/context.d.ts +4 -0
  102. package/dist/installers/context.js +120 -0
  103. package/dist/installers/context.js.map +1 -0
  104. package/dist/installers/index.d.ts +7 -0
  105. package/dist/installers/index.js +22 -0
  106. package/dist/installers/index.js.map +1 -0
  107. package/dist/installers/installer.d.ts +12 -0
  108. package/dist/installers/installer.js +30 -0
  109. package/dist/installers/installer.js.map +1 -0
  110. package/dist/installers/stencil/django-template/installer.d.ts +10 -0
  111. package/dist/installers/stencil/django-template/installer.js +77 -0
  112. package/dist/installers/stencil/django-template/installer.js.map +1 -0
  113. package/dist/installers/stencil/react/installer.d.ts +9 -0
  114. package/dist/installers/stencil/react/installer.js +22 -0
  115. package/dist/installers/stencil/react/installer.js.map +1 -0
  116. package/dist/installers/stencil/react/manifest.json +17 -0
  117. package/dist/installers/types.d.ts +24 -0
  118. package/dist/installers/types.js +2 -0
  119. package/dist/installers/types.js.map +1 -0
  120. package/dist/lock.d.ts +25 -0
  121. package/dist/lock.js +86 -0
  122. package/dist/lock.js.map +1 -0
  123. package/dist/manifest.d.ts +1 -0
  124. package/dist/manifest.js +93 -0
  125. package/dist/manifest.js.map +1 -0
  126. package/dist/pm/audit.d.ts +36 -0
  127. package/dist/pm/audit.js +147 -0
  128. package/dist/pm/audit.js.map +1 -0
  129. package/dist/pm/backlog.d.ts +3 -0
  130. package/dist/pm/backlog.js +123 -0
  131. package/dist/pm/backlog.js.map +1 -0
  132. package/dist/pm/brief.d.ts +4 -0
  133. package/dist/pm/brief.js +18 -0
  134. package/dist/pm/brief.js.map +1 -0
  135. package/dist/pm/git.d.ts +3 -0
  136. package/dist/pm/git.js +43 -0
  137. package/dist/pm/git.js.map +1 -0
  138. package/dist/pm/grid.d.ts +8 -0
  139. package/dist/pm/grid.js +16 -0
  140. package/dist/pm/grid.js.map +1 -0
  141. package/dist/pm/index.d.ts +25 -0
  142. package/dist/pm/index.js +199 -0
  143. package/dist/pm/index.js.map +1 -0
  144. package/dist/pm/observe.d.ts +55 -0
  145. package/dist/pm/observe.js +177 -0
  146. package/dist/pm/observe.js.map +1 -0
  147. package/dist/pm/plan.d.ts +54 -0
  148. package/dist/pm/plan.js +151 -0
  149. package/dist/pm/plan.js.map +1 -0
  150. package/dist/pm/refinement-worktree.d.ts +31 -0
  151. package/dist/pm/refinement-worktree.js +160 -0
  152. package/dist/pm/refinement-worktree.js.map +1 -0
  153. package/dist/pm/refinement.d.ts +79 -0
  154. package/dist/pm/refinement.js +326 -0
  155. package/dist/pm/refinement.js.map +1 -0
  156. package/dist/pm/render.d.ts +2 -0
  157. package/dist/pm/render.js +39 -0
  158. package/dist/pm/render.js.map +1 -0
  159. package/dist/pm/roadmap-rings.d.ts +7 -0
  160. package/dist/pm/roadmap-rings.js +31 -0
  161. package/dist/pm/roadmap-rings.js.map +1 -0
  162. package/dist/pm/roadmap.d.ts +2 -0
  163. package/dist/pm/roadmap.js +118 -0
  164. package/dist/pm/roadmap.js.map +1 -0
  165. package/dist/pm/snapshot.d.ts +10 -0
  166. package/dist/pm/snapshot.js +129 -0
  167. package/dist/pm/snapshot.js.map +1 -0
  168. package/dist/pm/types.d.ts +99 -0
  169. package/dist/pm/types.js +29 -0
  170. package/dist/pm/types.js.map +1 -0
  171. package/dist/registry-layout.d.ts +18 -0
  172. package/dist/registry-layout.js +122 -0
  173. package/dist/registry-layout.js.map +1 -0
  174. package/dist/scaffold-registry.d.ts +10 -0
  175. package/dist/scaffold-registry.js +283 -0
  176. package/dist/scaffold-registry.js.map +1 -0
  177. package/dist/scaffold.d.ts +1 -0
  178. package/dist/scaffold.js +32 -0
  179. package/dist/scaffold.js.map +1 -0
  180. package/dist/spec-from-react.d.ts +11 -0
  181. package/dist/spec-from-react.js +522 -0
  182. package/dist/spec-from-react.js.map +1 -0
  183. package/dist/spec-from-stencil.d.ts +7 -0
  184. package/dist/spec-from-stencil.js +275 -0
  185. package/dist/spec-from-stencil.js.map +1 -0
  186. package/dist/spec.d.ts +1 -0
  187. package/dist/spec.js +60 -0
  188. package/dist/spec.js.map +1 -0
  189. package/dist/tokens-map.d.ts +11 -0
  190. package/dist/tokens-map.js +43 -0
  191. package/dist/tokens-map.js.map +1 -0
  192. package/dist/update.d.ts +39 -0
  193. package/dist/update.js +490 -0
  194. package/dist/update.js.map +1 -0
  195. package/dist/workspace-init.d.ts +9 -0
  196. package/dist/workspace-init.js +119 -0
  197. package/dist/workspace-init.js.map +1 -0
  198. package/package.json +53 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent.js","sourceRoot":"","sources":["../../src/generator/agent.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import type { GenerationRequest } from "./request.js";
2
+ export interface ApiMessage {
3
+ role: "system" | "user";
4
+ content: string;
5
+ }
6
+ export declare function serializeForApi(req: GenerationRequest): ApiMessage[];
7
+ export declare function runApi(model: unknown, req: GenerationRequest): Promise<string>;
@@ -0,0 +1,42 @@
1
+ import { renderFewShotsBlock } from "./request.js";
2
+ export function serializeForApi(req) {
3
+ const userContent = [
4
+ "## Component spec (spec.json)",
5
+ "",
6
+ "```json\n" + req.spec + "\n```",
7
+ "",
8
+ "## Verifiable output requirements",
9
+ "",
10
+ req.derivedRequirements,
11
+ "",
12
+ "## Reference implementations",
13
+ "",
14
+ renderFewShotsBlock(req.fewShots),
15
+ "",
16
+ "## Output format",
17
+ "",
18
+ req.outputFormat,
19
+ "",
20
+ `Generate the ${req.targetStack} implementation of ${req.targetComponent}.`,
21
+ ].join("\n");
22
+ return [
23
+ { role: "system", content: req.preamble },
24
+ { role: "user", content: userContent },
25
+ ];
26
+ }
27
+ // runApi wraps the AI SDK generateText call. `ai` is imported dynamically
28
+ // so agent-mode invocations do not pay its module-load cost. `model` is
29
+ // unknown for the same reason described in config.ts:resolveModel — staying
30
+ // decoupled from a specific @ai-sdk major.
31
+ export async function runApi(model, req) {
32
+ const messages = serializeForApi(req);
33
+ const { generateText } = await import("ai");
34
+ const response = await generateText({
35
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
36
+ model: model,
37
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
38
+ messages: messages,
39
+ });
40
+ return response.text;
41
+ }
42
+ //# sourceMappingURL=api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.js","sourceRoot":"","sources":["../../src/generator/api.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAOnD,MAAM,UAAU,eAAe,CAAC,GAAsB;IACpD,MAAM,WAAW,GAAG;QAClB,+BAA+B;QAC/B,EAAE;QACF,WAAW,GAAG,GAAG,CAAC,IAAI,GAAG,OAAO;QAChC,EAAE;QACF,mCAAmC;QACnC,EAAE;QACF,GAAG,CAAC,mBAAmB;QACvB,EAAE;QACF,8BAA8B;QAC9B,EAAE;QACF,mBAAmB,CAAC,GAAG,CAAC,QAAQ,CAAC;QACjC,EAAE;QACF,kBAAkB;QAClB,EAAE;QACF,GAAG,CAAC,YAAY;QAChB,EAAE;QACF,gBAAgB,GAAG,CAAC,WAAW,sBAAsB,GAAG,CAAC,eAAe,GAAG;KAC5E,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACb,OAAO;QACL,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,CAAC,QAAQ,EAAE;QACzC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE;KACvC,CAAC;AACJ,CAAC;AAED,0EAA0E;AAC1E,wEAAwE;AACxE,4EAA4E;AAC5E,2CAA2C;AAC3C,MAAM,CAAC,KAAK,UAAU,MAAM,CAC1B,KAAc,EACd,GAAsB;IAEtB,MAAM,QAAQ,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC;IACtC,MAAM,EAAE,YAAY,EAAE,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,CAAC;IAC5C,MAAM,QAAQ,GAAG,MAAM,YAAY,CAAC;QAClC,8DAA8D;QAC9D,KAAK,EAAE,KAAY;QACnB,8DAA8D;QAC9D,QAAQ,EAAE,QAAe;KAC1B,CAAC,CAAC;IACH,OAAO,QAAQ,CAAC,IAAI,CAAC;AACvB,CAAC"}
@@ -0,0 +1,23 @@
1
+ declare const SUPPORTED_AGENTS: readonly ["claude-code"];
2
+ export type GeneratorConfig = {
3
+ generator: {
4
+ agent: (typeof SUPPORTED_AGENTS)[number];
5
+ };
6
+ } | {
7
+ generator: {
8
+ model: string;
9
+ };
10
+ };
11
+ export declare function isAgentConfig(c: GeneratorConfig): c is {
12
+ generator: {
13
+ agent: (typeof SUPPORTED_AGENTS)[number];
14
+ };
15
+ };
16
+ export declare function parseGeneratorConfigForTest(raw: unknown): GeneratorConfig;
17
+ export declare function loadGeneratorConfig(): Promise<GeneratorConfig>;
18
+ export declare function resolveModel(config: {
19
+ generator: {
20
+ model: string;
21
+ };
22
+ }): Promise<unknown>;
23
+ export {};
@@ -0,0 +1,121 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import { join } from "node:path";
3
+ import { z } from "zod";
4
+ import { resolveKitsRoot } from "@chiralkit/kits";
5
+ const registryRoot = join(resolveKitsRoot(), "ui", "registry");
6
+ const CONFIG_PATH = join(registryRoot, "generator.config.json");
7
+ const PROVIDER_DOCS_URL = "https://sdk.vercel.ai/providers/";
8
+ const SUPPORTED_AGENTS = ["claude-code"];
9
+ const agentBlockSchema = z
10
+ .object({
11
+ agent: z.enum(SUPPORTED_AGENTS, {
12
+ errorMap: () => ({
13
+ message: `generator.agent must be one of: ${SUPPORTED_AGENTS.join(", ")}`,
14
+ }),
15
+ }),
16
+ })
17
+ .strict();
18
+ const apiBlockSchema = z
19
+ .object({
20
+ model: z
21
+ .string()
22
+ .min(1)
23
+ .regex(/^[a-z0-9-]+\/.+$/, {
24
+ message: "generator.model must be '<provider>/<model-id>' (e.g. 'anthropic/claude-opus-4-8')",
25
+ }),
26
+ })
27
+ .strict();
28
+ export function isAgentConfig(c) {
29
+ return "agent" in c.generator;
30
+ }
31
+ // Exposed for unit tests — same validation as loadGeneratorConfig without I/O.
32
+ export function parseGeneratorConfigForTest(raw) {
33
+ return validate(raw);
34
+ }
35
+ function validate(raw) {
36
+ if (typeof raw !== "object" || raw === null || !("generator" in raw)) {
37
+ throw new Error("generator: config is missing the top-level `generator` block. Expected " +
38
+ '`{ "generator": { "agent": "claude-code" } }` or ' +
39
+ '`{ "generator": { "model": "<provider>/<model-id>" } }`.');
40
+ }
41
+ const gen = raw.generator;
42
+ if (typeof gen !== "object" || gen === null) {
43
+ throw new Error("generator: `generator` must be an object.");
44
+ }
45
+ const hasAgent = "agent" in gen;
46
+ const hasModel = "model" in gen;
47
+ if (hasAgent === hasModel) {
48
+ // both present or both absent
49
+ throw new Error("generator: exactly one of `generator.agent` or `generator.model` must be set.\n" +
50
+ " Agent mode: { \"generator\": { \"agent\": \"claude-code\" } }\n" +
51
+ " API mode: { \"generator\": { \"model\": \"anthropic/claude-opus-4-8\" } }\n" +
52
+ `See ${PROVIDER_DOCS_URL} for available API providers.`);
53
+ }
54
+ if (hasAgent) {
55
+ const parsed = agentBlockSchema.safeParse(gen);
56
+ if (!parsed.success)
57
+ throw new Error(zodMessage(parsed.error));
58
+ return { generator: parsed.data };
59
+ }
60
+ const parsed = apiBlockSchema.safeParse(gen);
61
+ if (!parsed.success)
62
+ throw new Error(zodMessage(parsed.error));
63
+ return { generator: parsed.data };
64
+ }
65
+ function zodMessage(err) {
66
+ return err.issues.map((i) => i.message).join("; ");
67
+ }
68
+ export async function loadGeneratorConfig() {
69
+ let raw;
70
+ try {
71
+ raw = await readFile(CONFIG_PATH, "utf8");
72
+ }
73
+ catch {
74
+ throw new Error(`generator: no config found at ${CONFIG_PATH}.\n` +
75
+ `Create it with ONE of:\n` +
76
+ ` { "generator": { "agent": "claude-code" } } # uses your local Claude Code CLI\n` +
77
+ ` { "generator": { "model": "anthropic/claude-opus-4-8" } } # requires ANTHROPIC_API_KEY`);
78
+ }
79
+ let parsedJson;
80
+ try {
81
+ parsedJson = JSON.parse(raw);
82
+ }
83
+ catch (e) {
84
+ throw new Error(`generator: ${CONFIG_PATH} is not valid JSON: ${e.message}`);
85
+ }
86
+ try {
87
+ return validate(parsedJson);
88
+ }
89
+ catch (e) {
90
+ throw new Error(`generator: ${CONFIG_PATH} failed validation:\n${e.message}`);
91
+ }
92
+ }
93
+ // Resolves the configured model into an AI SDK LanguageModel instance.
94
+ // Return type is `unknown` because the AI SDK's LanguageModel type is
95
+ // versioned per major; typing this precisely would couple the CLI to a
96
+ // specific @ai-sdk major and defeat the "swap the provider without
97
+ // touching this file" property. The caller passes it straight to
98
+ // generateText({ model }), which enforces the contract at the call site.
99
+ export async function resolveModel(config) {
100
+ const [provider, ...idParts] = config.generator.model.split("/");
101
+ const modelId = idParts.join("/");
102
+ if (!provider || !modelId) {
103
+ throw new Error(`generator: model '${config.generator.model}' is malformed. Expected '<provider>/<model-id>'.`);
104
+ }
105
+ switch (provider) {
106
+ case "anthropic": {
107
+ const mod = await import("@ai-sdk/anthropic");
108
+ const factory = mod.anthropic;
109
+ if (typeof factory !== "function") {
110
+ throw new Error(`generator: @ai-sdk/anthropic does not export the expected 'anthropic' factory. This is likely a version mismatch — reinstall matching versions of 'ai' and '@ai-sdk/anthropic'.`);
111
+ }
112
+ return factory(modelId);
113
+ }
114
+ default:
115
+ throw new Error(`generator: provider '${provider}' is not installed.\n` +
116
+ `Add it with: pnpm --filter @chiralkit/cli add @ai-sdk/${provider}\n` +
117
+ `Then wire it into resolveModel() in packages/cli/src/generator/config.ts.\n` +
118
+ `See ${PROVIDER_DOCS_URL} for the list of supported providers.`);
119
+ }
120
+ }
121
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/generator/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export interface ParsedFile {
2
+ path: string;
3
+ content: string;
4
+ }
5
+ export declare function parseResponse(text: string): ParsedFile[];
@@ -0,0 +1,58 @@
1
+ // Response format the prompt template mandates:
2
+ //
3
+ // === FILE: <relative-path> ===
4
+ // ```<lang>
5
+ // <content>
6
+ // ```
7
+ //
8
+ // Any content outside these blocks is ignored — LLMs sometimes wrap their
9
+ // output in surrounding prose, and being lenient about it is cheap and
10
+ // improves resilience. Any content INSIDE a fenced block after a FILE
11
+ // marker is captured verbatim, with the leading/trailing newline stripped.
12
+ //
13
+ const FORBIDDEN_BASENAMES = new Set(["generation.json"]);
14
+ export function parseResponse(text) {
15
+ // Constructed per-call so the /g flag's mutable `lastIndex` cannot leak
16
+ // between invocations (a rejection path throwing mid-loop would otherwise
17
+ // leave state on a shared regex object). Regex captures:
18
+ // 1: file path (letters, digits, dot, dash, underscore, slash)
19
+ // 2: language hint after the opening fence (may be empty)
20
+ // 3: the file content
21
+ const fileBlockRe = /^===\s*FILE:\s*([A-Za-z0-9._\-/]+)\s*===\s*\r?\n```([A-Za-z0-9._+-]*)\r?\n([\s\S]*?)\r?\n```/gm;
22
+ const files = [];
23
+ const seenPaths = new Set();
24
+ let m;
25
+ while ((m = fileBlockRe.exec(text)) !== null) {
26
+ const path = m[1];
27
+ const content = m[3];
28
+ validatePath(path);
29
+ if (seenPaths.has(path)) {
30
+ throw new Error(`generator: response contains duplicate file '${path}'. The LLM emitted the same file twice; refusing to guess which is authoritative.`);
31
+ }
32
+ seenPaths.add(path);
33
+ files.push({ path, content });
34
+ }
35
+ if (files.length === 0) {
36
+ throw new Error(`generator: response contained no '=== FILE: ... ===' blocks. The LLM did not follow the required output format. Re-run with --dry-run to inspect the raw response.`);
37
+ }
38
+ return files;
39
+ }
40
+ function validatePath(path) {
41
+ if (path.length === 0) {
42
+ throw new Error(`generator: response contains an empty file path.`);
43
+ }
44
+ if (path.startsWith("/")) {
45
+ throw new Error(`generator: response contains absolute path '${path}'. Only paths relative to implementations/<stack>/ are permitted.`);
46
+ }
47
+ if (path.includes("..")) {
48
+ throw new Error(`generator: response contains parent-directory reference in path '${path}'. Rejected as a safety measure.`);
49
+ }
50
+ if (path.includes("\0")) {
51
+ throw new Error(`generator: response contains null byte in path '${path}'. Rejected.`);
52
+ }
53
+ const basename = path.split("/").pop();
54
+ if (FORBIDDEN_BASENAMES.has(basename)) {
55
+ throw new Error(`generator: response tries to write '${basename}', which is managed by the CLI. Refusing.`);
56
+ }
57
+ }
58
+ //# sourceMappingURL=parse-response.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse-response.js","sourceRoot":"","sources":["../../src/generator/parse-response.ts"],"names":[],"mappings":"AAKA,gDAAgD;AAChD,EAAE;AACF,kCAAkC;AAClC,cAAc;AACd,cAAc;AACd,QAAQ;AACR,EAAE;AACF,0EAA0E;AAC1E,uEAAuE;AACvE,sEAAsE;AACtE,2EAA2E;AAC3E,EAAE;AACF,MAAM,mBAAmB,GAAG,IAAI,GAAG,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC;AAEzD,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,wEAAwE;IACxE,0EAA0E;IAC1E,yDAAyD;IACzD,iEAAiE;IACjE,4DAA4D;IAC5D,wBAAwB;IACxB,MAAM,WAAW,GACf,gGAAgG,CAAC;IACnG,MAAM,KAAK,GAAiB,EAAE,CAAC;IAC/B,MAAM,SAAS,GAAG,IAAI,GAAG,EAAU,CAAC;IACpC,IAAI,CAAyB,CAAC;IAC9B,OAAO,CAAC,CAAC,GAAG,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;QAC7C,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,CAAE,CAAC;QACnB,MAAM,OAAO,GAAG,CAAC,CAAC,CAAC,CAAE,CAAC;QACtB,YAAY,CAAC,IAAI,CAAC,CAAC;QACnB,IAAI,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YACxB,MAAM,IAAI,KAAK,CACb,gDAAgD,IAAI,mFAAmF,CACxI,CAAC;QACJ,CAAC;QACD,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACpB,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;IAChC,CAAC;IACD,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,MAAM,IAAI,KAAK,CACb,oKAAoK,CACrK,CAAC;IACJ,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,YAAY,CAAC,IAAY;IAChC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACtB,MAAM,IAAI,KAAK,CAAC,kDAAkD,CAAC,CAAC;IACtE,CAAC;IACD,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CACb,+CAA+C,IAAI,mEAAmE,CACvH,CAAC;IACJ,CAAC;IACD,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CACb,oEAAoE,IAAI,kCAAkC,CAC3G,CAAC;IACJ,CAAC;IACD,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CACb,mDAAmD,IAAI,cAAc,CACtE,CAAC;IACJ,CAAC;IACD,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAG,CAAC;IACxC,IAAI,mBAAmB,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;QACtC,MAAM,IAAI,KAAK,CACb,uCAAuC,QAAQ,2CAA2C,CAC3F,CAAC;IACJ,CAAC;AACH,CAAC"}
@@ -0,0 +1,9 @@
1
+ import type { ComponentContract } from "@chiralkit/registry-schema";
2
+ import type { GenerationRequest } from "./request.js";
3
+ export interface ComposeRequestInput {
4
+ spec: ComponentContract;
5
+ stack: string;
6
+ targetComponent: string;
7
+ fewShotPaths: string[];
8
+ }
9
+ export declare function composeRequest(input: ComposeRequestInput): Promise<GenerationRequest>;
@@ -0,0 +1,166 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import { basename, dirname, join } from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ const here = dirname(fileURLToPath(import.meta.url));
5
+ const PROMPTS_DIR = join(here, "..", "generators", "prompts");
6
+ export async function composeRequest(input) {
7
+ const { preamble, outputFormat } = await loadTemplate(input.stack);
8
+ return {
9
+ preamble,
10
+ outputFormat,
11
+ spec: JSON.stringify(input.spec, null, 2),
12
+ derivedRequirements: renderRequirements(input.spec),
13
+ fewShots: await loadFewShots(input.fewShotPaths),
14
+ targetComponent: input.targetComponent,
15
+ targetStack: input.stack,
16
+ };
17
+ }
18
+ // Splits the stack template into named sections keyed by their `## `
19
+ // heading text. Requires exactly `## Preamble` and `## OutputFormat`.
20
+ async function loadTemplate(stack) {
21
+ const path = join(PROMPTS_DIR, `${stack}.md`);
22
+ let raw;
23
+ try {
24
+ raw = await readFile(path, "utf8");
25
+ }
26
+ catch {
27
+ throw new Error(`generator: no prompt template for stack '${stack}' at ${path}. ` +
28
+ `Add packages/cli/src/generators/prompts/${stack}.md and rebuild.`);
29
+ }
30
+ const sections = splitByH2(raw);
31
+ const preamble = sections.get("Preamble");
32
+ const outputFormat = sections.get("OutputFormat");
33
+ if (!preamble) {
34
+ throw new Error(`generator: template ${path} is missing required '## Preamble' section.`);
35
+ }
36
+ if (!outputFormat) {
37
+ throw new Error(`generator: template ${path} is missing required '## OutputFormat' section.`);
38
+ }
39
+ return { preamble: preamble.trim(), outputFormat: outputFormat.trim() };
40
+ }
41
+ // Section split: iterates lines, treats each `## <name>` as a new bucket.
42
+ // Lines before the first `## ` heading are dropped (they belong to `# `
43
+ // title and its explanatory prose, which is not part of the request).
44
+ function splitByH2(md) {
45
+ const out = new Map();
46
+ let current = null;
47
+ let buf = [];
48
+ for (const line of md.split(/\r?\n/)) {
49
+ const m = /^##\s+(.+?)\s*$/.exec(line);
50
+ if (m && !line.startsWith("### ")) {
51
+ if (current !== null)
52
+ out.set(current, buf.join("\n"));
53
+ current = m[1];
54
+ buf = [];
55
+ }
56
+ else if (current !== null) {
57
+ buf.push(line);
58
+ }
59
+ }
60
+ if (current !== null)
61
+ out.set(current, buf.join("\n"));
62
+ return out;
63
+ }
64
+ async function loadFewShots(paths) {
65
+ const byComponent = new Map();
66
+ for (const abs of paths) {
67
+ // absolute path shape: .../registry/<component>/implementations/<stack>/<file>
68
+ const file = basename(abs);
69
+ const stackDir = dirname(abs);
70
+ const implDir = dirname(stackDir);
71
+ const componentDir = dirname(implDir);
72
+ const componentName = basename(componentDir);
73
+ const content = await readFile(abs, "utf8");
74
+ const existing = byComponent.get(componentName);
75
+ if (existing) {
76
+ existing.files.push({ path: file, content });
77
+ }
78
+ else {
79
+ byComponent.set(componentName, {
80
+ componentName,
81
+ files: [{ path: file, content }],
82
+ });
83
+ }
84
+ }
85
+ return Array.from(byComponent.values());
86
+ }
87
+ // Turns the spec's abstract fields into explicit testable statements the
88
+ // LLM can check its own output against.
89
+ function renderRequirements(spec) {
90
+ const lines = [];
91
+ if (spec.props) {
92
+ for (const [name, prop] of Object.entries(spec.props)) {
93
+ if (prop.type === "enum") {
94
+ const values = prop.values.map((v) => `"${v}"`).join(", ");
95
+ const dflt = prop.default !== undefined ? `, default "${prop.default}"` : "";
96
+ lines.push(`- Prop \`${name}\` is an enum with values [${values}]${dflt}.`);
97
+ }
98
+ else {
99
+ const dflt = "default" in prop && prop.default !== undefined
100
+ ? `, default ${JSON.stringify(prop.default)}`
101
+ : "";
102
+ lines.push(`- Prop \`${name}\` is of type \`${prop.type}\`${dflt}.`);
103
+ }
104
+ }
105
+ }
106
+ if (spec.events) {
107
+ for (const [name, evt] of Object.entries(spec.events)) {
108
+ const payload = typeof evt.payload === "string"
109
+ ? evt.payload
110
+ : evt.payload
111
+ ? "structured (see spec)"
112
+ : "void";
113
+ const cond = evt.condition ? ` when \`${evt.condition}\`` : "";
114
+ lines.push(`- Event \`${name}\` emits payload \`${payload}\`${cond}.`);
115
+ }
116
+ }
117
+ if (spec.slot) {
118
+ lines.push(`- Component renders a \`<slot>\` for: ${spec.slot.purpose}.`);
119
+ }
120
+ if (spec.tokens_used) {
121
+ for (const [bucket, values] of Object.entries(spec.tokens_used)) {
122
+ if (!values || values.length === 0)
123
+ continue;
124
+ const stems = values
125
+ .map((v) => `--ds-${singular(bucket)}-${v}`)
126
+ .join(", ");
127
+ lines.push(`- Consumes only these CSS tokens from bucket \`${bucket}\`: ${stems}.`);
128
+ }
129
+ }
130
+ if (spec.state_machine) {
131
+ const sm = spec.state_machine;
132
+ lines.push(`- State machine has initial state \`${sm.initial}\`.`);
133
+ for (const [state, def] of Object.entries(sm.states)) {
134
+ if (!def.on)
135
+ continue;
136
+ for (const [event, transition] of Object.entries(def.on)) {
137
+ const emit = transition.emit
138
+ ? ` and emits \`${transition.emit.event}\``
139
+ : "";
140
+ lines.push(`- In state \`${state}\`, event \`${event}\` transitions to \`${transition.target}\`${emit}.`);
141
+ }
142
+ }
143
+ }
144
+ if (spec.a11y && typeof spec.a11y === "object") {
145
+ for (const [key, value] of Object.entries(spec.a11y)) {
146
+ const val = Array.isArray(value)
147
+ ? value.map(String).join("; ")
148
+ : typeof value === "string"
149
+ ? value
150
+ : JSON.stringify(value);
151
+ lines.push(`- A11y (\`${key}\`): ${val}.`);
152
+ }
153
+ }
154
+ return lines.length > 0
155
+ ? lines.join("\n")
156
+ : "- (no verifiable requirements derived from spec)";
157
+ }
158
+ function singular(bucket) {
159
+ switch (bucket) {
160
+ case "colors":
161
+ return "color";
162
+ default:
163
+ return bucket;
164
+ }
165
+ }
166
+ //# sourceMappingURL=prompt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompt.js","sourceRoot":"","sources":["../../src/generator/prompt.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ export interface FewShot {
2
+ componentName: string;
3
+ files: Array<{
4
+ path: string;
5
+ content: string;
6
+ }>;
7
+ }
8
+ export interface GenerationRequest {
9
+ preamble: string;
10
+ spec: string;
11
+ derivedRequirements: string;
12
+ fewShots: FewShot[];
13
+ outputFormat: string;
14
+ targetComponent: string;
15
+ targetStack: string;
16
+ }
17
+ export declare function renderFewShotsBlock(fewShots: FewShot[]): string;
@@ -0,0 +1,15 @@
1
+ // Renders few-shot files as markdown fenced blocks, keeping the section
2
+ // empty-friendly (no examples on the first component per stack).
3
+ export function renderFewShotsBlock(fewShots) {
4
+ if (fewShots.length === 0) {
5
+ return "_(No prior implementations for this stack yet.)_";
6
+ }
7
+ const blocks = [];
8
+ for (const fs of fewShots) {
9
+ for (const f of fs.files) {
10
+ blocks.push(`### ${fs.componentName}/${f.path}\n\n\`\`\`\n${f.content}\n\`\`\``);
11
+ }
12
+ }
13
+ return blocks.join("\n\n");
14
+ }
15
+ //# sourceMappingURL=request.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"request.js","sourceRoot":"","sources":["../../src/generator/request.ts"],"names":[],"mappings":"AAeA,wEAAwE;AACxE,iEAAiE;AACjE,MAAM,UAAU,mBAAmB,CAAC,QAAmB;IACrD,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,OAAO,kDAAkD,CAAC;IAC5D,CAAC;IACD,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,KAAK,MAAM,EAAE,IAAI,QAAQ,EAAE,CAAC;QAC1B,KAAK,MAAM,CAAC,IAAI,EAAE,CAAC,KAAK,EAAE,CAAC;YACzB,MAAM,CAAC,IAAI,CACT,OAAO,EAAE,CAAC,aAAa,IAAI,CAAC,CAAC,IAAI,eAAe,CAAC,CAAC,OAAO,UAAU,CACpE,CAAC;QACJ,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AAC7B,CAAC"}
@@ -0,0 +1,45 @@
1
+ # Stack: Stencil (Web Components via @stencil/core)
2
+
3
+ ## Preamble
4
+
5
+ You are generating source code for a Stencil component. Follow these conventions strictly.
6
+
7
+ ### File shape
8
+
9
+ Emit exactly one `.tsx` file and one `.css` file. Do NOT emit a `readme.md`, a `generation.json`, a test file, or any other file. The tsx file exports a class decorated with `@Component({ tag, styleUrl, shadow: true })` where `tag` matches the value in the spec's `name` prefixed with `ds-` (`spec.name = "button"` → `tag: "ds-button"`).
10
+
11
+ ### Class shape
12
+
13
+ - One `class Ds<PascalName>` per file (e.g. `class DsButton`).
14
+ - Every prop from `spec.props` becomes `@Prop() <name>: <type> = <default>;` — use TypeScript primitive types (`boolean`, `string`, `number`) for the corresponding spec types; use string-literal unions for enums (`"a" | "b" | "c"`). Optional props (no default in the spec) get a trailing `?` on the name: `@Prop() href?: string;`.
15
+ - Every event from `spec.events` becomes `@Event() <name>!: EventEmitter<<Payload>>;` where `<Payload>` is the spec's `payload` type string (or an inline object type when the spec's payload is structured).
16
+ - The render method returns `<Host>...</Host>` with a `<slot />` when the spec declares a default slot.
17
+
18
+ ### Styling
19
+
20
+ - Import nothing from the CSS file — `styleUrl` handles the wiring.
21
+ - Reference tokens via `var(--ds-<category>-<leaf>)`, where `<category>` matches the bucket in `spec.tokens_used` (colors → `--ds-color-*`, spacing → `--ds-spacing-*`, radius → `--ds-radius-*`, font → `--ds-font-*`, shadow → `--ds-shadow-*`).
22
+ - Do NOT reference any token NOT listed in `spec.tokens_used`. Doing so breaks the cross-stack vocabulary contract.
23
+ - Do NOT invent component-local `--ds-<name>-*` custom properties unless the spec's a11y or notes section explicitly says the component should expose overridable defaults; the shared token vocabulary is the contract, component-local props are the exception.
24
+
25
+ ### Accessibility
26
+
27
+ - Use the native element named by `spec.a11y.native_element` as the outermost host child.
28
+ - Respect `spec.a11y.disabled_semantics` (typically `native_disabled_attribute` — use the native `disabled` attribute, do not fake it with a class).
29
+ - If the spec defines `spec.a11y.keyboard`, ensure the native element handles those keys without adding custom keydown handlers (Enter and Space on `<button>` are native).
30
+
31
+ ## OutputFormat
32
+
33
+ Return ONLY the file contents, using this exact format for each file:
34
+
35
+ === FILE: ds-<name>.tsx ===
36
+ ```tsx
37
+ <file contents>
38
+ ```
39
+
40
+ === FILE: ds-<name>.css ===
41
+ ```css
42
+ <file contents>
43
+ ```
44
+
45
+ Every file MUST be preceded by a `=== FILE: <relative-path> ===` marker on its own line. Paths are relative to `registry/<name>/implementations/stencil/`. Do NOT use absolute paths, `..`, or subdirectories. Do NOT emit any prose outside the fenced code blocks.
@@ -0,0 +1,54 @@
1
+ # Stack: Vue 3 (Single-File Components)
2
+
3
+ ## Preamble
4
+
5
+ You are generating source code for a Vue 3 component. Follow these conventions strictly.
6
+
7
+ ### File shape
8
+
9
+ Emit exactly one `.vue` Single-File Component per component, named `<PascalName>.vue` where `PascalName` is the spec's `name` in PascalCase (`spec.name = "button"` → `Button.vue`, `spec.name = "code-block"` → `CodeBlock.vue`). The file has three sections in this order: `<script setup lang="ts">`, `<template>`, `<style scoped>`. Do NOT emit a `readme.md`, a `generation.json`, a test file, or any other file.
10
+
11
+ ### Script shape
12
+
13
+ - Use the Composition API via `<script setup lang="ts">`. Do NOT use the Options API or export a default component.
14
+ - Map `spec.props` to a `defineProps<{ ... }>()` type argument:
15
+ - `boolean` → `boolean`
16
+ - `string` → `string`
17
+ - `number` → `number`
18
+ - `enum` → string-literal union (`'a' | 'b' | 'c'`)
19
+ - Optional props (no `default` in the spec) get `?` in the type argument: `href?: string`.
20
+ - When any prop declares a `default`, wrap with `withDefaults`: `const props = withDefaults(defineProps<{ ... }>(), { <name>: <default>, ... })`. When no prop has a default, use plain `defineProps<{ ... }>()` and do NOT import `withDefaults`.
21
+ - Map `spec.events` to `defineEmits<{ (e: '<name>', payload: <Payload>): void }>()`. Use the spec's `payload` string verbatim as `<Payload>` when it names a known DOM/JS type (e.g. `MouseEvent`, `string`), or emit an inline object type when the payload is structured. If `spec.events` is empty or missing, omit `defineEmits` entirely.
22
+ - Only import from `vue` what is actually used. Do NOT pull in `ref`, `reactive`, or `computed` unless the spec's `state_machine` or event handling requires reactive local state.
23
+
24
+ ### Template shape
25
+
26
+ - The outermost element is the native element named by `spec.a11y.native_element`.
27
+ - When `native_element` names two elements with a conditional (e.g. `"button or a (when href is set)"`), branch with `v-if` / `v-else` at the template root so exactly one native element renders per state. Do NOT wrap the conditional in an extra `<div>` — the root must BE the native element.
28
+ - Render `<slot />` inside the native element when the spec declares a default slot.
29
+ - Bind class names using an object or array binding when they depend on props: `:class="['button', ` `` `button--${props.variant}` `` `]"`. Do NOT use inline styles unless a token cannot express the constraint.
30
+
31
+ ### Styling
32
+
33
+ - Use `<style scoped>` — no unscoped globals.
34
+ - Reference tokens via `var(--ds-<category>-<leaf>)`, where `<category>` matches the bucket in `spec.tokens_used` (colors → `--ds-color-*`, spacing → `--ds-spacing-*`, radius → `--ds-radius-*`, font → `--ds-font-*`, shadow → `--ds-shadow-*`).
35
+ - Do NOT reference any token NOT listed in `spec.tokens_used`. Doing so breaks the cross-stack vocabulary contract.
36
+ - Use component-local class names WITHOUT the `ds-` prefix (e.g. `.button`, `.button--primary`) — Vue's `scoped` styles handle isolation. The `ds-` prefix is a Web Component tag convention that does not apply here.
37
+ - Do NOT invent component-local `--ds-<name>-*` custom properties unless the spec's a11y or notes section explicitly says the component should expose overridable defaults; the shared token vocabulary is the contract, component-local props are the exception.
38
+
39
+ ### Accessibility
40
+
41
+ - Use the native element named by `spec.a11y.native_element` as the outermost template child.
42
+ - Respect `spec.a11y.disabled_semantics` (typically `native_disabled_attribute` — bind the native `disabled` attribute directly, do not fake it with a class).
43
+ - If the spec defines `spec.a11y.keyboard`, ensure the native element handles those keys without adding custom `@keydown` handlers (Enter and Space on `<button>` are native).
44
+
45
+ ## OutputFormat
46
+
47
+ Return ONLY the file contents, using this exact format for each file:
48
+
49
+ === FILE: <PascalName>.vue ===
50
+ ```vue
51
+ <file contents>
52
+ ```
53
+
54
+ Every file MUST be preceded by a `=== FILE: <relative-path> ===` marker on its own line. Paths are relative to `registry/<name>/implementations/vue/`. Do NOT use absolute paths, `..`, or subdirectories. Do NOT emit any prose outside the fenced code blocks.
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export declare function main(argv?: string[]): Promise<number>;