@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 @@
1
+ {"version":3,"file":"generate-cli-command.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/generate-cli-command.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA2BzC,wBAAgB,iCAAiC,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAkCxE"}
@@ -0,0 +1,64 @@
1
+ /**
2
+ * loom generate cli-command <name>
3
+ *
4
+ * Create cli/src/commands/<name>.ts skeleton with defineCommand template.
5
+ */
6
+ import chalk from 'chalk';
7
+ import { promises as fs } from 'fs';
8
+ import path from 'path';
9
+ import { resolveProjectRoot } from '../utils.js';
10
+ const CLI_COMMAND_TEMPLATE = (name) => `import { defineCommand } from '@loom-framework/core';
11
+
12
+ export default defineCommand({
13
+ name: '${name}',
14
+ description: 'TODO: Describe this command',
15
+ options: {
16
+ // TODO: Define command options
17
+ // example: {
18
+ // type: 'string',
19
+ // description: 'Example option',
20
+ // required: false,
21
+ // },
22
+ },
23
+ async execute(args, context) {
24
+ const adapter = context.getDataAdapter();
25
+ // TODO: Implement command logic
26
+ return JSON.stringify({ message: '${name} command executed', args });
27
+ },
28
+ });
29
+ `;
30
+ export function registerGenerateCliCommandCommand(program) {
31
+ program
32
+ .command('cli-command <name>')
33
+ .description('Create a new CLI command skeleton with defineCommand template')
34
+ .action(async (name) => {
35
+ try {
36
+ const projectRoot = await resolveProjectRoot();
37
+ const commandDir = path.join(projectRoot, 'cli', 'src', 'commands');
38
+ const commandPath = path.join(commandDir, `${name}.ts`);
39
+ // Check if command already exists
40
+ try {
41
+ await fs.access(commandPath);
42
+ console.error(chalk.red(`Command "${name}" already exists at ${commandPath}`));
43
+ process.exit(1);
44
+ }
45
+ catch {
46
+ // File does not exist, proceed
47
+ }
48
+ await fs.mkdir(commandDir, { recursive: true });
49
+ await fs.writeFile(commandPath, CLI_COMMAND_TEMPLATE(name), 'utf-8');
50
+ console.log(chalk.green('CLI command created successfully!'));
51
+ console.log();
52
+ console.log(chalk.bold(' Command:'), name);
53
+ console.log(chalk.bold(' Path:'), path.join('cli', 'src', 'commands', `${name}.ts`));
54
+ console.log();
55
+ console.log(chalk.dim(` Edit the command to implement its logic.`));
56
+ }
57
+ catch (err) {
58
+ const message = err instanceof Error ? err.message : String(err);
59
+ console.error(chalk.red('Failed to create CLI command:'), message);
60
+ process.exit(1);
61
+ }
62
+ });
63
+ }
64
+ //# sourceMappingURL=generate-cli-command.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate-cli-command.js","sourceRoot":"","sources":["../../../src/cli/commands/generate-cli-command.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,IAAI,CAAC;AACpC,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAEjD,MAAM,oBAAoB,GAAG,CAAC,IAAY,EAAU,EAAE,CAAC;;;WAG5C,IAAI;;;;;;;;;;;;;wCAayB,IAAI;;;CAG3C,CAAC;AAEF,MAAM,UAAU,iCAAiC,CAAC,OAAgB;IAChE,OAAO;SACJ,OAAO,CAAC,oBAAoB,CAAC;SAC7B,WAAW,CAAC,+DAA+D,CAAC;SAC5E,MAAM,CAAC,KAAK,EAAE,IAAY,EAAE,EAAE;QAC7B,IAAI,CAAC;YACH,MAAM,WAAW,GAAG,MAAM,kBAAkB,EAAE,CAAC;YAC/C,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,KAAK,EAAE,KAAK,EAAE,UAAU,CAAC,CAAC;YACpE,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,GAAG,IAAI,KAAK,CAAC,CAAC;YAExD,kCAAkC;YAClC,IAAI,CAAC;gBACH,MAAM,EAAE,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;gBAC7B,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,YAAY,IAAI,uBAAuB,WAAW,EAAE,CAAC,CAAC,CAAC;gBAC/E,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC;YAAC,MAAM,CAAC;gBACP,+BAA+B;YACjC,CAAC;YAED,MAAM,EAAE,CAAC,KAAK,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YAChD,MAAM,EAAE,CAAC,SAAS,CAAC,WAAW,EAAE,oBAAoB,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC,CAAC;YAErE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,mCAAmC,CAAC,CAAC,CAAC;YAC9D,OAAO,CAAC,GAAG,EAAE,CAAC;YACd,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,EAAE,IAAI,CAAC,CAAC;YAC5C,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,EAAE,UAAU,EAAE,GAAG,IAAI,KAAK,CAAC,CAAC,CAAC;YACtF,OAAO,CAAC,GAAG,EAAE,CAAC;YACd,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,4CAA4C,CAAC,CAAC,CAAC;QACvE,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACjE,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,+BAA+B,CAAC,EAAE,OAAO,CAAC,CAAC;YACnE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC,CAAC,CAAC;AACP,CAAC"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * loom generate dashboard <name>
3
+ *
4
+ * Reads dashboard.config.json from the project root,
5
+ * generates a Dashboard page with G2 charts.
6
+ */
7
+ import type { Command } from 'commander';
8
+ export declare function registerGenerateDashboardCommand(program: Command): void;
9
+ //# sourceMappingURL=generate-dashboard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate-dashboard.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/generate-dashboard.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAiZzC,wBAAgB,gCAAgC,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CA2FvE"}
@@ -0,0 +1,452 @@
1
+ /**
2
+ * loom generate dashboard <name>
3
+ *
4
+ * Reads dashboard.config.json from the project root,
5
+ * generates a Dashboard page with G2 charts.
6
+ */
7
+ import chalk from 'chalk';
8
+ import { promises as fs } from 'fs';
9
+ import path from 'path';
10
+ import { loadConfig, getModelSchema, loadDashboardConfig } from '../../index.js';
11
+ import { resolveProjectRoot } from '../utils.js';
12
+ import { toPascalCase } from '../helpers/naming.js';
13
+ import { wireAppTsxAutomatic } from '../helpers/app-tsx-wiring.js';
14
+ /** Build variable name for chart data: e.g. "subjectPieData" */
15
+ function buildChartDataVarName(widget) {
16
+ const prefix = widget.groupBy ? toPascalCase(widget.groupBy) : '';
17
+ const suffix = toPascalCase(widget.type);
18
+ return `${prefix.charAt(0).toLowerCase() + prefix.slice(1)}${suffix}Data`;
19
+ }
20
+ /** Build useChartData() call string */
21
+ function buildUseChartDataCall(widget, modelName, pascalModelName, isBooleanField) {
22
+ const listVar = `${pascalModelName.charAt(0).toLowerCase() + pascalModelName.slice(1)}List`;
23
+ const varName = buildChartDataVarName(widget);
24
+ const options = [];
25
+ if (widget.type === 'stat') {
26
+ // Stats don't use useChartData
27
+ return '';
28
+ }
29
+ // 2D charts use useCrossGroupChartData
30
+ const is2D = ['heatmap', 'stacked_bar', 'grouped_bar'].includes(widget.type) && widget.crossGroupBy;
31
+ // Treemap uses useTreemapChartData
32
+ const isTreemap = widget.type === 'treemap';
33
+ if (widget.groupBy) {
34
+ if (isBooleanField) {
35
+ options.push(`groupByBoolean: '${widget.groupBy}'`);
36
+ }
37
+ else {
38
+ options.push(`groupBy: '${widget.groupBy}'`);
39
+ }
40
+ }
41
+ if (widget.crossGroupBy) {
42
+ options.push(`crossGroupBy: '${widget.crossGroupBy}'`);
43
+ }
44
+ if (widget.aggregate && widget.aggregate !== 'count') {
45
+ options.push(`aggregate: '${widget.aggregate}'`);
46
+ }
47
+ if (widget.field) {
48
+ options.push(`field: '${widget.field}'`);
49
+ }
50
+ if (widget.interval) {
51
+ options.push(`interval: '${widget.interval}'`);
52
+ }
53
+ if (widget.filter) {
54
+ options.push(`filter: ${JSON.stringify(widget.filter)}`);
55
+ }
56
+ const optionsStr = options.length > 0 ? `{ ${options.join(', ')} }` : '{}';
57
+ if (is2D) {
58
+ return `const ${varName} = useCrossGroupChartData(${listVar}, ${optionsStr});`;
59
+ }
60
+ if (isTreemap) {
61
+ return `const ${varName} = useTreemapChartData(${listVar}, ${optionsStr});`;
62
+ }
63
+ return `const ${varName} = useChartData(${listVar}, ${optionsStr});`;
64
+ }
65
+ /** Build G2 Spec object literal code */
66
+ function buildG2Spec(widget) {
67
+ const varName = buildChartDataVarName(widget);
68
+ switch (widget.type) {
69
+ case 'pie':
70
+ return `{
71
+ type: 'interval',
72
+ data: ${varName},
73
+ encode: { y: 'value', color: 'name' },
74
+ coordinate: { type: 'theta' },
75
+ transform: [{ type: 'stackY' }],
76
+ labels: [{ text: 'name', position: 'outside' }],
77
+ }`;
78
+ case 'ring':
79
+ return `{
80
+ type: 'interval',
81
+ data: ${varName},
82
+ encode: { y: 'value', color: 'name' },
83
+ coordinate: { type: 'theta', innerRadius: 0.6 },
84
+ transform: [{ type: 'stackY' }],
85
+ labels: [{ text: 'name', position: 'outside' }],
86
+ }`;
87
+ case 'bar':
88
+ return `{
89
+ type: 'interval',
90
+ data: ${varName},
91
+ encode: { x: 'value', y: 'name', color: 'name' },
92
+ coordinate: { transform: [{ type: 'transpose' }] },
93
+ }`;
94
+ case 'stacked_bar':
95
+ if (widget.crossGroupBy) {
96
+ return `{
97
+ type: 'interval',
98
+ data: ${varName},
99
+ encode: { x: 'group', y: 'value', color: 'name' },
100
+ coordinate: { transform: [{ type: 'transpose' }] },
101
+ transform: [{ type: 'stackY' }],
102
+ }`;
103
+ }
104
+ return `{
105
+ type: 'interval',
106
+ data: ${varName},
107
+ encode: { x: 'value', y: 'name', color: 'name' },
108
+ coordinate: { transform: [{ type: 'transpose' }] },
109
+ transform: [{ type: 'stackY' }],
110
+ }`;
111
+ case 'grouped_bar':
112
+ if (widget.crossGroupBy) {
113
+ return `{
114
+ type: 'interval',
115
+ data: ${varName},
116
+ encode: { x: 'group', y: 'value', color: 'name' },
117
+ coordinate: { transform: [{ type: 'transpose' }] },
118
+ transform: [{ type: 'dodgeX' }],
119
+ }`;
120
+ }
121
+ return `{
122
+ type: 'interval',
123
+ data: ${varName},
124
+ encode: { x: 'value', y: 'name', color: 'name' },
125
+ coordinate: { transform: [{ type: 'transpose' }] },
126
+ transform: [{ type: 'dodgeX' }],
127
+ }`;
128
+ case 'line':
129
+ return `{
130
+ type: 'line',
131
+ data: ${varName},
132
+ encode: { x: 'name', y: 'value' },
133
+ }`;
134
+ case 'area':
135
+ return `{
136
+ type: 'area',
137
+ data: ${varName},
138
+ encode: { x: 'name', y: 'value' },
139
+ }`;
140
+ case 'scatter':
141
+ return `{
142
+ type: 'point',
143
+ data: ${varName},
144
+ encode: { x: 'name', y: 'value', color: 'name', size: 4 },
145
+ }`;
146
+ case 'radar':
147
+ return `{
148
+ type: 'line',
149
+ data: ${varName},
150
+ encode: { x: 'name', y: 'value', color: 'name' },
151
+ coordinate: { type: 'polar' },
152
+ }`;
153
+ case 'funnel':
154
+ return `{
155
+ type: 'interval',
156
+ data: ${varName},
157
+ encode: { x: 'name', y: 'value', color: 'name' },
158
+ coordinate: { transform: [{ type: 'transpose' }] },
159
+ transform: [{ type: 'stackY' }],
160
+ scale: { y: { type: 'identity' } },
161
+ }`;
162
+ case 'treemap':
163
+ return `{
164
+ type: 'treemap',
165
+ data: ${varName},
166
+ encode: { value: 'value' },
167
+ }`;
168
+ case 'gauge':
169
+ return `{
170
+ type: 'gauge',
171
+ data: ${varName}.length ? [${varName}[0].value] : [0],
172
+ scale: { color: { range: ['#5B8FF9', '#E8E8E8'] } },
173
+ }`;
174
+ case 'liquid':
175
+ return `{
176
+ type: 'liquid',
177
+ data: ${varName}.length ? [${varName}[0].value] : [0],
178
+ style: { outline: { border: 4, distance: 8 } },
179
+ }`;
180
+ case 'heatmap':
181
+ if (widget.crossGroupBy) {
182
+ return `{
183
+ type: 'cell',
184
+ data: ${varName},
185
+ encode: { x: 'name', y: 'group', color: 'value' },
186
+ style: { inset: 1 },
187
+ }`;
188
+ }
189
+ return `{
190
+ type: 'cell',
191
+ data: ${varName},
192
+ encode: { x: 'name', y: 'name', color: 'value' },
193
+ style: { inset: 1 },
194
+ }`;
195
+ default:
196
+ return `{
197
+ type: 'interval',
198
+ data: ${varName},
199
+ encode: { x: 'name', y: 'value', color: 'name' },
200
+ }`;
201
+ }
202
+ }
203
+ /** Build stat card code */
204
+ function statCardCode(widget, modelName, pascalModelName) {
205
+ const listVar = `${pascalModelName.charAt(0).toLowerCase() + pascalModelName.slice(1)}List`;
206
+ if (widget.aggregate === 'ratio') {
207
+ // Ratio: filtered count / total count, displayed as percentage
208
+ if (widget.filter && Object.keys(widget.filter).length > 0) {
209
+ const filterExpr = Object.entries(widget.filter)
210
+ .map(([key, val]) => {
211
+ if (typeof val === 'boolean')
212
+ return `d.${key} === ${val}`;
213
+ if (typeof val === 'string')
214
+ return `d.${key} === '${val}'`;
215
+ return `d.${key} === ${JSON.stringify(val)}`;
216
+ })
217
+ .join(' && ');
218
+ return `<Statistic title="${widget.title}" value={${listVar}.length ? Math.round(${listVar}.filter(d => ${filterExpr}).length / ${listVar}.length * 1000) / 10 : 0} suffix="%" precision={1} />`;
219
+ }
220
+ return `<Statistic title="${widget.title}" value={100} suffix="%" />`;
221
+ }
222
+ if (widget.aggregate === 'count' || !widget.aggregate) {
223
+ if (widget.filter && Object.keys(widget.filter).length > 0) {
224
+ // Filtered count — use inline filter in JSX
225
+ const filterExpr = Object.entries(widget.filter)
226
+ .map(([key, val]) => {
227
+ if (typeof val === 'boolean')
228
+ return `d.${key} === ${val}`;
229
+ if (typeof val === 'string')
230
+ return `d.${key} === '${val}'`;
231
+ return `d.${key} === ${JSON.stringify(val)}`;
232
+ })
233
+ .join(' && ');
234
+ return `<Statistic title="${widget.title}" value={${listVar}.filter(d => ${filterExpr}).length} />`;
235
+ }
236
+ return `<Statistic title="${widget.title}" value={${listVar}.length} />`;
237
+ }
238
+ // sum/avg/min/max on a field
239
+ const agg = widget.aggregate;
240
+ const field = widget.field || 'value';
241
+ if (agg === 'sum') {
242
+ return `<Statistic title="${widget.title}" value={${listVar}.reduce((s, d) => s + (Number(d.${field}) || 0), 0)} precision={1} />`;
243
+ }
244
+ if (agg === 'avg') {
245
+ return `<Statistic title="${widget.title}" value={${listVar}.length ? ${listVar}.reduce((s, d) => s + (Number(d.${field}) || 0), 0) / ${listVar}.length : 0} precision={1} />`;
246
+ }
247
+ if (agg === 'min') {
248
+ return `<Statistic title="${widget.title}" value={${listVar}.length ? Math.min(...${listVar}.map(d => Number(d.${field}) || 0)) : 0} />`;
249
+ }
250
+ if (agg === 'max') {
251
+ return `<Statistic title="${widget.title}" value={${listVar}.length ? Math.max(...${listVar}.map(d => Number(d.${field}) || 0)) : 0} />`;
252
+ }
253
+ return `<Statistic title="${widget.title}" value={${listVar}.length} />`;
254
+ }
255
+ /** Detect boolean fields for groupByBoolean usage in generated code */
256
+ function detectBooleanFields(models) {
257
+ const booleanFields = new Set();
258
+ for (const model of models) {
259
+ for (const field of model.fields) {
260
+ if (field.type === 'boolean') {
261
+ booleanFields.add(`${model.name}.${field.name}`);
262
+ }
263
+ }
264
+ }
265
+ return booleanFields;
266
+ }
267
+ /** Generate the full Dashboard page TSX */
268
+ function dashboardPageTemplate(dashboard, models) {
269
+ const pascalName = toPascalCase(dashboard.name);
270
+ const pageLabel = dashboard.description || pascalName;
271
+ const booleanFields = detectBooleanFields(models);
272
+ // Collect unique model names used in widgets
273
+ const usedModels = new Set();
274
+ for (const row of dashboard.layout) {
275
+ for (const widget of row.row) {
276
+ usedModels.add(widget.model);
277
+ }
278
+ }
279
+ // Also include all declared models
280
+ for (const modelName of dashboard.models) {
281
+ usedModels.add(modelName);
282
+ }
283
+ // Build useData hooks for each model
284
+ const useDataHooks = Array.from(usedModels).map((modelName) => {
285
+ const pascalModel = toPascalCase(modelName);
286
+ const listVar = `${pascalModel.charAt(0).toLowerCase() + pascalModel.slice(1)}List`;
287
+ return `const { list: ${listVar} } = useData('${modelName}');`;
288
+ }).join('\n ');
289
+ // Build useChartData calls — collect all chart (non-stat) widget data hooks
290
+ const chartDataHooks = [];
291
+ for (const row of dashboard.layout) {
292
+ for (const widget of row.row) {
293
+ if (widget.type !== 'stat') {
294
+ const pascalModel = toPascalCase(widget.model);
295
+ const isBoolean = booleanFields.has(`${widget.model}.${widget.groupBy}`);
296
+ const hookCall = buildUseChartDataCall(widget, widget.model, pascalModel, isBoolean);
297
+ if (hookCall) {
298
+ chartDataHooks.push(hookCall);
299
+ }
300
+ }
301
+ }
302
+ }
303
+ // Build layout rows JSX
304
+ const layoutJsx = dashboard.layout.map((layoutRow) => {
305
+ const colCount = layoutRow.row.length;
306
+ const defaultSpan = Math.floor(24 / colCount);
307
+ const cols = layoutRow.row.map((widget) => {
308
+ const span = widget.span || defaultSpan;
309
+ if (widget.type === 'stat') {
310
+ const pascalModel = toPascalCase(widget.model);
311
+ const statCode = statCardCode(widget, widget.model, pascalModel);
312
+ return ` <Col span={${span}}>
313
+ <Card styles={{ body: { textAlign: 'center' } }}>
314
+ ${statCode}
315
+ </Card>
316
+ </Col>`;
317
+ }
318
+ // Chart widget
319
+ const varName = buildChartDataVarName(widget);
320
+ const spec = buildG2Spec(widget);
321
+ return ` <Col span={${span}}>
322
+ <Card title="${widget.title}" styles={{ body: { padding: '8px 16px 16px' } }}>
323
+ <DashboardChart spec={${spec}} />
324
+ </Card>
325
+ </Col>`;
326
+ }).join('\n');
327
+ return ` <Row gutter={16}>
328
+ ${cols}
329
+ </Row>`;
330
+ }).join('\n');
331
+ // Build TypeScript interfaces for each model
332
+ const interfaces = models.map((model) => {
333
+ const pascalModel = toPascalCase(model.name);
334
+ const fieldDefs = model.fields.map((f) => {
335
+ const tsType = f.type === 'string[]' ? 'string[]'
336
+ : f.type === 'number[]' ? 'number[]'
337
+ : f.type === 'json' ? 'Record<string, unknown>'
338
+ : f.type === 'number' ? 'number'
339
+ : f.type === 'boolean' ? 'boolean'
340
+ : f.type === 'date' ? 'string'
341
+ : 'string';
342
+ return ` ${f.name}${f.required ? '' : '?'}: ${tsType};`;
343
+ }).join('\n');
344
+ return `interface ${pascalModel}Record {\n id: string;\n${fieldDefs}\n}`;
345
+ }).join('\n\n');
346
+ return `import React from 'react';
347
+ import { Row, Col, Card, Statistic } from 'antd';
348
+ import { useData, useChartData, useCrossGroupChartData, useTreemapChartData, DashboardChart } from '@loom-framework/frontend-antd';
349
+
350
+ ${interfaces}
351
+
352
+ export function ${pascalName}Page(): React.ReactElement {
353
+ ${useDataHooks}
354
+ ${chartDataHooks.join('\n ')}
355
+
356
+ return (
357
+ <div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
358
+ ${layoutJsx}
359
+ </div>
360
+ );
361
+ }
362
+
363
+ export default ${pascalName}Page;
364
+ `;
365
+ }
366
+ export function registerGenerateDashboardCommand(program) {
367
+ program
368
+ .command('dashboard <name>')
369
+ .description('Generate a Dashboard page from dashboard.config.json')
370
+ .action(async (name) => {
371
+ try {
372
+ const projectRoot = await resolveProjectRoot();
373
+ const pascalName = toPascalCase(name);
374
+ // 1. Load dashboard.config.json
375
+ const dashboard = await loadDashboardConfig(projectRoot);
376
+ if (!dashboard) {
377
+ console.error(chalk.red('No dashboard.config.json found in project root.'));
378
+ console.error(chalk.dim('Create one first — see the Loom skill Dashboard section for guidance.'));
379
+ process.exit(1);
380
+ }
381
+ if (dashboard.name !== name) {
382
+ console.error(chalk.red(`Dashboard name mismatch: command expects "${name}" but config has "${dashboard.name}"`));
383
+ process.exit(1);
384
+ }
385
+ // 2. Load loom.config.ts and validate referenced models
386
+ const config = await loadConfig(projectRoot);
387
+ const modelSchemas = [];
388
+ for (const modelName of dashboard.models) {
389
+ const schema = getModelSchema(config, modelName);
390
+ if (!schema) {
391
+ console.error(chalk.red(`Model "${modelName}" referenced in dashboard.config.json not found in loom.config.ts`));
392
+ console.error(chalk.dim(`Available models: ${config.data.models.map(m => m.name).join(', ')}`));
393
+ process.exit(1);
394
+ }
395
+ modelSchemas.push(schema);
396
+ }
397
+ // 3. Generate Dashboard page
398
+ const pageDir = path.join(projectRoot, 'frontend', 'src', 'components', 'pages');
399
+ const pagePath = path.join(pageDir, `${pascalName}.tsx`);
400
+ // Check if page already exists
401
+ try {
402
+ await fs.access(pagePath);
403
+ console.error(chalk.red(`Page "${pascalName}" already exists at ${pagePath}`));
404
+ console.error(chalk.dim('Delete the existing page first if you want to regenerate.'));
405
+ process.exit(1);
406
+ }
407
+ catch {
408
+ // File does not exist, proceed
409
+ }
410
+ const template = dashboardPageTemplate(dashboard, modelSchemas);
411
+ await fs.mkdir(pageDir, { recursive: true });
412
+ await fs.writeFile(pagePath, template, 'utf-8');
413
+ console.log(chalk.green('Dashboard page created successfully!'));
414
+ console.log();
415
+ console.log(chalk.bold(' Page:'), `${pascalName}Page`);
416
+ console.log(chalk.bold(' Path:'), path.join('frontend', 'src', 'components', 'pages', `${pascalName}.tsx`));
417
+ console.log(chalk.bold(' Models:'), dashboard.models.join(', '));
418
+ console.log(chalk.bold(' Widgets:'), dashboard.layout.reduce((sum, row) => sum + row.row.length, 0).toString());
419
+ // 4. Auto-wire App.tsx
420
+ const navLabel = dashboard.description || pascalName;
421
+ const wired = await wireAppTsxAutomatic(projectRoot, pascalName, dashboard.name, navLabel);
422
+ if (wired) {
423
+ console.log(chalk.green(' App.tsx wired automatically'));
424
+ }
425
+ else {
426
+ console.log(chalk.yellow(' Could not auto-wire App.tsx — add the page import, navItem, and switch case manually'));
427
+ }
428
+ // 5. Check if @antv/g2 is installed
429
+ const frontendPkgPath = path.join(projectRoot, 'frontend', 'package.json');
430
+ try {
431
+ const pkgContent = await fs.readFile(frontendPkgPath, 'utf-8');
432
+ const pkg = JSON.parse(pkgContent);
433
+ const hasG2 = (pkg.dependencies && pkg.dependencies['@antv/g2']) ||
434
+ (pkg.devDependencies && pkg.devDependencies['@antv/g2']);
435
+ if (!hasG2) {
436
+ console.log();
437
+ console.log(chalk.yellow(' @antv/g2 is not installed in frontend/.'));
438
+ console.log(chalk.dim(' Run: cd frontend && pnpm add @antv/g2'));
439
+ }
440
+ }
441
+ catch {
442
+ // No package.json found, skip check
443
+ }
444
+ }
445
+ catch (err) {
446
+ const message = err instanceof Error ? err.message : String(err);
447
+ console.error(chalk.red('Failed to create dashboard:'), message);
448
+ process.exit(1);
449
+ }
450
+ });
451
+ }
452
+ //# sourceMappingURL=generate-dashboard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate-dashboard.js","sourceRoot":"","sources":["../../../src/cli/commands/generate-dashboard.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * loom generate page <name>
3
+ *
4
+ * With --model: generate capabilities → CRUD page → auto-wire App.tsx
5
+ * Without --model: generate minimal skeleton page
6
+ */
7
+ import type { Command } from 'commander';
8
+ export declare function registerGeneratePageCommand(program: Command): void;
9
+ //# sourceMappingURL=generate-page.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate-page.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/generate-page.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAybzC,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAwFlE"}