@loom-framework/core 0.1.0-alpha.8 → 0.1.0-alpha.81

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 (178) hide show
  1. package/dist/adapter-base.d.ts +29 -0
  2. package/dist/adapter-base.d.ts.map +1 -0
  3. package/dist/adapter-base.js +62 -0
  4. package/dist/adapter-base.js.map +1 -0
  5. package/dist/adapter-factory.d.ts +8 -0
  6. package/dist/adapter-factory.d.ts.map +1 -0
  7. package/dist/adapter-factory.js +25 -0
  8. package/dist/adapter-factory.js.map +1 -0
  9. package/dist/adapter-filesystem.d.ts +6 -11
  10. package/dist/adapter-filesystem.d.ts.map +1 -1
  11. package/dist/adapter-filesystem.js +56 -41
  12. package/dist/adapter-filesystem.js.map +1 -1
  13. package/dist/adapter-sqlite.d.ts +6 -23
  14. package/dist/adapter-sqlite.d.ts.map +1 -1
  15. package/dist/adapter-sqlite.js +65 -50
  16. package/dist/adapter-sqlite.js.map +1 -1
  17. package/dist/backend/ai/button-resolver.d.ts +18 -0
  18. package/dist/backend/ai/button-resolver.d.ts.map +1 -0
  19. package/dist/backend/ai/button-resolver.js +58 -0
  20. package/dist/backend/ai/button-resolver.js.map +1 -0
  21. package/dist/backend/ai/engine.d.ts +52 -0
  22. package/dist/backend/ai/engine.d.ts.map +1 -0
  23. package/dist/backend/ai/engine.js +186 -0
  24. package/dist/backend/ai/engine.js.map +1 -0
  25. package/dist/backend/ai/index.d.ts +11 -0
  26. package/dist/backend/ai/index.d.ts.map +1 -0
  27. package/dist/backend/ai/index.js +8 -0
  28. package/dist/backend/ai/index.js.map +1 -0
  29. package/dist/backend/ai/output-parser.d.ts +29 -0
  30. package/dist/backend/ai/output-parser.d.ts.map +1 -0
  31. package/dist/backend/ai/output-parser.js +247 -0
  32. package/dist/backend/ai/output-parser.js.map +1 -0
  33. package/dist/backend/ai/session-manager.d.ts +103 -0
  34. package/dist/backend/ai/session-manager.d.ts.map +1 -0
  35. package/dist/backend/ai/session-manager.js +298 -0
  36. package/dist/backend/ai/session-manager.js.map +1 -0
  37. package/dist/backend/index.d.ts +61 -0
  38. package/dist/backend/index.d.ts.map +1 -0
  39. package/dist/backend/index.js +161 -0
  40. package/dist/backend/index.js.map +1 -0
  41. package/dist/backend/observe/index.d.ts +6 -0
  42. package/dist/backend/observe/index.d.ts.map +1 -0
  43. package/dist/backend/observe/index.js +5 -0
  44. package/dist/backend/observe/index.js.map +1 -0
  45. package/dist/backend/observe/logger.d.ts +28 -0
  46. package/dist/backend/observe/logger.d.ts.map +1 -0
  47. package/dist/backend/observe/logger.js +80 -0
  48. package/dist/backend/observe/logger.js.map +1 -0
  49. package/dist/backend/observe/types.d.ts +26 -0
  50. package/dist/backend/observe/types.d.ts.map +1 -0
  51. package/dist/backend/observe/types.js +7 -0
  52. package/dist/backend/observe/types.js.map +1 -0
  53. package/dist/backend/routes/chat.d.ts +31 -0
  54. package/dist/backend/routes/chat.d.ts.map +1 -0
  55. package/dist/backend/routes/chat.js +426 -0
  56. package/dist/backend/routes/chat.js.map +1 -0
  57. package/dist/backend/routes/data.d.ts +13 -0
  58. package/dist/backend/routes/data.d.ts.map +1 -0
  59. package/dist/backend/routes/data.js +134 -0
  60. package/dist/backend/routes/data.js.map +1 -0
  61. package/dist/backend/routes/health.d.ts +7 -0
  62. package/dist/backend/routes/health.d.ts.map +1 -0
  63. package/dist/backend/routes/health.js +15 -0
  64. package/dist/backend/routes/health.js.map +1 -0
  65. package/dist/backend/routes/index.d.ts +11 -0
  66. package/dist/backend/routes/index.d.ts.map +1 -0
  67. package/dist/backend/routes/index.js +9 -0
  68. package/dist/backend/routes/index.js.map +1 -0
  69. package/dist/backend/routes/skills.d.ts +16 -0
  70. package/dist/backend/routes/skills.d.ts.map +1 -0
  71. package/dist/backend/routes/skills.js +590 -0
  72. package/dist/backend/routes/skills.js.map +1 -0
  73. package/dist/backend/routes/upload.d.ts +24 -0
  74. package/dist/backend/routes/upload.d.ts.map +1 -0
  75. package/dist/backend/routes/upload.js +67 -0
  76. package/dist/backend/routes/upload.js.map +1 -0
  77. package/dist/bin.d.ts +8 -0
  78. package/dist/bin.d.ts.map +1 -0
  79. package/dist/bin.js +12 -0
  80. package/dist/bin.js.map +1 -0
  81. package/dist/capability-generator.d.ts +21 -6
  82. package/dist/capability-generator.d.ts.map +1 -1
  83. package/dist/capability-generator.js +88 -261
  84. package/dist/capability-generator.js.map +1 -1
  85. package/dist/cli/commands/build.d.ts +11 -0
  86. package/dist/cli/commands/build.d.ts.map +1 -0
  87. package/dist/cli/commands/build.js +170 -0
  88. package/dist/cli/commands/build.js.map +1 -0
  89. package/dist/cli/commands/data.d.ts +12 -0
  90. package/dist/cli/commands/data.d.ts.map +1 -0
  91. package/dist/cli/commands/data.js +158 -0
  92. package/dist/cli/commands/data.js.map +1 -0
  93. package/dist/cli/commands/dev.d.ts +9 -0
  94. package/dist/cli/commands/dev.d.ts.map +1 -0
  95. package/dist/cli/commands/dev.js +114 -0
  96. package/dist/cli/commands/dev.js.map +1 -0
  97. package/dist/cli/commands/generate-capabilities.d.ts +8 -0
  98. package/dist/cli/commands/generate-capabilities.d.ts.map +1 -0
  99. package/dist/cli/commands/generate-capabilities.js +40 -0
  100. package/dist/cli/commands/generate-capabilities.js.map +1 -0
  101. package/dist/cli/commands/generate-cli-command.d.ts +8 -0
  102. package/dist/cli/commands/generate-cli-command.d.ts.map +1 -0
  103. package/dist/cli/commands/generate-cli-command.js +64 -0
  104. package/dist/cli/commands/generate-cli-command.js.map +1 -0
  105. package/dist/cli/commands/generate-dashboard.d.ts +9 -0
  106. package/dist/cli/commands/generate-dashboard.d.ts.map +1 -0
  107. package/dist/cli/commands/generate-dashboard.js +452 -0
  108. package/dist/cli/commands/generate-dashboard.js.map +1 -0
  109. package/dist/cli/commands/generate-page.d.ts +9 -0
  110. package/dist/cli/commands/generate-page.d.ts.map +1 -0
  111. package/dist/cli/commands/generate-page.js +518 -0
  112. package/dist/cli/commands/generate-page.js.map +1 -0
  113. package/dist/cli/commands/generate-skill.d.ts +8 -0
  114. package/dist/cli/commands/generate-skill.d.ts.map +1 -0
  115. package/dist/cli/commands/generate-skill.js +75 -0
  116. package/dist/cli/commands/generate-skill.js.map +1 -0
  117. package/dist/cli/commands/generate.d.ts +6 -0
  118. package/dist/cli/commands/generate.d.ts.map +1 -0
  119. package/dist/cli/commands/generate.js +19 -0
  120. package/dist/cli/commands/generate.js.map +1 -0
  121. package/dist/cli/commands/init.d.ts +8 -0
  122. package/dist/cli/commands/init.d.ts.map +1 -0
  123. package/dist/cli/commands/init.js +539 -0
  124. package/dist/cli/commands/init.js.map +1 -0
  125. package/dist/cli/commands/observe.d.ts +9 -0
  126. package/dist/cli/commands/observe.d.ts.map +1 -0
  127. package/dist/cli/commands/observe.js +142 -0
  128. package/dist/cli/commands/observe.js.map +1 -0
  129. package/dist/cli/commands/skill.d.ts +9 -0
  130. package/dist/cli/commands/skill.d.ts.map +1 -0
  131. package/dist/cli/commands/skill.js +186 -0
  132. package/dist/cli/commands/skill.js.map +1 -0
  133. package/dist/cli/helpers/app-tsx-wiring.d.ts +17 -0
  134. package/dist/cli/helpers/app-tsx-wiring.d.ts.map +1 -0
  135. package/dist/cli/helpers/app-tsx-wiring.js +132 -0
  136. package/dist/cli/helpers/app-tsx-wiring.js.map +1 -0
  137. package/dist/cli/helpers/duration.d.ts +5 -0
  138. package/dist/cli/helpers/duration.d.ts.map +1 -0
  139. package/dist/cli/helpers/duration.js +19 -0
  140. package/dist/cli/helpers/duration.js.map +1 -0
  141. package/dist/cli/helpers/field-template.d.ts +10 -0
  142. package/dist/cli/helpers/field-template.d.ts.map +1 -0
  143. package/dist/cli/helpers/field-template.js +100 -0
  144. package/dist/cli/helpers/field-template.js.map +1 -0
  145. package/dist/cli/helpers/naming.d.ts +12 -0
  146. package/dist/cli/helpers/naming.d.ts.map +1 -0
  147. package/dist/cli/helpers/naming.js +25 -0
  148. package/dist/cli/helpers/naming.js.map +1 -0
  149. package/dist/cli/index.d.ts +9 -0
  150. package/dist/cli/index.d.ts.map +1 -0
  151. package/dist/cli/index.js +33 -0
  152. package/dist/cli/index.js.map +1 -0
  153. package/dist/cli/utils.d.ts +10 -0
  154. package/dist/cli/utils.d.ts.map +1 -0
  155. package/dist/cli/utils.js +31 -0
  156. package/dist/cli/utils.js.map +1 -0
  157. package/dist/config.d.ts +118 -42
  158. package/dist/config.d.ts.map +1 -1
  159. package/dist/config.js +59 -10
  160. package/dist/config.js.map +1 -1
  161. package/dist/index.d.ts +7 -2
  162. package/dist/index.d.ts.map +1 -1
  163. package/dist/index.js +7 -1
  164. package/dist/index.js.map +1 -1
  165. package/dist/server-bin.d.ts +12 -0
  166. package/dist/server-bin.d.ts.map +1 -0
  167. package/dist/server-bin.js +75 -0
  168. package/dist/server-bin.js.map +1 -0
  169. package/dist/types.d.ts +71 -20
  170. package/dist/types.d.ts.map +1 -1
  171. package/package.json +25 -10
  172. package/templates/app-skill/SKILL.md +27 -0
  173. package/templates/app-skill/references/data-semantics.md +44 -0
  174. package/templates/app-skill/references/models.md +31 -0
  175. package/templates/loom-skill/SKILL.md +153 -0
  176. package/templates/loom-skill/references/README.md +128 -0
  177. package/templates/loom-skill/references/dashboard.md +161 -0
  178. package/templates/loom-skill/references/data-model.md +78 -0
