@vedangiitb/qwintly-core 1.4.12 → 1.5.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 (146) hide show
  1. package/dist/ai/generate/gemini.client.js +1 -1
  2. package/dist/ai/generate/gemini.client.js.map +1 -1
  3. package/dist/ai/generate/generateClient.d.ts.map +1 -1
  4. package/dist/ai/generate/generateClient.js +7 -3
  5. package/dist/ai/generate/generateClient.js.map +1 -1
  6. package/dist/ai/toolLoop/helpers/aiCall.helper.d.ts +16 -0
  7. package/dist/ai/toolLoop/helpers/aiCall.helper.d.ts.map +1 -0
  8. package/dist/ai/toolLoop/helpers/aiCall.helper.js +23 -0
  9. package/dist/ai/toolLoop/helpers/aiCall.helper.js.map +1 -0
  10. package/dist/ai/toolLoop/helpers/applyPatch.helper.d.ts +6 -0
  11. package/dist/ai/toolLoop/helpers/applyPatch.helper.d.ts.map +1 -0
  12. package/dist/ai/toolLoop/helpers/applyPatch.helper.js +10 -0
  13. package/dist/ai/toolLoop/helpers/applyPatch.helper.js.map +1 -0
  14. package/dist/ai/toolLoop/helpers/errors.helper.d.ts +15 -0
  15. package/dist/ai/toolLoop/helpers/errors.helper.d.ts.map +1 -0
  16. package/dist/ai/toolLoop/helpers/errors.helper.js +50 -0
  17. package/dist/ai/toolLoop/helpers/errors.helper.js.map +1 -0
  18. package/dist/ai/toolLoop/helpers/fsHelpers.d.ts +5 -0
  19. package/dist/ai/toolLoop/helpers/fsHelpers.d.ts.map +1 -0
  20. package/dist/ai/toolLoop/helpers/fsHelpers.js +28 -0
  21. package/dist/ai/toolLoop/helpers/fsHelpers.js.map +1 -0
  22. package/dist/ai/toolLoop/helpers/patchRetry.helper.d.ts +11 -0
  23. package/dist/ai/toolLoop/helpers/patchRetry.helper.d.ts.map +1 -0
  24. package/dist/ai/toolLoop/helpers/patchRetry.helper.js +30 -0
  25. package/dist/ai/toolLoop/helpers/patchRetry.helper.js.map +1 -0
  26. package/dist/ai/toolLoop/helpers/persistTokens.helpers.d.ts +7 -0
  27. package/dist/ai/toolLoop/helpers/persistTokens.helpers.d.ts.map +1 -0
  28. package/dist/ai/toolLoop/helpers/persistTokens.helpers.js +25 -0
  29. package/dist/ai/toolLoop/helpers/persistTokens.helpers.js.map +1 -0
  30. package/dist/ai/toolLoop/{plannerTaskParser.d.ts → helpers/plannerTaskParser.d.ts} +1 -1
  31. package/dist/ai/toolLoop/helpers/plannerTaskParser.d.ts.map +1 -0
  32. package/dist/ai/toolLoop/{plannerTaskParser.js → helpers/plannerTaskParser.js} +5 -1
  33. package/dist/ai/toolLoop/helpers/plannerTaskParser.js.map +1 -0
  34. package/dist/ai/toolLoop/helpers/readFile.helpers.d.ts +10 -0
  35. package/dist/ai/toolLoop/helpers/readFile.helpers.d.ts.map +1 -0
  36. package/dist/ai/toolLoop/helpers/readFile.helpers.js +26 -0
  37. package/dist/ai/toolLoop/helpers/readFile.helpers.js.map +1 -0
  38. package/dist/ai/toolLoop/helpers/signatures.helper.d.ts +2 -0
  39. package/dist/ai/toolLoop/helpers/signatures.helper.d.ts.map +1 -0
  40. package/dist/ai/toolLoop/helpers/signatures.helper.js +23 -0
  41. package/dist/ai/toolLoop/helpers/signatures.helper.js.map +1 -0
  42. package/dist/ai/toolLoop/helpers/toolArgs.helper.d.ts +12 -0
  43. package/dist/ai/toolLoop/helpers/toolArgs.helper.d.ts.map +1 -0
  44. package/dist/ai/toolLoop/helpers/toolArgs.helper.js +40 -0
  45. package/dist/ai/toolLoop/helpers/toolArgs.helper.js.map +1 -0
  46. package/dist/ai/toolLoop/helpers/toolExecution.helper.d.ts +22 -0
  47. package/dist/ai/toolLoop/helpers/toolExecution.helper.d.ts.map +1 -0
  48. package/dist/ai/toolLoop/helpers/toolExecution.helper.js +75 -0
  49. package/dist/ai/toolLoop/helpers/toolExecution.helper.js.map +1 -0
  50. package/dist/ai/toolLoop/helpers/toolHandlers.helper.d.ts +6 -0
  51. package/dist/ai/toolLoop/helpers/toolHandlers.helper.d.ts.map +1 -0
  52. package/dist/ai/toolLoop/helpers/toolHandlers.helper.js +86 -0
  53. package/dist/ai/toolLoop/helpers/toolHandlers.helper.js.map +1 -0
  54. package/dist/ai/toolLoop/toolEventSummary.d.ts +28 -0
  55. package/dist/ai/toolLoop/toolEventSummary.d.ts.map +1 -0
  56. package/dist/ai/toolLoop/toolEventSummary.js +253 -0
  57. package/dist/ai/toolLoop/toolEventSummary.js.map +1 -0
  58. package/dist/ai/toolLoop/toolLoopContext.d.ts +0 -14
  59. package/dist/ai/toolLoop/toolLoopContext.d.ts.map +1 -1
  60. package/dist/ai/toolLoop/toolLoopContext.js +7 -50
  61. package/dist/ai/toolLoop/toolLoopContext.js.map +1 -1
  62. package/dist/ai/toolLoop/toolLoopRunner.d.ts +6 -5
  63. package/dist/ai/toolLoop/toolLoopRunner.d.ts.map +1 -1
  64. package/dist/ai/toolLoop/toolLoopRunner.js +48 -281
  65. package/dist/ai/toolLoop/toolLoopRunner.js.map +1 -1
  66. package/dist/ai/toolLoop/toolStatusMessage.d.ts +6 -0
  67. package/dist/ai/toolLoop/toolStatusMessage.d.ts.map +1 -0
  68. package/dist/ai/toolLoop/toolStatusMessage.js +140 -0
  69. package/dist/ai/toolLoop/toolStatusMessage.js.map +1 -0
  70. package/dist/ai/tools/helpers/applyPatch.helpers.d.ts.map +1 -1
  71. package/dist/ai/tools/helpers/applyPatch.helpers.js +9 -4
  72. package/dist/ai/tools/helpers/applyPatch.helpers.js.map +1 -1
  73. package/dist/ai/tools/helpers/fileSystem.helpers.d.ts.map +1 -1
  74. package/dist/ai/tools/helpers/fileSystem.helpers.js +7 -1
  75. package/dist/ai/tools/helpers/fileSystem.helpers.js.map +1 -1
  76. package/dist/ai/tools/helpers/pageConfigJson.helpers.d.ts +13 -0
  77. package/dist/ai/tools/helpers/pageConfigJson.helpers.d.ts.map +1 -1
  78. package/dist/ai/tools/helpers/pageConfigJson.helpers.js +51 -21
  79. package/dist/ai/tools/helpers/pageConfigJson.helpers.js.map +1 -1
  80. package/dist/ai/tools/implementations/applyPatch.impl.js +2 -2
  81. package/dist/ai/tools/implementations/applyPatch.impl.js.map +1 -1
  82. package/dist/ai/tools/implementations/createNewRoute.impl.js +1 -1
  83. package/dist/ai/tools/implementations/createNewRoute.impl.js.map +1 -1
  84. package/dist/ai/tools/implementations/deleteElement.impl.d.ts.map +1 -1
  85. package/dist/ai/tools/implementations/deleteElement.impl.js +5 -37
  86. package/dist/ai/tools/implementations/deleteElement.impl.js.map +1 -1
  87. package/dist/ai/tools/implementations/insertElement.impl.d.ts.map +1 -1
  88. package/dist/ai/tools/implementations/insertElement.impl.js +9 -46
  89. package/dist/ai/tools/implementations/insertElement.impl.js.map +1 -1
  90. package/dist/ai/tools/implementations/updateClassName.impl.d.ts.map +1 -1
  91. package/dist/ai/tools/implementations/updateClassName.impl.js +5 -37
  92. package/dist/ai/tools/implementations/updateClassName.impl.js.map +1 -1
  93. package/dist/ai/tools/implementations/updateGlobalStyles.impl.d.ts.map +1 -1
  94. package/dist/ai/tools/implementations/updateGlobalStyles.impl.js +4 -3
  95. package/dist/ai/tools/implementations/updateGlobalStyles.impl.js.map +1 -1
  96. package/dist/ai/tools/implementations/updateProps.impl.d.ts.map +1 -1
  97. package/dist/ai/tools/implementations/updateProps.impl.js +5 -37
  98. package/dist/ai/tools/implementations/updateProps.impl.js.map +1 -1
  99. package/dist/ai/tools/schemas/createNewRoute.schema.d.ts.map +1 -1
  100. package/dist/ai/tools/schemas/createNewRoute.schema.js +1 -1
  101. package/dist/ai/tools/schemas/createNewRoute.schema.js.map +1 -1
  102. package/dist/ai/tools/schemas/deleteElement.schema.d.ts.map +1 -1
  103. package/dist/ai/tools/schemas/deleteElement.schema.js +1 -2
  104. package/dist/ai/tools/schemas/deleteElement.schema.js.map +1 -1
  105. package/dist/ai/tools/schemas/elementProps.schema.d.ts +101 -0
  106. package/dist/ai/tools/schemas/elementProps.schema.d.ts.map +1 -0
  107. package/dist/ai/tools/schemas/elementProps.schema.js +74 -0
  108. package/dist/ai/tools/schemas/elementProps.schema.js.map +1 -0
  109. package/dist/ai/tools/schemas/insertElement.schema.d.ts.map +1 -1
  110. package/dist/ai/tools/schemas/insertElement.schema.js +2 -74
  111. package/dist/ai/tools/schemas/insertElement.schema.js.map +1 -1
  112. package/dist/ai/tools/schemas/updateClassName.schema.d.ts.map +1 -1
  113. package/dist/ai/tools/schemas/updateClassName.schema.js +1 -2
  114. package/dist/ai/tools/schemas/updateClassName.schema.js.map +1 -1
  115. package/dist/ai/tools/schemas/updateProps.schema.d.ts +9 -9
  116. package/dist/ai/tools/schemas/updateProps.schema.d.ts.map +1 -1
  117. package/dist/ai/tools/schemas/updateProps.schema.js +3 -69
  118. package/dist/ai/tools/schemas/updateProps.schema.js.map +1 -1
  119. package/dist/image/unsplash.service.d.ts.map +1 -1
  120. package/dist/image/unsplash.service.js +6 -2
  121. package/dist/image/unsplash.service.js.map +1 -1
  122. package/dist/indexer/projectInfoIndex.d.ts.map +1 -1
  123. package/dist/indexer/projectInfoIndex.js +33 -25
  124. package/dist/indexer/projectInfoIndex.js.map +1 -1
  125. package/dist/tests/plannerTaskParser.test.d.ts +2 -0
  126. package/dist/tests/plannerTaskParser.test.d.ts.map +1 -0
  127. package/dist/tests/plannerTaskParser.test.js +49 -0
  128. package/dist/tests/plannerTaskParser.test.js.map +1 -0
  129. package/dist/types/styleConfig.d.ts.map +1 -1
  130. package/dist/types/styleConfig.js +2 -3
  131. package/dist/types/styleConfig.js.map +1 -1
  132. package/dist/utils/utils.d.ts +3 -0
  133. package/dist/utils/utils.d.ts.map +1 -1
  134. package/dist/utils/utils.js +8 -0
  135. package/dist/utils/utils.js.map +1 -1
  136. package/dist/utils/workspace.d.ts +1 -1
  137. package/dist/utils/workspace.d.ts.map +1 -1
  138. package/dist/utils/workspace.js +6 -11
  139. package/dist/utils/workspace.js.map +1 -1
  140. package/package.json +1 -1
  141. package/dist/ai/toolLoop/plannerTaskParser.d.ts.map +0 -1
  142. package/dist/ai/toolLoop/plannerTaskParser.js.map +0 -1
  143. package/dist/ai/toolLoop/toolLoopRunnerUtils.d.ts +0 -51
  144. package/dist/ai/toolLoop/toolLoopRunnerUtils.d.ts.map +0 -1
  145. package/dist/ai/toolLoop/toolLoopRunnerUtils.js +0 -367
  146. package/dist/ai/toolLoop/toolLoopRunnerUtils.js.map +0 -1
