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

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 (169) 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-page.d.ts +9 -0
  106. package/dist/cli/commands/generate-page.d.ts.map +1 -0
  107. package/dist/cli/commands/generate-page.js +641 -0
  108. package/dist/cli/commands/generate-page.js.map +1 -0
  109. package/dist/cli/commands/generate-skill.d.ts +8 -0
  110. package/dist/cli/commands/generate-skill.d.ts.map +1 -0
  111. package/dist/cli/commands/generate-skill.js +75 -0
  112. package/dist/cli/commands/generate-skill.js.map +1 -0
  113. package/dist/cli/commands/generate.d.ts +6 -0
  114. package/dist/cli/commands/generate.d.ts.map +1 -0
  115. package/dist/cli/commands/generate.js +17 -0
  116. package/dist/cli/commands/generate.js.map +1 -0
  117. package/dist/cli/commands/init.d.ts +8 -0
  118. package/dist/cli/commands/init.d.ts.map +1 -0
  119. package/dist/cli/commands/init.js +539 -0
  120. package/dist/cli/commands/init.js.map +1 -0
  121. package/dist/cli/commands/observe.d.ts +9 -0
  122. package/dist/cli/commands/observe.d.ts.map +1 -0
  123. package/dist/cli/commands/observe.js +142 -0
  124. package/dist/cli/commands/observe.js.map +1 -0
  125. package/dist/cli/commands/skill.d.ts +9 -0
  126. package/dist/cli/commands/skill.d.ts.map +1 -0
  127. package/dist/cli/commands/skill.js +186 -0
  128. package/dist/cli/commands/skill.js.map +1 -0
  129. package/dist/cli/helpers/duration.d.ts +5 -0
  130. package/dist/cli/helpers/duration.d.ts.map +1 -0
  131. package/dist/cli/helpers/duration.js +19 -0
  132. package/dist/cli/helpers/duration.js.map +1 -0
  133. package/dist/cli/helpers/field-template.d.ts +10 -0
  134. package/dist/cli/helpers/field-template.d.ts.map +1 -0
  135. package/dist/cli/helpers/field-template.js +100 -0
  136. package/dist/cli/helpers/field-template.js.map +1 -0
  137. package/dist/cli/helpers/naming.d.ts +12 -0
  138. package/dist/cli/helpers/naming.d.ts.map +1 -0
  139. package/dist/cli/helpers/naming.js +25 -0
  140. package/dist/cli/helpers/naming.js.map +1 -0
  141. package/dist/cli/index.d.ts +9 -0
  142. package/dist/cli/index.d.ts.map +1 -0
  143. package/dist/cli/index.js +33 -0
  144. package/dist/cli/index.js.map +1 -0
  145. package/dist/cli/utils.d.ts +10 -0
  146. package/dist/cli/utils.d.ts.map +1 -0
  147. package/dist/cli/utils.js +31 -0
  148. package/dist/cli/utils.js.map +1 -0
  149. package/dist/config.d.ts +8 -40
  150. package/dist/config.d.ts.map +1 -1
  151. package/dist/config.js +6 -8
  152. package/dist/config.js.map +1 -1
  153. package/dist/index.d.ts +6 -1
  154. package/dist/index.d.ts.map +1 -1
  155. package/dist/index.js +6 -0
  156. package/dist/index.js.map +1 -1
  157. package/dist/server-bin.d.ts +12 -0
  158. package/dist/server-bin.d.ts.map +1 -0
  159. package/dist/server-bin.js +75 -0
  160. package/dist/server-bin.js.map +1 -0
  161. package/dist/types.d.ts +33 -20
  162. package/dist/types.d.ts.map +1 -1
  163. package/package.json +25 -10
  164. package/templates/app-skill/SKILL.md +27 -0
  165. package/templates/app-skill/references/data-semantics.md +44 -0
  166. package/templates/app-skill/references/models.md +31 -0
  167. package/templates/loom-skill/SKILL.md +140 -0
  168. package/templates/loom-skill/references/README.md +128 -0
  169. package/templates/loom-skill/references/data-model.md +78 -0
