@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,142 @@
1
+ /**
2
+ * loom observe - Observability commands
3
+ *
4
+ * loom observe logs [--session <id>] [--last <duration>]
5
+ * loom observe metrics
6
+ */
7
+ import chalk from 'chalk';
8
+ import { promises as fs } from 'fs';
9
+ import path from 'path';
10
+ import { resolveProjectRoot } from '../utils.js';
11
+ import { parseDuration } from '../helpers/duration.js';
12
+ export function registerObserveCommand(program) {
13
+ const observe = program
14
+ .command('observe')
15
+ .description('Observability: logs and metrics');
16
+ // loom observe logs
17
+ observe
18
+ .command('logs')
19
+ .description('View AI interaction logs')
20
+ .option('--session <id>', 'Filter by session ID')
21
+ .option('--last <duration>', 'Filter by time range (e.g. 1h, 30m, 7d)')
22
+ .option('--limit <number>', 'Max number of logs to show', parseInt, 20)
23
+ .action(async (options) => {
24
+ try {
25
+ const projectRoot = await resolveProjectRoot();
26
+ const logsDir = path.join(projectRoot, '.loom', 'logs');
27
+ const logs = await readLogs(logsDir, {
28
+ session: options.session,
29
+ last: options.last,
30
+ });
31
+ if (logs.length === 0) {
32
+ console.log(chalk.dim('No interaction logs found.'));
33
+ return;
34
+ }
35
+ const display = logs.slice(0, options.limit);
36
+ for (const entry of display) {
37
+ const duration = chalk.dim(`${entry.duration}ms`);
38
+ const ts = chalk.gray(new Date(entry.timestamp).toLocaleString());
39
+ const session = chalk.cyan(entry.sessionId.slice(0, 16));
40
+ const tokens = entry.usage
41
+ ? chalk.dim(`in:${entry.usage.inputTokens} out:${entry.usage.outputTokens}`)
42
+ : '';
43
+ console.log(chalk.bold(`[${entry.messageId}]`) + ` ${ts} ${session} ${duration} ${tokens}`);
44
+ console.log(` ${chalk.dim('Prompt:')} ${entry.prompt.slice(0, 100)}${entry.prompt.length > 100 ? '...' : ''}`);
45
+ console.log(` ${chalk.dim('Response:')} ${entry.response.slice(0, 100)}${entry.response.length > 100 ? '...' : ''}`);
46
+ if (entry.error) {
47
+ console.log(` ${chalk.red('Error:')} ${entry.error}`);
48
+ }
49
+ if (entry.mcpCalls.length > 0) {
50
+ console.log(` ${chalk.dim('MCP:')} ${entry.mcpCalls.join(', ')}`);
51
+ }
52
+ if (entry.cliCalls.length > 0) {
53
+ console.log(` ${chalk.dim('CLI:')} ${entry.cliCalls.join(', ')}`);
54
+ }
55
+ console.log();
56
+ }
57
+ console.log(chalk.dim(`Showing ${display.length} of ${logs.length} logs`));
58
+ }
59
+ catch (err) {
60
+ const message = err instanceof Error ? err.message : String(err);
61
+ console.error(chalk.red('Failed to read logs:'), message);
62
+ process.exit(1);
63
+ }
64
+ });
65
+ // loom observe metrics
66
+ observe
67
+ .command('metrics')
68
+ .description('View aggregated metrics from AI interaction logs')
69
+ .action(async () => {
70
+ try {
71
+ const projectRoot = await resolveProjectRoot();
72
+ const logsDir = path.join(projectRoot, '.loom', 'logs');
73
+ const logs = await readLogs(logsDir);
74
+ if (logs.length === 0) {
75
+ console.log(chalk.dim('No interaction logs found. Run some AI interactions first.'));
76
+ return;
77
+ }
78
+ const totalInteractions = logs.length;
79
+ const avgResponseTime = Math.round(logs.reduce((sum, l) => sum + l.duration, 0) / totalInteractions);
80
+ const errorLogs = logs.filter((l) => l.error);
81
+ const errorRate = ((errorLogs.length / totalInteractions) * 100).toFixed(1);
82
+ const totalInputTokens = logs.reduce((sum, l) => sum + (l.usage?.inputTokens || 0), 0);
83
+ const totalOutputTokens = logs.reduce((sum, l) => sum + (l.usage?.outputTokens || 0), 0);
84
+ // Skill trigger counts from mcpCalls / cliCalls
85
+ const skillCounts = {};
86
+ for (const log of logs) {
87
+ for (const call of [...log.mcpCalls, ...log.cliCalls]) {
88
+ skillCounts[call] = (skillCounts[call] || 0) + 1;
89
+ }
90
+ }
91
+ console.log(chalk.bold('Loom Metrics'));
92
+ console.log();
93
+ console.log(` ${chalk.cyan('Total Interactions:')} ${totalInteractions}`);
94
+ console.log(` ${chalk.cyan('Avg Response Time:')} ${avgResponseTime}ms`);
95
+ console.log(` ${chalk.cyan('Tokens Used:')} in:${totalInputTokens} out:${totalOutputTokens}`);
96
+ console.log(` ${chalk.cyan('Error Rate:')} ${errorRate}%`);
97
+ if (Object.keys(skillCounts).length > 0) {
98
+ console.log();
99
+ console.log(chalk.cyan(' Tool/Skill Calls:'));
100
+ for (const [name, count] of Object.entries(skillCounts).sort((a, b) => b[1] - a[1])) {
101
+ console.log(` ${name}: ${count}`);
102
+ }
103
+ }
104
+ }
105
+ catch (err) {
106
+ const message = err instanceof Error ? err.message : String(err);
107
+ console.error(chalk.red('Failed to compute metrics:'), message);
108
+ process.exit(1);
109
+ }
110
+ });
111
+ }
112
+ async function readLogs(logsDir, filter) {
113
+ try {
114
+ const files = await fs.readdir(logsDir);
115
+ const logs = [];
116
+ for (const file of files) {
117
+ if (!file.endsWith('.json'))
118
+ continue;
119
+ try {
120
+ const content = await fs.readFile(path.join(logsDir, file), 'utf-8');
121
+ const entry = JSON.parse(content);
122
+ if (filter?.session && entry.sessionId !== filter.session)
123
+ continue;
124
+ if (filter?.last) {
125
+ const cutoff = Date.now() - parseDuration(filter.last);
126
+ if (new Date(entry.timestamp).getTime() < cutoff)
127
+ continue;
128
+ }
129
+ logs.push(entry);
130
+ }
131
+ catch {
132
+ // Skip malformed
133
+ }
134
+ }
135
+ logs.sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime());
136
+ return logs;
137
+ }
138
+ catch {
139
+ return [];
140
+ }
141
+ }
142
+ //# sourceMappingURL=observe.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"observe.js","sourceRoot":"","sources":["../../../src/cli/commands/observe.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * loom skill - Skill management commands
3
+ *
4
+ * loom skill list - Scan .claude/skills/ directory, list all skills
5
+ * loom skill validate [name] - Validate SKILL.md frontmatter and references
6
+ */
7
+ import type { Command } from 'commander';
8
+ export declare function registerSkillCommand(program: Command): void;
9
+ //# sourceMappingURL=skill.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skill.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/skill.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAOzC,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CA+H3D"}
@@ -0,0 +1,186 @@
1
+ /**
2
+ * loom skill - Skill management commands
3
+ *
4
+ * loom skill list - Scan .claude/skills/ directory, list all skills
5
+ * loom skill validate [name] - Validate SKILL.md frontmatter and references
6
+ */
7
+ import chalk from 'chalk';
8
+ import { promises as fs } from 'fs';
9
+ import path from 'path';
10
+ import { resolveProjectRoot } from '../utils.js';
11
+ export function registerSkillCommand(program) {
12
+ const skill = program
13
+ .command('skill')
14
+ .description('Skill management commands');
15
+ // loom skill list
16
+ skill
17
+ .command('list')
18
+ .description('List all skills in the project')
19
+ .action(async () => {
20
+ try {
21
+ const projectRoot = await resolveProjectRoot();
22
+ const skillsDir = path.join(projectRoot, '.claude', 'skills');
23
+ let entries;
24
+ try {
25
+ entries = await fs.readdir(skillsDir);
26
+ }
27
+ catch {
28
+ console.log(chalk.yellow('No skills directory found.'));
29
+ console.log(chalk.dim(' Run `loom generate skill <name>` to create one.'));
30
+ return;
31
+ }
32
+ const skillDirs = entries.filter(async (entry) => {
33
+ const stat = await fs.stat(path.join(skillsDir, entry));
34
+ return stat.isDirectory();
35
+ });
36
+ const validSkillDirs = [];
37
+ for (const entry of entries) {
38
+ const entryPath = path.join(skillsDir, entry);
39
+ try {
40
+ const stat = await fs.stat(entryPath);
41
+ if (stat.isDirectory()) {
42
+ validSkillDirs.push(entry);
43
+ }
44
+ }
45
+ catch {
46
+ continue;
47
+ }
48
+ }
49
+ if (validSkillDirs.length === 0) {
50
+ console.log(chalk.yellow('No skills found.'));
51
+ console.log(chalk.dim(' Run `loom generate skill <name>` to create one.'));
52
+ return;
53
+ }
54
+ console.log(chalk.bold(`Skills (${validSkillDirs.length}):`));
55
+ console.log();
56
+ for (const dirName of validSkillDirs) {
57
+ const skillMdPath = path.join(skillsDir, dirName, 'SKILL.md');
58
+ let hasSkillMd = false;
59
+ try {
60
+ await fs.access(skillMdPath);
61
+ hasSkillMd = true;
62
+ }
63
+ catch {
64
+ // No SKILL.md
65
+ }
66
+ const marker = hasSkillMd ? chalk.green('✓') : chalk.red('✗');
67
+ console.log(` ${marker} ${chalk.cyan(dirName)}`);
68
+ if (!hasSkillMd) {
69
+ console.log(chalk.dim(` Missing SKILL.md`));
70
+ }
71
+ }
72
+ }
73
+ catch (err) {
74
+ const message = err instanceof Error ? err.message : String(err);
75
+ console.error(chalk.red('Failed to list skills:'), message);
76
+ process.exit(1);
77
+ }
78
+ });
79
+ // loom skill validate [name]
80
+ skill
81
+ .command('validate [name]')
82
+ .description('Validate skill SKILL.md frontmatter and references')
83
+ .action(async (name) => {
84
+ try {
85
+ const projectRoot = await resolveProjectRoot();
86
+ const skillsDir = path.join(projectRoot, '.claude', 'skills');
87
+ if (name) {
88
+ // Validate specific skill
89
+ await validateSkill(skillsDir, name);
90
+ }
91
+ else {
92
+ // Validate all skills
93
+ let entries;
94
+ try {
95
+ entries = await fs.readdir(skillsDir);
96
+ }
97
+ catch {
98
+ console.log(chalk.yellow('No skills directory found.'));
99
+ return;
100
+ }
101
+ const dirs = [];
102
+ for (const entry of entries) {
103
+ try {
104
+ const stat = await fs.stat(path.join(skillsDir, entry));
105
+ if (stat.isDirectory())
106
+ dirs.push(entry);
107
+ }
108
+ catch {
109
+ continue;
110
+ }
111
+ }
112
+ if (dirs.length === 0) {
113
+ console.log(chalk.yellow('No skills to validate.'));
114
+ return;
115
+ }
116
+ let allValid = true;
117
+ for (const dir of dirs) {
118
+ const valid = await validateSkill(skillsDir, dir);
119
+ if (!valid)
120
+ allValid = false;
121
+ }
122
+ if (!allValid) {
123
+ process.exit(1);
124
+ }
125
+ }
126
+ }
127
+ catch (err) {
128
+ const message = err instanceof Error ? err.message : String(err);
129
+ console.error(chalk.red('Validation failed:'), message);
130
+ process.exit(1);
131
+ }
132
+ });
133
+ }
134
+ /**
135
+ * Validate a single skill directory
136
+ */
137
+ async function validateSkill(skillsDir, name) {
138
+ const skillDir = path.join(skillsDir, name);
139
+ const errors = [];
140
+ // Check SKILL.md exists
141
+ const skillMdPath = path.join(skillDir, 'SKILL.md');
142
+ try {
143
+ const content = await fs.readFile(skillMdPath, 'utf-8');
144
+ // Check frontmatter exists
145
+ if (!content.startsWith('---')) {
146
+ errors.push('SKILL.md is missing frontmatter (must start with ---)');
147
+ }
148
+ else {
149
+ const frontmatterEnd = content.indexOf('---', 3);
150
+ if (frontmatterEnd === -1) {
151
+ errors.push('SKILL.md has unclosed frontmatter');
152
+ }
153
+ else {
154
+ const frontmatter = content.slice(3, frontmatterEnd).trim();
155
+ // Check for required frontmatter fields
156
+ if (!frontmatter.includes('name:')) {
157
+ errors.push('SKILL.md frontmatter missing "name" field');
158
+ }
159
+ if (!frontmatter.includes('version:')) {
160
+ errors.push('SKILL.md frontmatter missing "version" field');
161
+ }
162
+ }
163
+ }
164
+ }
165
+ catch {
166
+ errors.push('SKILL.md not found');
167
+ }
168
+ // Check references/ directory exists
169
+ const referencesDir = path.join(skillDir, 'references');
170
+ try {
171
+ await fs.access(referencesDir);
172
+ }
173
+ catch {
174
+ errors.push('references/ directory not found');
175
+ }
176
+ if (errors.length > 0) {
177
+ console.log(chalk.red(` ✗ ${name}`));
178
+ for (const error of errors) {
179
+ console.log(chalk.dim(` - ${error}`));
180
+ }
181
+ return false;
182
+ }
183
+ console.log(chalk.green(` ✓ ${name}`));
184
+ return true;
185
+ }
186
+ //# sourceMappingURL=skill.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skill.js","sourceRoot":"","sources":["../../../src/cli/commands/skill.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * App.tsx wiring utilities - shared between generate-page and generate-dashboard
3
+ *
4
+ * Surgically modifies App.tsx to add imports, navItems, and switch cases.
5
+ */
6
+ /**
7
+ * Auto-wire App.tsx: add import, navItem, and switch case for a new page.
8
+ * Returns true if successful, false if App.tsx structure is unexpected.
9
+ */
10
+ export declare function wireAppTsxAutomatic(projectRoot: string, pascalName: string, navKey: string, navLabel: string): Promise<boolean>;
11
+ /**
12
+ * Auto-wire the SkillManagementPage into App.tsx.
13
+ * Called once when the first CRUD page is generated.
14
+ * Returns true if successful, false if already wired or structure is unexpected.
15
+ */
16
+ export declare function wireSkillManagementPage(projectRoot: string): Promise<boolean>;
17
+ //# sourceMappingURL=app-tsx-wiring.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app-tsx-wiring.d.ts","sourceRoot":"","sources":["../../../src/cli/helpers/app-tsx-wiring.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH;;;GAGG;AACH,wBAAsB,mBAAmB,CACvC,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,OAAO,CAAC,CAkElB;AAED;;;;GAIG;AACH,wBAAsB,uBAAuB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAiDnF"}
@@ -0,0 +1,132 @@
1
+ /**
2
+ * App.tsx wiring utilities - shared between generate-page and generate-dashboard
3
+ *
4
+ * Surgically modifies App.tsx to add imports, navItems, and switch cases.
5
+ */
6
+ import { promises as fs } from 'fs';
7
+ import path from 'path';
8
+ /**
9
+ * Auto-wire App.tsx: add import, navItem, and switch case for a new page.
10
+ * Returns true if successful, false if App.tsx structure is unexpected.
11
+ */
12
+ export async function wireAppTsxAutomatic(projectRoot, pascalName, navKey, navLabel) {
13
+ const appPath = path.join(projectRoot, 'frontend', 'src', 'App.tsx');
14
+ let content;
15
+ try {
16
+ content = await fs.readFile(appPath, 'utf-8');
17
+ }
18
+ catch {
19
+ return false;
20
+ }
21
+ // Check if this page is already wired (avoid duplicates)
22
+ if (content.includes(`from './components/pages/${pascalName}'`) || content.includes(`<${pascalName}Page`)) {
23
+ return false;
24
+ }
25
+ // Also check if navItem with same key already exists
26
+ if (content.includes(`key: '${navKey}'`)) {
27
+ return false;
28
+ }
29
+ let modified = content;
30
+ // 1. Add import after the last import line
31
+ const importLine = `import ${pascalName}Page from './components/pages/${pascalName}';`;
32
+ const lastImportEnd = modified.lastIndexOf('\n', modified.indexOf('\nexport'));
33
+ if (lastImportEnd === -1)
34
+ return false;
35
+ modified = modified.slice(0, lastImportEnd + 1) + importLine + '\n' + modified.slice(lastImportEnd + 1);
36
+ // 2. Add navItem (before the closing ] of navItems array)
37
+ const navItemLine = ` { key: '${navKey}', label: '${navLabel}' },`;
38
+ const navItemsEnd = modified.indexOf('// Add more nav items');
39
+ if (navItemsEnd !== -1) {
40
+ // Insert before the comment placeholder
41
+ const lineStart = modified.lastIndexOf('\n', navItemsEnd) + 1;
42
+ modified = modified.slice(0, lineStart) + navItemLine + '\n' + modified.slice(lineStart);
43
+ }
44
+ else {
45
+ // Fallback: find the closing ] of navItems array
46
+ const navArrayMatch = modified.match(/const navItems\s*=\s*\[/);
47
+ if (!navArrayMatch)
48
+ return false;
49
+ const arrayStart = navArrayMatch.index + navArrayMatch[0].length;
50
+ // Find the matching ]
51
+ let depth = 1;
52
+ let pos = arrayStart;
53
+ while (pos < modified.length && depth > 0) {
54
+ if (modified[pos] === '[')
55
+ depth++;
56
+ else if (modified[pos] === ']')
57
+ depth--;
58
+ pos++;
59
+ }
60
+ const closingBracket = pos - 1;
61
+ modified = modified.slice(0, closingBracket) + navItemLine + '\n' + modified.slice(closingBracket);
62
+ }
63
+ // 3. Add switch case — before skill-management case if present, otherwise before default
64
+ const caseLine = ` case '${navKey}': return <${pascalName}Page />;`;
65
+ const skillCaseIdx = modified.indexOf("case 'skill-management':");
66
+ const insertAnchor = skillCaseIdx !== -1 ? skillCaseIdx : modified.indexOf('default:');
67
+ if (insertAnchor === -1)
68
+ return false;
69
+ const insertLineStart = modified.lastIndexOf('\n', insertAnchor) + 1;
70
+ modified = modified.slice(0, insertLineStart) + caseLine + '\n' + modified.slice(insertLineStart);
71
+ // 4. Ensure baseUrl="" on AppShell (prevent /api/v1/api/v1 double prefix)
72
+ if (modified.includes('<AppShell') && !modified.includes('baseUrl=')) {
73
+ modified = modified.replace('<AppShell', '<AppShell\n baseUrl=""');
74
+ }
75
+ await fs.writeFile(appPath, modified, 'utf-8');
76
+ return true;
77
+ }
78
+ /**
79
+ * Auto-wire the SkillManagementPage into App.tsx.
80
+ * Called once when the first CRUD page is generated.
81
+ * Returns true if successful, false if already wired or structure is unexpected.
82
+ */
83
+ export async function wireSkillManagementPage(projectRoot) {
84
+ const appPath = path.join(projectRoot, 'frontend', 'src', 'App.tsx');
85
+ let content;
86
+ try {
87
+ content = await fs.readFile(appPath, 'utf-8');
88
+ }
89
+ catch {
90
+ return false;
91
+ }
92
+ // Check if already wired (avoid duplicates)
93
+ if (content.includes('SkillManagementPage')) {
94
+ return false;
95
+ }
96
+ let modified = content;
97
+ // 1. Add import after the last import line
98
+ const importLine = `import { SkillManagementPage } from '@loom-framework/frontend-antd';`;
99
+ const lastImportEnd = modified.lastIndexOf('\n', modified.indexOf('\nexport'));
100
+ if (lastImportEnd === -1)
101
+ return false;
102
+ modified = modified.slice(0, lastImportEnd + 1) + importLine + '\n' + modified.slice(lastImportEnd + 1);
103
+ // 2. Add navItem — always at the end of the array so it stays below all model pages
104
+ const navItemLine = ` { key: 'skill-management', label: 'Skill 管理' },`;
105
+ const navArrayMatch = modified.match(/const navItems\s*=\s*\[/);
106
+ if (!navArrayMatch)
107
+ return false;
108
+ const arrayStart = navArrayMatch.index + navArrayMatch[0].length;
109
+ let depth = 1;
110
+ let pos = arrayStart;
111
+ while (pos < modified.length && depth > 0) {
112
+ if (modified[pos] === '[')
113
+ depth++;
114
+ else if (modified[pos] === ']')
115
+ depth--;
116
+ pos++;
117
+ }
118
+ const closingBracket = pos - 1;
119
+ // Insert before the line containing the closing bracket
120
+ const lineStart = modified.lastIndexOf('\n', closingBracket) + 1;
121
+ modified = modified.slice(0, lineStart) + navItemLine + '\n' + modified.slice(lineStart);
122
+ // 3. Add switch case before default
123
+ const caseLine = ` case 'skill-management': return <SkillManagementPage />;`;
124
+ const defaultCase = modified.indexOf('default:');
125
+ if (defaultCase === -1)
126
+ return false;
127
+ const defaultLineStart = modified.lastIndexOf('\n', defaultCase) + 1;
128
+ modified = modified.slice(0, defaultLineStart) + caseLine + '\n' + modified.slice(defaultLineStart);
129
+ await fs.writeFile(appPath, modified, 'utf-8');
130
+ return true;
131
+ }
132
+ //# sourceMappingURL=app-tsx-wiring.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app-tsx-wiring.js","sourceRoot":"","sources":["../../../src/cli/helpers/app-tsx-wiring.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Duration parsing utility - extracted for testability
3
+ */
4
+ export declare function parseDuration(duration: string): number;
5
+ //# sourceMappingURL=duration.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"duration.d.ts","sourceRoot":"","sources":["../../../src/cli/helpers/duration.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CActD"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Duration parsing utility - extracted for testability
3
+ */
4
+ export function parseDuration(duration) {
5
+ const match = duration.match(/^(\d+)(s|m|h|d)$/);
6
+ if (!match) {
7
+ throw new Error(`Invalid duration: ${duration}. Use format like '1h', '30m', '7d'`);
8
+ }
9
+ const value = parseInt(match[1], 10);
10
+ const unit = match[2];
11
+ switch (unit) {
12
+ case 's': return value * 1000;
13
+ case 'm': return value * 60 * 1000;
14
+ case 'h': return value * 60 * 60 * 1000;
15
+ case 'd': return value * 24 * 60 * 60 * 1000;
16
+ default: throw new Error(`Unknown unit: ${unit}`);
17
+ }
18
+ }
19
+ //# sourceMappingURL=duration.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"duration.js","sourceRoot":"","sources":["../../../src/cli/helpers/duration.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,UAAU,aAAa,CAAC,QAAgB;IAC5C,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC;IACjD,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CAAC,qBAAqB,QAAQ,qCAAqC,CAAC,CAAC;IACtF,CAAC;IACD,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IACrC,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;IACtB,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,GAAG,CAAC,CAAC,OAAO,KAAK,GAAG,IAAI,CAAC;QAC9B,KAAK,GAAG,CAAC,CAAC,OAAO,KAAK,GAAG,EAAE,GAAG,IAAI,CAAC;QACnC,KAAK,GAAG,CAAC,CAAC,OAAO,KAAK,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;QACxC,KAAK,GAAG,CAAC,CAAC,OAAO,KAAK,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;QAC7C,OAAO,CAAC,CAAC,MAAM,IAAI,KAAK,CAAC,iBAAiB,IAAI,EAAE,CAAC,CAAC;IACpD,CAAC;AACH,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Field-to-template utilities - extracted for testability
3
+ */
4
+ import type { FieldDefinition, FieldType } from '../../index.js';
5
+ /** Map FieldType to Ant Design table column render hint */
6
+ export declare function fieldToColumnType(type: FieldType): string;
7
+ export declare function getFieldLabel(field: FieldDefinition): string;
8
+ /** Generate Ant Design form item for a field */
9
+ export declare function fieldToFormItem(field: FieldDefinition, modelName: string): string;
10
+ //# sourceMappingURL=field-template.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"field-template.d.ts","sourceRoot":"","sources":["../../../src/cli/helpers/field-template.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAEjE,2DAA2D;AAC3D,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,SAAS,GAAG,MAAM,CAYzD;AAQD,wBAAgB,aAAa,CAAC,KAAK,EAAE,eAAe,GAAG,MAAM,CAE5D;AAiCD,gDAAgD;AAChD,wBAAgB,eAAe,CAAC,KAAK,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CA+CjF"}