@@ -1,46 +1,14 @@
1
- import { ensureElementIds, extractAllIdsDeep, findElementById, resolvePageConfigJsonPath, parsePageConfigJson, stringifyPageConfigJson, writeFileAtomic, } from "../helpers/pageConfigJson.helpers.js";
1
+ import { findElementById, loadAndPreparePageConfig, stringifyPageConfigJson, writeFileAtomic, } from "../helpers/pageConfigJson.helpers.js";
2
2
  export const createUpdateClassNameImpl = (deps) => {
3
3
  const { workspaceRoot, fs } = deps;
4
4
  return async (route, elementId, className) => {
5
5
  const id = String(elementId ?? "").trim();
6
6
  if (!id)
7
7
  return { success: false, error: "invalid element_id" };
8
- let configPath;
9
- try {
10
- configPath = await resolvePageConfigJsonPath(workspaceRoot, route, fs);
11
- }
12
- catch (err) {
13
- return {
14
- success: false,
15
- error: err instanceof Error ? err.message : String(err),
16
- };
17
- }
18
- let before = "";
19
- try {
20
- before = await fs.readFile(configPath);
21
- }
22
- catch (err) {
23
- const code = err?.code;
24
- if (code === "ENOENT")
25
- return { success: false, error: "not found" };
26
- return {
27
- success: false,
28
- error: err instanceof Error ? err.message : String(err),
29
- };
30
- }
31
- let parsed;
32
- try {
33
- parsed = parsePageConfigJson(before);
34
- }
35
- catch (err) {
36
- return {
37
- success: false,
38
- error: err instanceof Error ? err.message : String(err),
39
- };
40
- }
41
- const elements = parsed.elements ?? [];
42
- const existingIds = extractAllIdsDeep(elements);
43
- ensureElementIds(elements, existingIds);
8
+ const prep = await loadAndPreparePageConfig(workspaceRoot, route, fs);
9
+ if (!prep.success)
10
+ return prep;
11
+ const { configPath, elements } = prep;
44
12
  const el = findElementById(elements, id);
45
13
  if (!el)
46
14
  return { success: false, error: "element not found" };
@@ -1 +1 @@
1
- {"version":3,"file":"updateClassName.impl.js","sourceRoot":"","sources":["../../../../src/ai/tools/implementations/updateClassName.impl.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n ensureElementIds,\n extractAllIdsDeep,\n findElementById,\n resolvePageConfigJsonPath,\n parsePageConfigJson,\n stringifyPageConfigJson,\n writeFileAtomic,\n} from \"../helpers/pageConfigJson.helpers.js\";\nimport { type WorkspaceDeps } from \"./workspaceDeps.js\";\n\nexport const createUpdateClassNameImpl = (deps: WorkspaceDeps) => {\n const { workspaceRoot, fs } = deps;\n\n return async (route: string, elementId: string, className: string) => {\n const id = String(elementId ?? \"\").trim();\n if (!id) return { success: false, error: \"invalid element_id\" };\n\n let configPath: string;\n try {\n configPath = await resolvePageConfigJsonPath(workspaceRoot, 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 const el = findElementById(elements, id);\n if (!el) return { success: false, error: \"element not found\" };\n\n (el as any).className = String(className ?? \"\");\n\n const after = stringifyPageConfigJson({ elements });\n try {\n await writeFileAtomic(configPath, after);\n return { success: true, changed: true, updated_id: id };\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":"updateClassName.impl.js","sourceRoot":"","sources":["../../../../src/ai/tools/implementations/updateClassName.impl.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,eAAe,EACf,wBAAwB,EACxB,uBAAuB,EACvB,eAAe,GAChB,MAAM,sCAAsC,CAAC;AAG9C,MAAM,CAAC,MAAM,yBAAyB,GAAG,CAAC,IAAmB,EAAE,EAAE;IAC/D,MAAM,EAAE,aAAa,EAAE,EAAE,EAAE,GAAG,IAAI,CAAC;IAEnC,OAAO,KAAK,EAAE,KAAa,EAAE,SAAiB,EAAE,SAAiB,EAAE,EAAE;QACnE,MAAM,EAAE,GAAG,MAAM,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;QAC1C,IAAI,CAAC,EAAE;YAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,oBAAoB,EAAE,CAAC;QAEhE,MAAM,IAAI,GAAG,MAAM,wBAAwB,CAAC,aAAa,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC;QACtE,IAAI,CAAC,IAAI,CAAC,OAAO;YAAE,OAAO,IAAI,CAAC;QAE/B,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,GAAG,IAAI,CAAC;QAEtC,MAAM,EAAE,GAAG,eAAe,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;QACzC,IAAI,CAAC,EAAE;YAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,mBAAmB,EAAE,CAAC;QAE9D,EAAU,CAAC,SAAS,GAAG,MAAM,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC;QAEhD,MAAM,KAAK,GAAG,uBAAuB,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC;QACpD,IAAI,CAAC;YACH,MAAM,eAAe,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;YACzC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC;QAC1D,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,KAAK,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;aACxD,CAAC;QACJ,CAAC;IACH,CAAC,CAAC;AACJ,CAAC,CAAC","sourcesContent":["import {\n findElementById,\n loadAndPreparePageConfig,\n stringifyPageConfigJson,\n writeFileAtomic,\n} from \"../helpers/pageConfigJson.helpers.js\";\nimport { type WorkspaceDeps } from \"./workspaceDeps.js\";\n\nexport const createUpdateClassNameImpl = (deps: WorkspaceDeps) => {\n const { workspaceRoot, fs } = deps;\n\n return async (route: string, elementId: string, className: string) => {\n const id = String(elementId ?? \"\").trim();\n if (!id) return { success: false, error: \"invalid element_id\" };\n\n const prep = await loadAndPreparePageConfig(workspaceRoot, route, fs);\n if (!prep.success) return prep;\n\n const { configPath, elements } = prep;\n\n const el = findElementById(elements, id);\n if (!el) return { success: false, error: \"element not found\" };\n\n (el as any).className = String(className ?? \"\");\n\n const after = stringifyPageConfigJson({ elements });\n try {\n await writeFileAtomic(configPath, after);\n return { success: true, changed: true, updated_id: id };\n } catch (err) {\n return {\n success: false,\n error: err instanceof Error ? err.message : String(err),\n };\n }\n };\n};\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"updateGlobalStyles.impl.d.ts","sourceRoot":"","sources":["../../../../src/ai/tools/implementations/updateGlobalStyles.impl.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,KAAK,aAAa,EAAE,MAAM,oBAAoB,CAAC;AA+ExD,eAAO,MAAM,4BAA4B,GAAI,MAAM,aAAa,MAGhD,SAAS,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAoF/B,CAAC"}
1
+ {"version":3,"file":"updateGlobalStyles.impl.d.ts","sourceRoot":"","sources":["../../../../src/ai/tools/implementations/updateGlobalStyles.impl.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,KAAK,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAgFxD,eAAO,MAAM,4BAA4B,GAAI,MAAM,aAAa,MAGhD,SAAS,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAoF/B,CAAC"}
@@ -38,12 +38,13 @@ const extractAllValidTokens = (value) => {
38
38
  }
39
39
  catch { }
40
40
  // If it's a string and not valid JSON, try to extract key-value patterns (e.g. key: "value", "key": 'value', etc.)
41
- const regex = /(?:["']?([a-zA-Z0-9_-]+)["']?\s*:\s*["']([^"']+)["'])/g;
41
+ const regex = /(?:(?:["']([a-zA-Z0-9_-]+)["']|([a-zA-Z0-9_-]+))\s*:\s*["']([^"']+)["'])/g;
42
42
  let match;
43
43
  let foundAny = false;
44
44
  while ((match = regex.exec(trimmedVal)) !== null) {
45
- const [, k, v] = match;
46
- if (allowed.has(k) && isSafeCssValue(v)) {
45
+ const k = match[1] ?? match[2];
46
+ const v = match[3];
47
+ if (k && allowed.has(k) && isSafeCssValue(v)) {
47
48
  out[k] = v.trim();
48
49
  foundAny = true;
49
50
  }
@@ -1 +1 @@
1
- {"version":3,"file":"updateGlobalStyles.impl.js","sourceRoot":"","sources":["../../../../src/ai/tools/implementations/updateGlobalStyles.impl.ts"],"names":[],"mappings":"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","sourcesContent":["import path from \"node:path\";\nimport { toWorkspacePath } from \"../helpers/fileSystem.helpers.js\";\nimport { writeFileAtomic } from \"../helpers/pageConfigJson.helpers.js\";\nimport {\n assertStyleConfig,\n defaultStyleConfigJson,\n type StyleConfig,\n type StyleTokenKey,\n STYLE_TOKEN_KEYS,\n} from \"../../../types/styleConfig.js\";\nimport { type WorkspaceDeps } from \"./workspaceDeps.js\";\n\nconst STYLE_CONFIG_REL_PATH = path.posix.join(\"app\", \"styleConfig.json\");\n\nconst parseStyleConfigOrDefault = (raw: string): StyleConfig => {\n try {\n const parsed = JSON.parse(String(raw ?? \"\"));\n return assertStyleConfig(parsed);\n } catch {\n return assertStyleConfig(defaultStyleConfigJson);\n }\n};\n\nconst isSafeCssValue = (value: string): boolean => {\n if (!value.trim()) return false;\n if (value.includes(\"<\") || value.includes(\">\")) return false;\n if (value.toLowerCase().includes(\"</style\")) return false;\n return true;\n};\n\nconst extractAllValidTokens = (value: unknown): Partial<Record<StyleTokenKey, string>> => {\n const allowed = new Set<string>(STYLE_TOKEN_KEYS as unknown as string[]);\n const out: Record<string, string> = {};\n const visited = new WeakSet<object>();\n\n const traverse = (val: unknown) => {\n if (typeof val === \"string\") {\n const trimmedVal = val.trim();\n if (!trimmedVal) return;\n\n // Try to parse string as JSON first\n try {\n const parsed = JSON.parse(trimmedVal);\n traverse(parsed);\n return;\n } catch {}\n\n // If it's a string and not valid JSON, try to extract key-value patterns (e.g. key: \"value\", \"key\": 'value', etc.)\n const regex = /(?:[\"']?([a-zA-Z0-9_-]+)[\"']?\\s*:\\s*[\"']([^\"']+)[\"'])/g;\n let match;\n let foundAny = false;\n while ((match = regex.exec(trimmedVal)) !== null) {\n const [, k, v] = match;\n if (allowed.has(k) && isSafeCssValue(v)) {\n out[k] = v.trim();\n foundAny = true;\n }\n }\n if (foundAny) return;\n\n // As a last resort, if the string itself is a safe value and allowed keys can be matched elsewhere,\n // or if we want to handle a plain string value, but without a key we can't map it.\n return;\n }\n\n if (typeof val !== \"object\" || val === null) return;\n if (visited.has(val)) return;\n visited.add(val);\n\n if (Array.isArray(val)) {\n for (const item of val) {\n traverse(item);\n }\n return;\n }\n\n for (const [k, v] of Object.entries(val)) {\n if (allowed.has(k) && typeof v === \"string\" && isSafeCssValue(v)) {\n out[k] = v.trim();\n } else {\n traverse(v);\n }\n }\n };\n\n traverse(value);\n return out as any;\n};\n\nexport const createUpdateGlobalStylesImpl = (deps: WorkspaceDeps) => {\n const { workspaceRoot, fs } = deps;\n\n return async (rawArgs: unknown) => {\n const normalizedArgs: unknown = (() => {\n if (typeof rawArgs !== \"string\") return rawArgs;\n try {\n return JSON.parse(rawArgs);\n } catch {\n return rawArgs;\n }\n })();\n\n const tokensPatch = extractAllValidTokens(normalizedArgs);\n\n if (Object.keys(tokensPatch).length === 0) {\n return {\n success: false,\n error: \"invalid args\",\n error_detail: {\n formErrors: [\"must include at least one token key/value\"],\n fieldErrors: {},\n },\n note: \"update_global_styles requires at least one valid token key/value (e.g. { primary: \\\"oklch(...)\\\" }).\",\n };\n }\n\n\n const configPath = toWorkspacePath(workspaceRoot, STYLE_CONFIG_REL_PATH);\n\n let beforeConfig: StyleConfig;\n let existed = true;\n try {\n const raw = await fs.readFile(configPath);\n beforeConfig = parseStyleConfigOrDefault(raw);\n } catch (err) {\n const code = (err as NodeJS.ErrnoException | null)?.code;\n if (code !== \"ENOENT\") {\n return {\n success: false,\n error: err instanceof Error ? err.message : String(err),\n };\n }\n existed = false;\n beforeConfig = assertStyleConfig(defaultStyleConfigJson);\n }\n\n const merged: StyleConfig = {\n version: beforeConfig.version,\n tokens: {\n ...beforeConfig.tokens,\n ...(tokensPatch as Partial<Record<StyleTokenKey, string>>),\n } as any,\n };\n\n let validated: StyleConfig;\n try {\n validated = assertStyleConfig(merged);\n } catch (err) {\n return {\n success: false,\n error: err instanceof Error ? err.message : String(err),\n };\n }\n\n const nextVersion = Number.isFinite(validated.version)\n ? validated.version + 1\n : 1;\n const afterConfig: StyleConfig = { ...validated, version: nextVersion };\n\n const after = JSON.stringify(afterConfig, null, 2) + \"\\n\";\n try {\n await writeFileAtomic(configPath, after);\n return {\n success: true,\n changed: true,\n file: STYLE_CONFIG_REL_PATH,\n version: nextVersion,\n created: !existed,\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":"updateGlobalStyles.impl.js","sourceRoot":"","sources":["../../../../src/ai/tools/implementations/updateGlobalStyles.impl.ts"],"names":[],"mappings":"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","sourcesContent":["import path from \"node:path\";\nimport { toWorkspacePath } from \"../helpers/fileSystem.helpers.js\";\nimport { writeFileAtomic } from \"../helpers/pageConfigJson.helpers.js\";\nimport {\n assertStyleConfig,\n defaultStyleConfigJson,\n type StyleConfig,\n type StyleTokenKey,\n STYLE_TOKEN_KEYS,\n} from \"../../../types/styleConfig.js\";\nimport { type WorkspaceDeps } from \"./workspaceDeps.js\";\n\nconst STYLE_CONFIG_REL_PATH = path.posix.join(\"app\", \"styleConfig.json\");\n\nconst parseStyleConfigOrDefault = (raw: string): StyleConfig => {\n try {\n const parsed = JSON.parse(String(raw ?? \"\"));\n return assertStyleConfig(parsed);\n } catch {\n return assertStyleConfig(defaultStyleConfigJson);\n }\n};\n\nconst isSafeCssValue = (value: string): boolean => {\n if (!value.trim()) return false;\n if (value.includes(\"<\") || value.includes(\">\")) return false;\n if (value.toLowerCase().includes(\"</style\")) return false;\n return true;\n};\n\nconst extractAllValidTokens = (value: unknown): Partial<Record<StyleTokenKey, string>> => {\n const allowed = new Set<string>(STYLE_TOKEN_KEYS as unknown as string[]);\n const out: Record<string, string> = {};\n const visited = new WeakSet<object>();\n\n const traverse = (val: unknown) => {\n if (typeof val === \"string\") {\n const trimmedVal = val.trim();\n if (!trimmedVal) return;\n\n // Try to parse string as JSON first\n try {\n const parsed = JSON.parse(trimmedVal);\n traverse(parsed);\n return;\n } catch {}\n\n // If it's a string and not valid JSON, try to extract key-value patterns (e.g. key: \"value\", \"key\": 'value', etc.)\n const regex = /(?:(?:[\"']([a-zA-Z0-9_-]+)[\"']|([a-zA-Z0-9_-]+))\\s*:\\s*[\"']([^\"']+)[\"'])/g;\n let match;\n let foundAny = false;\n while ((match = regex.exec(trimmedVal)) !== null) {\n const k = match[1] ?? match[2];\n const v = match[3];\n if (k && allowed.has(k) && isSafeCssValue(v)) {\n out[k] = v.trim();\n foundAny = true;\n }\n }\n if (foundAny) return;\n\n // As a last resort, if the string itself is a safe value and allowed keys can be matched elsewhere,\n // or if we want to handle a plain string value, but without a key we can't map it.\n return;\n }\n\n if (typeof val !== \"object\" || val === null) return;\n if (visited.has(val)) return;\n visited.add(val);\n\n if (Array.isArray(val)) {\n for (const item of val) {\n traverse(item);\n }\n return;\n }\n\n for (const [k, v] of Object.entries(val)) {\n if (allowed.has(k) && typeof v === \"string\" && isSafeCssValue(v)) {\n out[k] = v.trim();\n } else {\n traverse(v);\n }\n }\n };\n\n traverse(value);\n return out as any;\n};\n\nexport const createUpdateGlobalStylesImpl = (deps: WorkspaceDeps) => {\n const { workspaceRoot, fs } = deps;\n\n return async (rawArgs: unknown) => {\n const normalizedArgs: unknown = (() => {\n if (typeof rawArgs !== \"string\") return rawArgs;\n try {\n return JSON.parse(rawArgs);\n } catch {\n return rawArgs;\n }\n })();\n\n const tokensPatch = extractAllValidTokens(normalizedArgs);\n\n if (Object.keys(tokensPatch).length === 0) {\n return {\n success: false,\n error: \"invalid args\",\n error_detail: {\n formErrors: [\"must include at least one token key/value\"],\n fieldErrors: {},\n },\n note: \"update_global_styles requires at least one valid token key/value (e.g. { primary: \\\"oklch(...)\\\" }).\",\n };\n }\n\n\n const configPath = toWorkspacePath(workspaceRoot, STYLE_CONFIG_REL_PATH);\n\n let beforeConfig: StyleConfig;\n let existed = true;\n try {\n const raw = await fs.readFile(configPath);\n beforeConfig = parseStyleConfigOrDefault(raw);\n } catch (err) {\n const code = (err as NodeJS.ErrnoException | null)?.code;\n if (code !== \"ENOENT\") {\n return {\n success: false,\n error: err instanceof Error ? err.message : String(err),\n };\n }\n existed = false;\n beforeConfig = assertStyleConfig(defaultStyleConfigJson);\n }\n\n const merged: StyleConfig = {\n version: beforeConfig.version,\n tokens: {\n ...beforeConfig.tokens,\n ...(tokensPatch as Partial<Record<StyleTokenKey, string>>),\n } as any,\n };\n\n let validated: StyleConfig;\n try {\n validated = assertStyleConfig(merged);\n } catch (err) {\n return {\n success: false,\n error: err instanceof Error ? err.message : String(err),\n };\n }\n\n const nextVersion = Number.isFinite(validated.version)\n ? validated.version + 1\n : 1;\n const afterConfig: StyleConfig = { ...validated, version: nextVersion };\n\n const after = JSON.stringify(afterConfig, null, 2) + \"\\n\";\n try {\n await writeFileAtomic(configPath, after);\n return {\n success: true,\n changed: true,\n file: STYLE_CONFIG_REL_PATH,\n version: nextVersion,\n created: !existed,\n };\n } catch (err) {\n return {\n success: false,\n error: err instanceof Error ? err.message : String(err),\n };\n }\n };\n};\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"updateProps.impl.d.ts","sourceRoot":"","sources":["../../../../src/ai/tools/implementations/updateProps.impl.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAkB,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAUhF,OAAO,EAAE,KAAK,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAExD,KAAK,eAAe,GAAG;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;CACpB,GAAG,OAAO,CAAC;IACV,OAAO,EAAE,aAAa,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC,CAAC;AA2BH,eAAO,MAAM,qBAAqB,GAAI,MAAM,aAAa,MAGzC,MAAM,eAAe;;;;;;;;;;EA8DpC,CAAC"}
1
+ {"version":3,"file":"updateProps.impl.d.ts","sourceRoot":"","sources":["../../../../src/ai/tools/implementations/updateProps.impl.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAkB,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAOhF,OAAO,EAAE,KAAK,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAExD,KAAK,eAAe,GAAG;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;CACpB,GAAG,OAAO,CAAC;IACV,OAAO,EAAE,aAAa,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC,CAAC;AA2BH,eAAO,MAAM,qBAAqB,GAAI,MAAM,aAAa,MAGzC,MAAM,eAAe;;;;;;;;;;EA+BpC,CAAC"}
@@ -1,5 +1,5 @@
1
1
  import { resolveUnsplashImageForElement } from "../../../image/unsplash.service.js";
2
- import { ensureElementIds, extractAllIdsDeep, findElementById, resolvePageConfigJsonPath, parsePageConfigJson, stringifyPageConfigJson, writeFileAtomic, } from "../helpers/pageConfigJson.helpers.js";
2
+ import { findElementById, loadAndPreparePageConfig, stringifyPageConfigJson, writeFileAtomic, } from "../helpers/pageConfigJson.helpers.js";
3
3
  const applyPropsPatch = (el, patch) => {
4
4
  const anyEl = el;
5
5
  if (!anyEl.props || typeof anyEl.props !== "object")
@@ -29,42 +29,10 @@ export const createUpdatePropsImpl = (deps) => {
29
29
  const id = String(args?.element_id ?? "").trim();
30
30
  if (!id)
31
31
  return { success: false, error: "invalid element_id" };
32
- let configPath;
33
- try {
34
- configPath = await resolvePageConfigJsonPath(workspaceRoot, args.route, fs);
35
- }
36
- catch (err) {
37
- return {
38
- success: false,
39
- error: err instanceof Error ? err.message : String(err),
40
- };
41
- }
42
- let before = "";
43
- try {
44
- before = await fs.readFile(configPath);
45
- }
46
- catch (err) {
47
- const code = err?.code;
48
- if (code === "ENOENT")
49
- return { success: false, error: "not found" };
50
- return {
51
- success: false,
52
- error: err instanceof Error ? err.message : String(err),
53
- };
54
- }
55
- let parsed;
56
- try {
57
- parsed = parsePageConfigJson(before);
58
- }
59
- catch (err) {
60
- return {
61
- success: false,
62
- error: err instanceof Error ? err.message : String(err),
63
- };
64
- }
65
- const elements = parsed.elements ?? [];
66
- const existingIds = extractAllIdsDeep(elements);
67
- ensureElementIds(elements, existingIds);
32
+ const prep = await loadAndPreparePageConfig(workspaceRoot, args.route, fs);
33
+ if (!prep.success)
34
+ return prep;
35
+ const { configPath, elements } = prep;
68
36
  const el = findElementById(elements, id);
69
37
  if (!el)
70
38
  return { success: false, error: "element not found" };
@@ -1 +1 @@
1
- {"version":3,"file":"updateProps.impl.js","sourceRoot":"","sources":["../../../../src/ai/tools/implementations/updateProps.impl.ts"],"names":[],"mappings":"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","sourcesContent":["import { resolveUnsplashImageForElement } from \"../../../image/unsplash.service.js\";\nimport type { BuilderElement, OnClickAction } 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 { type WorkspaceDeps } from \"./workspaceDeps.js\";\n\ntype UpdatePropsArgs = {\n route: string;\n element_id: string;\n} & Partial<{\n onClick: OnClickAction;\n text: string;\n href: string;\n placeholder: string;\n alt: string;\n target: string;\n rel: string;\n value: string;\n type: string;\n name: string;\n size: number;\n color: string;\n strokeWidth: number;\n}>;\n\nconst applyPropsPatch = (el: BuilderElement, patch: UpdatePropsArgs) => {\n const anyEl = el as any;\n if (!anyEl.props || typeof anyEl.props !== \"object\") anyEl.props = {};\n\n const apply = (key: string, value: unknown) => {\n if (value === undefined || value === null) return;\n anyEl.props[key] = value;\n };\n\n apply(\"onClick\", patch.onClick);\n apply(\"text\", patch.text);\n apply(\"href\", patch.href);\n apply(\"placeholder\", patch.placeholder);\n apply(\"alt\", patch.alt);\n apply(\"target\", patch.target);\n apply(\"rel\", patch.rel);\n apply(\"value\", patch.value);\n apply(\"type\", patch.type);\n\n apply(\"name\", patch.name);\n apply(\"size\", patch.size);\n apply(\"color\", patch.color);\n apply(\"strokeWidth\", patch.strokeWidth);\n};\n\nexport const createUpdatePropsImpl = (deps: WorkspaceDeps) => {\n const { workspaceRoot, fs } = deps;\n\n return async (args: UpdatePropsArgs) => {\n const id = String(args?.element_id ?? \"\").trim();\n if (!id) return { success: false, error: \"invalid element_id\" };\n\n let configPath: string;\n try {\n configPath = await resolvePageConfigJsonPath(workspaceRoot, args.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 const el = findElementById(elements, id);\n if (!el) return { success: false, error: \"element not found\" };\n\n applyPropsPatch(el, args);\n\n if (el.type === \"image\") {\n const anyEl = el as any;\n const alt = String(args.alt ?? anyEl?.props?.alt ?? \"\").trim();\n await resolveUnsplashImageForElement(el, alt);\n }\n\n const after = stringifyPageConfigJson({ elements });\n try {\n await writeFileAtomic(configPath, after);\n return { success: true, changed: true, updated_id: id };\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":"updateProps.impl.js","sourceRoot":"","sources":["../../../../src/ai/tools/implementations/updateProps.impl.ts"],"names":[],"mappings":"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","sourcesContent":["import { resolveUnsplashImageForElement } from \"../../../image/unsplash.service.js\";\nimport type { BuilderElement, OnClickAction } from \"../../../types/elements.js\";\nimport {\n findElementById,\n loadAndPreparePageConfig,\n stringifyPageConfigJson,\n writeFileAtomic,\n} from \"../helpers/pageConfigJson.helpers.js\";\nimport { type WorkspaceDeps } from \"./workspaceDeps.js\";\n\ntype UpdatePropsArgs = {\n route: string;\n element_id: string;\n} & Partial<{\n onClick: OnClickAction;\n text: string;\n href: string;\n placeholder: string;\n alt: string;\n target: string;\n rel: string;\n value: string;\n type: string;\n name: string;\n size: number;\n color: string;\n strokeWidth: number;\n}>;\n\nconst applyPropsPatch = (el: BuilderElement, patch: UpdatePropsArgs) => {\n const anyEl = el as any;\n if (!anyEl.props || typeof anyEl.props !== \"object\") anyEl.props = {};\n\n const apply = (key: string, value: unknown) => {\n if (value === undefined || value === null) return;\n anyEl.props[key] = value;\n };\n\n apply(\"onClick\", patch.onClick);\n apply(\"text\", patch.text);\n apply(\"href\", patch.href);\n apply(\"placeholder\", patch.placeholder);\n apply(\"alt\", patch.alt);\n apply(\"target\", patch.target);\n apply(\"rel\", patch.rel);\n apply(\"value\", patch.value);\n apply(\"type\", patch.type);\n\n apply(\"name\", patch.name);\n apply(\"size\", patch.size);\n apply(\"color\", patch.color);\n apply(\"strokeWidth\", patch.strokeWidth);\n};\n\nexport const createUpdatePropsImpl = (deps: WorkspaceDeps) => {\n const { workspaceRoot, fs } = deps;\n\n return async (args: UpdatePropsArgs) => {\n const id = String(args?.element_id ?? \"\").trim();\n if (!id) return { success: false, error: \"invalid element_id\" };\n\n const prep = await loadAndPreparePageConfig(workspaceRoot, args.route, fs);\n if (!prep.success) return prep;\n\n const { configPath, elements } = prep;\n\n const el = findElementById(elements, id);\n if (!el) return { success: false, error: \"element not found\" };\n\n applyPropsPatch(el, args);\n\n if (el.type === \"image\") {\n const anyEl = el as any;\n const alt = String(args.alt ?? anyEl?.props?.alt ?? \"\").trim();\n await resolveUnsplashImageForElement(el, alt);\n }\n\n const after = stringifyPageConfigJson({ elements });\n try {\n await writeFileAtomic(configPath, after);\n return { success: true, changed: true, updated_id: id };\n } catch (err) {\n return {\n success: false,\n error: err instanceof Error ? err.message : String(err),\n };\n }\n };\n};\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"createNewRoute.schema.d.ts","sourceRoot":"","sources":["../../../../src/ai/tools/schemas/createNewRoute.schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAErC,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;CAuBhC,CAAC"}
1
+ {"version":3,"file":"createNewRoute.schema.d.ts","sourceRoot":"","sources":["../../../../src/ai/tools/schemas/createNewRoute.schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAErC,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;CAsBhC,CAAC"}
@@ -8,7 +8,7 @@ export const CreateNewRouteSchema = {
8
8
  parent_route: {
9
9
  type: Type.STRING,
10
10
  // Accept both "/dashboard" and "dashboard" (caller might omit the leading slash).
11
- pattern: "^(?:/|/(?:[A-Za-z0-9_.[\\\\\]-]+(?:/[A-Za-z0-9_.[\\\\\]-]+)*)?|[A-Za-z0-9_.[\\\\\]-]+(?:/[A-Za-z0-9_.[\\\\\]-]+)*)$",
11
+ pattern: String.raw `^(?:/|/(?:[A-Za-z0-9_.[\\\]-]+(?:/[A-Za-z0-9_.[\\\]-]+)*)?|[A-Za-z0-9_.[\\\]-]+(?:/[A-Za-z0-9_.[\\\]-]+)*)$`,
12
12
  description: 'The parent route ("/" for app root). Example: "/" or "/dashboard". If you forget the leading "/", it will be assumed (e.g. "dashboard" -> "/dashboard"). NEVER pass empty string, use "/" if not sure about parent route.',
13
13
  },
14
14
  route_name: {
@@ -1 +1 @@
1
- {"version":3,"file":"createNewRoute.schema.js","sourceRoot":"","sources":["../../../../src/ai/tools/schemas/createNewRoute.schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAErC,MAAM,CAAC,MAAM,oBAAoB,GAAG;IAClC,IAAI,EAAE,kBAAkB;IACxB,WAAW,EACT,2HAA2H;IAC7H,UAAU,EAAE;QACV,IAAI,EAAE,IAAI,CAAC,MAAM;QACjB,UAAU,EAAE;YACV,YAAY,EAAE;gBACZ,IAAI,EAAE,IAAI,CAAC,MAAM;gBACjB,kFAAkF;gBAClF,OAAO,EACL,qHAAqH;gBACvH,WAAW,EACT,2NAA2N;aAC9N;YACD,UAAU,EAAE;gBACV,IAAI,EAAE,IAAI,CAAC,MAAM;gBACjB,WAAW,EACT,yFAAyF;aAC5F;SACF;QACD,QAAQ,EAAE,CAAC,cAAc,EAAE,YAAY,CAAC;KACzC;CACF,CAAC","sourcesContent":["import { Type } from \"@google/genai\";\n\nexport const CreateNewRouteSchema = {\n name: \"create_new_route\",\n description:\n \"Creates a new Next.js App Router route folder under /app/<parent_route>/<route_name> with a page.tsx and pageConfig.json.\",\n parameters: {\n type: Type.OBJECT,\n properties: {\n parent_route: {\n type: Type.STRING,\n // Accept both \"/dashboard\" and \"dashboard\" (caller might omit the leading slash).\n pattern:\n \"^(?:/|/(?:[A-Za-z0-9_.[\\\\\\\\\\]-]+(?:/[A-Za-z0-9_.[\\\\\\\\\\]-]+)*)?|[A-Za-z0-9_.[\\\\\\\\\\]-]+(?:/[A-Za-z0-9_.[\\\\\\\\\\]-]+)*)$\",\n description:\n 'The parent route (\"/\" for app root). Example: \"/\" or \"/dashboard\". If you forget the leading \"/\", it will be assumed (e.g. \"dashboard\" -> \"/dashboard\"). NEVER pass empty string, use \"/\" if not sure about parent route.',\n },\n route_name: {\n type: Type.STRING,\n description:\n 'The new route segment to create under the parent route. Example: \"about\" or \"settings\".',\n },\n },\n required: [\"parent_route\", \"route_name\"],\n },\n};\n"]}
1
+ {"version":3,"file":"createNewRoute.schema.js","sourceRoot":"","sources":["../../../../src/ai/tools/schemas/createNewRoute.schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAErC,MAAM,CAAC,MAAM,oBAAoB,GAAG;IAClC,IAAI,EAAE,kBAAkB;IACxB,WAAW,EACT,2HAA2H;IAC7H,UAAU,EAAE;QACV,IAAI,EAAE,IAAI,CAAC,MAAM;QACjB,UAAU,EAAE;YACV,YAAY,EAAE;gBACZ,IAAI,EAAE,IAAI,CAAC,MAAM;gBACjB,kFAAkF;gBAClF,OAAO,EAAE,MAAM,CAAC,GAAG,CAAA,6GAA6G;gBAChI,WAAW,EACT,2NAA2N;aAC9N;YACD,UAAU,EAAE;gBACV,IAAI,EAAE,IAAI,CAAC,MAAM;gBACjB,WAAW,EACT,yFAAyF;aAC5F;SACF;QACD,QAAQ,EAAE,CAAC,cAAc,EAAE,YAAY,CAAC;KACzC;CACF,CAAC","sourcesContent":["import { Type } from \"@google/genai\";\n\nexport const CreateNewRouteSchema = {\n name: \"create_new_route\",\n description:\n \"Creates a new Next.js App Router route folder under /app/<parent_route>/<route_name> with a page.tsx and pageConfig.json.\",\n parameters: {\n type: Type.OBJECT,\n properties: {\n parent_route: {\n type: Type.STRING,\n // Accept both \"/dashboard\" and \"dashboard\" (caller might omit the leading slash).\n pattern: String.raw`^(?:/|/(?:[A-Za-z0-9_.[\\\\\\]-]+(?:/[A-Za-z0-9_.[\\\\\\]-]+)*)?|[A-Za-z0-9_.[\\\\\\]-]+(?:/[A-Za-z0-9_.[\\\\\\]-]+)*)$`,\n description:\n 'The parent route (\"/\" for app root). Example: \"/\" or \"/dashboard\". If you forget the leading \"/\", it will be assumed (e.g. \"dashboard\" -> \"/dashboard\"). NEVER pass empty string, use \"/\" if not sure about parent route.',\n },\n route_name: {\n type: Type.STRING,\n description:\n 'The new route segment to create under the parent route. Example: \"about\" or \"settings\".',\n },\n },\n required: [\"parent_route\", \"route_name\"],\n },\n};\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"deleteElement.schema.d.ts","sourceRoot":"","sources":["../../../../src/ai/tools/schemas/deleteElement.schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAErC,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;CAqB/B,CAAC"}
1
+ {"version":3,"file":"deleteElement.schema.d.ts","sourceRoot":"","sources":["../../../../src/ai/tools/schemas/deleteElement.schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAErC,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;CAmB/B,CAAC"}
@@ -7,8 +7,7 @@ export const DeleteElementSchema = {
7
7
  properties: {
8
8
  route: {
9
9
  type: Type.STRING,
10
- // Accept both "/about" and "about" (caller might omit the leading slash).
11
- pattern: "^(?:/(?:[A-Za-z0-9_.[\\\\\]-]+(?:/[A-Za-z0-9_.[\\\\\]-]+)*)?|[A-Za-z0-9_.[\\\\\]-]+(?:/[A-Za-z0-9_.[\\\\\]-]+)*)$",
10
+ pattern: String.raw `^(?:/(?:[A-Za-z0-9_.[\\\]-]+(?:/[A-Za-z0-9_.[\\\]-]+)*)?|[A-Za-z0-9_.[\\\]-]+(?:/[A-Za-z0-9_.[\\\]-]+)*)$`,
12
11
  description: "The route to delete the element at. Example: '/' or '/about'. If you forget the leading '/', it will be assumed (e.g. 'about' -> '/about').",
13
12
  },
14
13
  element_id: {
@@ -1 +1 @@
1
- {"version":3,"file":"deleteElement.schema.js","sourceRoot":"","sources":["../../../../src/ai/tools/schemas/deleteElement.schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAErC,MAAM,CAAC,MAAM,mBAAmB,GAAG;IACjC,IAAI,EAAE,gBAAgB;IACtB,WAAW,EAAE,uBAAuB;IACpC,UAAU,EAAE;QACV,IAAI,EAAE,IAAI,CAAC,MAAM;QACjB,UAAU,EAAE;YACV,KAAK,EAAE;gBACL,IAAI,EAAE,IAAI,CAAC,MAAM;gBACjB,0EAA0E;gBAC1E,OAAO,EACL,mHAAmH;gBACrH,WAAW,EACT,6IAA6I;aAChJ;YACD,UAAU,EAAE;gBACV,IAAI,EAAE,IAAI,CAAC,MAAM;gBACjB,WAAW,EAAE,sCAAsC;aACpD;SACF;QACD,QAAQ,EAAE,CAAC,OAAO,EAAE,YAAY,CAAC;KAClC;CACF,CAAC","sourcesContent":["import { Type } from \"@google/genai\";\r\n\r\nexport const DeleteElementSchema = {\n name: \"delete_element\",\n description: \"Deletes element code.\",\n parameters: {\n type: Type.OBJECT,\n properties: {\n route: {\n type: Type.STRING,\n // Accept both \"/about\" and \"about\" (caller might omit the leading slash).\n pattern:\n \"^(?:/(?:[A-Za-z0-9_.[\\\\\\\\\\]-]+(?:/[A-Za-z0-9_.[\\\\\\\\\\]-]+)*)?|[A-Za-z0-9_.[\\\\\\\\\\]-]+(?:/[A-Za-z0-9_.[\\\\\\\\\\]-]+)*)$\",\n description:\n \"The route to delete the element at. Example: '/' or '/about'. If you forget the leading '/', it will be assumed (e.g. 'about' -> '/about').\",\n },\n element_id: {\n type: Type.STRING,\n description: \"The id of the element to be deleted.\",\n },\n },\r\n required: [\"route\", \"element_id\"],\r\n },\r\n};\r\n"]}
1
+ {"version":3,"file":"deleteElement.schema.js","sourceRoot":"","sources":["../../../../src/ai/tools/schemas/deleteElement.schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAErC,MAAM,CAAC,MAAM,mBAAmB,GAAG;IACjC,IAAI,EAAE,gBAAgB;IACtB,WAAW,EAAE,uBAAuB;IACpC,UAAU,EAAE;QACV,IAAI,EAAE,IAAI,CAAC,MAAM;QACjB,UAAU,EAAE;YACV,KAAK,EAAE;gBACL,IAAI,EAAE,IAAI,CAAC,MAAM;gBACjB,OAAO,EAAE,MAAM,CAAC,GAAG,CAAA,2GAA2G;gBAC9H,WAAW,EACT,6IAA6I;aAChJ;YACD,UAAU,EAAE;gBACV,IAAI,EAAE,IAAI,CAAC,MAAM;gBACjB,WAAW,EAAE,sCAAsC;aACpD;SACF;QACD,QAAQ,EAAE,CAAC,OAAO,EAAE,YAAY,CAAC;KAClC;CACF,CAAC","sourcesContent":["import { Type } from \"@google/genai\";\r\n\r\nexport const DeleteElementSchema = {\n name: \"delete_element\",\n description: \"Deletes element code.\",\n parameters: {\n type: Type.OBJECT,\n properties: {\n route: {\n type: Type.STRING,\n pattern: String.raw`^(?:/(?:[A-Za-z0-9_.[\\\\\\]-]+(?:/[A-Za-z0-9_.[\\\\\\]-]+)*)?|[A-Za-z0-9_.[\\\\\\]-]+(?:/[A-Za-z0-9_.[\\\\\\]-]+)*)$`,\n description:\n \"The route to delete the element at. Example: '/' or '/about'. If you forget the leading '/', it will be assumed (e.g. 'about' -> '/about').\",\n },\n element_id: {\n type: Type.STRING,\n description: \"The id of the element to be deleted.\",\n },\n },\r\n required: [\"route\", \"element_id\"],\r\n },\r\n};\r\n"]}
@@ -0,0 +1,101 @@
1
+ import { Type } from "@google/genai";
2
+ export declare const OnClickActionSchema: {
3
+ type: Type;
4
+ properties: {
5
+ kind: {
6
+ type: Type;
7
+ enum: string[];
8
+ description: string;
9
+ };
10
+ href: {
11
+ type: Type;
12
+ description: string;
13
+ };
14
+ replace: {
15
+ type: Type;
16
+ description: string;
17
+ };
18
+ newTab: {
19
+ type: Type;
20
+ description: string;
21
+ };
22
+ };
23
+ required: string[];
24
+ };
25
+ export declare const BuilderElementPropsSchema: {
26
+ type: Type;
27
+ properties: {
28
+ onClick: {
29
+ type: Type;
30
+ properties: {
31
+ kind: {
32
+ type: Type;
33
+ enum: string[];
34
+ description: string;
35
+ };
36
+ href: {
37
+ type: Type;
38
+ description: string;
39
+ };
40
+ replace: {
41
+ type: Type;
42
+ description: string;
43
+ };
44
+ newTab: {
45
+ type: Type;
46
+ description: string;
47
+ };
48
+ };
49
+ required: string[];
50
+ };
51
+ text: {
52
+ type: Type;
53
+ description: string;
54
+ };
55
+ href: {
56
+ type: Type;
57
+ description: string;
58
+ };
59
+ placeholder: {
60
+ type: Type;
61
+ description: string;
62
+ };
63
+ alt: {
64
+ type: Type;
65
+ description: string;
66
+ };
67
+ target: {
68
+ type: Type;
69
+ description: string;
70
+ };
71
+ rel: {
72
+ type: Type;
73
+ description: string;
74
+ };
75
+ value: {
76
+ type: Type;
77
+ description: string;
78
+ };
79
+ type: {
80
+ type: Type;
81
+ description: string;
82
+ };
83
+ name: {
84
+ type: Type;
85
+ description: string;
86
+ };
87
+ size: {
88
+ type: Type;
89
+ description: string;
90
+ };
91
+ color: {
92
+ type: Type;
93
+ description: string;
94
+ };
95
+ strokeWidth: {
96
+ type: Type;
97
+ description: string;
98
+ };
99
+ };
100
+ };
101
+ //# sourceMappingURL=elementProps.schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"elementProps.schema.d.ts","sourceRoot":"","sources":["../../../../src/ai/tools/schemas/elementProps.schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAErC,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;CAwB/B,CAAC;AAEF,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqDrC,CAAC"}
@@ -0,0 +1,74 @@
1
+ import { Type } from "@google/genai";
2
+ export const OnClickActionSchema = {
3
+ type: Type.OBJECT,
4
+ properties: {
5
+ kind: {
6
+ type: Type.STRING,
7
+ enum: ["route", "back", "reload", "external"],
8
+ description: "What happens when the element is clicked. 'route' navigates within the app, 'external' opens a URL, 'back' goes back, 'reload' refreshes.",
9
+ },
10
+ href: {
11
+ type: Type.STRING,
12
+ description: "URL to navigate to (used for kind='route' and kind='external').",
13
+ },
14
+ replace: {
15
+ type: Type.BOOLEAN,
16
+ description: "For kind='route': replace history instead of pushing.",
17
+ },
18
+ newTab: {
19
+ type: Type.BOOLEAN,
20
+ description: "For kind='external': open link in a new tab.",
21
+ },
22
+ },
23
+ required: ["kind"],
24
+ };
25
+ export const BuilderElementPropsSchema = {
26
+ type: Type.OBJECT,
27
+ properties: {
28
+ onClick: OnClickActionSchema,
29
+ text: {
30
+ type: Type.STRING,
31
+ description: "Text content used by 'text' (<p>), 'button' (label), and as a fallback for 'link' when it has no children.",
32
+ },
33
+ href: {
34
+ type: Type.STRING,
35
+ description: "For 'link': the href attribute (defaults to '#').",
36
+ },
37
+ placeholder: {
38
+ type: Type.STRING,
39
+ description: "For 'input' and 'textarea': placeholder shown when empty.",
40
+ },
41
+ alt: {
42
+ type: Type.STRING,
43
+ description: "For 'image': alt text for accessibility AND the query used to fetch a suitable Unsplash image (src is auto-resolved from alt).",
44
+ },
45
+ target: {
46
+ type: Type.STRING,
47
+ description: "For 'link': target attribute (e.g. '_blank').",
48
+ },
49
+ rel: {
50
+ type: Type.STRING,
51
+ description: "For 'link': rel attribute (e.g. 'noreferrer').",
52
+ },
53
+ value: {
54
+ type: Type.STRING,
55
+ description: "For 'input' and 'textarea': default value (maps to defaultValue).",
56
+ },
57
+ type: {
58
+ type: Type.STRING,
59
+ description: "For 'input': input type (e.g. 'text', 'email', 'password'). Defaults to 'text'.",
60
+ },
61
+ // icon
62
+ name: {
63
+ type: Type.STRING,
64
+ description: "For 'icon': Lucide icon name (e.g. 'ArrowRight', 'Menu').",
65
+ },
66
+ size: { type: Type.NUMBER, description: "For 'icon': size in px." },
67
+ color: { type: Type.STRING, description: "For 'icon': stroke color." },
68
+ strokeWidth: {
69
+ type: Type.NUMBER,
70
+ description: "For 'icon': stroke width.",
71
+ },
72
+ },
73
+ };
74
+ //# sourceMappingURL=elementProps.schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"elementProps.schema.js","sourceRoot":"","sources":["../../../../src/ai/tools/schemas/elementProps.schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAErC,MAAM,CAAC,MAAM,mBAAmB,GAAG;IACjC,IAAI,EAAE,IAAI,CAAC,MAAM;IACjB,UAAU,EAAE;QACV,IAAI,EAAE;YACJ,IAAI,EAAE,IAAI,CAAC,MAAM;YACjB,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAU,CAAC;YAC7C,WAAW,EACT,2IAA2I;SAC9I;QACD,IAAI,EAAE;YACJ,IAAI,EAAE,IAAI,CAAC,MAAM;YACjB,WAAW,EACT,iEAAiE;SACpE;QACD,OAAO,EAAE;YACP,IAAI,EAAE,IAAI,CAAC,OAAO;YAClB,WAAW,EAAE,uDAAuD;SACrE;QACD,MAAM,EAAE;YACN,IAAI,EAAE,IAAI,CAAC,OAAO;YAClB,WAAW,EAAE,8CAA8C;SAC5D;KACF;IACD,QAAQ,EAAE,CAAC,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,CAAC,MAAM,yBAAyB,GAAG;IACvC,IAAI,EAAE,IAAI,CAAC,MAAM;IACjB,UAAU,EAAE;QACV,OAAO,EAAE,mBAAmB;QAC5B,IAAI,EAAE;YACJ,IAAI,EAAE,IAAI,CAAC,MAAM;YACjB,WAAW,EACT,4GAA4G;SAC/G;QACD,IAAI,EAAE;YACJ,IAAI,EAAE,IAAI,CAAC,MAAM;YACjB,WAAW,EAAE,mDAAmD;SACjE;QACD,WAAW,EAAE;YACX,IAAI,EAAE,IAAI,CAAC,MAAM;YACjB,WAAW,EAAE,2DAA2D;SACzE;QACD,GAAG,EAAE;YACH,IAAI,EAAE,IAAI,CAAC,MAAM;YACjB,WAAW,EACT,gIAAgI;SACnI;QACD,MAAM,EAAE;YACN,IAAI,EAAE,IAAI,CAAC,MAAM;YACjB,WAAW,EAAE,+CAA+C;SAC7D;QACD,GAAG,EAAE;YACH,IAAI,EAAE,IAAI,CAAC,MAAM;YACjB,WAAW,EAAE,gDAAgD;SAC9D;QACD,KAAK,EAAE;YACL,IAAI,EAAE,IAAI,CAAC,MAAM;YACjB,WAAW,EACT,mEAAmE;SACtE;QACD,IAAI,EAAE;YACJ,IAAI,EAAE,IAAI,CAAC,MAAM;YACjB,WAAW,EACT,iFAAiF;SACpF;QAED,OAAO;QACP,IAAI,EAAE;YACJ,IAAI,EAAE,IAAI,CAAC,MAAM;YACjB,WAAW,EAAE,2DAA2D;SACzE;QACD,IAAI,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,MAAM,EAAE,WAAW,EAAE,yBAAyB,EAAE;QACnE,KAAK,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,MAAM,EAAE,WAAW,EAAE,2BAA2B,EAAE;QACtE,WAAW,EAAE;YACX,IAAI,EAAE,IAAI,CAAC,MAAM;YACjB,WAAW,EAAE,2BAA2B;SACzC;KACF;CACF,CAAC","sourcesContent":["import { Type } from \"@google/genai\";\n\nexport const OnClickActionSchema = {\n type: Type.OBJECT,\n properties: {\n kind: {\n type: Type.STRING,\n enum: [\"route\", \"back\", \"reload\", \"external\"],\n description:\n \"What happens when the element is clicked. 'route' navigates within the app, 'external' opens a URL, 'back' goes back, 'reload' refreshes.\",\n },\n href: {\n type: Type.STRING,\n description:\n \"URL to navigate to (used for kind='route' and kind='external').\",\n },\n replace: {\n type: Type.BOOLEAN,\n description: \"For kind='route': replace history instead of pushing.\",\n },\n newTab: {\n type: Type.BOOLEAN,\n description: \"For kind='external': open link in a new tab.\",\n },\n },\n required: [\"kind\"],\n};\n\nexport const BuilderElementPropsSchema = {\n type: Type.OBJECT,\n properties: {\n onClick: OnClickActionSchema,\n text: {\n type: Type.STRING,\n description:\n \"Text content used by 'text' (<p>), 'button' (label), and as a fallback for 'link' when it has no children.\",\n },\n href: {\n type: Type.STRING,\n description: \"For 'link': the href attribute (defaults to '#').\",\n },\n placeholder: {\n type: Type.STRING,\n description: \"For 'input' and 'textarea': placeholder shown when empty.\",\n },\n alt: {\n type: Type.STRING,\n description:\n \"For 'image': alt text for accessibility AND the query used to fetch a suitable Unsplash image (src is auto-resolved from alt).\",\n },\n target: {\n type: Type.STRING,\n description: \"For 'link': target attribute (e.g. '_blank').\",\n },\n rel: {\n type: Type.STRING,\n description: \"For 'link': rel attribute (e.g. 'noreferrer').\",\n },\n value: {\n type: Type.STRING,\n description:\n \"For 'input' and 'textarea': default value (maps to defaultValue).\",\n },\n type: {\n type: Type.STRING,\n description:\n \"For 'input': input type (e.g. 'text', 'email', 'password'). Defaults to 'text'.\",\n },\n\n // icon\n name: {\n type: Type.STRING,\n description: \"For 'icon': Lucide icon name (e.g. 'ArrowRight', 'Menu').\",\n },\n size: { type: Type.NUMBER, description: \"For 'icon': size in px.\" },\n color: { type: Type.STRING, description: \"For 'icon': stroke color.\" },\n strokeWidth: {\n type: Type.NUMBER,\n description: \"For 'icon': stroke width.\",\n },\n },\n};\n"]}
@@ -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;AAmFX,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6D/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;AAGrC,eAAO,MAAM,aAAa,8FAUhB,CAAC;AAEX,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2D/B,CAAC"}
@@ -1,4 +1,5 @@
1
1
  import { Type } from "@google/genai";
2
+ import { BuilderElementPropsSchema } from "./elementProps.schema.js";
2
3
  export const ELEMENT_TYPES = [
3
4
  "fragment",
4
5
  "div",
@@ -10,78 +11,6 @@ export const ELEMENT_TYPES = [
10
11
  "link",
11
12
  "icon",
12
13
  ];
13
- const OnClickActionSchema = {
14
- type: Type.OBJECT,
15
- properties: {
16
- kind: {
17
- type: Type.STRING,
18
- enum: ["route", "back", "reload", "external"],
19
- description: "What happens when the element is clicked. 'route' navigates within the app, 'external' opens a URL, 'back' goes back, 'reload' refreshes.",
20
- },
21
- href: {
22
- type: Type.STRING,
23
- description: "URL to navigate to (used for kind='route' and kind='external').",
24
- },
25
- replace: {
26
- type: Type.BOOLEAN,
27
- description: "For kind='route': replace history instead of pushing.",
28
- },
29
- newTab: {
30
- type: Type.BOOLEAN,
31
- description: "For kind='external': open link in a new tab.",
32
- },
33
- },
34
- required: ["kind"],
35
- };
36
- const BuilderElementPropsSchema = {
37
- type: Type.OBJECT,
38
- properties: {
39
- onClick: OnClickActionSchema,
40
- text: {
41
- type: Type.STRING,
42
- description: "Text content used by 'text' (<p>), 'button' (label), and as a fallback for 'link' when it has no children.",
43
- },
44
- href: {
45
- type: Type.STRING,
46
- description: "For 'link': the href attribute (defaults to '#').",
47
- },
48
- placeholder: {
49
- type: Type.STRING,
50
- description: "For 'input' and 'textarea': placeholder shown when empty.",
51
- },
52
- alt: {
53
- type: Type.STRING,
54
- description: "For 'image': alt text for accessibility AND the query used to fetch a suitable Unsplash image (src is auto-resolved from alt).",
55
- },
56
- target: {
57
- type: Type.STRING,
58
- description: "For 'link': target attribute (e.g. '_blank').",
59
- },
60
- rel: {
61
- type: Type.STRING,
62
- description: "For 'link': rel attribute (e.g. 'noreferrer').",
63
- },
64
- value: {
65
- type: Type.STRING,
66
- description: "For 'input' and 'textarea': default value (maps to defaultValue).",
67
- },
68
- type: {
69
- type: Type.STRING,
70
- description: "For 'input': input type (e.g. 'text', 'email', 'password'). Defaults to 'text'.",
71
- },
72
- // icon
73
- name: {
74
- type: Type.STRING,
75
- description: "For 'icon': Lucide icon name (e.g. 'ArrowRight', 'Menu').",
76
- },
77
- size: { type: Type.NUMBER, description: "For 'icon': size in px." },
78
- color: { type: Type.STRING, description: "For 'icon': stroke color." },
79
- strokeWidth: {
80
- type: Type.NUMBER,
81
- description: "For 'icon': stroke width.",
82
- },
83
- },
84
- };
85
14
  export const InsertElementSchema = {
86
15
  name: "insert_element",
87
16
  description: "Inserts a tree of UI elements represented as a flat array of elements. One or more elements can have parentId set to 'parent' to be the roots (siblings inserted at the same level). Subsequent children point to their parent using temporary ID references (e.g., parentId set to parent's temporary id).",
@@ -90,8 +19,7 @@ export const InsertElementSchema = {
90
19
  properties: {
91
20
  route: {
92
21
  type: Type.STRING,
93
- // Accept both "/about" and "about" (caller might omit the leading slash).
94
- pattern: "^(?:/(?:[A-Za-z0-9_.[\\\\\]-]+(?:/[A-Za-z0-9_.[\\\\\]-]+)*)?|[A-Za-z0-9_.[\\\\\]-]+(?:/[A-Za-z0-9_.[\\\\\]-]+)*)$",
22
+ pattern: String.raw `^(?:/(?:[A-Za-z0-9_.[\\\]-]+(?:/[A-Za-z0-9_.[\\\]-]+)*)?|[A-Za-z0-9_.[\\\]-]+(?:/[A-Za-z0-9_.[\\\]-]+)*)$`,
95
23
  description: "The route to insert the element at. Use URL paths with forward slashes only. Examples: '/', '/about', '/pricing'. If you forget the leading '/', it will be assumed (e.g. 'about' -> '/about'). Never send Windows-style backslashes (e.g. '\\\\') or filesystem paths like 'app/pricing'. Never send empty string.",
96
24
  },
97
25
  parent_id: {