@@ -0,0 +1,8 @@
1
+ /**
2
+ * loom generate skill <name>
3
+ *
4
+ * Create .claude/skills/<name>/SKILL.md skeleton and references/ directory.
5
+ */
6
+ import type { Command } from 'commander';
7
+ export declare function registerGenerateSkillCommand(program: Command): void;
8
+ //# sourceMappingURL=generate-skill.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate-skill.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/generate-skill.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAgCzC,wBAAgB,4BAA4B,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAyCnE"}
@@ -0,0 +1,75 @@
1
+ /**
2
+ * loom generate skill <name>
3
+ *
4
+ * Create .claude/skills/<name>/SKILL.md skeleton and references/ directory.
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 SKILL_MD_TEMPLATE = (name) => `---
11
+ name: ${name}
12
+ version: 0.1.0
13
+ description: ""
14
+ tags: []
15
+ ---
16
+
17
+ # ${name}
18
+
19
+ ## Overview
20
+
21
+ TODO: Describe what this skill does.
22
+
23
+ ## Instructions
24
+
25
+ TODO: Step-by-step instructions for the skill.
26
+
27
+ ## Examples
28
+
29
+ TODO: Example inputs and outputs.
30
+
31
+ ## References
32
+
33
+ TODO: List reference files in the references/ directory.
34
+ `;
35
+ export function registerGenerateSkillCommand(program) {
36
+ program
37
+ .command('skill <name>')
38
+ .description('Create a new skill skeleton with SKILL.md and references directory')
39
+ .action(async (name) => {
40
+ try {
41
+ const projectRoot = await resolveProjectRoot();
42
+ const skillDir = path.join(projectRoot, '.claude', 'skills', name);
43
+ const skillMdPath = path.join(skillDir, 'SKILL.md');
44
+ const referencesDir = path.join(skillDir, 'references');
45
+ // Check if skill already exists
46
+ try {
47
+ await fs.access(skillDir);
48
+ console.error(chalk.red(`Skill "${name}" already exists at ${skillDir}`));
49
+ process.exit(1);
50
+ }
51
+ catch {
52
+ // Directory does not exist, proceed
53
+ }
54
+ await fs.mkdir(referencesDir, { recursive: true });
55
+ await fs.writeFile(skillMdPath, SKILL_MD_TEMPLATE(name), 'utf-8');
56
+ // Create a .gitkeep in references so the directory is tracked
57
+ await fs.writeFile(path.join(referencesDir, '.gitkeep'), '', 'utf-8');
58
+ console.log(chalk.green('Skill created successfully!'));
59
+ console.log();
60
+ console.log(chalk.bold(' Skill:'), name);
61
+ console.log(chalk.bold(' Path:'), skillDir);
62
+ console.log(chalk.bold(' Files:'));
63
+ console.log(chalk.gray(' -'), 'SKILL.md');
64
+ console.log(chalk.gray(' -'), 'references/');
65
+ console.log();
66
+ console.log(chalk.dim(` Edit ${path.join('.claude/skills', name, 'SKILL.md')} to define the skill.`));
67
+ }
68
+ catch (err) {
69
+ const message = err instanceof Error ? err.message : String(err);
70
+ console.error(chalk.red('Failed to create skill:'), message);
71
+ process.exit(1);
72
+ }
73
+ });
74
+ }
75
+ //# sourceMappingURL=generate-skill.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate-skill.js","sourceRoot":"","sources":["../../../src/cli/commands/generate-skill.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,iBAAiB,GAAG,CAAC,IAAY,EAAU,EAAE,CAAC;QAC5C,IAAI;;;;;;IAMR,IAAI;;;;;;;;;;;;;;;;;CAiBP,CAAC;AAEF,MAAM,UAAU,4BAA4B,CAAC,OAAgB;IAC3D,OAAO;SACJ,OAAO,CAAC,cAAc,CAAC;SACvB,WAAW,CAAC,oEAAoE,CAAC;SACjF,MAAM,CAAC,KAAK,EAAE,IAAY,EAAE,EAAE;QAC7B,IAAI,CAAC;YACH,MAAM,WAAW,GAAG,MAAM,kBAAkB,EAAE,CAAC;YAC/C,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;YACnE,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;YACpD,MAAM,aAAa,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;YAExD,gCAAgC;YAChC,IAAI,CAAC;gBACH,MAAM,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;gBAC1B,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,UAAU,IAAI,uBAAuB,QAAQ,EAAE,CAAC,CAAC,CAAC;gBAC1E,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC;YAAC,MAAM,CAAC;gBACP,oCAAoC;YACtC,CAAC;YAED,MAAM,EAAE,CAAC,KAAK,CAAC,aAAa,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YACnD,MAAM,EAAE,CAAC,SAAS,CAAC,WAAW,EAAE,iBAAiB,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC,CAAC;YAElE,8DAA8D;YAC9D,MAAM,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,UAAU,CAAC,EAAE,EAAE,EAAE,OAAO,CAAC,CAAC;YAEtE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,6BAA6B,CAAC,CAAC,CAAC;YACxD,OAAO,CAAC,GAAG,EAAE,CAAC;YACd,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,IAAI,CAAC,CAAC;YAC1C,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,QAAQ,CAAC,CAAC;YAC7C,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;YACpC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,UAAU,CAAC,CAAC;YAC7C,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,aAAa,CAAC,CAAC;YAChD,OAAO,CAAC,GAAG,EAAE,CAAC;YACd,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,UAAU,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,IAAI,EAAE,UAAU,CAAC,uBAAuB,CAAC,CAAC,CAAC;QACzG,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,yBAAyB,CAAC,EAAE,OAAO,CAAC,CAAC;YAC7D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC,CAAC,CAAC;AACP,CAAC"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * loom generate - Code generation commands
3
+ */
4
+ import type { Command } from 'commander';
5
+ export declare function registerGenerateCommand(program: Command): void;
6
+ //# sourceMappingURL=generate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/generate.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAMzC,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAS9D"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * loom generate - Code generation commands
3
+ */
4
+ import { registerGenerateCapabilitiesCommand } from './generate-capabilities.js';
5
+ import { registerGenerateSkillCommand } from './generate-skill.js';
6
+ import { registerGeneratePageCommand } from './generate-page.js';
7
+ import { registerGenerateCliCommandCommand } from './generate-cli-command.js';
8
+ export function registerGenerateCommand(program) {
9
+ const generate = program
10
+ .command('generate')
11
+ .description('Generate code from config and templates');
12
+ registerGenerateCapabilitiesCommand(generate);
13
+ registerGenerateSkillCommand(generate);
14
+ registerGeneratePageCommand(generate);
15
+ registerGenerateCliCommandCommand(generate);
16
+ }
17
+ //# sourceMappingURL=generate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate.js","sourceRoot":"","sources":["../../../src/cli/commands/generate.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,mCAAmC,EAAE,MAAM,4BAA4B,CAAC;AACjF,OAAO,EAAE,4BAA4B,EAAE,MAAM,qBAAqB,CAAC;AACnE,OAAO,EAAE,2BAA2B,EAAE,MAAM,oBAAoB,CAAC;AACjE,OAAO,EAAE,iCAAiC,EAAE,MAAM,2BAA2B,CAAC;AAE9E,MAAM,UAAU,uBAAuB,CAAC,OAAgB;IACtD,MAAM,QAAQ,GAAG,OAAO;SACrB,OAAO,CAAC,UAAU,CAAC;SACnB,WAAW,CAAC,yCAAyC,CAAC,CAAC;IAE1D,mCAAmC,CAAC,QAAQ,CAAC,CAAC;IAC9C,4BAA4B,CAAC,QAAQ,CAAC,CAAC;IACvC,2BAA2B,CAAC,QAAQ,CAAC,CAAC;IACtC,iCAAiC,CAAC,QAAQ,CAAC,CAAC;AAC9C,CAAC"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * loom init <name>
3
+ *
4
+ * Create a new Loom project. All options via CLI flags, no interactive prompts.
5
+ */
6
+ import type { Command } from 'commander';
7
+ export declare function registerInitCommand(program: Command): void;
8
+ //# sourceMappingURL=init.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/init.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAYzC,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAe1D"}
@@ -0,0 +1,539 @@
1
+ /**
2
+ * loom init <name>
3
+ *
4
+ * Create a new Loom project. All options via CLI flags, no interactive prompts.
5
+ */
6
+ import chalk from 'chalk';
7
+ import { promises as fs } from 'fs';
8
+ import path from 'path';
9
+ import { fileURLToPath } from 'url';
10
+ export function registerInitCommand(program) {
11
+ program
12
+ .command('init <name>')
13
+ .description('Create a new Loom project')
14
+ .option('-d, --description <desc>', 'Project description', '')
15
+ .option('-a, --adapter <adapter>', 'Data adapter (filesystem|sqlite)', 'filesystem')
16
+ .action(async (name, cmdOptions) => {
17
+ const options = {
18
+ name,
19
+ description: cmdOptions.description || '',
20
+ adapter: cmdOptions.adapter === 'sqlite' ? 'sqlite' : 'filesystem',
21
+ };
22
+ await createProject(options);
23
+ });
24
+ }
25
+ async function createProject(options) {
26
+ const cwd = process.cwd();
27
+ const cwdName = path.basename(cwd);
28
+ // If current directory name matches project name, initialize in place (like npm init)
29
+ const targetDir = cwdName === options.name
30
+ ? cwd
31
+ : path.resolve(cwd, options.name);
32
+ // Check if directory already exists (only for non-cwd case)
33
+ if (targetDir !== cwd) {
34
+ try {
35
+ await fs.access(targetDir);
36
+ console.error(chalk.red(`Directory "${options.name}" already exists.`));
37
+ process.exit(1);
38
+ }
39
+ catch {
40
+ // Directory does not exist, proceed
41
+ }
42
+ }
43
+ console.log();
44
+ console.log(chalk.bold.cyan(' Welcome to Loom!'));
45
+ console.log(chalk.dim(' Weave AI capabilities into your application'));
46
+ console.log();
47
+ console.log(chalk.dim(` Creating project in ${targetDir}...`));
48
+ console.log();
49
+ // Create directory structure
50
+ await createDirectoryStructure(targetDir);
51
+ // Copy SKILL.md + references from templates
52
+ await copySkillTemplates(targetDir);
53
+ // Create loom.config.ts
54
+ await createLoomConfig(targetDir, options);
55
+ // Create package.json
56
+ await createPackageJson(targetDir, options);
57
+ // Create README
58
+ await createReadme(targetDir, options);
59
+ // Create tsconfig
60
+ await createTsconfig(targetDir);
61
+ // Create vite config
62
+ await createViteConfig(targetDir);
63
+ // Create frontend entry files
64
+ await createFrontendEntry(targetDir, options);
65
+ // Create backend entry file
66
+ await createBackendEntry(targetDir);
67
+ // Create .gitignore
68
+ await createGitignore(targetDir);
69
+ // Install dependencies
70
+ await installDependencies(targetDir);
71
+ // Verify better-sqlite3 native module if sqlite adapter selected
72
+ if (options.adapter === 'sqlite') {
73
+ await verifySqliteNativeModule(targetDir);
74
+ }
75
+ console.log();
76
+ console.log(chalk.green.bold(' Project created successfully!'));
77
+ console.log();
78
+ console.log(chalk.dim(' Next steps:'));
79
+ if (targetDir !== cwd) {
80
+ console.log(chalk.cyan(` cd ${options.name}`));
81
+ }
82
+ console.log(chalk.cyan(` loom generate page <Name> --model <model-name>`));
83
+ console.log(chalk.cyan(' loom dev'));
84
+ console.log();
85
+ }
86
+ async function createDirectoryStructure(targetDir) {
87
+ const dirs = [
88
+ '',
89
+ 'data',
90
+ '.claude',
91
+ '.claude/skills',
92
+ '.claude/skills/loom',
93
+ '.claude/skills/loom/references',
94
+ '.loom',
95
+ 'cli',
96
+ 'cli/src',
97
+ 'cli/src/commands',
98
+ 'frontend',
99
+ 'frontend/src',
100
+ 'frontend/src/components',
101
+ 'frontend/src/components/pages',
102
+ 'backend',
103
+ 'backend/src',
104
+ ];
105
+ for (const dir of dirs) {
106
+ await fs.mkdir(path.join(targetDir, dir), { recursive: true });
107
+ }
108
+ // Create .gitkeep files for empty directories
109
+ const gitkeepDirs = ['data', '.loom', 'cli/src/commands', 'frontend/src/components/pages', '.claude/skills/loom/references'];
110
+ for (const dir of gitkeepDirs) {
111
+ await fs.writeFile(path.join(targetDir, dir, '.gitkeep'), '', 'utf-8');
112
+ }
113
+ console.log(chalk.green(' ✓'), 'Directory structure');
114
+ }
115
+ async function copySkillTemplates(targetDir) {
116
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
117
+ // From dist/cli/commands/ → go up to package root → templates/loom-skill/
118
+ const templatesDir = path.resolve(__dirname, '../../../templates/loom-skill');
119
+ // Copy SKILL.md
120
+ const skillMd = await fs.readFile(path.join(templatesDir, 'SKILL.md'), 'utf-8');
121
+ await fs.writeFile(path.join(targetDir, '.claude/skills/loom/SKILL.md'), skillMd, 'utf-8');
122
+ console.log(chalk.green(' ✓'), '.claude/skills/loom/SKILL.md');
123
+ // Copy references
124
+ const refsDir = path.join(templatesDir, 'references');
125
+ const refFiles = await fs.readdir(refsDir);
126
+ for (const file of refFiles) {
127
+ if (file.endsWith('.md')) {
128
+ const content = await fs.readFile(path.join(refsDir, file), 'utf-8');
129
+ await fs.writeFile(path.join(targetDir, '.claude/skills/loom/references', file), content, 'utf-8');
130
+ }
131
+ }
132
+ console.log(chalk.green(' ✓'), `.claude/skills/loom/references/ (${refFiles.filter(f => f.endsWith('.md')).length} files)`);
133
+ }
134
+ async function createLoomConfig(targetDir, options) {
135
+ const config = `import { defineConfig } from '@loom-framework/core';
136
+
137
+ export default defineConfig({
138
+ project: {
139
+ name: '${options.name}',
140
+ description: '${options.description}',
141
+ },
142
+ data: {
143
+ defaultAdapter: '${options.adapter}',
144
+ models: [
145
+ {
146
+ name: 'items',
147
+ fields: [
148
+ { name: 'id', type: 'string', required: true },
149
+ { name: 'name', type: 'string', required: true },
150
+ { name: 'description', type: 'string' },
151
+ { name: 'createdAt', type: 'date' },
152
+ ],
153
+ // 示例数据实体 - 实体名将作为 React 组件名,运行 loom generate page Items --model items 后可自定义
154
+ description: 'Example items model - customize or remove',
155
+ },
156
+ ],
157
+ },
158
+ });
159
+ `;
160
+ await fs.writeFile(path.join(targetDir, 'loom.config.ts'), config, 'utf-8');
161
+ console.log(chalk.green(' ✓'), 'loom.config.ts');
162
+ }
163
+ async function createPackageJson(targetDir, options) {
164
+ const pkg = {
165
+ name: options.name,
166
+ version: '0.1.0',
167
+ type: 'module',
168
+ scripts: {
169
+ dev: 'loom dev',
170
+ build: 'loom build',
171
+ generate: 'loom generate capabilities',
172
+ },
173
+ dependencies: {
174
+ '@loom-framework/core': '^0.1.0-alpha.80',
175
+ '@loom-framework/frontend-antd': '^0.1.0-alpha.80',
176
+ 'fastify': '^5.2.0',
177
+ '@ant-design/x': '^2.5.0',
178
+ '@ant-design/x-sdk': '^2.5.0',
179
+ '@ant-design/x-markdown': '^2.5.0',
180
+ '@ant-design/icons': '^6.1.1',
181
+ '@fastify/cors': '^10.0.0',
182
+ '@fastify/static': '^8.0.0',
183
+ 'react': '^19.0.0',
184
+ 'react-dom': '^19.0.0',
185
+ 'antd': '^6.3.5',
186
+ 'dayjs': '^1.11.0',
187
+ },
188
+ devDependencies: {
189
+ 'typescript': '^5.6.0',
190
+ 'tsx': '^4.7.0',
191
+ 'vite': '^6.0.0',
192
+ '@types/react': '^19.0.0',
193
+ '@types/react-dom': '^19.0.0',
194
+ '@vitejs/plugin-react': '^4.3.0',
195
+ },
196
+ };
197
+ await fs.writeFile(path.join(targetDir, 'package.json'), JSON.stringify(pkg, null, 2), 'utf-8');
198
+ console.log(chalk.green(' ✓'), 'package.json');
199
+ }
200
+ async function createReadme(targetDir, options) {
201
+ const readme = `# ${options.name}
202
+
203
+ ${options.description || 'A Loom application.'}
204
+
205
+ ## Getting Started
206
+
207
+ \`\`\`bash
208
+ # Generate a CRUD page from your data model
209
+ loom generate page <Name> --model <model-name>
210
+
211
+ # Start development servers (frontend + backend, hot-reload)
212
+ loom dev
213
+
214
+ # Build for production
215
+ loom build
216
+ \`\`\`
217
+
218
+ ## Project Structure
219
+
220
+ \`\`\`
221
+ ${options.name}/
222
+ ├── loom.config.ts # Project configuration
223
+ ├── data/ # Data storage (filesystem adapter)
224
+ ├── .claude/skills/ # AI skill definitions
225
+ ├── cli/ # CLI commands
226
+ ├── frontend/ # Frontend application
227
+ ├── backend/ # Backend server
228
+ └── .loom/ # Generated files (MCP server, etc.)
229
+ \`\`\`
230
+
231
+ ## Commands
232
+
233
+ - \`loom init <name>\` - Create a new project
234
+ - \`loom generate page <Name> --model <model>\` - Generate CRUD page (includes capabilities + wiring)
235
+ - \`loom generate skill <name>\` - Create a new skill
236
+ - \`loom dev\` - Start development servers
237
+ - \`loom build\` - Build all components
238
+ - \`loom data <command>\` - Data operations
239
+ - \`loom skill list\` - List skills
240
+ - \`loom skill validate\` - Validate skill definitions
241
+ `;
242
+ await fs.writeFile(path.join(targetDir, 'README.md'), readme, 'utf-8');
243
+ console.log(chalk.green(' ✓'), 'README.md');
244
+ }
245
+ async function createTsconfig(targetDir) {
246
+ const tsconfig = {
247
+ compilerOptions: {
248
+ target: 'ES2022',
249
+ module: 'Node16',
250
+ moduleResolution: 'Node16',
251
+ strict: true,
252
+ esModuleInterop: true,
253
+ skipLibCheck: true,
254
+ forceConsistentCasingInFileNames: true,
255
+ resolveJsonModule: true,
256
+ declaration: true,
257
+ sourceMap: true,
258
+ },
259
+ exclude: ['node_modules', 'dist', 'frontend'],
260
+ };
261
+ await fs.writeFile(path.join(targetDir, 'tsconfig.json'), JSON.stringify(tsconfig, null, 2), 'utf-8');
262
+ console.log(chalk.green(' ✓'), 'tsconfig.json');
263
+ }
264
+ async function createViteConfig(targetDir) {
265
+ const viteConfig = `import { defineConfig } from 'vite';
266
+ import react from '@vitejs/plugin-react';
267
+
268
+ export default defineConfig({
269
+ plugins: [react()],
270
+ root: 'frontend',
271
+ build: {
272
+ outDir: '../dist/frontend',
273
+ emptyOutDir: true,
274
+ },
275
+ server: {
276
+ port: 5173,
277
+ proxy: {
278
+ '/api': 'http://localhost:3000',
279
+ },
280
+ },
281
+ });
282
+ `;
283
+ await fs.writeFile(path.join(targetDir, 'vite.config.ts'), viteConfig, 'utf-8');
284
+ console.log(chalk.green(' ✓'), 'vite.config.ts');
285
+ }
286
+ async function createFrontendEntry(targetDir, options) {
287
+ const mainTsx = `import React from 'react';
288
+ import ReactDOM from 'react-dom/client';
289
+ import App from './App';
290
+
291
+ ReactDOM.createRoot(document.getElementById('root')!).render(
292
+ <React.StrictMode>
293
+ <App />
294
+ </React.StrictMode>,
295
+ );
296
+ `;
297
+ const appTsx = `import React, { useState } from 'react';
298
+ import { AppShell } from '@loom-framework/frontend-antd';
299
+
300
+ const navItems = [
301
+ { key: 'home', label: '首页' },
302
+ // Add more nav items as you generate pages:
303
+ // { key: 'model-name', label: '数据实体名' },
304
+ ];
305
+
306
+ export default function App() {
307
+ const [selectedKey, setSelectedKey] = useState('home');
308
+
309
+ const renderPage = () => {
310
+ switch (selectedKey) {
311
+ case 'home':
312
+ return (
313
+ <div style={{ padding: 24 }}>
314
+ <h2>${options.name}</h2>
315
+ <p>${options.description || 'A Loom application.'}</p>
316
+ <p>运行 <code>loom generate page &lt;Name&gt; --model &lt;model&gt;</code> 生成页面后,在此处引入。</p>
317
+ </div>
318
+ );
319
+ default:
320
+ return (
321
+ <div style={{ padding: 24 }}>
322
+ <h2>${options.name}</h2>
323
+ </div>
324
+ );
325
+ }
326
+ };
327
+
328
+ return (
329
+ <AppShell
330
+ title="${options.name}"
331
+ navItems={navItems}
332
+ selectedNavKey={selectedKey}
333
+ onNavClick={setSelectedKey}
334
+ baseUrl=""
335
+ >
336
+ {renderPage()}
337
+ </AppShell>
338
+ );
339
+ }
340
+ `;
341
+ const indexHtml = `<!DOCTYPE html>
342
+ <html lang="en">
343
+ <head>
344
+ <meta charset="UTF-8" />
345
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
346
+ <title>${options.name}</title>
347
+ </head>
348
+ <body>
349
+ <div id="root"></div>
350
+ <script type="module" src="/src/main.tsx"></script>
351
+ </body>
352
+ </html>
353
+ `;
354
+ await fs.writeFile(path.join(targetDir, 'frontend/src/main.tsx'), mainTsx, 'utf-8');
355
+ await fs.writeFile(path.join(targetDir, 'frontend/src/App.tsx'), appTsx, 'utf-8');
356
+ await fs.writeFile(path.join(targetDir, 'frontend/index.html'), indexHtml, 'utf-8');
357
+ const frontendTsconfig = `{
358
+ "compilerOptions": {
359
+ "target": "ES2022",
360
+ "lib": ["ES2022", "DOM", "DOM.Iterable"],
361
+ "module": "ESNext",
362
+ "moduleResolution": "bundler",
363
+ "jsx": "react-jsx",
364
+ "strict": true,
365
+ "esModuleInterop": true,
366
+ "skipLibCheck": true,
367
+ "forceConsistentCasingInFileNames": true,
368
+ "resolveJsonModule": true,
369
+ "isolatedModules": true,
370
+ "noEmit": true
371
+ },
372
+ "include": ["src"]
373
+ }
374
+ `;
375
+ await fs.writeFile(path.join(targetDir, 'frontend/tsconfig.json'), frontendTsconfig, 'utf-8');
376
+ console.log(chalk.green(' ✓'), 'frontend entry files');
377
+ }
378
+ async function createBackendEntry(targetDir) {
379
+ const serverTs = `import { fileURLToPath } from 'url';
380
+ import path from 'path';
381
+ import { LoomServer } from '@loom-framework/core';
382
+
383
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
384
+ const projectRoot = path.resolve(__dirname, '../..');
385
+
386
+ const server = new LoomServer({ projectRoot });
387
+ await server.initialize();
388
+ await server.start();
389
+ `;
390
+ await fs.writeFile(path.join(targetDir, 'backend/src/index.ts'), serverTs, 'utf-8');
391
+ console.log(chalk.green(' ✓'), 'backend/src/index.ts');
392
+ }
393
+ async function createGitignore(targetDir) {
394
+ const gitignore = `node_modules/
395
+ dist/
396
+ .loom/
397
+ *.local
398
+ .env
399
+ data/*.db
400
+ `;
401
+ await fs.writeFile(path.join(targetDir, '.gitignore'), gitignore, 'utf-8');
402
+ console.log(chalk.green(' ✓'), '.gitignore');
403
+ }
404
+ async function detectPackageManager(targetDir) {
405
+ const { existsSync } = await import('fs');
406
+ const path = await import('path');
407
+ // 1. Check lockfiles in target directory (most reliable)
408
+ if (existsSync(path.join(targetDir, 'pnpm-lock.yaml')))
409
+ return 'pnpm';
410
+ if (existsSync(path.join(targetDir, 'yarn.lock')))
411
+ return 'yarn';
412
+ if (existsSync(path.join(targetDir, 'bun.lockb')) || existsSync(path.join(targetDir, 'bun.lock')))
413
+ return 'bun';
414
+ // 2. Check lockfiles in current working directory (user may be in a monorepo)
415
+ const cwd = process.cwd();
416
+ if (cwd !== targetDir) {
417
+ if (existsSync(path.join(cwd, 'pnpm-lock.yaml')))
418
+ return 'pnpm';
419
+ if (existsSync(path.join(cwd, 'yarn.lock')))
420
+ return 'yarn';
421
+ if (existsSync(path.join(cwd, 'bun.lockb')) || existsSync(path.join(cwd, 'bun.lock')))
422
+ return 'bun';
423
+ }
424
+ // 3. Check which package managers are globally available
425
+ const { execSync } = await import('child_process');
426
+ for (const pm of ['pnpm', 'yarn', 'bun']) {
427
+ try {
428
+ execSync(`${pm} --version`, { stdio: 'pipe', timeout: 5000 });
429
+ return pm;
430
+ }
431
+ catch {
432
+ continue;
433
+ }
434
+ }
435
+ return 'npm';
436
+ }
437
+ async function installDependencies(targetDir) {
438
+ const { execSync } = await import('child_process');
439
+ const { existsSync } = await import('fs');
440
+ const path = await import('path');
441
+ const pm = await detectPackageManager(targetDir);
442
+ const installCmd = pm === 'npm' ? 'npm install' : `${pm} install`;
443
+ // For pnpm inside a workspace, add --ignore-workspace flag
444
+ const cwd = process.cwd();
445
+ let finalCmd = installCmd;
446
+ if (pm === 'pnpm' && cwd !== targetDir) {
447
+ // If CWD has pnpm-workspace.yaml, the new project is inside a monorepo
448
+ if (existsSync(path.join(cwd, 'pnpm-workspace.yaml'))) {
449
+ finalCmd = 'pnpm install --ignore-workspace';
450
+ }
451
+ }
452
+ console.log(chalk.dim(` Installing dependencies (${pm})...`));
453
+ try {
454
+ execSync(finalCmd, {
455
+ cwd: targetDir,
456
+ stdio: 'pipe',
457
+ timeout: 300000,
458
+ });
459
+ console.log(chalk.green(' ✓'), `Dependencies installed (${pm})`);
460
+ }
461
+ catch {
462
+ console.log(chalk.yellow(' ⚠'), `Dependency installation failed. Run \`${finalCmd}\` manually.`);
463
+ }
464
+ }
465
+ async function verifySqliteNativeModule(targetDir) {
466
+ const { execSync } = await import('child_process');
467
+ const path = await import('path');
468
+ // Step 1: Check if native module loads
469
+ try {
470
+ execSync('node -e "require(\'better-sqlite3\')(\':memory:\').close()"', {
471
+ cwd: targetDir,
472
+ stdio: 'pipe',
473
+ timeout: 10000,
474
+ });
475
+ return; // OK, no fix needed
476
+ }
477
+ catch {
478
+ // Native module missing, proceed to auto-fix
479
+ }
480
+ // Step 2: Auto-rebuild from source
481
+ console.log(chalk.yellow(' ⚠ better-sqlite3 native binary not found, rebuilding from source...'));
482
+ // Find the actual better-sqlite3 package dir (pnpm uses .pnpm store)
483
+ let bs3Dir;
484
+ try {
485
+ const resolved = execSync('node -e "console.log(require.resolve(\'better-sqlite3/package.json\'))"', {
486
+ cwd: targetDir,
487
+ stdio: ['pipe', 'pipe', 'pipe'],
488
+ timeout: 10000,
489
+ }).toString().trim();
490
+ bs3Dir = path.dirname(resolved);
491
+ }
492
+ catch {
493
+ // Fallback: try direct node_modules path
494
+ const directPath = path.join(targetDir, 'node_modules', 'better-sqlite3');
495
+ const { existsSync } = await import('fs');
496
+ if (existsSync(directPath)) {
497
+ bs3Dir = directPath;
498
+ }
499
+ }
500
+ if (bs3Dir) {
501
+ try {
502
+ execSync('npx --yes node-gyp rebuild', {
503
+ cwd: bs3Dir,
504
+ stdio: 'pipe',
505
+ timeout: 120000,
506
+ });
507
+ // Verify the fix worked
508
+ try {
509
+ execSync('node -e "require(\'better-sqlite3\')(\':memory:\').close()"', {
510
+ cwd: targetDir,
511
+ stdio: 'pipe',
512
+ timeout: 10000,
513
+ });
514
+ console.log(chalk.green(' ✓'), 'better-sqlite3 native module rebuilt successfully');
515
+ return;
516
+ }
517
+ catch {
518
+ // Rebuild succeeded but still can't load — fall through to fallback
519
+ }
520
+ }
521
+ catch {
522
+ // Rebuild failed — fall through to fallback
523
+ }
524
+ }
525
+ // Step 3: Fallback — switch to filesystem adapter
526
+ console.log(chalk.yellow(' ⚠ Could not rebuild better-sqlite3, switching to filesystem adapter'));
527
+ const configPath = path.join(targetDir, 'loom.config.ts');
528
+ const { readFile, writeFile } = await import('fs/promises');
529
+ try {
530
+ let config = await readFile(configPath, 'utf-8');
531
+ config = config.replace('defaultAdapter: \'sqlite\'', 'defaultAdapter: \'filesystem\'');
532
+ await writeFile(configPath, config, 'utf-8');
533
+ console.log(chalk.green(' ✓'), 'Switched defaultAdapter to "filesystem" in loom.config.ts');
534
+ }
535
+ catch {
536
+ console.log(chalk.dim(' Please manually change defaultAdapter to "filesystem" in loom.config.ts'));
537
+ }
538
+ }
539
+ //# sourceMappingURL=init.js.map