@vedangiitb/qwintly-core 1.4.6 → 1.4.8

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 (26) hide show
  1. package/dist/ai/prompts/codegen.prompt.js +2 -2
  2. package/dist/ai/prompts/codegen.prompt.js.map +1 -1
  3. package/dist/ai/prompts/examples/codegen.examples.d.ts.map +1 -1
  4. package/dist/ai/prompts/examples/codegen.examples.js +40 -22
  5. package/dist/ai/prompts/examples/codegen.examples.js.map +1 -1
  6. package/dist/ai/tools/implementations/factories.d.ts +40 -2
  7. package/dist/ai/tools/implementations/factories.d.ts.map +1 -1
  8. package/dist/ai/tools/implementations/insertElement.impl.d.ts +40 -2
  9. package/dist/ai/tools/implementations/insertElement.impl.d.ts.map +1 -1
  10. package/dist/ai/tools/implementations/insertElement.impl.js +67 -8
  11. package/dist/ai/tools/implementations/insertElement.impl.js.map +1 -1
  12. package/dist/ai/tools/schemas/insertElement.schema.d.ts +107 -2
  13. package/dist/ai/tools/schemas/insertElement.schema.d.ts.map +1 -1
  14. package/dist/ai/tools/schemas/insertElement.schema.js +35 -42
  15. package/dist/ai/tools/schemas/insertElement.schema.js.map +1 -1
  16. package/dist/ai/tools/validators/builderElement.zod.d.ts +89 -1
  17. package/dist/ai/tools/validators/builderElement.zod.d.ts.map +1 -1
  18. package/dist/ai/tools/validators/builderElement.zod.js +34 -20
  19. package/dist/ai/tools/validators/builderElement.zod.js.map +1 -1
  20. package/dist/image/unsplash.service.js +1 -1
  21. package/dist/image/unsplash.service.js.map +1 -1
  22. package/dist/tests/insertUpdate.impl.test.js +113 -0
  23. package/dist/tests/insertUpdate.impl.test.js.map +1 -1
  24. package/dist/tests/unsplash.service.test.js +2 -0
  25. package/dist/tests/unsplash.service.test.js.map +1 -1
  26. package/package.json +1 -1