@@ -0,0 +1,100 @@
1
+ /**
2
+ * Field-to-template utilities - extracted for testability
3
+ */
4
+ /** Map FieldType to Ant Design table column render hint */
5
+ export function fieldToColumnType(type) {
6
+ switch (type) {
7
+ case 'number':
8
+ case 'number[]':
9
+ return "'right'";
10
+ case 'boolean':
11
+ return "'bool'";
12
+ case 'date':
13
+ return "'date'";
14
+ default:
15
+ return "'text'";
16
+ }
17
+ }
18
+ /** Fallback labels for common field names without description */
19
+ const FALLBACK_LABELS = {
20
+ createdAt: '创建时间',
21
+ updatedAt: '更新时间',
22
+ };
23
+ export function getFieldLabel(field) {
24
+ return field.description || FALLBACK_LABELS[field.name] || field.name;
25
+ }
26
+ /** Guess if a field is a long-text field (should use TextArea instead of Input) */
27
+ function isLongTextField(field) {
28
+ const name = field.name.toLowerCase();
29
+ return (field.type === 'string' &&
30
+ !field.enum &&
31
+ (name.includes('content') ||
32
+ name.includes('description') ||
33
+ name.includes('body') ||
34
+ name.includes('text') ||
35
+ name.includes('note') ||
36
+ name.includes('remark') ||
37
+ name.includes('bio') ||
38
+ name.includes('summary')));
39
+ }
40
+ /** Get appropriate required rule message based on field type */
41
+ function getRequiredRule(field, label) {
42
+ if (field.enum || field.type === 'string[]') {
43
+ return ` rules={[{ required: true, message: '请选择${label}' }]}`;
44
+ }
45
+ if (field.type === 'date') {
46
+ return ` rules={[{ required: true, message: '请选择${label}' }]}`;
47
+ }
48
+ if (field.type === 'number') {
49
+ return ` rules={[{ required: true, message: '请输入${label}' }]}`;
50
+ }
51
+ return ` rules={[{ required: true, message: '请输入${label}' }]}`;
52
+ }
53
+ /** Generate Ant Design form item for a field */
54
+ export function fieldToFormItem(field, modelName) {
55
+ const name = field.name;
56
+ const label = getFieldLabel(field);
57
+ const requiredRule = field.required ? getRequiredRule(field, label) : '';
58
+ if (field.enum) {
59
+ const options = field.enum.map((v) => ` <Select.Option value="${v}">${v}</Select.Option>`).join('\n');
60
+ return ` <Form.Item name="${name}" label="${label}"${requiredRule}>
61
+ <Select placeholder="请选择${label}">
62
+ ${options}
63
+ </Select>
64
+ </Form.Item>`;
65
+ }
66
+ switch (field.type) {
67
+ case 'boolean':
68
+ return ` <Form.Item name="${name}" label="${label}" valuePropName="checked">
69
+ <Switch />
70
+ </Form.Item>`;
71
+ case 'number':
72
+ case 'number[]':
73
+ return ` <Form.Item name="${name}" label="${label}"${requiredRule}>
74
+ <InputNumber style={{ width: '100%' }} />
75
+ </Form.Item>`;
76
+ case 'string[]':
77
+ return ` <Form.Item name="${name}" label="${label}"${requiredRule}>
78
+ <Select mode="tags" placeholder="请输入${label}" />
79
+ </Form.Item>`;
80
+ case 'json':
81
+ return ` <Form.Item name="${name}" label="${label}">
82
+ <Input.TextArea rows={4} placeholder="请输入JSON" />
83
+ </Form.Item>`;
84
+ case 'date':
85
+ return ` <Form.Item name="${name}" label="${label}"${requiredRule}>
86
+ <DatePicker style={{ width: '100%' }} />
87
+ </Form.Item>`;
88
+ default:
89
+ // Long text fields use TextArea
90
+ if (isLongTextField(field)) {
91
+ return ` <Form.Item name="${name}" label="${label}"${requiredRule}>
92
+ <Input.TextArea rows={3} placeholder="请输入${label}" />
93
+ </Form.Item>`;
94
+ }
95
+ return ` <Form.Item name="${name}" label="${label}"${requiredRule}>
96
+ <Input placeholder="请输入${label}" />
97
+ </Form.Item>`;
98
+ }
99
+ }
100
+ //# sourceMappingURL=field-template.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"field-template.js","sourceRoot":"","sources":["../../../src/cli/helpers/field-template.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,2DAA2D;AAC3D,MAAM,UAAU,iBAAiB,CAAC,IAAe;IAC/C,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,QAAQ,CAAC;QACd,KAAK,UAAU;YACb,OAAO,SAAS,CAAC;QACnB,KAAK,SAAS;YACZ,OAAO,QAAQ,CAAC;QAClB,KAAK,MAAM;YACT,OAAO,QAAQ,CAAC;QAClB;YACE,OAAO,QAAQ,CAAC;IACpB,CAAC;AACH,CAAC;AAED,iEAAiE;AACjE,MAAM,eAAe,GAA2B;IAC9C,SAAS,EAAE,MAAM;IACjB,SAAS,EAAE,MAAM;CAClB,CAAC;AAEF,MAAM,UAAU,aAAa,CAAC,KAAsB;IAClD,OAAO,KAAK,CAAC,WAAW,IAAI,eAAe,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC;AACxE,CAAC;AAED,mFAAmF;AACnF,SAAS,eAAe,CAAC,KAAsB;IAC7C,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;IACtC,OAAO,CACL,KAAK,CAAC,IAAI,KAAK,QAAQ;QACvB,CAAC,KAAK,CAAC,IAAI;QACX,CAAC,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC;YACvB,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC;YAC5B,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC;YACrB,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC;YACrB,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC;YACrB,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC;YACvB,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC;YACpB,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAC5B,CAAC;AACJ,CAAC;AAED,gEAAgE;AAChE,SAAS,eAAe,CAAC,KAAsB,EAAE,KAAa;IAC5D,IAAI,KAAK,CAAC,IAAI,IAAI,KAAK,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;QAC5C,OAAO,2CAA2C,KAAK,OAAO,CAAC;IACjE,CAAC;IACD,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;QAC1B,OAAO,2CAA2C,KAAK,OAAO,CAAC;IACjE,CAAC;IACD,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC5B,OAAO,2CAA2C,KAAK,OAAO,CAAC;IACjE,CAAC;IACD,OAAO,2CAA2C,KAAK,OAAO,CAAC;AACjE,CAAC;AAED,gDAAgD;AAChD,MAAM,UAAU,eAAe,CAAC,KAAsB,EAAE,SAAiB;IACvE,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC;IACxB,MAAM,KAAK,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC;IACnC,MAAM,YAAY,GAAG,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,eAAe,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAEzE,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC;QACf,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,iCAAiC,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC7G,OAAO,0BAA0B,IAAI,YAAY,KAAK,IAAI,YAAY;kCACxC,KAAK;EACrC,OAAO;;mBAEU,CAAC;IAClB,CAAC;IAED,QAAQ,KAAK,CAAC,IAAI,EAAE,CAAC;QACnB,KAAK,SAAS;YACZ,OAAO,0BAA0B,IAAI,YAAY,KAAK;;mBAEzC,CAAC;QAChB,KAAK,QAAQ,CAAC;QACd,KAAK,UAAU;YACb,OAAO,0BAA0B,IAAI,YAAY,KAAK,IAAI,YAAY;;mBAEzD,CAAC;QAChB,KAAK,UAAU;YACb,OAAO,0BAA0B,IAAI,YAAY,KAAK,IAAI,YAAY;8CAC9B,KAAK;mBAChC,CAAC;QAChB,KAAK,MAAM;YACT,OAAO,0BAA0B,IAAI,YAAY,KAAK;;mBAEzC,CAAC;QAChB,KAAK,MAAM;YACT,OAAO,0BAA0B,IAAI,YAAY,KAAK,IAAI,YAAY;;mBAEzD,CAAC;QAChB;YACE,gCAAgC;YAChC,IAAI,eAAe,CAAC,KAAK,CAAC,EAAE,CAAC;gBAC3B,OAAO,0BAA0B,IAAI,YAAY,KAAK,IAAI,YAAY;mDAC3B,KAAK;mBACrC,CAAC;YACd,CAAC;YACD,OAAO,0BAA0B,IAAI,YAAY,KAAK,IAAI,YAAY;iCAC3C,KAAK;mBACnB,CAAC;IAClB,CAAC;AACH,CAAC"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Naming utilities - extracted for testability
3
+ *
4
+ * Converts model names to valid JS identifiers for generated code.
5
+ * Only transforms what's strictly necessary:
6
+ * - Replace hyphens (invalid in JS identifiers) → capitalize next letter
7
+ * - Capitalize first letter (React requirement)
8
+ * Everything else (camelCase, snake_case, PascalCase) is preserved as-is.
9
+ */
10
+ export declare function toPascalCase(name: string): string;
11
+ export declare function toCamelCase(name: string): string;
12
+ //# sourceMappingURL=naming.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"naming.d.ts","sourceRoot":"","sources":["../../../src/cli/helpers/naming.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAMH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAMjD;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAGhD"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Naming utilities - extracted for testability
3
+ *
4
+ * Converts model names to valid JS identifiers for generated code.
5
+ * Only transforms what's strictly necessary:
6
+ * - Replace hyphens (invalid in JS identifiers) → capitalize next letter
7
+ * - Capitalize first letter (React requirement)
8
+ * Everything else (camelCase, snake_case, PascalCase) is preserved as-is.
9
+ */
10
+ function capitalizeFirst(s) {
11
+ return s.charAt(0).toUpperCase() + s.slice(1);
12
+ }
13
+ export function toPascalCase(name) {
14
+ if (!name)
15
+ return name;
16
+ // Split on hyphens and underscores, PascalCase-join the parts,
17
+ // then capitalize first letter.
18
+ const parts = name.split(/[-_]/).map(capitalizeFirst).join('');
19
+ return capitalizeFirst(parts);
20
+ }
21
+ export function toCamelCase(name) {
22
+ const pascal = toPascalCase(name);
23
+ return pascal.charAt(0).toLowerCase() + pascal.slice(1);
24
+ }
25
+ //# sourceMappingURL=naming.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"naming.js","sourceRoot":"","sources":["../../../src/cli/helpers/naming.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,SAAS,eAAe,CAAC,CAAS;IAChC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAChD,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,IAAY;IACvC,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC;IACvB,+DAA+D;IAC/D,gCAAgC;IAChC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC/D,OAAO,eAAe,CAAC,KAAK,CAAC,CAAC;AAChC,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,IAAY;IACtC,MAAM,MAAM,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;IAClC,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC1D,CAAC"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Loom CLI - Main Program
3
+ *
4
+ * Registers all subcommands and runs the CLI.
5
+ */
6
+ import { Command } from 'commander';
7
+ export declare function createProgram(): Command;
8
+ export declare function run(): Promise<void>;
9
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAUpC,wBAAgB,aAAa,IAAI,OAAO,CAiBvC;AAED,wBAAsB,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC,CAGzC"}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Loom CLI - Main Program
3
+ *
4
+ * Registers all subcommands and runs the CLI.
5
+ */
6
+ import { Command } from 'commander';
7
+ import { registerGenerateCommand } from './commands/generate.js';
8
+ import { registerDevCommand } from './commands/dev.js';
9
+ import { registerBuildCommand } from './commands/build.js';
10
+ import { registerDataCommand } from './commands/data.js';
11
+ import { registerSkillCommand } from './commands/skill.js';
12
+ import { registerObserveCommand } from './commands/observe.js';
13
+ import { registerInitCommand } from './commands/init.js';
14
+ export function createProgram() {
15
+ const program = new Command();
16
+ program
17
+ .name('loom')
18
+ .description('Loom - Weave AI capabilities into your application')
19
+ .version('0.1.0');
20
+ registerInitCommand(program);
21
+ registerGenerateCommand(program);
22
+ registerDevCommand(program);
23
+ registerBuildCommand(program);
24
+ registerDataCommand(program);
25
+ registerSkillCommand(program);
26
+ registerObserveCommand(program);
27
+ return program;
28
+ }
29
+ export async function run() {
30
+ const program = createProgram();
31
+ await program.parseAsync(process.argv);
32
+ }
33
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AACjE,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAEzD,MAAM,UAAU,aAAa;IAC3B,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;IAE9B,OAAO;SACJ,IAAI,CAAC,MAAM,CAAC;SACZ,WAAW,CAAC,oDAAoD,CAAC;SACjE,OAAO,CAAC,OAAO,CAAC,CAAC;IAEpB,mBAAmB,CAAC,OAAO,CAAC,CAAC;IAC7B,uBAAuB,CAAC,OAAO,CAAC,CAAC;IACjC,kBAAkB,CAAC,OAAO,CAAC,CAAC;IAC5B,oBAAoB,CAAC,OAAO,CAAC,CAAC;IAC9B,mBAAmB,CAAC,OAAO,CAAC,CAAC;IAC7B,oBAAoB,CAAC,OAAO,CAAC,CAAC;IAC9B,sBAAsB,CAAC,OAAO,CAAC,CAAC;IAEhC,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,GAAG;IACvB,MAAM,OAAO,GAAG,aAAa,EAAE,CAAC;IAChC,MAAM,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;AACzC,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Shared CLI utilities
3
+ */
4
+ /**
5
+ * Resolve the project root directory.
6
+ * Walks up from CWD looking for loom.config.ts or loom.config.js.
7
+ * Falls back to CWD if no config found.
8
+ */
9
+ export declare function resolveProjectRoot(): Promise<string>;
10
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/cli/utils.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH;;;;GAIG;AACH,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,MAAM,CAAC,CAoB1D"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Shared CLI utilities
3
+ */
4
+ import { promises as fs } from 'fs';
5
+ import path from 'path';
6
+ /**
7
+ * Resolve the project root directory.
8
+ * Walks up from CWD looking for loom.config.ts or loom.config.js.
9
+ * Falls back to CWD if no config found.
10
+ */
11
+ export async function resolveProjectRoot() {
12
+ let current = process.cwd();
13
+ for (let i = 0; i < 20; i++) {
14
+ for (const candidate of ['loom.config.ts', 'loom.config.js']) {
15
+ try {
16
+ await fs.access(path.join(current, candidate));
17
+ return current;
18
+ }
19
+ catch {
20
+ continue;
21
+ }
22
+ }
23
+ const parent = path.dirname(current);
24
+ if (parent === current)
25
+ break; // reached root
26
+ current = parent;
27
+ }
28
+ // Fallback to CWD
29
+ return process.cwd();
30
+ }
31
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/cli/utils.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,IAAI,CAAC;AACpC,OAAO,IAAI,MAAM,MAAM,CAAC;AAExB;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB;IACtC,IAAI,OAAO,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;IAE5B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC;QAC5B,KAAK,MAAM,SAAS,IAAI,CAAC,gBAAgB,EAAE,gBAAgB,CAAC,EAAE,CAAC;YAC7D,IAAI,CAAC;gBACH,MAAM,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC,CAAC;gBAC/C,OAAO,OAAO,CAAC;YACjB,CAAC;YAAC,MAAM,CAAC;gBACP,SAAS;YACX,CAAC;QACH,CAAC;QAED,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QACrC,IAAI,MAAM,KAAK,OAAO;YAAE,MAAM,CAAC,eAAe;QAC9C,OAAO,GAAG,MAAM,CAAC;IACnB,CAAC;IAED,kBAAkB;IAClB,OAAO,OAAO,CAAC,GAAG,EAAE,CAAC;AACvB,CAAC"}
package/dist/config.d.ts CHANGED
@@ -5,7 +5,7 @@
5
5
  * loadConfig() - Load and validate loom.config.ts
