@loom-framework/core 0.1.0-alpha.1

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.
@@ -0,0 +1,288 @@
1
+ /**
2
+ * Capability Generator
3
+ *
4
+ * Core innovation: One schema definition → MCP Server + CLI commands
5
+ *
6
+ * From loom.config.ts model definitions, generates:
7
+ * 1. MCP Server (.loom/mcp-server/) - structured data CRUD tools
8
+ * 2. CLI data commands (cli/commands/data/) - dev/debug data access
9
+ * 3. MCP config (.loom/mcp.json) - Claude Code MCP registration
10
+ */
11
+ import { promises as fs } from 'fs';
12
+ import path from 'path';
13
+ // ── MCP Tool Generation ──
14
+ /**
15
+ * Generate MCP server code from model schemas
16
+ */
17
+ function generateMcpToolForModel(model) {
18
+ const modelName = model.name;
19
+ const capitalName = modelName.split(/[-_]/).map(s => s.charAt(0).toUpperCase() + s.slice(1)).join('');
20
+ const readParams = generateMcpParams(model, 'read');
21
+ const writeParams = generateMcpParams(model, 'write');
22
+ return `// Auto-generated by loom generate capabilities
23
+ // Model: ${modelName}
24
+
25
+ import { z } from 'zod';
26
+ import type { DataAdapter } from '@loom-framework/core';
27
+
28
+ const ${modelName}Schema = z.object({
29
+ ${model.fields.map(f => ` ${f.name}: ${fieldToZod(f)},`).join('\n')}
30
+ });
31
+
32
+ export function register${capitalName}Tools(
33
+ server: { tool: (name: string, description: string, schema: z.ZodObject<any>, handler: (params: any) => Promise<{ content: Array<{ type: string; text: string }> }>) => void },
34
+ adapter: DataAdapter
35
+ ) {
36
+ // read_${modelName}
37
+ server.tool(
38
+ 'read_${modelName}',
39
+ 'Read ${modelName} records${model.description ? ': ' + model.description : ''}',
40
+ z.object({
41
+ id: z.string().optional().describe('Record ID for single lookup'),
42
+ filter: z.record(z.unknown()).optional().describe('Filter conditions'),
43
+ limit: z.number().optional().describe('Max records to return'),
44
+ }),
45
+ async (params) => {
46
+ const result = await adapter.read('${modelName}', params);
47
+ return {
48
+ content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
49
+ };
50
+ }
51
+ );
52
+
53
+ // write_${modelName}
54
+ server.tool(
55
+ 'write_${modelName}',
56
+ 'Create a new ${modelName} record',
57
+ ${modelName}Schema,
58
+ async (params) => {
59
+ const result = await adapter.write('${modelName}', params);
60
+ return {
61
+ content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
62
+ };
63
+ }
64
+ );
65
+
66
+ // update_${modelName}
67
+ server.tool(
68
+ 'update_${modelName}',
69
+ 'Update an existing ${modelName} record',
70
+ z.object({
71
+ id: z.string().describe('Record ID to update'),
72
+ data: ${modelName}Schema.partial().describe('Fields to update'),
73
+ }),
74
+ async (params) => {
75
+ const result = await adapter.update('${modelName}', params.id, params.data);
76
+ return {
77
+ content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
78
+ };
79
+ }
80
+ );
81
+
82
+ // delete_${modelName}
83
+ server.tool(
84
+ 'delete_${modelName}',
85
+ 'Delete a ${modelName} record',
86
+ z.object({
87
+ id: z.string().describe('Record ID to delete'),
88
+ }),
89
+ async (params) => {
90
+ await adapter.delete('${modelName}', params.id);
91
+ return {
92
+ content: [{ type: 'text', text: \`Deleted ${modelName} record: \${params.id}\` }],
93
+ };
94
+ }
95
+ );
96
+ }`;
97
+ }
98
+ function fieldToZod(field) {
99
+ const base = (() => {
100
+ switch (field.type) {
101
+ case 'string': return 'z.string()';
102
+ case 'number': return 'z.number()';
103
+ case 'boolean': return 'z.boolean()';
104
+ case 'date': return 'z.string().describe("ISO date string")';
105
+ case 'string[]': return 'z.array(z.string())';
106
+ case 'number[]': return 'z.array(z.number())';
107
+ case 'json': return 'z.unknown()';
108
+ }
109
+ })();
110
+ const withDesc = field.description ? `${base}.describe("${field.description}")` : base;
111
+ const withEnum = field.enum ? `z.enum([${field.enum.map(e => `"${e}"`).join(', ')}])` : withDesc;
112
+ const withRequired = field.required ? withEnum : `${withEnum}.optional()`;
113
+ return withRequired;
114
+ }
115
+ function generateMcpParams(model, operation) {
116
+ if (operation === 'read') {
117
+ return `{ id?: string, filter?: Record<string, unknown>, limit?: number }`;
118
+ }
119
+ return `{\n${model.fields.map(f => ` ${f.name}: ${f.type}${f.required ? '' : '?'},`).join('\n')}\n}`;
120
+ }
121
+ /**
122
+ * Generate MCP Server index.ts
123
+ */
124
+ function generateMcpServerIndex(models) {
125
+ const imports = models.map(m => {
126
+ const capitalName = m.name.split(/[-_]/).map(s => s.charAt(0).toUpperCase() + s.slice(1)).join('');
127
+ return `import { register${capitalName}Tools } from './tools/${m.name}.js';`;
128
+ }).join('\n');
129
+ const registrations = models.map(m => {
130
+ const capitalName = m.name.split(/[-_]/).map(s => s.charAt(0).toUpperCase() + s.slice(1)).join('');
131
+ return ` register${capitalName}Tools(server, adapter);`;
132
+ }).join('\n');
133
+ return `// Auto-generated by loom generate capabilities
134
+ // Loom MCP Server - Data Access Layer
135
+
136
+ import path from 'path';
137
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
138
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
139
+ import { FileSystemAdapter } from '@loom-framework/core';
140
+ import { loadConfig } from '@loom-framework/core';
141
+ ${imports}
142
+
143
+ async function main() {
144
+ const projectRoot = process.env.LOOM_PROJECT_ROOT || process.cwd();
145
+ const config = await loadConfig(projectRoot);
146
+ const adapter = new FileSystemAdapter({
147
+ dataDir: process.env.LOOM_DATA_DIR || path.join(projectRoot, 'data'),
148
+ config,
149
+ });
150
+ await adapter.initialize();
151
+
152
+ const server = new McpServer({
153
+ name: 'loom-data',
154
+ version: '1.0.0',
155
+ });
156
+
157
+ ${registrations}
158
+
159
+ const transport = new StdioServerTransport();
160
+ await server.connect(transport);
161
+ }
162
+
163
+ main().catch(console.error);
164
+ `;
165
+ }
166
+ /**
167
+ * Generate .loom/mcp.json
168
+ */
169
+ function generateMcpJson(projectRoot) {
170
+ return JSON.stringify({
171
+ mcpServers: {
172
+ 'loom-data': {
173
+ command: 'npx',
174
+ args: ['tsx', '.loom/mcp-server/index.ts'],
175
+ env: {
176
+ LOOM_PROJECT_ROOT: projectRoot,
177
+ LOOM_DATA_DIR: './data',
178
+ },
179
+ },
180
+ },
181
+ }, null, 2);
182
+ }
183
+ // ── CLI Command Generation ──
184
+ /**
185
+ * Generate CLI data command for a model
186
+ */
187
+ function generateCliDataCommand(model) {
188
+ const modelName = model.name;
189
+ return `// Auto-generated by loom generate capabilities
190
+ // Model: ${modelName}
191
+
192
+ import { defineCommand } from '@loom-framework/core';
193
+
194
+ export default defineCommand({
195
+ name: 'data:read:${modelName}',
196
+ description: 'Read ${modelName} records${model.description ? ' - ' + model.description : ''}',
197
+ options: {
198
+ id: { type: 'string', description: 'Record ID for single lookup' },
199
+ filter: { type: 'json', description: 'Filter conditions as JSON' },
200
+ limit: { type: 'number', description: 'Max records to return' },
201
+ },
202
+ async execute(args, context) {
203
+ const adapter = context.getDataAdapter();
204
+ const result = await adapter.read('${modelName}', {
205
+ id: args.id as string | undefined,
206
+ filter: args.filter as Record<string, unknown> | undefined,
207
+ limit: args.limit as number | undefined,
208
+ });
209
+ return JSON.stringify(result, null, 2);
210
+ },
211
+ });
212
+ `;
213
+ }
214
+ /**
215
+ * Generate all capabilities from config
216
+ */
217
+ export async function generateCapabilities(projectRoot, config) {
218
+ const loomDir = path.join(projectRoot, '.loom');
219
+ const mcpServerDir = path.join(loomDir, 'mcp-server');
220
+ const mcpToolsDir = path.join(mcpServerDir, 'tools');
221
+ const cliDataDir = path.join(projectRoot, 'cli', 'src', 'commands', 'data');
222
+ const filesWritten = [];
223
+ // Clean and create directories
224
+ await fs.mkdir(mcpToolsDir, { recursive: true });
225
+ await fs.mkdir(cliDataDir, { recursive: true });
226
+ // Generate MCP tools for each model
227
+ for (const model of config.data.models) {
228
+ // MCP tool file
229
+ const mcpToolPath = path.join(mcpToolsDir, `${model.name}.ts`);
230
+ await fs.writeFile(mcpToolPath, generateMcpToolForModel(model), 'utf-8');
231
+ filesWritten.push(mcpToolPath);
232
+ // CLI data command
233
+ const cliCmdPath = path.join(cliDataDir, `${model.name}.ts`);
234
+ await fs.writeFile(cliCmdPath, generateCliDataCommand(model), 'utf-8');
235
+ filesWritten.push(cliCmdPath);
236
+ }
237
+ // Generate MCP Server index
238
+ const indexPath = path.join(mcpServerDir, 'index.ts');
239
+ await fs.writeFile(indexPath, generateMcpServerIndex(config.data.models), 'utf-8');
240
+ filesWritten.push(indexPath);
241
+ // Generate MCP Server package.json
242
+ // Note: @loom-framework/core is resolved from parent project's node_modules at runtime (via tsx)
243
+ const mcpPkgPath = path.join(mcpServerDir, 'package.json');
244
+ await fs.writeFile(mcpPkgPath, JSON.stringify({
245
+ name: 'loom-mcp-server',
246
+ version: '1.0.0',
247
+ type: 'module',
248
+ main: 'index.js',
249
+ dependencies: {
250
+ '@modelcontextprotocol/sdk': '^1.12.0',
251
+ '@loom-framework/core': '^0.1.0',
252
+ 'zod': '^3.23.0',
253
+ },
254
+ devDependencies: {
255
+ '@types/node': '^22.0.0',
256
+ 'tsx': '^4.7.0',
257
+ 'typescript': '^5.6.0',
258
+ },
259
+ }, null, 2), 'utf-8');
260
+ filesWritten.push(mcpPkgPath);
261
+ // Generate MCP Server tsconfig (self-contained, no external extends)
262
+ const mcpTsconfigPath = path.join(mcpServerDir, 'tsconfig.json');
263
+ await fs.writeFile(mcpTsconfigPath, JSON.stringify({
264
+ compilerOptions: {
265
+ target: 'ES2022',
266
+ module: 'Node16',
267
+ moduleResolution: 'Node16',
268
+ lib: ['ES2022'],
269
+ strict: true,
270
+ esModuleInterop: true,
271
+ skipLibCheck: true,
272
+ forceConsistentCasingInFileNames: true,
273
+ resolveJsonModule: true,
274
+ declaration: true,
275
+ sourceMap: true,
276
+ outDir: '.',
277
+ rootDir: '.',
278
+ },
279
+ include: ['*.ts', 'tools/*.ts'],
280
+ }, null, 2), 'utf-8');
281
+ filesWritten.push(mcpTsconfigPath);
282
+ // Generate mcp.json
283
+ const mcpJsonPath = path.join(loomDir, 'mcp.json');
284
+ await fs.writeFile(mcpJsonPath, generateMcpJson(projectRoot), 'utf-8');
285
+ filesWritten.push(mcpJsonPath);
286
+ return { mcpServerDir, filesWritten };
287
+ }
288
+ //# sourceMappingURL=capability-generator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capability-generator.js","sourceRoot":"","sources":["../src/capability-generator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * CLI Command Framework
3
+ *
4
+ * defineCommand() - Type-safe command registration
5
+ * Auto-discovery from cli/commands/ directory
6
+ */
7
+ import type { CommandDefinition, CommandContext, LoomConfig, DataAdapter } from './types.js';
8
+ /**
9
+ * Define a CLI command with type safety
10
+ *
11
+ * @example
12
+ * ```ts
13
+ * export default defineCommand({
14
+ * name: 'data:read:users',
15
+ * description: 'Read user records',
16
+ * options: {
17
+ * id: { type: 'string', description: 'User ID' },
18
+ * },
19
+ * async execute(args, context) {
20
+ * const adapter = context.getDataAdapter();
21
+ * const result = await adapter.read('users', { id: args.id as string });
22
+ * return JSON.stringify(result, null, 2);
23
+ * },
24
+ * });
25
+ * ```
26
+ */
27
+ export declare function defineCommand(command: CommandDefinition): CommandDefinition;
28
+ /**
29
+ * Context factory for command execution
30
+ */
31
+ export declare function createCommandContext(config: LoomConfig, configPath: string, projectRoot: string, dataAdapter: DataAdapter): CommandContext;
32
+ //# sourceMappingURL=commands.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../src/commands.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,cAAc,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE7F;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,iBAAiB,GAAG,iBAAiB,CAE3E;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,UAAU,EAClB,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,WAAW,GACvB,cAAc,CAOhB"}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * CLI Command Framework
3
+ *
4
+ * defineCommand() - Type-safe command registration
5
+ * Auto-discovery from cli/commands/ directory
6
+ */
7
+ /**
8
+ * Define a CLI command with type safety
9
+ *
10
+ * @example
11
+ * ```ts
12
+ * export default defineCommand({
13
+ * name: 'data:read:users',
14
+ * description: 'Read user records',
15
+ * options: {
16
+ * id: { type: 'string', description: 'User ID' },
17
+ * },
18
+ * async execute(args, context) {
19
+ * const adapter = context.getDataAdapter();
20
+ * const result = await adapter.read('users', { id: args.id as string });
21
+ * return JSON.stringify(result, null, 2);
22
+ * },
23
+ * });
24
+ * ```
25
+ */
26
+ export function defineCommand(command) {
27
+ return command;
28
+ }
29
+ /**
30
+ * Context factory for command execution
31
+ */
32
+ export function createCommandContext(config, configPath, projectRoot, dataAdapter) {
33
+ return {
34
+ config,
35
+ configPath,
36
+ projectRoot,
37
+ getDataAdapter: () => dataAdapter,
38
+ };
39
+ }
40
+ //# sourceMappingURL=commands.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commands.js","sourceRoot":"","sources":["../src/commands.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,UAAU,aAAa,CAAC,OAA0B;IACtD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,oBAAoB,CAClC,MAAkB,EAClB,UAAkB,EAClB,WAAmB,EACnB,WAAwB;IAExB,OAAO;QACL,MAAM;QACN,UAAU;QACV,WAAW;QACX,cAAc,EAAE,GAAG,EAAE,CAAC,WAAW;KAClC,CAAC;AACJ,CAAC"}