@@ -21,7 +21,7 @@ export const codegenPrompt = (params) => {
21
21
  - update_global_styles: Update app/styleConfig.json global design tokens
22
22
  - list_dir: List directory
23
23
  - create_new_route: Create route with page.tsx + pageConfig.json
24
- - insert_element: Insert element tree
24
+ - insert_element: Insert element tree (using flat array of elements)
25
25
  - delete_element: Delete element
26
26
  - update_classname: Update className
27
27
  - update_props: Update props
@@ -29,7 +29,7 @@ export const codegenPrompt = (params) => {
29
29
  - submit_codegen_done: Finish task
30
30
 
31
31
  Rules:
32
- - One insert_element per tree (include children inline) unless depth blocks it.
32
+ - Use \`insert_element\` to insert an entire UI tree at once. Pass a flat array of elements under \`elements\`. The root element of your new subtree must have \`parentId\` set to \`\"parent\"\`. All other elements in the array must set \`parentId\` matching the temporary \`id\` of their parent in that same array.
33
33
  - Create missing routes with create_new_route.
34
34
  - For any tool arg named route, always use URL paths with forward slashes (e.g. '/', '/pricing'); never use '\\' or filesystem paths like 'app/pricing'.
35
35
  - insert_element supports optional before_id to insert before an existing sibling; if omitted or not found, it appends to the end.
@@ -1 +1 @@
1
- {"version":3,"file":"codegen.prompt.js","sourceRoot":"","sources":["../../../src/ai/prompts/codegen.prompt.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AACjE,OAAO,EACL,SAAS,EACT,SAAS,EACT,gBAAgB,GACjB,MAAM,iCAAiC,CAAC;AASzC,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,MAA+B,EAAE,EAAE;IAC/D,MAAM,EAAE,IAAI,EAAE,YAAY,EAAE,gBAAgB,EAAE,YAAY,EAAE,GAAG,MAAM,CAAC;IAEtE,MAAM,MAAM,GAAG;;;;;;;;;MASX,gBAAgB,CAAC,YAAY,EAAE,SAAS,CAAC;GAC5C,CAAC,IAAI,EAAE,CAAC;IAET,MAAM,QAAQ,GAAG,SAAS,CACxB,mBAAmB,EACnB,SAAS,CAAC,MAAM,EAAE,IAAI,IAAI,IAAI,CAAC,CAChC,CAAC;IAEF,MAAM,SAAS,GAAG,SAAS,CACzB,OAAO,EACP;;;;;;;;;;;;;;;;;;;;;;;;;;;MA2BE,CAAC,IAAI,EAAE,CACT,CAAC;IAEH,MAAM,oBAAoB,GAAG,SAAS,CACpC,gBAAgB,EAChB;QACE,SAAS,CAAC,WAAW,EAAE,YAAY,CAAC,cAAc,CAAC,eAAe,CAAC;QAEnE,SAAS,CAAC,SAAS,EAAE,YAAY,CAAC,cAAc,CAAC,aAAa,CAAC;QAE/D,SAAS,CAAC,WAAW,EAAE,YAAY,CAAC,cAAc,CAAC,eAAe,CAAC;KACpE,CAAC,IAAI,CAAC,IAAI,CAAC,CACb,CAAC;IAEF,MAAM,OAAO,GAAG,SAAS,CACvB,kBAAkB,EAClB,SAAS,CAAC,SAAS,EAAE,gBAAgB,IAAI,EAAE,CAAC,CAC7C,CAAC;IAEF,MAAM,QAAQ,GAAG;QACf,MAAM;QACN,QAAQ;QACR,SAAS;QACT,oBAAoB;QACpB,OAAO;QACP,eAAe;KAChB,CAAC;IAEF,OAAO,QAAQ,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;AACtC,CAAC,CAAC","sourcesContent":["import { CodegenIndex, CollectedContext } from \"../../types/public.js\";\r\nimport { codegenExamples } from \"./examples/codegen.examples.js\";\r\nimport {\r\n jsonBlock,\r\n mdSection,\r\n projectStateNote,\r\n} from \"./helpers/promptParts.helper.js\";\r\n\r\nexport type CodegenNodePromptParams = {\r\n task: any;\r\n codegenIndex: CodegenIndex;\r\n collectedContext: CollectedContext;\r\n isNewProject: boolean;\r\n};\r\n\r\nexport const codegenPrompt = (params: CodegenNodePromptParams) => {\r\n const { task, codegenIndex, collectedContext, isNewProject } = params;\r\n\r\n const system = `\r\n You are a senior software engineer implementing tasks in an existing codebase.\r\n\r\n Rules:\r\n - Implement ONLY the requested task.\r\n - Prefer incremental edits over rewrites.\r\n - Be concise and deterministic.\r\n - Do not output code directly; use tools.\r\n\r\n ${projectStateNote(isNewProject, \"codegen\")}\r\n `.trim();\r\n\r\n const taskInfo = mdSection(\r\n \"Task to implement\",\r\n jsonBlock(\"task\", task ?? null),\r\n );\r\n\r\n const toolsInfo = mdSection(\r\n \"Tools\",\r\n `\r\n Available tools:\r\n\r\n - read_file: Read file\r\n - update_global_styles: Update app/styleConfig.json global design tokens\r\n - list_dir: List directory\r\n - create_new_route: Create route with page.tsx + pageConfig.json\r\n - insert_element: Insert element tree\r\n - delete_element: Delete element\r\n - update_classname: Update className\r\n - update_props: Update props\r\n - get_available_routes: Get available routes\r\n - submit_codegen_done: Finish task\r\n\r\n Rules:\r\n - One insert_element per tree (include children inline) unless depth blocks it.\r\n - Create missing routes with create_new_route.\r\n - For any tool arg named route, always use URL paths with forward slashes (e.g. '/', '/pricing'); never use '\\\\' or filesystem paths like 'app/pricing'.\r\n - insert_element supports optional before_id to insert before an existing sibling; if omitted or not found, it appends to the end.\r\n - Include images whenever mentoned to be included. Just use alt tag for images. image src auto-generated from alt\r\n - lucide-react icons only\r\n - Prefer semantic Tailwind tokens (bg-background, text-foreground, border-border, ring-ring, etc.) over hardcoded colors (e.g. slate-*, bg-white) for global styles. If you need different global colors/radius, call update_global_styles first, then use token-based classes.\r\n - update_global_styles args MUST be a flat JSON object with token keys as optional params. Include at least 1 key.\r\n - While updating global styles make sure that the styles updating (ex. background, foreground) are used in the right places (using bg-background, text-foreground, etc.). If not include them by updating the classname using update_classname tool\r\n - Never call update_global_styles with {} (empty object). If you don't need to change styles, do not call this tool.\r\n - Example: {\"radius\":\"0.75rem\",\"background\":\"oklch(0.98 0.01 80)\"}.\r\n\r\n `.trim(),\r\n );\r\n\r\n const projectConfiguration = mdSection(\r\n \"Project Config\",\r\n [\r\n jsonBlock(\"framework\", codegenIndex.projectConfigs.frameworkConfig),\r\n\r\n jsonBlock(\"runtime\", codegenIndex.projectConfigs.runtimeConfig),\r\n\r\n jsonBlock(\"rendering\", codegenIndex.projectConfigs.renderingConfig),\r\n ].join(\"\\n\"),\r\n );\r\n\r\n const context = mdSection(\r\n \"Relevant Context\",\r\n jsonBlock(\"context\", collectedContext ?? {}),\r\n );\r\n\r\n const sections = [\r\n system,\r\n taskInfo,\r\n toolsInfo,\r\n projectConfiguration,\r\n context,\r\n codegenExamples,\r\n ];\r\n\r\n return sections.join(\"\\n\\n---\\n\\n\");\r\n};\r\n"]}
1
+ {"version":3,"file":"codegen.prompt.js","sourceRoot":"","sources":["../../../src/ai/prompts/codegen.prompt.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AACjE,OAAO,EACL,SAAS,EACT,SAAS,EACT,gBAAgB,GACjB,MAAM,iCAAiC,CAAC;AASzC,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,MAA+B,EAAE,EAAE;IAC/D,MAAM,EAAE,IAAI,EAAE,YAAY,EAAE,gBAAgB,EAAE,YAAY,EAAE,GAAG,MAAM,CAAC;IAEtE,MAAM,MAAM,GAAG;;;;;;;;;MASX,gBAAgB,CAAC,YAAY,EAAE,SAAS,CAAC;GAC5C,CAAC,IAAI,EAAE,CAAC;IAET,MAAM,QAAQ,GAAG,SAAS,CACxB,mBAAmB,EACnB,SAAS,CAAC,MAAM,EAAE,IAAI,IAAI,IAAI,CAAC,CAChC,CAAC;IAEF,MAAM,SAAS,GAAG,SAAS,CACzB,OAAO,EACP;;;;;;;;;;;;;;;;;;;;;;;;;;;MA2BE,CAAC,IAAI,EAAE,CACT,CAAC;IAEH,MAAM,oBAAoB,GAAG,SAAS,CACpC,gBAAgB,EAChB;QACE,SAAS,CAAC,WAAW,EAAE,YAAY,CAAC,cAAc,CAAC,eAAe,CAAC;QAEnE,SAAS,CAAC,SAAS,EAAE,YAAY,CAAC,cAAc,CAAC,aAAa,CAAC;QAE/D,SAAS,CAAC,WAAW,EAAE,YAAY,CAAC,cAAc,CAAC,eAAe,CAAC;KACpE,CAAC,IAAI,CAAC,IAAI,CAAC,CACb,CAAC;IAEF,MAAM,OAAO,GAAG,SAAS,CACvB,kBAAkB,EAClB,SAAS,CAAC,SAAS,EAAE,gBAAgB,IAAI,EAAE,CAAC,CAC7C,CAAC;IAEF,MAAM,QAAQ,GAAG;QACf,MAAM;QACN,QAAQ;QACR,SAAS;QACT,oBAAoB;QACpB,OAAO;QACP,eAAe;KAChB,CAAC;IAEF,OAAO,QAAQ,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;AACtC,CAAC,CAAC","sourcesContent":["import { CodegenIndex, CollectedContext } from \"../../types/public.js\";\r\nimport { codegenExamples } from \"./examples/codegen.examples.js\";\r\nimport {\r\n jsonBlock,\r\n mdSection,\r\n projectStateNote,\r\n} from \"./helpers/promptParts.helper.js\";\r\n\r\nexport type CodegenNodePromptParams = {\r\n task: any;\r\n codegenIndex: CodegenIndex;\r\n collectedContext: CollectedContext;\r\n isNewProject: boolean;\r\n};\r\n\r\nexport const codegenPrompt = (params: CodegenNodePromptParams) => {\r\n const { task, codegenIndex, collectedContext, isNewProject } = params;\r\n\r\n const system = `\r\n You are a senior software engineer implementing tasks in an existing codebase.\r\n\r\n Rules:\r\n - Implement ONLY the requested task.\r\n - Prefer incremental edits over rewrites.\r\n - Be concise and deterministic.\r\n - Do not output code directly; use tools.\r\n\r\n ${projectStateNote(isNewProject, \"codegen\")}\r\n `.trim();\r\n\r\n const taskInfo = mdSection(\r\n \"Task to implement\",\r\n jsonBlock(\"task\", task ?? null),\r\n );\r\n\r\n const toolsInfo = mdSection(\r\n \"Tools\",\r\n `\r\n Available tools:\r\n\r\n - read_file: Read file\r\n - update_global_styles: Update app/styleConfig.json global design tokens\r\n - list_dir: List directory\r\n - create_new_route: Create route with page.tsx + pageConfig.json\r\n - insert_element: Insert element tree (using flat array of elements)\r\n - delete_element: Delete element\r\n - update_classname: Update className\r\n - update_props: Update props\r\n - get_available_routes: Get available routes\r\n - submit_codegen_done: Finish task\r\n\r\n Rules:\r\n - Use \\`insert_element\\` to insert an entire UI tree at once. Pass a flat array of elements under \\`elements\\`. The root element of your new subtree must have \\`parentId\\` set to \\`\\\"parent\\\"\\`. All other elements in the array must set \\`parentId\\` matching the temporary \\`id\\` of their parent in that same array.\r\n - Create missing routes with create_new_route.\r\n - For any tool arg named route, always use URL paths with forward slashes (e.g. '/', '/pricing'); never use '\\\\' or filesystem paths like 'app/pricing'.\r\n - insert_element supports optional before_id to insert before an existing sibling; if omitted or not found, it appends to the end.\r\n - Include images whenever mentoned to be included. Just use alt tag for images. image src auto-generated from alt\r\n - lucide-react icons only\r\n - Prefer semantic Tailwind tokens (bg-background, text-foreground, border-border, ring-ring, etc.) over hardcoded colors (e.g. slate-*, bg-white) for global styles. If you need different global colors/radius, call update_global_styles first, then use token-based classes.\r\n - update_global_styles args MUST be a flat JSON object with token keys as optional params. Include at least 1 key.\r\n - While updating global styles make sure that the styles updating (ex. background, foreground) are used in the right places (using bg-background, text-foreground, etc.). If not include them by updating the classname using update_classname tool\r\n - Never call update_global_styles with {} (empty object). If you don't need to change styles, do not call this tool.\r\n - Example: {\"radius\":\"0.75rem\",\"background\":\"oklch(0.98 0.01 80)\"}.\r\n\r\n `.trim(),\r\n );\r\n\r\n const projectConfiguration = mdSection(\r\n \"Project Config\",\r\n [\r\n jsonBlock(\"framework\", codegenIndex.projectConfigs.frameworkConfig),\r\n\r\n jsonBlock(\"runtime\", codegenIndex.projectConfigs.runtimeConfig),\r\n\r\n jsonBlock(\"rendering\", codegenIndex.projectConfigs.renderingConfig),\r\n ].join(\"\\n\"),\r\n );\r\n\r\n const context = mdSection(\r\n \"Relevant Context\",\r\n jsonBlock(\"context\", collectedContext ?? {}),\r\n );\r\n\r\n const sections = [\r\n system,\r\n taskInfo,\r\n toolsInfo,\r\n projectConfiguration,\r\n context,\r\n codegenExamples,\r\n ];\r\n\r\n return sections.join(\"\\n\\n---\\n\\n\");\r\n};\r\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"codegen.examples.d.ts","sourceRoot":"","sources":["../../../../src/ai/prompts/examples/codegen.examples.ts"],"names":[],"mappings":"AAsGA,eAAO,MAAM,eAAe,QAAsB,CAAC"}
1
+ {"version":3,"file":"codegen.examples.d.ts","sourceRoot":"","sources":["../../../../src/ai/prompts/examples/codegen.examples.ts"],"names":[],"mappings":"AAwHA,eAAO,MAAM,eAAe,QAAsB,CAAC"}
@@ -10,34 +10,52 @@ Tool call:
10
10
  "route": "/",
11
11
  "parent_id": "root",
12
12
  "before_id": "el_existing_sibling_id",
13
- "element": {
14
- "type": "div",
15
- "className": "mt-10 flex items-center justify-between gap-6 rounded-2xl border border-border bg-background p-6 text-foreground",
16
- "children": [
17
- {
18
- "type": "div",
19
- "className": "flex flex-col gap-1",
20
- "children": [
21
- { "type": "text", "className": "text-lg font-semibold", "props": { "text": "Ready to get started?" } },
22
- { "type": "text", "className": "text-sm text-muted-foreground", "props": { "text": "Create your first project in under a minute." } }
23
- ]
24
- },
25
- {
26
- "type": "button",
27
- "className": "inline-flex items-center justify-center rounded-xl bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:opacity-90",
28
- "props": {
29
- "text": "Get Started",
30
- "onClick": { "kind": "route", "href": "/signup" }
31
- }
13
+ "elements": [
14
+ {
15
+ "id": "cta_section",
16
+ "parentId": "parent",
17
+ "type": "div",
18
+ "className": "mt-10 flex items-center justify-between gap-6 rounded-2xl border border-border bg-background p-6 text-foreground"
19
+ },
20
+ {
21
+ "id": "text_container",
22
+ "parentId": "cta_section",
23
+ "type": "div",
24
+ "className": "flex flex-col gap-1"
25
+ },
26
+ {
27
+ "id": "cta_heading",
28
+ "parentId": "text_container",
29
+ "type": "text",
30
+ "className": "text-lg font-semibold",
31
+ "props": { "text": "Ready to get started?" }
32
+ },
33
+ {
34
+ "id": "cta_subheading",
35
+ "parentId": "text_container",
36
+ "type": "text",
37
+ "className": "text-sm text-muted-foreground",
38
+ "props": { "text": "Create your first project in under a minute." }
39
+ },
40
+ {
41
+ "id": "cta_btn",
42
+ "parentId": "cta_section",
43
+ "type": "button",
44
+ "className": "inline-flex items-center justify-center rounded-xl bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:opacity-90",
45
+ "props": {
46
+ "text": "Get Started",
47
+ "onClick": { "kind": "route", "href": "/signup" }
32
48
  }
33
- ]
34
- }
49
+ }
50
+ ]
35
51
  }
36
52
  \`\`\`
37
53
 
38
54
  Notes:
39
55
  - Always pass a complete \`className\` string (Tailwind only).
40
- - Use \`children\` to nest elements; children can themselves have \`children\` (deep nesting is supported).
56
+ - Use \`elements\` flat list to represent UI structures of arbitrary depth.
57
+ - Link child elements to their parent in the array by setting \`parentId\` to the parent element's temporary \`id\`.
58
+ - The root element in the \`elements\` array must have \`parentId\` set to \`"parent"\`.
41
59
  - Optional \`before_id\` inserts before an existing sibling; omit it to append at the end.
42
60
  - Use the returned \`inserted_id\` for follow-up updates.`,
43
61
  `### Example: \`update_global_styles\` (change global tokens)
@@ -1 +1 @@
1
- {"version":3,"file":"codegen.examples.js","sourceRoot":"","sources":["../../../../src/ai/prompts/examples/codegen.examples.ts"],"names":[],"mappings":"AAAA,MAAM,QAAQ,GAAG;IACf;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4DAwC0D;IAE1D;;;;;;;;;;;;;;;wEAesE;IAEtE;;;;;;;;;;;;;+DAa6D;IAE7D;;;;;;;;;;;;;;;;;;;;;;;;8FAwB4F;CAC7F,CAAC;AAEF,MAAM,CAAC,MAAM,eAAe,GAAG,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC","sourcesContent":["const examples = [\n `## Examples of tool calls\n\n ### Example: \\`insert_element\\` (add a CTA section)\n Goal: Insert a new section under the page root on route \\`/\\`.\n\nTool call:\n\\`\\`\\`json\n{\n \"route\": \"/\",\n \"parent_id\": \"root\",\n \"before_id\": \"el_existing_sibling_id\",\n \"element\": {\n \"type\": \"div\",\n \"className\": \"mt-10 flex items-center justify-between gap-6 rounded-2xl border border-border bg-background p-6 text-foreground\",\n \"children\": [\n {\n \"type\": \"div\",\n \"className\": \"flex flex-col gap-1\",\n \"children\": [\n { \"type\": \"text\", \"className\": \"text-lg font-semibold\", \"props\": { \"text\": \"Ready to get started?\" } },\n { \"type\": \"text\", \"className\": \"text-sm text-muted-foreground\", \"props\": { \"text\": \"Create your first project in under a minute.\" } }\n ]\n },\n {\n \"type\": \"button\",\n \"className\": \"inline-flex items-center justify-center rounded-xl bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:opacity-90\",\n \"props\": {\n \"text\": \"Get Started\",\n \"onClick\": { \"kind\": \"route\", \"href\": \"/signup\" }\n }\n }\n ]\n }\n}\n\\`\\`\\`\n\n Notes:\n - Always pass a complete \\`className\\` string (Tailwind only).\n - Use \\`children\\` to nest elements; children can themselves have \\`children\\` (deep nesting is supported).\n - Optional \\`before_id\\` inserts before an existing sibling; omit it to append at the end.\n - Use the returned \\`inserted_id\\` for follow-up updates.`,\n\n `### Example: \\`update_global_styles\\` (change global tokens)\nGoal: Adjust global theme tokens so semantic Tailwind classes (\\`bg-background\\`, \\`text-foreground\\`, \\`border-border\\`, etc.) reflect the desired look.\n\nTool call:\n\\`\\`\\`json\n{\n \"radius\": \"0.75rem\",\n \"background\": \"oklch(0.985 0.008 80.2)\",\n \"primary\": \"oklch(0.62 0.16 199.4)\"\n}\n\\`\\`\\`\n\nNotes:\n- Args are a flat JSON object with token keys as optional params.\n- Include at least 1 key/value; never call \\`update_global_styles\\` with \\`{}\\`.\n- Use safe, non-empty CSS strings (avoid \\`<\\`, \\`>\\`, or \\`</style\\`).`,\n\n `### Example: \\`update_classname\\` (replace className fully)\nGoal: Update styling on an existing element.\n\nTool call:\n\\`\\`\\`json\n{\n \"route\": \"/\",\n \"element_id\": \"el_123abc\",\n \"className\": \"mt-8 grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3\"\n}\n\\`\\`\\`\n\nNotes:\n- Provide the full \\`className\\`; do not send partial patches.`,\n\n `### Example: \\`update_props\\` (update element props)\nGoal: Update the text and click action for a button.\n\nTool call (function name in tool schema is \\`update_props\\`):\n\\`\\`\\`json\n{\n \"route\": \"/\",\n \"element_id\": \"el_123abc\",\n \"text\": \"Start free trial\",\n \"onClick\": { \"kind\": \"route\", \"href\": \"/pricing\", \"replace\": false }\n}\n\\`\\`\\`\n\nOther common prop updates:\n\\`\\`\\`json\n{\n \"route\": \"/\",\n \"element_id\": \"el_img_001\",\n \"alt\": \"A person collaborating on a laptop in a bright office\"\n}\n\\`\\`\\`\n\nNotes:\n- Only include props you want to change; omitted fields remain unchanged.\n- For images, \\`alt\\` is also used to fetch a suitable Unsplash image (src is auto-resolved).`,\n];\n\nexport const codegenExamples = examples.join(\"\\n\");\n"]}
1
+ {"version":3,"file":"codegen.examples.js","sourceRoot":"","sources":["../../../../src/ai/prompts/examples/codegen.examples.ts"],"names":[],"mappings":"AAAA,MAAM,QAAQ,GAAG;IACf;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4DA0D0D;IAE1D;;;;;;;;;;;;;;;wEAesE;IAEtE;;;;;;;;;;;;;+DAa6D;IAE7D;;;;;;;;;;;;;;;;;;;;;;;;8FAwB4F;CAC7F,CAAC;AAEF,MAAM,CAAC,MAAM,eAAe,GAAG,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC","sourcesContent":["const examples = [\n `## Examples of tool calls\n\n ### Example: \\`insert_element\\` (add a CTA section)\n Goal: Insert a new section under the page root on route \\`/\\`.\n\nTool call:\n\\`\\`\\`json\n{\n \"route\": \"/\",\n \"parent_id\": \"root\",\n \"before_id\": \"el_existing_sibling_id\",\n \"elements\": [\n {\n \"id\": \"cta_section\",\n \"parentId\": \"parent\",\n \"type\": \"div\",\n \"className\": \"mt-10 flex items-center justify-between gap-6 rounded-2xl border border-border bg-background p-6 text-foreground\"\n },\n {\n \"id\": \"text_container\",\n \"parentId\": \"cta_section\",\n \"type\": \"div\",\n \"className\": \"flex flex-col gap-1\"\n },\n {\n \"id\": \"cta_heading\",\n \"parentId\": \"text_container\",\n \"type\": \"text\",\n \"className\": \"text-lg font-semibold\",\n \"props\": { \"text\": \"Ready to get started?\" }\n },\n {\n \"id\": \"cta_subheading\",\n \"parentId\": \"text_container\",\n \"type\": \"text\",\n \"className\": \"text-sm text-muted-foreground\",\n \"props\": { \"text\": \"Create your first project in under a minute.\" }\n },\n {\n \"id\": \"cta_btn\",\n \"parentId\": \"cta_section\",\n \"type\": \"button\",\n \"className\": \"inline-flex items-center justify-center rounded-xl bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:opacity-90\",\n \"props\": {\n \"text\": \"Get Started\",\n \"onClick\": { \"kind\": \"route\", \"href\": \"/signup\" }\n }\n }\n ]\n}\n\\`\\`\\`\n\n Notes:\n - Always pass a complete \\`className\\` string (Tailwind only).\n - Use \\`elements\\` flat list to represent UI structures of arbitrary depth.\n - Link child elements to their parent in the array by setting \\`parentId\\` to the parent element's temporary \\`id\\`.\n - The root element in the \\`elements\\` array must have \\`parentId\\` set to \\`\"parent\"\\`.\n - Optional \\`before_id\\` inserts before an existing sibling; omit it to append at the end.\n - Use the returned \\`inserted_id\\` for follow-up updates.`,\n\n `### Example: \\`update_global_styles\\` (change global tokens)\nGoal: Adjust global theme tokens so semantic Tailwind classes (\\`bg-background\\`, \\`text-foreground\\`, \\`border-border\\`, etc.) reflect the desired look.\n\nTool call:\n\\`\\`\\`json\n{\n \"radius\": \"0.75rem\",\n \"background\": \"oklch(0.985 0.008 80.2)\",\n \"primary\": \"oklch(0.62 0.16 199.4)\"\n}\n\\`\\`\\`\n\nNotes:\n- Args are a flat JSON object with token keys as optional params.\n- Include at least 1 key/value; never call \\`update_global_styles\\` with \\`{}\\`.\n- Use safe, non-empty CSS strings (avoid \\`<\\`, \\`>\\`, or \\`</style\\`).`,\n\n `### Example: \\`update_classname\\` (replace className fully)\nGoal: Update styling on an existing element.\n\nTool call:\n\\`\\`\\`json\n{\n \"route\": \"/\",\n \"element_id\": \"el_123abc\",\n \"className\": \"mt-8 grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3\"\n}\n\\`\\`\\`\n\nNotes:\n- Provide the full \\`className\\`; do not send partial patches.`,\n\n `### Example: \\`update_props\\` (update element props)\nGoal: Update the text and click action for a button.\n\nTool call (function name in tool schema is \\`update_props\\`):\n\\`\\`\\`json\n{\n \"route\": \"/\",\n \"element_id\": \"el_123abc\",\n \"text\": \"Start free trial\",\n \"onClick\": { \"kind\": \"route\", \"href\": \"/pricing\", \"replace\": false }\n}\n\\`\\`\\`\n\nOther common prop updates:\n\\`\\`\\`json\n{\n \"route\": \"/\",\n \"element_id\": \"el_img_001\",\n \"alt\": \"A person collaborating on a laptop in a bright office\"\n}\n\\`\\`\\`\n\nNotes:\n- Only include props you want to change; omitted fields remain unchanged.\n- For images, \\`alt\\` is also used to fetch a suitable Unsplash image (src is auto-resolved).`,\n];\n\nexport const codegenExamples = examples.join(\"\\n\");\n"]}
@@ -155,27 +155,65 @@ export declare const createWorkspaceToolImpls: (deps: SearchDeps) => {
155
155
  deleted_id: string;
156
156
  error?: undefined;
157
157
  }>;
158
- insertElementImpl: (routeOrArgs: string | Record<string, unknown>, parentId?: string, element?: import("../../../types/elements.js").BuilderElement, beforeId?: string) => Promise<{
158
+ insertElementImpl: (routeOrArgs: string | Record<string, unknown>, parentId?: string, element?: import("../../../types/elements.js").BuilderElement | any[], beforeId?: string) => Promise<{
159
159
  success: boolean;
160
160
  error: string;
161
161
  error_detail: import("zod").ZodFlattenedError<{
162
162
  route: string;
163
163
  parent_id: string;
164
- element: any;
165
164
  before_id?: string | undefined;
165
+ element?: any;
166
+ elements?: {
167
+ id: string;
168
+ parentId: string;
169
+ type: "input" | "fragment" | "div" | "text" | "image" | "button" | "textarea" | "link" | "icon";
170
+ className?: string | undefined;
171
+ visible?: boolean | undefined;
172
+ props?: {
173
+ [x: string]: unknown;
174
+ onClick?: {
175
+ kind: "route";
176
+ href: string;
177
+ replace?: boolean | undefined;
178
+ } | {
179
+ kind: "back";
180
+ } | {
181
+ kind: "reload";
182
+ } | {
183
+ kind: "external";
184
+ href: string;
185
+ newTab?: boolean | undefined;
186
+ } | undefined;
187
+ text?: string | undefined;
188
+ href?: string | undefined;
189
+ placeholder?: string | undefined;
190
+ alt?: string | undefined;
191
+ target?: string | undefined;
192
+ rel?: string | undefined;
193
+ value?: string | undefined;
194
+ type?: string | undefined;
195
+ name?: string | undefined;
196
+ size?: number | undefined;
197
+ color?: string | undefined;
198
+ strokeWidth?: number | undefined;
199
+ } | undefined;
200
+ }[] | undefined;
166
201
  }, string>;
167
202
  changed?: undefined;
168
203
  inserted_id?: undefined;
204
+ inserted_ids?: undefined;
169
205
  } | {
170
206
  success: boolean;
171
207
  error: string;
172
208
  error_detail?: undefined;
173
209
  changed?: undefined;
174
210
  inserted_id?: undefined;
211
+ inserted_ids?: undefined;
175
212
  } | {
176
213
  success: boolean;
177
214
  changed: boolean;
178
215
  inserted_id: any;
216
+ inserted_ids: any[];
179
217
  error?: undefined;
180
218
  error_detail?: undefined;
181
219
  }>;
@@ -1 +1 @@
1
- {"version":3,"file":"factories.d.ts","sourceRoot":"","sources":["../../../../src/ai/tools/implementations/factories.ts"],"names":[],"mappings":"AAMA,OAAO,EAAoB,KAAK,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAMrE,OAAO,EAAE,0BAA0B,EAAE,MAAM,oBAAoB,CAAC;AAChE,YAAY,EACV,UAAU,EACV,MAAM,EACN,aAAa,GACd,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EAAE,wBAAwB,EAAE,MAAM,0BAA0B,CAAC;AACpE,OAAO,EAAE,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AAClE,OAAO,EAAE,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AAClE,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,EACL,gBAAgB,EAChB,KAAK,UAAU,EACf,KAAK,YAAY,GAClB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,yBAAyB,EAAE,MAAM,2BAA2B,CAAC;AACtE,OAAO,EAAE,4BAA4B,EAAE,MAAM,8BAA8B,CAAC;AAC5E,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAE1D,eAAO,MAAM,wBAAwB,GAAI,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA0BxD,CAAC"}
1
+ {"version":3,"file":"factories.d.ts","sourceRoot":"","sources":["../../../../src/ai/tools/implementations/factories.ts"],"names":[],"mappings":"AAMA,OAAO,EAAoB,KAAK,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAMrE,OAAO,EAAE,0BAA0B,EAAE,MAAM,oBAAoB,CAAC;AAChE,YAAY,EACV,UAAU,EACV,MAAM,EACN,aAAa,GACd,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EAAE,wBAAwB,EAAE,MAAM,0BAA0B,CAAC;AACpE,OAAO,EAAE,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AAClE,OAAO,EAAE,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AAClE,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,EACL,gBAAgB,EAChB,KAAK,UAAU,EACf,KAAK,YAAY,GAClB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,yBAAyB,EAAE,MAAM,2BAA2B,CAAC;AACtE,OAAO,EAAE,4BAA4B,EAAE,MAAM,8BAA8B,CAAC;AAC5E,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAE1D,eAAO,MAAM,wBAAwB,GAAI,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA0BxD,CAAC"}
@@ -1,26 +1,64 @@
1
1
  import type { BuilderElement } from "../../../types/elements.js";
2
2
  import { type WorkspaceDeps } from "./workspaceDeps.js";
3
- export declare const createInsertElementImpl: (deps: WorkspaceDeps) => (routeOrArgs: string | Record<string, unknown>, parentId?: string, element?: BuilderElement, beforeId?: string) => Promise<{
3
+ export declare const createInsertElementImpl: (deps: WorkspaceDeps) => (routeOrArgs: string | Record<string, unknown>, parentId?: string, element?: BuilderElement | any[], beforeId?: string) => Promise<{
4
4
  success: boolean;
5
5
  error: string;
6
6
  error_detail: import("zod").ZodFlattenedError<{
7
7
  route: string;
8
8
  parent_id: string;
9
- element: any;
10
9
  before_id?: string | undefined;
10
+ element?: any;
11
+ elements?: {
12
+ id: string;
13
+ parentId: string;
14
+ type: "input" | "fragment" | "div" | "text" | "image" | "button" | "textarea" | "link" | "icon";
15
+ className?: string | undefined;
16
+ visible?: boolean | undefined;
17
+ props?: {
18
+ [x: string]: unknown;
19
+ onClick?: {
20
+ kind: "route";
21
+ href: string;
22
+ replace?: boolean | undefined;
23
+ } | {
24
+ kind: "back";
25
+ } | {
26
+ kind: "reload";
27
+ } | {
28
+ kind: "external";
29
+ href: string;
30
+ newTab?: boolean | undefined;
31
+ } | undefined;
32
+ text?: string | undefined;
33
+ href?: string | undefined;
34
+ placeholder?: string | undefined;
35
+ alt?: string | undefined;
36
+ target?: string | undefined;
37
+ rel?: string | undefined;
38
+ value?: string | undefined;
39
+ type?: string | undefined;
40
+ name?: string | undefined;
41
+ size?: number | undefined;
42
+ color?: string | undefined;
43
+ strokeWidth?: number | undefined;
44
+ } | undefined;
45
+ }[] | undefined;
11
46
  }, string>;
12
47
  changed?: undefined;
13
48
  inserted_id?: undefined;
49
+ inserted_ids?: undefined;
14
50
  } | {
15
51
  success: boolean;
16
52
  error: string;
17
53
  error_detail?: undefined;
18
54
  changed?: undefined;
19
55
  inserted_id?: undefined;
56
+ inserted_ids?: undefined;
20
57
  } | {
21
58
  success: boolean;
22
59
  changed: boolean;
23
60
  inserted_id: any;
61
+ inserted_ids: any[];
24
62
  error?: undefined;
25
63
  error_detail?: undefined;
26
64
  }>;
@@ -1 +1 @@
1
- {"version":3,"file":"insertElement.impl.d.ts","sourceRoot":"","sources":["../../../../src/ai/tools/implementations/insertElement.impl.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAWjE,OAAO,EAAE,KAAK,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAExD,eAAO,MAAM,uBAAuB,GAAI,MAAM,aAAa,MAIvD,aAAa,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7C,WAAW,MAAM,EACjB,UAAU,cAAc,EACxB,WAAW,MAAM;;;;;;;;;;;;;;;;;;;;;;;EAuGpB,CAAC"}
1
+ {"version":3,"file":"insertElement.impl.d.ts","sourceRoot":"","sources":["../../../../src/ai/tools/implementations/insertElement.impl.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAWjE,OAAO,EAAE,KAAK,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAyCxD,eAAO,MAAM,uBAAuB,GAAI,MAAM,aAAa,MAIvD,aAAa,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7C,WAAW,MAAM,EACjB,UAAU,cAAc,GAAG,GAAG,EAAE,EAChC,WAAW,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA6HpB,CAAC"}
@@ -1,6 +1,39 @@
1
1
  import { resolveUnsplashImagesDeep } from "../../../image/unsplash.service.js";
2
2
  import { ensureElementIds, extractAllIdsDeep, findElementById, resolvePageConfigJsonPath, parsePageConfigJson, stringifyPageConfigJson, writeFileAtomic, } from "../helpers/pageConfigJson.helpers.js";
3
3
  import { InsertElementArgsZod } from "../validators/builderElement.zod.js";
4
+ function reconstructTree(flatElements) {
5
+ const rootFlats = flatElements.filter((el) => el.parentId === "parent");
6
+ if (rootFlats.length === 0) {
7
+ throw new Error("No root element found with parentId 'parent'");
8
+ }
9
+ const buildMap = new Map();
10
+ for (const flat of flatElements) {
11
+ buildMap.set(flat.id, {
12
+ type: flat.type,
13
+ className: flat.className,
14
+ visible: flat.visible,
15
+ props: flat.props ? JSON.parse(JSON.stringify(flat.props)) : undefined,
16
+ children: [],
17
+ });
18
+ }
19
+ for (const flat of flatElements) {
20
+ if (flat.parentId === "parent") {
21
+ continue;
22
+ }
23
+ const parentNode = buildMap.get(flat.parentId);
24
+ if (!parentNode) {
25
+ throw new Error(`Parent element with id '${flat.parentId}' not found in the list`);
26
+ }
27
+ const currentNode = buildMap.get(flat.id);
28
+ if (currentNode) {
29
+ if (!parentNode.children) {
30
+ parentNode.children = [];
31
+ }
32
+ parentNode.children.push(currentNode);
33
+ }
34
+ }
35
+ return rootFlats.map((rootFlat) => buildMap.get(rootFlat.id));
36
+ }
4
37
  export const createInsertElementImpl = (deps) => {
5
38
  const { workspaceRoot, fs } = deps;
6
39
  return async (routeOrArgs, parentId, element, beforeId) => {
@@ -10,7 +43,8 @@ export const createInsertElementImpl = (deps) => {
10
43
  route: routeOrArgs,
11
44
  parent_id: parentId,
12
45
  before_id: beforeId,
13
- element,
46
+ element: !Array.isArray(element) ? element : undefined,
47
+ elements: Array.isArray(element) ? element : undefined,
14
48
  };
15
49
  const parsedArgs = InsertElementArgsZod.safeParse(rawArgs);
16
50
  if (!parsedArgs.success) {
@@ -61,9 +95,33 @@ export const createInsertElementImpl = (deps) => {
61
95
  const existingIds = extractAllIdsDeep(elements);
62
96
  ensureElementIds(elements, existingIds);
63
97
  // Clone + inject ids for the inserted element subtree.
64
- const toInsert = JSON.parse(JSON.stringify(parsedArgs.data.element ?? null));
65
- await resolveUnsplashImagesDeep(toInsert);
66
- ensureElementIds([toInsert], existingIds);
98
+ let toInsert;
99
+ if (parsedArgs.data.elements) {
100
+ try {
101
+ toInsert = reconstructTree(parsedArgs.data.elements);
102
+ }
103
+ catch (err) {
104
+ return {
105
+ success: false,
106
+ error: err instanceof Error ? err.message : String(err),
107
+ };
108
+ }
109
+ }
110
+ else if (parsedArgs.data.element) {
111
+ toInsert = [
112
+ JSON.parse(JSON.stringify(parsedArgs.data.element ?? null)),
113
+ ];
114
+ }
115
+ else {
116
+ return {
117
+ success: false,
118
+ error: "invalid elements format: neither element nor elements provided",
119
+ };
120
+ }
121
+ for (const el of toInsert) {
122
+ await resolveUnsplashImagesDeep(el);
123
+ }
124
+ ensureElementIds(toInsert, existingIds);
67
125
  const parent = findElementById(elements, parent_id);
68
126
  if (!parent)
69
127
  return { success: false, error: "parent not found" };
@@ -74,14 +132,14 @@ export const createInsertElementImpl = (deps) => {
74
132
  if (before_id) {
75
133
  const idx = children.findIndex((c) => String(c?.id ?? "") === before_id);
76
134
  if (idx >= 0) {
77
- children.splice(idx, 0, toInsert);
135
+ children.splice(idx, 0, ...toInsert);
78
136
  }
79
137
  else {
80
- children.push(toInsert);
138
+ children.push(...toInsert);
81
139
  }
82
140
  }
83
141
  else {
84
- children.push(toInsert);
142
+ children.push(...toInsert);
85
143
  }
86
144
  const after = stringifyPageConfigJson({ elements });
87
145
  try {
@@ -89,7 +147,8 @@ export const createInsertElementImpl = (deps) => {
89
147
  return {
90
148
  success: true,
91
149
  changed: true,
92
- inserted_id: toInsert.id,
150
+ inserted_id: toInsert[0].id,
151
+ inserted_ids: toInsert.map((el) => el.id),
93
152
  };
94
153
  }
95
154
  catch (err) {
@@ -1 +1 @@
1
- {"version":3,"file":"insertElement.impl.js","sourceRoot":"","sources":["../../../../src/ai/tools/implementations/insertElement.impl.ts"],"names":[],"mappings":"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","sourcesContent":["import { resolveUnsplashImagesDeep } from \"../../../image/unsplash.service.js\";\nimport type { BuilderElement } from \"../../../types/elements.js\";\nimport {\n ensureElementIds,\n extractAllIdsDeep,\n findElementById,\n resolvePageConfigJsonPath,\n parsePageConfigJson,\n stringifyPageConfigJson,\n writeFileAtomic,\n} from \"../helpers/pageConfigJson.helpers.js\";\nimport { InsertElementArgsZod } from \"../validators/builderElement.zod.js\";\nimport { type WorkspaceDeps } from \"./workspaceDeps.js\";\n\nexport const createInsertElementImpl = (deps: WorkspaceDeps) => {\n const { workspaceRoot, fs } = deps;\n\n return async (\n routeOrArgs: string | Record<string, unknown>,\n parentId?: string,\n element?: BuilderElement,\n beforeId?: string,\n ) => {\n const rawArgs =\n typeof routeOrArgs === \"object\" && routeOrArgs !== null\n ? (routeOrArgs as Record<string, unknown>)\n : {\n route: routeOrArgs,\n parent_id: parentId,\n before_id: beforeId,\n element,\n };\n\n const parsedArgs = InsertElementArgsZod.safeParse(rawArgs);\n if (!parsedArgs.success) {\n return {\n success: false,\n error: \"invalid args\",\n error_detail: parsedArgs.error.flatten(),\n };\n }\n\n const parent_id = String(parsedArgs.data.parent_id ?? \"\").trim();\n if (!parent_id) return { success: false, error: \"invalid parent_id\" };\n\n const before_id = String(parsedArgs.data.before_id ?? \"\").trim();\n\n let configPath: string;\n try {\n configPath = await resolvePageConfigJsonPath(workspaceRoot, parsedArgs.data.route, fs);\n } catch (err) {\n return {\n success: false,\n error: err instanceof Error ? err.message : String(err),\n };\n }\n\n let before = \"\";\n try {\n before = await fs.readFile(configPath);\n } catch (err) {\n const code = (err as NodeJS.ErrnoException | null)?.code;\n if (code === \"ENOENT\") return { success: false, error: \"not found\" };\n return {\n success: false,\n error: err instanceof Error ? err.message : String(err),\n };\n }\n\n let parsed: ReturnType<typeof parsePageConfigJson>;\n try {\n parsed = parsePageConfigJson(before);\n } catch (err) {\n return {\n success: false,\n error: err instanceof Error ? err.message : String(err),\n };\n }\n\n const elements = parsed.elements ?? [];\n const existingIds = extractAllIdsDeep(elements);\n ensureElementIds(elements, existingIds);\n\n // Clone + inject ids for the inserted element subtree.\n const toInsert = JSON.parse(\n JSON.stringify(parsedArgs.data.element ?? null),\n ) as BuilderElement;\n await resolveUnsplashImagesDeep(toInsert);\n ensureElementIds([toInsert], existingIds);\n\n const parent = findElementById(elements, parent_id);\n if (!parent) return { success: false, error: \"parent not found\" };\n\n const anyParent = parent as any;\n if (!anyParent.children || !Array.isArray(anyParent.children))\n anyParent.children = [];\n\n const children = anyParent.children as BuilderElement[];\n if (before_id) {\n const idx = children.findIndex((c: any) => String(c?.id ?? \"\") === before_id);\n if (idx >= 0) {\n children.splice(idx, 0, toInsert);\n } else {\n children.push(toInsert);\n }\n } else {\n children.push(toInsert);\n }\n\n const after = stringifyPageConfigJson({ elements });\n try {\n await writeFileAtomic(configPath, after);\n return {\n success: true,\n changed: true,\n inserted_id: (toInsert as any).id,\n };\n } catch (err) {\n return {\n success: false,\n error: err instanceof Error ? err.message : String(err),\n };\n }\n };\n};\n"]}
1
+ {"version":3,"file":"insertElement.impl.js","sourceRoot":"","sources":["../../../../src/ai/tools/implementations/insertElement.impl.ts"],"names":[],"mappings":"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","sourcesContent":["import { resolveUnsplashImagesDeep } from \"../../../image/unsplash.service.js\";\nimport type { BuilderElement } from \"../../../types/elements.js\";\nimport {\n ensureElementIds,\n extractAllIdsDeep,\n findElementById,\n resolvePageConfigJsonPath,\n parsePageConfigJson,\n stringifyPageConfigJson,\n writeFileAtomic,\n} from \"../helpers/pageConfigJson.helpers.js\";\nimport { InsertElementArgsZod } from \"../validators/builderElement.zod.js\";\nimport { type WorkspaceDeps } from \"./workspaceDeps.js\";\n\nfunction reconstructTree(flatElements: any[]): BuilderElement[] {\n const rootFlats = flatElements.filter((el) => el.parentId === \"parent\");\n if (rootFlats.length === 0) {\n throw new Error(\"No root element found with parentId 'parent'\");\n }\n\n const buildMap = new Map<string, any>();\n for (const flat of flatElements) {\n buildMap.set(flat.id, {\n type: flat.type,\n className: flat.className,\n visible: flat.visible,\n props: flat.props ? JSON.parse(JSON.stringify(flat.props)) : undefined,\n children: [],\n });\n }\n\n for (const flat of flatElements) {\n if (flat.parentId === \"parent\") {\n continue;\n }\n const parentNode = buildMap.get(flat.parentId);\n if (!parentNode) {\n throw new Error(\n `Parent element with id '${flat.parentId}' not found in the list`,\n );\n }\n const currentNode = buildMap.get(flat.id);\n if (currentNode) {\n if (!parentNode.children) {\n parentNode.children = [];\n }\n parentNode.children.push(currentNode);\n }\n }\n\n return rootFlats.map((rootFlat) => buildMap.get(rootFlat.id));\n}\n\nexport const createInsertElementImpl = (deps: WorkspaceDeps) => {\n const { workspaceRoot, fs } = deps;\n\n return async (\n routeOrArgs: string | Record<string, unknown>,\n parentId?: string,\n element?: BuilderElement | any[],\n beforeId?: string,\n ) => {\n const rawArgs =\n typeof routeOrArgs === \"object\" && routeOrArgs !== null\n ? (routeOrArgs as Record<string, unknown>)\n : {\n route: routeOrArgs,\n parent_id: parentId,\n before_id: beforeId,\n element: !Array.isArray(element) ? element : undefined,\n elements: Array.isArray(element) ? element : undefined,\n };\n\n const parsedArgs = InsertElementArgsZod.safeParse(rawArgs);\n if (!parsedArgs.success) {\n return {\n success: false,\n error: \"invalid args\",\n error_detail: parsedArgs.error.flatten(),\n };\n }\n\n const parent_id = String(parsedArgs.data.parent_id ?? \"\").trim();\n if (!parent_id) return { success: false, error: \"invalid parent_id\" };\n\n const before_id = String(parsedArgs.data.before_id ?? \"\").trim();\n\n let configPath: string;\n try {\n configPath = await resolvePageConfigJsonPath(workspaceRoot, parsedArgs.data.route, fs);\n } catch (err) {\n return {\n success: false,\n error: err instanceof Error ? err.message : String(err),\n };\n }\n\n let before = \"\";\n try {\n before = await fs.readFile(configPath);\n } catch (err) {\n const code = (err as NodeJS.ErrnoException | null)?.code;\n if (code === \"ENOENT\") return { success: false, error: \"not found\" };\n return {\n success: false,\n error: err instanceof Error ? err.message : String(err),\n };\n }\n\n let parsed: ReturnType<typeof parsePageConfigJson>;\n try {\n parsed = parsePageConfigJson(before);\n } catch (err) {\n return {\n success: false,\n error: err instanceof Error ? err.message : String(err),\n };\n }\n\n const elements = parsed.elements ?? [];\n const existingIds = extractAllIdsDeep(elements);\n ensureElementIds(elements, existingIds);\n\n // Clone + inject ids for the inserted element subtree.\n let toInsert: BuilderElement[];\n if (parsedArgs.data.elements) {\n try {\n toInsert = reconstructTree(parsedArgs.data.elements);\n } catch (err) {\n return {\n success: false,\n error: err instanceof Error ? err.message : String(err),\n };\n }\n } else if (parsedArgs.data.element) {\n toInsert = [\n JSON.parse(JSON.stringify(parsedArgs.data.element ?? null)) as BuilderElement,\n ];\n } else {\n return {\n success: false,\n error: \"invalid elements format: neither element nor elements provided\",\n };\n }\n\n for (const el of toInsert) {\n await resolveUnsplashImagesDeep(el);\n }\n ensureElementIds(toInsert, existingIds);\n\n const parent = findElementById(elements, parent_id);\n if (!parent) return { success: false, error: \"parent not found\" };\n\n const anyParent = parent as any;\n if (!anyParent.children || !Array.isArray(anyParent.children))\n anyParent.children = [];\n\n const children = anyParent.children as BuilderElement[];\n if (before_id) {\n const idx = children.findIndex((c: any) => String(c?.id ?? \"\") === before_id);\n if (idx >= 0) {\n children.splice(idx, 0, ...toInsert);\n } else {\n children.push(...toInsert);\n }\n } else {\n children.push(...toInsert);\n }\n\n const after = stringifyPageConfigJson({ elements });\n try {\n await writeFileAtomic(configPath, after);\n return {\n success: true,\n changed: true,\n inserted_id: (toInsert[0] as any).id,\n inserted_ids: toInsert.map((el: any) => el.id),\n };\n } catch (err) {\n return {\n success: false,\n error: err instanceof Error ? err.message : String(err),\n };\n }\n };\n};\n"]}
@@ -1,6 +1,5 @@
1
1
  import { Type } from "@google/genai";
2
2
  export declare const ELEMENT_TYPES: readonly ["fragment", "div", "text", "image", "button", "input", "textarea", "link", "icon"];
3
- export declare const BuilderElementSchema: any;
4
3
  export declare const InsertElementSchema: {
5
4
  name: string;
6
5
  description: string;
@@ -20,7 +19,113 @@ export declare const InsertElementSchema: {
20
19
  type: Type;
21
20
  description: string;
22
21
  };
23
- element: any;
22
+ elements: {
23
+ type: Type;
24
+ description: string;
25
+ items: {
26
+ type: Type;
27
+ properties: {
28
+ id: {
29
+ type: Type;
30
+ description: string;
31
+ };
32
+ parentId: {
33
+ type: Type;
34
+ description: string;
35
+ };
36
+ type: {
37
+ type: Type;
38
+ enum: readonly ["fragment", "div", "text", "image", "button", "input", "textarea", "link", "icon"];
39
+ description: string;
40
+ };
41
+ className: {
42
+ type: Type;
43
+ description: string;
44
+ };
45
+ visible: {
46
+ type: Type;
47
+ description: string;
48
+ };
49
+ props: {
50
+ type: Type;
51
+ properties: {
52
+ onClick: {
53
+ type: Type;
54
+ properties: {
55
+ kind: {
56
+ type: Type;
57
+ enum: string[];
58
+ description: string;
59
+ };
60
+ href: {
61
+ type: Type;
62
+ description: string;
63
+ };
64
+ replace: {
65
+ type: Type;
66
+ description: string;
67
+ };
68
+ newTab: {
69
+ type: Type;
70
+ description: string;
71
+ };
72
+ };
73
+ required: string[];
74
+ };
75
+ text: {
76
+ type: Type;
77
+ description: string;
78
+ };
79
+ href: {
80
+ type: Type;
81
+ description: string;
82
+ };
83
+ placeholder: {
84
+ type: Type;
85
+ description: string;
86
+ };
87
+ alt: {
88
+ type: Type;
89
+ description: string;
90
+ };
91
+ target: {
92
+ type: Type;
93
+ description: string;
94
+ };
95
+ rel: {
96
+ type: Type;
97
+ description: string;
98
+ };
99
+ value: {
100
+ type: Type;
101
+ description: string;
102
+ };
103
+ type: {
104
+ type: Type;
105
+ description: string;
106
+ };
107
+ name: {
108
+ type: Type;
109
+ description: string;
110
+ };
111
+ size: {
112
+ type: Type;
113
+ description: string;
114
+ };
115
+ color: {
116
+ type: Type;
117
+ description: string;
118
+ };
119
+ strokeWidth: {
120
+ type: Type;
121
+ description: string;
122
+ };
123
+ };
124
+ };
125
+ };
126
+ required: string[];
127
+ };
128
+ };
24
129
  };
25
130
  required: string[];
26
131
  };
@@ -1 +1 @@
1
- {"version":3,"file":"insertElement.schema.d.ts","sourceRoot":"","sources":["../../../../src/ai/tools/schemas/insertElement.schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAErC,eAAO,MAAM,aAAa,8FAUhB,CAAC;AA0HX,eAAO,MAAM,oBAAoB,EAAE,GAAkC,CAAC;AAEtE,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;CA+B/B,CAAC"}
1
+ {"version":3,"file":"insertElement.schema.d.ts","sourceRoot":"","sources":["../../../../src/ai/tools/schemas/insertElement.schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAErC,eAAO,MAAM,aAAa,8FAUhB,CAAC;AAmFX,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6D/B,CAAC"}