6
6
  */
7
7
  import { z } from 'zod';
8
- import type { LoomConfig, ModelSchema } from './types.js';
8
+ import type { LoomConfig, ModelSchema, DashboardConfig } from './types.js';
9
9
  declare const LoomConfigSchema: z.ZodObject<{
10
10
  project: z.ZodObject<{
11
11
  name: z.ZodString;
@@ -222,19 +222,16 @@ declare const LoomConfigSchema: z.ZodObject<{
222
222
  pluginRoot: z.ZodOptional<z.ZodString>;
223
223
  timeout: z.ZodOptional<z.ZodNumber>;
224
224
  skipPermissions: z.ZodOptional<z.ZodBoolean>;
225
- defaultModel: z.ZodOptional<z.ZodString>;
226
225
  }, "strip", z.ZodTypeAny, {
227
226
  path?: string | undefined;
228
227
  pluginRoot?: string | undefined;
229
228
  timeout?: number | undefined;
230
229
  skipPermissions?: boolean | undefined;
231
- defaultModel?: string | undefined;
232
230
  }, {
233
231
  path?: string | undefined;
234
232
  pluginRoot?: string | undefined;
235
233
  timeout?: number | undefined;
236
234
  skipPermissions?: boolean | undefined;
237
- defaultModel?: string | undefined;
238
235
  }>>;
239
236
  }, "strip", z.ZodTypeAny, {
240
237
  engine?: string | undefined;
@@ -243,7 +240,6 @@ declare const LoomConfigSchema: z.ZodObject<{
243
240
  pluginRoot?: string | undefined;
244
241
  timeout?: number | undefined;
245
242
  skipPermissions?: boolean | undefined;
246
- defaultModel?: string | undefined;
247
243
  } | undefined;
248
244
  }, {
249
245
  engine?: string | undefined;
@@ -252,7 +248,6 @@ declare const LoomConfigSchema: z.ZodObject<{
252
248
  pluginRoot?: string | undefined;
253
249
  timeout?: number | undefined;
254
250
  skipPermissions?: boolean | undefined;
255
- defaultModel?: string | undefined;
256
251
  } | undefined;
257
252
  }>>;
258
253
  server: z.ZodOptional<z.ZodObject<{
@@ -271,45 +266,23 @@ declare const LoomConfigSchema: z.ZodObject<{
271
266
  cors?: boolean | undefined;
272
267
  staticDir?: string | undefined;
273
268
  }>>;
274
- aiButtons: z.ZodOptional<z.ZodArray<z.ZodEffects<z.ZodObject<{
269
+ aiButtons: z.ZodOptional<z.ZodArray<z.ZodObject<{
275
270
  id: z.ZodString;
276
271
  label: z.ZodString;
277
272
  icon: z.ZodOptional<z.ZodString>;
278
- prompt: z.ZodOptional<z.ZodString>;
279
- promptTemplate: z.ZodOptional<z.ZodString>;
280
- contextVars: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
273
+ prompt: z.ZodString;
281
274
  placement: z.ZodOptional<z.ZodString>;
282
275
  }, "strip", z.ZodTypeAny, {
283
276
  id: string;
284
277
  label: string;
278
+ prompt: string;
285
279
  icon?: string | undefined;
286
- prompt?: string | undefined;
287
- promptTemplate?: string | undefined;
288
- contextVars?: string[] | undefined;
289
280
  placement?: string | undefined;
290
281
  }, {
291
282
  id: string;
292
283
  label: string;
284
+ prompt: string;
293
285
  icon?: string | undefined;
294
- prompt?: string | undefined;
295
- promptTemplate?: string | undefined;
296
- contextVars?: string[] | undefined;
297
- placement?: string | undefined;
298
- }>, {
299
- id: string;
300
- label: string;
301
- icon?: string | undefined;
302
- prompt?: string | undefined;
303
- promptTemplate?: string | undefined;
304
- contextVars?: string[] | undefined;
305
- placement?: string | undefined;
306
- }, {
307
- id: string;
308
- label: string;
309
- icon?: string | undefined;
310
- prompt?: string | undefined;
311
- promptTemplate?: string | undefined;
312
- contextVars?: string[] | undefined;
313
286
  placement?: string | undefined;
314
287
  }>, "many">>;
315
288
  }, "strip", z.ZodTypeAny, {
@@ -356,7 +329,6 @@ declare const LoomConfigSchema: z.ZodObject<{
356
329
  pluginRoot?: string | undefined;
357
330
  timeout?: number | undefined;
358
331
  skipPermissions?: boolean | undefined;
359
- defaultModel?: string | undefined;
360
332
  } | undefined;
361
333
  } | undefined;
362
334
  server?: {
@@ -368,10 +340,8 @@ declare const LoomConfigSchema: z.ZodObject<{
368
340
  aiButtons?: {
369
341
  id: string;
370
342
  label: string;
343
+ prompt: string;
371
344
  icon?: string | undefined;
372
- prompt?: string | undefined;
373
- promptTemplate?: string | undefined;
374
- contextVars?: string[] | undefined;
375
345
  placement?: string | undefined;
376
346
  }[] | undefined;
377
347
  }, {
@@ -418,7 +388,6 @@ declare const LoomConfigSchema: z.ZodObject<{
418
388
  pluginRoot?: string | undefined;
419
389
  timeout?: number | undefined;
420
390
  skipPermissions?: boolean | undefined;
421
- defaultModel?: string | undefined;
422
391
  } | undefined;
423
392
  } | undefined;
424
393
  server?: {
@@ -430,10 +399,8 @@ declare const LoomConfigSchema: z.ZodObject<{
430
399
  aiButtons?: {
431
400
  id: string;
432
401
  label: string;
402
+ prompt: string;
433
403
  icon?: string | undefined;
434
- prompt?: string | undefined;
435
- promptTemplate?: string | undefined;
436
- contextVars?: string[] | undefined;
437
404
  placement?: string | undefined;
438
405
  }[] | undefined;
439
406
  }>;
@@ -450,7 +417,8 @@ declare const LoomConfigSchema: z.ZodObject<{
450
417
  * defaultAdapter: 'filesystem',
451
418
  * models: [
452
419
  * {
453
- * name: 'users',
420
+ * // Model names accept any casing: kebab-case, camelCase, PascalCase, snake_case
421
+ * name: 'wrongQuestions',
454
422
  * fields: [
455
423
  * { name: 'id', type: 'string', required: true },
456
424
  * { name: 'name', type: 'string', required: true },
@@ -479,5 +447,113 @@ export declare function getModelSchema(config: LoomConfig, modelName: string): M
479
447
  * Validate that all model names are unique
480
448
  */
481
449
  export declare function validateModelUniqueness(config: LoomConfig): string[];
482
- export { LoomConfigSchema };
450
+ declare const DashboardConfigSchema: z.ZodObject<{
451
+ name: z.ZodString;
452
+ description: z.ZodOptional<z.ZodString>;
453
+ models: z.ZodArray<z.ZodString, "many">;
454
+ layout: z.ZodArray<z.ZodObject<{
455
+ row: z.ZodArray<z.ZodObject<{
456
+ type: z.ZodEnum<["stat", "pie", "ring", "bar", "line", "area", "scatter", "radar", "funnel", "treemap", "gauge", "liquid", "heatmap", "stacked_bar", "grouped_bar"]>;
457
+ title: z.ZodString;
458
+ model: z.ZodString;
459
+ span: z.ZodOptional<z.ZodNumber>;
460
+ groupBy: z.ZodOptional<z.ZodString>;
461
+ crossGroupBy: z.ZodOptional<z.ZodString>;
462
+ aggregate: z.ZodOptional<z.ZodEnum<["count", "sum", "avg", "min", "max", "ratio"]>>;
463
+ field: z.ZodOptional<z.ZodString>;
464
+ filter: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
465
+ interval: z.ZodOptional<z.ZodEnum<["day", "week", "month"]>>;
466
+ }, "strip", z.ZodTypeAny, {
467
+ type: "stat" | "pie" | "ring" | "bar" | "line" | "area" | "scatter" | "radar" | "funnel" | "treemap" | "gauge" | "liquid" | "heatmap" | "stacked_bar" | "grouped_bar";
468
+ title: string;
469
+ model: string;
470
+ filter?: Record<string, unknown> | undefined;
471
+ field?: string | undefined;
472
+ span?: number | undefined;
473
+ groupBy?: string | undefined;
474
+ crossGroupBy?: string | undefined;
475
+ aggregate?: "count" | "sum" | "avg" | "min" | "max" | "ratio" | undefined;
476
+ interval?: "day" | "week" | "month" | undefined;
477
+ }, {
478
+ type: "stat" | "pie" | "ring" | "bar" | "line" | "area" | "scatter" | "radar" | "funnel" | "treemap" | "gauge" | "liquid" | "heatmap" | "stacked_bar" | "grouped_bar";
479
+ title: string;
480
+ model: string;
481
+ filter?: Record<string, unknown> | undefined;
482
+ field?: string | undefined;
483
+ span?: number | undefined;
484
+ groupBy?: string | undefined;
485
+ crossGroupBy?: string | undefined;
486
+ aggregate?: "count" | "sum" | "avg" | "min" | "max" | "ratio" | undefined;
487
+ interval?: "day" | "week" | "month" | undefined;
488
+ }>, "many">;
489
+ }, "strip", z.ZodTypeAny, {
490
+ row: {
491
+ type: "stat" | "pie" | "ring" | "bar" | "line" | "area" | "scatter" | "radar" | "funnel" | "treemap" | "gauge" | "liquid" | "heatmap" | "stacked_bar" | "grouped_bar";
492
+ title: string;
493
+ model: string;
494
+ filter?: Record<string, unknown> | undefined;
495
+ field?: string | undefined;
496
+ span?: number | undefined;
497
+ groupBy?: string | undefined;
498
+ crossGroupBy?: string | undefined;
499
+ aggregate?: "count" | "sum" | "avg" | "min" | "max" | "ratio" | undefined;
500
+ interval?: "day" | "week" | "month" | undefined;
501
+ }[];
502
+ }, {
503
+ row: {
504
+ type: "stat" | "pie" | "ring" | "bar" | "line" | "area" | "scatter" | "radar" | "funnel" | "treemap" | "gauge" | "liquid" | "heatmap" | "stacked_bar" | "grouped_bar";
505
+ title: string;
506
+ model: string;
507
+ filter?: Record<string, unknown> | undefined;
508
+ field?: string | undefined;
509
+ span?: number | undefined;
510
+ groupBy?: string | undefined;
511
+ crossGroupBy?: string | undefined;
512
+ aggregate?: "count" | "sum" | "avg" | "min" | "max" | "ratio" | undefined;
513
+ interval?: "day" | "week" | "month" | undefined;
514
+ }[];
515
+ }>, "many">;
516
+ }, "strip", z.ZodTypeAny, {
517
+ name: string;
518
+ models: string[];
519
+ layout: {
520
+ row: {
521
+ type: "stat" | "pie" | "ring" | "bar" | "line" | "area" | "scatter" | "radar" | "funnel" | "treemap" | "gauge" | "liquid" | "heatmap" | "stacked_bar" | "grouped_bar";
522
+ title: string;
523
+ model: string;
524
+ filter?: Record<string, unknown> | undefined;
525
+ field?: string | undefined;
526
+ span?: number | undefined;
527
+ groupBy?: string | undefined;
528
+ crossGroupBy?: string | undefined;
529
+ aggregate?: "count" | "sum" | "avg" | "min" | "max" | "ratio" | undefined;
530
+ interval?: "day" | "week" | "month" | undefined;
531
+ }[];
532
+ }[];
533
+ description?: string | undefined;
534
+ }, {
535
+ name: string;
536
+ models: string[];
537
+ layout: {
538
+ row: {
539
+ type: "stat" | "pie" | "ring" | "bar" | "line" | "area" | "scatter" | "radar" | "funnel" | "treemap" | "gauge" | "liquid" | "heatmap" | "stacked_bar" | "grouped_bar";
540
+ title: string;
541
+ model: string;
542
+ filter?: Record<string, unknown> | undefined;
543
+ field?: string | undefined;
544
+ span?: number | undefined;
545
+ groupBy?: string | undefined;
546
+ crossGroupBy?: string | undefined;
547
+ aggregate?: "count" | "sum" | "avg" | "min" | "max" | "ratio" | undefined;
548
+ interval?: "day" | "week" | "month" | undefined;
549
+ }[];
550
+ }[];
551
+ description?: string | undefined;
552
+ }>;
553
+ /**
554
+ * Load dashboard.config.json from a project directory.
555
+ * Returns the validated DashboardConfig, or null if no config file exists.
556
+ */
557
+ export declare function loadDashboardConfig(projectRoot: string): Promise<DashboardConfig | null>;
558
+ export { LoomConfigSchema, DashboardConfigSchema };
483
559
  //# sourceMappingURL=config.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAmB,MAAM,YAAY,CAAC;AAmD3E,QAAA,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA6BpB,CAAC;AAIH;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,UAAU,GAAG,UAAU,CAU3D;AAID;;;GAGG;AACH,wBAAsB,UAAU,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAqBzE;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAoBnF;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS,CAE7F;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,EAAE,CAUpE;AAGD,OAAO,EAAE,gBAAgB,EAAE,CAAC"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAmC,eAAe,EAAE,MAAM,YAAY,CAAC;AA8C5G,QAAA,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA4BpB,CAAC;AAIH;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,UAAU,GAAG,UAAU,CAU3D;AAID;;;GAGG;AACH,wBAAsB,UAAU,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAqBzE;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAoBnF;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS,CAE7F;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,EAAE,CAUpE;AAqBD,QAAA,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAKY,CAAC;AAExC;;;GAGG;AACH,wBAAsB,mBAAmB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CA0B9F;AAGD,OAAO,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,CAAC"}
package/dist/config.js CHANGED
@@ -12,7 +12,7 @@ const FieldTypeSchema = z.enum([
12
12
  'string[]', 'number[]', 'json',
13
13
  ]);
14
14
  const FieldDefinitionSchema = z.object({
15
- name: z.string(),
15
+ name: z.string().regex(/^[a-zA-Z_][a-zA-Z0-9_]*$/, 'Field name must start with a letter or underscore, and contain only alphanumeric characters and underscores'),
16
16
  type: FieldTypeSchema,
17
17
  required: z.boolean().optional(),
18
18
  description: z.string().optional(),
@@ -20,7 +20,7 @@ const FieldDefinitionSchema = z.object({
20
20
  enum: z.array(z.string()).optional(),
21
21
  });
22
22
  const ModelSchemaSchema = z.object({
23
- name: z.string().regex(/^[a-z][a-z0-9_-]*$/, 'Model name must be lowercase with hyphens/underscores'),
23
+ name: z.string().regex(/^[a-zA-Z][a-zA-Z0-9_]*$/, 'Model name must start with a letter and contain only letters, digits, or underscores (no hyphens)'),
24
24
  fields: z.array(FieldDefinitionSchema).min(1),
25
25
  indexes: z.array(z.object({
26
26
  fields: z.array(z.string()),
@@ -42,11 +42,9 @@ const AIButtonConfigSchema = z.object({
42
42
  id: z.string(),
43
43
  label: z.string(),
44
44
  icon: z.string().optional(),
45
- prompt: z.string().optional(),
46
- promptTemplate: z.string().optional(),
47
- contextVars: z.array(z.string()).optional(),
45
+ prompt: z.string(),
48
46
  placement: z.string().optional(),
49
- }).refine((data) => data.prompt || data.promptTemplate, 'AI button must have either prompt or promptTemplate');
47
+ });
50
48
  const LoomConfigSchema = z.object({
51
49
  project: z.object({
52
50
  name: z.string(),
@@ -66,7 +64,6 @@ const LoomConfigSchema = z.object({
66
64
  pluginRoot: z.string().optional(),
67
65
  timeout: z.number().optional(),
68
66
  skipPermissions: z.boolean().optional(),
69
- defaultModel: z.string().optional(),
70
67
  }).optional(),
71
68
  }).optional(),
72
69
  server: z.object({
@@ -91,7 +88,8 @@ const LoomConfigSchema = z.object({
91
88
  * defaultAdapter: 'filesystem',
92
89
  * models: [
93
90
  * {
94
- * name: 'users',
91
+ * // Model names accept any casing: kebab-case, camelCase, PascalCase, snake_case
92
+ * name: 'wrongQuestions',
95
93
  * fields: [
96
94
  * { name: 'id', type: 'string', required: true },
97
95
  * { name: 'name', type: 'string', required: true },
@@ -174,6 +172,57 @@ export function validateModelUniqueness(config) {
174
172
  }
175
173
  return errors;
176
174
  }
177
- // Re-export zod schema for external validation
178
- export { LoomConfigSchema };
175
+ // ── Dashboard Config Schema ──
176
+ const DashboardWidgetSchema = z.object({
177
+ type: z.enum(['stat', 'pie', 'ring', 'bar', 'line', 'area', 'scatter', 'radar', 'funnel', 'treemap', 'gauge', 'liquid', 'heatmap', 'stacked_bar', 'grouped_bar']),
178
+ title: z.string(),
179
+ model: z.string(),
180
+ span: z.number().int().min(1).max(24).optional(),
181
+ groupBy: z.string().optional(),
182
+ crossGroupBy: z.string().optional(),
183
+ aggregate: z.enum(['count', 'sum', 'avg', 'min', 'max', 'ratio']).optional(),
184
+ field: z.string().optional(),
185
+ filter: z.record(z.unknown()).optional(),
186
+ interval: z.enum(['day', 'week', 'month']).optional(),
187
+ });
188
+ const DashboardLayoutRowSchema = z.object({
189
+ row: z.array(DashboardWidgetSchema).min(1),
190
+ });
191
+ const DashboardConfigSchema = z.object({
192
+ name: z.string().regex(/^[a-zA-Z][a-zA-Z0-9_]*$/, 'Dashboard name must start with a letter and contain only letters, digits, or underscores'),
193
+ description: z.string().optional(),
194
+ models: z.array(z.string()).min(1),
195
+ layout: z.array(DashboardLayoutRowSchema).min(1),
196
+ });
197
+ /**
198
+ * Load dashboard.config.json from a project directory.
199
+ * Returns the validated DashboardConfig, or null if no config file exists.
200
+ */
201
+ export async function loadDashboardConfig(projectRoot) {
202
+ const fs = await import('fs/promises');
203
+ const path = await import('path');
204
+ const configPath = path.resolve(projectRoot, 'dashboard.config.json');
205
+ try {
206
+ const raw = await fs.readFile(configPath, 'utf-8');
207
+ const json = JSON.parse(raw);
208
+ const result = DashboardConfigSchema.safeParse(json);
209
+ if (!result.success) {
210
+ const errors = result.error.issues.map((i) => ` ${i.path.join('.')}: ${i.message}`).join('\n');
211
+ throw new Error(`Invalid dashboard.config.json:\n${errors}`);
212
+ }
213
+ return result.data;
214
+ }
215
+ catch (err) {
216
+ if (err instanceof SyntaxError) {
217
+ throw new Error(`dashboard.config.json is not valid JSON: ${err.message}`);
218
+ }
219
+ // File not found → return null (dashboard is optional)
220
+ if (err.code === 'ENOENT') {
221
+ return null;
222
+ }
223
+ throw err;
224
+ }
225
+ }
226
+ // Re-export zod schemas for external validation
227
+ export { LoomConfigSchema, DashboardConfigSchema };
179
228
  //# sourceMappingURL=config.js.map