create-feltdb 0.2.0

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.
package/README.md ADDED
@@ -0,0 +1,70 @@
1
+ # create-feltdb
2
+
3
+ Interactive CLI tool to scaffold new FeltDB applications.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install -g create-feltdb
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ Create a new project:
14
+
15
+ ```bash
16
+ npx create-feltdb my-app
17
+ ```
18
+
19
+ Or use the installed command:
20
+
21
+ ```bash
22
+ create-feltdb my-app
23
+ ```
24
+
25
+ ### Options
26
+
27
+ - `--yes` or `-y` - Skip interactive prompts and use defaults
28
+
29
+ ## What Gets Generated
30
+
31
+ ```
32
+ my-app/
33
+ ├── feltdb/
34
+ │ ├── capabilities/
35
+ │ ├── workflows/
36
+ │ ├── agents/
37
+ │ └── schema/
38
+ ├── src/
39
+ │ ├── App.tsx
40
+ │ ├── feltdb.ts
41
+ │ └── index.ts
42
+ ├── public/
43
+ │ └── index.html
44
+ ├── feltdb.config.json
45
+ ├── package.json
46
+ ├── tsconfig.json
47
+ └── README.md
48
+ ```
49
+
50
+ ## Quick Start
51
+
52
+ After running `create-feltdb`:
53
+
54
+ ```bash
55
+ cd my-app
56
+ npm install
57
+ npm run dev
58
+ ```
59
+
60
+ ## Default Configuration
61
+
62
+ The generated project uses:
63
+ - **Runtime**: Browser
64
+ - **Storage**: OPFS (with IndexedDB fallback)
65
+ - **Distributed**: Enabled by default
66
+ - **Capabilities**: Search enabled, Vector disabled
67
+
68
+ ## License
69
+
70
+ MIT
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+
3
+ await import('../dist/cli.js');
package/dist/cli.js ADDED
@@ -0,0 +1,157 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * create-feltdb
4
+ *
5
+ * Interactive CLI for creating new FeltDB applications
6
+ */
7
+ import path from 'path';
8
+ import { fileURLToPath } from 'url';
9
+ import readline from 'readline';
10
+ import { createProject } from './create.js';
11
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
12
+ function parseArgs(args) {
13
+ const options = {
14
+ runtime: 'browser',
15
+ framework: 'react',
16
+ distributed: true,
17
+ agents: true,
18
+ capabilities: 'search',
19
+ };
20
+ for (let i = 0; i < args.length; i++) {
21
+ switch (args[i]) {
22
+ case '--runtime':
23
+ options.runtime = args[++i];
24
+ break;
25
+ case '--framework':
26
+ options.framework = args[++i];
27
+ break;
28
+ case '--no-distributed':
29
+ options.distributed = false;
30
+ break;
31
+ case '--no-agents':
32
+ options.agents = false;
33
+ break;
34
+ case '--capabilities':
35
+ options.capabilities = args[++i];
36
+ break;
37
+ }
38
+ }
39
+ return options;
40
+ }
41
+ async function select(message, choices, initialValue) {
42
+ let selected = Math.max(0, choices.findIndex(choice => choice.value === initialValue));
43
+ const input = process.stdin;
44
+ const output = process.stdout;
45
+ const wasRaw = input.isRaw;
46
+ readline.emitKeypressEvents(input);
47
+ input.setRawMode(true);
48
+ input.resume();
49
+ const render = (moveUp) => {
50
+ if (moveUp)
51
+ output.write(`\x1b[${choices.length}A`);
52
+ for (let index = 0; index < choices.length; index++) {
53
+ const choice = choices[index];
54
+ const active = index === selected;
55
+ const detail = choice.description ? ` \x1b[2m— ${choice.description}\x1b[22m` : '';
56
+ output.write(`\x1b[2K\r ${active ? '\x1b[36m❯' : ' '} ${choice.label}${active ? '\x1b[0m' : ''}${detail}\n`);
57
+ }
58
+ };
59
+ output.write(`${message}\n`);
60
+ render(false);
61
+ return new Promise(resolve => {
62
+ const finish = () => {
63
+ input.off('keypress', onKeypress);
64
+ input.setRawMode(Boolean(wasRaw));
65
+ input.pause();
66
+ resolve(choices[selected].value);
67
+ };
68
+ const onKeypress = (_value, key) => {
69
+ if (key.ctrl && key.name === 'c') {
70
+ output.write('\n');
71
+ input.setRawMode(Boolean(wasRaw));
72
+ process.exit(130);
73
+ }
74
+ if (key.name === 'up')
75
+ selected = (selected - 1 + choices.length) % choices.length;
76
+ else if (key.name === 'down')
77
+ selected = (selected + 1) % choices.length;
78
+ else if (key.name === 'return' || key.name === 'enter')
79
+ return finish();
80
+ else
81
+ return;
82
+ render(true);
83
+ };
84
+ input.on('keypress', onKeypress);
85
+ });
86
+ }
87
+ async function promptForOptions(defaults) {
88
+ if (!process.stdin.isTTY || !process.stdout.isTTY)
89
+ return defaults;
90
+ console.log('Configure your application. Use ↑/↓ to move and Enter to select.\n');
91
+ const yesNo = [
92
+ { label: 'Yes', value: true },
93
+ { label: 'No', value: false },
94
+ ];
95
+ return {
96
+ runtime: await select('Where should FeltDB run?', [
97
+ { label: 'Browser', value: 'browser', description: 'local-first with durable browser storage' },
98
+ { label: 'Node.js', value: 'node', description: 'application server or worker' },
99
+ { label: 'Self-hosted', value: 'self-hosted', description: 'dedicated FeltDB server' },
100
+ ], defaults.runtime),
101
+ framework: await select('Choose an application framework:', [
102
+ { label: 'React', value: 'react' },
103
+ { label: 'Vanilla TypeScript', value: 'vanilla' },
104
+ ], defaults.framework),
105
+ distributed: await select('Enable distributed operation?', yesNo, defaults.distributed),
106
+ agents: await select('Include an autonomous agent example?', yesNo, defaults.agents),
107
+ capabilities: await select('Choose starter capabilities:', [
108
+ { label: 'Search', value: 'search' },
109
+ { label: 'Vector search', value: 'vector' },
110
+ { label: 'Search + vector search', value: 'search,vector' },
111
+ ], defaults.capabilities),
112
+ };
113
+ }
114
+ async function main() {
115
+ const args = process.argv.slice(2);
116
+ const projectName = args[0] || 'feltdb-app';
117
+ const shouldAutoYes = args.includes('--yes') || args.includes('-y');
118
+ let options = parseArgs(args);
119
+ console.log('\n✨ Creating FeltDB Application\n');
120
+ if (!shouldAutoYes) {
121
+ options = await promptForOptions(options);
122
+ console.log('\nConfiguration:');
123
+ console.log(` Runtime: ${options.runtime}`);
124
+ console.log(` Framework: ${options.framework}`);
125
+ console.log(` Distributed: ${options.distributed ? 'yes' : 'no'}`);
126
+ console.log(` Agents: ${options.agents ? 'yes' : 'no'}`);
127
+ console.log(` Capabilities: ${options.capabilities}\n`);
128
+ }
129
+ try {
130
+ await createProject({
131
+ projectName,
132
+ autoYes: shouldAutoYes,
133
+ templatesDir: path.join(__dirname, '../templates'),
134
+ runtime: options.runtime,
135
+ framework: options.framework,
136
+ distributed: options.distributed,
137
+ agents: options.agents,
138
+ capabilities: options.capabilities,
139
+ });
140
+ console.log('\n✅ FeltDB application created successfully!\n');
141
+ console.log(`Next steps:`);
142
+ console.log(` cd ${projectName}`);
143
+ console.log(` npm install`);
144
+ if (options.runtime === 'self-hosted') {
145
+ console.log(` feltdb server --data ./data`);
146
+ }
147
+ else {
148
+ console.log(` npm run dev`);
149
+ }
150
+ console.log('');
151
+ }
152
+ catch (error) {
153
+ console.error('❌ Failed to create project:', error);
154
+ process.exit(1);
155
+ }
156
+ }
157
+ main();
package/dist/create.js ADDED
@@ -0,0 +1,573 @@
1
+ /**
2
+ * Project creation logic
3
+ */
4
+ import fs from 'fs';
5
+ import path from 'path';
6
+ import { feltdbPackageRange } from './package-versions.js';
7
+ export async function createProject(options) {
8
+ const { projectName, templatesDir } = options;
9
+ const projectDir = path.resolve(process.cwd(), projectName);
10
+ const applicationName = path.basename(projectDir);
11
+ // Create project directory
12
+ if (!fs.existsSync(projectDir)) {
13
+ fs.mkdirSync(projectDir, { recursive: true });
14
+ }
15
+ // Create feltdb directory structure
16
+ const feltdbDir = path.join(projectDir, 'feltdb');
17
+ const srcDir = path.join(projectDir, 'src');
18
+ const publicDir = path.join(projectDir, 'public');
19
+ const feltdbConfigDir = path.join(projectDir, '.feltdb');
20
+ fs.mkdirSync(path.join(feltdbDir, 'capabilities'), { recursive: true });
21
+ fs.mkdirSync(path.join(feltdbDir, 'workflows'), { recursive: true });
22
+ fs.mkdirSync(path.join(feltdbDir, 'agents'), { recursive: true });
23
+ fs.mkdirSync(path.join(feltdbDir, 'schema'), { recursive: true });
24
+ fs.mkdirSync(srcDir, { recursive: true });
25
+ fs.mkdirSync(publicDir, { recursive: true });
26
+ fs.mkdirSync(feltdbConfigDir, { recursive: true });
27
+ const runtime = options.runtime || 'browser';
28
+ const framework = options.framework || 'react';
29
+ const distributed = options.distributed !== false;
30
+ const hasAgents = options.agents !== false;
31
+ const capabilities = options.capabilities || 'search';
32
+ // Create package.json
33
+ const packageJson = {
34
+ name: applicationName,
35
+ version: '0.1.0',
36
+ description: `A FeltDB application`,
37
+ main: 'src/index.ts',
38
+ type: 'module',
39
+ scripts: {
40
+ dev: 'feltdb dev',
41
+ build: 'feltdb build',
42
+ test: 'node --test',
43
+ feltdb: 'feltdb',
44
+ 'feltdb:server': 'feltdb server',
45
+ 'feltdb:connect': 'feltdb connect http://localhost:7700',
46
+ 'feltdb:status': 'feltdb status',
47
+ 'feltdb:studio': 'feltdb studio',
48
+ 'feltdb:validate': 'feltdb validate',
49
+ 'feltdb:diff': 'feltdb diff',
50
+ 'feltdb:deploy': 'feltdb deploy',
51
+ },
52
+ dependencies: {
53
+ '@feltdb/core': feltdbPackageRange,
54
+ },
55
+ devDependencies: {
56
+ '@feltdb/cli': feltdbPackageRange,
57
+ typescript: '^5.0.0',
58
+ '@types/node': '^20.0.0',
59
+ vite: '^8.2.1',
60
+ },
61
+ };
62
+ if (framework === 'react') {
63
+ packageJson.dependencies['@feltdb/react'] = feltdbPackageRange;
64
+ packageJson.dependencies['react'] = '^18.0.0';
65
+ packageJson.dependencies['react-dom'] = '^18.0.0';
66
+ packageJson.devDependencies['@types/react'] = '^18.0.0';
67
+ packageJson.devDependencies['@types/react-dom'] = '^18.0.0';
68
+ }
69
+ fs.writeFileSync(path.join(projectDir, 'package.json'), JSON.stringify(packageJson, null, 2));
70
+ // Create feltdb.config.json
71
+ const feltdbConfig = {
72
+ namespace: applicationName,
73
+ runtime,
74
+ storage: runtime === 'browser' ? 'opfs' : 'durable',
75
+ distributed,
76
+ agents: {
77
+ enabled: hasAgents,
78
+ },
79
+ capabilities: {},
80
+ };
81
+ if (capabilities.includes('search')) {
82
+ feltdbConfig.capabilities.search = true;
83
+ }
84
+ if (capabilities.includes('vector')) {
85
+ feltdbConfig.capabilities['vector-search'] = true;
86
+ }
87
+ fs.writeFileSync(path.join(projectDir, 'feltdb.config.json'), JSON.stringify(feltdbConfig, null, 2));
88
+ const appName = applicationName.replace(/[^A-Za-z0-9_]/g, '_').replace(/^[^A-Za-z_]/, 'App_');
89
+ const flowSpec = `app ${appName} {
90
+ collection Document {
91
+ title: text
92
+ content: text
93
+ createdAt: datetime
94
+ index search using fulltext(content)
95
+ }
96
+
97
+ collection Report {
98
+ title: text
99
+ content: text
100
+ document: ref Document
101
+ }
102
+
103
+ capability Research {
104
+ read Document
105
+ write Report
106
+ }
107
+
108
+ agent Researcher {
109
+ capability Research
110
+ workflow ResearchDocument
111
+ }
112
+
113
+ workflow ResearchDocument(document: Document) {
114
+ step search {
115
+ input document.content
116
+ }
117
+ step identity {
118
+ input search.output
119
+ }
120
+ }
121
+
122
+ trigger on Document.created {
123
+ workflow ResearchDocument(document)
124
+ }
125
+
126
+ policy Document {
127
+ read: authenticated
128
+ write: authenticated
129
+ }
130
+ }
131
+ `;
132
+ fs.writeFileSync(path.join(projectDir, 'feltdb.flow'), flowSpec);
133
+ // Create tsconfig.json
134
+ const tsconfig = {
135
+ compilerOptions: {
136
+ target: 'ES2020',
137
+ module: 'ESNext',
138
+ lib: ['ES2020', 'DOM'],
139
+ declaration: true,
140
+ outDir: './dist',
141
+ rootDir: './src',
142
+ strict: true,
143
+ esModuleInterop: true,
144
+ skipLibCheck: true,
145
+ forceConsistentCasingInFileNames: true,
146
+ moduleResolution: 'node',
147
+ },
148
+ include: ['src/**/*'],
149
+ exclude: ['node_modules'],
150
+ };
151
+ if (framework === 'react') {
152
+ tsconfig.compilerOptions.jsx = 'react-jsx';
153
+ }
154
+ fs.writeFileSync(path.join(projectDir, 'tsconfig.json'), JSON.stringify(tsconfig, null, 2));
155
+ // Create main application files
156
+ const feltdbTs = `import { createFeltDB } from '@feltdb/core';
157
+
158
+ export const db = createFeltDB({
159
+ namespace: '${applicationName}',
160
+ memory: true, // Development-only; configure \`server\` for durable customer data.
161
+ });
162
+
163
+ // Collections
164
+ export const documents = db.collection('documents');
165
+ export const reports = db.collection('reports');
166
+ `;
167
+ fs.writeFileSync(path.join(srcDir, 'feltdb.ts'), feltdbTs);
168
+ // Create a sample agent if enabled
169
+ if (hasAgents) {
170
+ const agentTs = `import { db } from '../feltdb';
171
+
172
+ /**
173
+ * Researcher Agent
174
+ *
175
+ * This agent demonstrates distributed agent execution
176
+ * across peers in the FeltDB fabric.
177
+ */
178
+ export const researcher = db.defineAgent({
179
+ name: 'researcher',
180
+ description: 'Search and analyze documents across the fabric',
181
+ capabilities: [
182
+ 'document-read',
183
+ 'vector-search',
184
+ 'report-write'
185
+ ],
186
+ async run(options: any) {
187
+ console.log('🤖 Researcher agent starting...');
188
+ console.log('Goal:', options.goal);
189
+ console.log('Inputs:', options.inputs);
190
+
191
+ // The agent will execute capabilities across peers
192
+ // Results are automatically acquired from remote locations
193
+
194
+ return {
195
+ status: 'complete',
196
+ results: {
197
+ message: 'Research completed successfully'
198
+ }
199
+ };
200
+ }
201
+ });
202
+ `;
203
+ fs.writeFileSync(path.join(feltdbDir, 'agents', 'researcher.ts'), agentTs);
204
+ }
205
+ // Create capabilities index
206
+ const capabilitiesTs = `/**
207
+ * Capabilities
208
+ *
209
+ * Define capabilities that can be executed by agents
210
+ * across distributed peers
211
+ */
212
+
213
+ export const capabilities = {
214
+ 'document-read': {
215
+ enabled: true,
216
+ scope: ['documents:read'],
217
+ },
218
+ 'vector-search': {
219
+ enabled: ${capabilities.includes('vector')},
220
+ scope: ['documents:read', 'capabilities:execute'],
221
+ },
222
+ 'report-write': {
223
+ enabled: true,
224
+ scope: ['reports:write'],
225
+ },
226
+ };
227
+ `;
228
+ fs.writeFileSync(path.join(feltdbDir, 'capabilities', 'index.ts'), capabilitiesTs);
229
+ // Create main application file based on framework
230
+ if (framework === 'react') {
231
+ const appTsx = `import React, { useState, useEffect } from 'react';
232
+ import { db, documents } from './feltdb';
233
+
234
+ export function App() {
235
+ const [docs, setDocs] = useState<any[]>([]);
236
+ const [loading, setLoading] = useState(true);
237
+
238
+ useEffect(() => {
239
+ const loadDocs = async () => {
240
+ try {
241
+ const allDocs = await documents.find({});
242
+ setDocs(allDocs);
243
+ } catch (err) {
244
+ console.error('Error loading documents:', err);
245
+ } finally {
246
+ setLoading(false);
247
+ }
248
+ };
249
+
250
+ loadDocs();
251
+ }, []);
252
+
253
+ const handleAddDocument = async () => {
254
+ try {
255
+ await documents.insert({
256
+ title: 'New Document',
257
+ content: 'Enter content here',
258
+ createdAt: new Date(),
259
+ });
260
+ // Reload documents
261
+ const allDocs = await documents.find({});
262
+ setDocs(allDocs);
263
+ } catch (err) {
264
+ console.error('Error adding document:', err);
265
+ }
266
+ };
267
+
268
+ return (
269
+ <div className="app">
270
+ <header>
271
+ <h1>🌊 FeltDB Research App</h1>
272
+ <p>Distributed document management with agents and capabilities</p>
273
+ </header>
274
+
275
+ <main>
276
+ <section className="stats">
277
+ <div className="stat">
278
+ <span className="label">Documents:</span>
279
+ <span className="value">{docs.length}</span>
280
+ </div>
281
+ <div className="stat">
282
+ <span className="label">Runtime:</span>
283
+ <span className="value">${runtime}</span>
284
+ </div>
285
+ <div className="stat">
286
+ <span className="label">Distributed:</span>
287
+ <span className="value">${distributed ? '✓' : '✗'}</span>
288
+ </div>
289
+ </section>
290
+
291
+ <section className="documents">
292
+ <h2>Documents</h2>
293
+ {loading ? (
294
+ <p>Loading...</p>
295
+ ) : docs.length === 0 ? (
296
+ <p>No documents yet</p>
297
+ ) : (
298
+ <ul>
299
+ {docs.map((doc: any) => (
300
+ <li key={doc.id}>
301
+ <h3>{doc.title}</h3>
302
+ <p>{doc.content}</p>
303
+ </li>
304
+ ))}
305
+ </ul>
306
+ )}
307
+ <button onClick={handleAddDocument}>Add Document</button>
308
+ </section>
309
+ </main>
310
+
311
+ <style>{\`
312
+ body {
313
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto;
314
+ margin: 0;
315
+ padding: 0;
316
+ background: #f5f5f5;
317
+ }
318
+
319
+ .app {
320
+ max-width: 1200px;
321
+ margin: 0 auto;
322
+ padding: 20px;
323
+ }
324
+
325
+ header {
326
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
327
+ color: white;
328
+ padding: 30px;
329
+ border-radius: 8px;
330
+ margin-bottom: 30px;
331
+ }
332
+
333
+ header h1 {
334
+ margin: 0 0 10px 0;
335
+ font-size: 28px;
336
+ }
337
+
338
+ header p {
339
+ margin: 0;
340
+ opacity: 0.9;
341
+ }
342
+
343
+ main {
344
+ background: white;
345
+ padding: 20px;
346
+ border-radius: 8px;
347
+ box-shadow: 0 2px 8px rgba(0,0,0,0.1);
348
+ }
349
+
350
+ .stats {
351
+ display: grid;
352
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
353
+ gap: 20px;
354
+ margin-bottom: 30px;
355
+ }
356
+
357
+ .stat {
358
+ padding: 15px;
359
+ background: #f9f9f9;
360
+ border-radius: 4px;
361
+ border-left: 3px solid #667eea;
362
+ }
363
+
364
+ .stat .label {
365
+ display: block;
366
+ color: #666;
367
+ font-size: 12px;
368
+ text-transform: uppercase;
369
+ margin-bottom: 5px;
370
+ }
371
+
372
+ .stat .value {
373
+ display: block;
374
+ font-size: 24px;
375
+ font-weight: bold;
376
+ color: #333;
377
+ }
378
+
379
+ .documents h2 {
380
+ margin-top: 0;
381
+ }
382
+
383
+ .documents ul {
384
+ list-style: none;
385
+ padding: 0;
386
+ margin: 0 0 20px 0;
387
+ }
388
+
389
+ .documents li {
390
+ padding: 15px;
391
+ background: #f9f9f9;
392
+ border-radius: 4px;
393
+ margin-bottom: 10px;
394
+ }
395
+
396
+ .documents h3 {
397
+ margin: 0 0 10px 0;
398
+ color: #333;
399
+ }
400
+
401
+ .documents p {
402
+ margin: 0;
403
+ color: #666;
404
+ font-size: 14px;
405
+ }
406
+
407
+ button {
408
+ background: #667eea;
409
+ color: white;
410
+ border: none;
411
+ padding: 10px 20px;
412
+ border-radius: 4px;
413
+ cursor: pointer;
414
+ font-size: 14px;
415
+ font-weight: 500;
416
+ }
417
+
418
+ button:hover {
419
+ background: #5568d3;
420
+ }
421
+ \`}</style>
422
+ </div>
423
+ );
424
+ }
425
+ `;
426
+ fs.writeFileSync(path.join(srcDir, 'App.tsx'), appTsx);
427
+ const indexTsx = `import React from 'react';
428
+ import ReactDOM from 'react-dom/client';
429
+ import { App } from './App';
430
+
431
+ const root = ReactDOM.createRoot(document.getElementById('root')!);
432
+ root.render(
433
+ <React.StrictMode>
434
+ <App />
435
+ </React.StrictMode>
436
+ );
437
+ `;
438
+ fs.writeFileSync(path.join(srcDir, 'index.tsx'), indexTsx);
439
+ }
440
+ else {
441
+ // Create vanilla JS app
442
+ const indexJs = `import { db, documents } from './feltdb';
443
+
444
+ async function main() {
445
+ console.log('🌊 FeltDB Research App');
446
+ console.log('Runtime: ${runtime}');
447
+ console.log('Distributed: ${distributed}');
448
+ }
449
+
450
+ main().catch(console.error);
451
+ `;
452
+ fs.writeFileSync(path.join(srcDir, 'index.js'), indexJs);
453
+ }
454
+ // Create index.html
455
+ const indexHtml = `<!DOCTYPE html>
456
+ <html lang="en">
457
+ <head>
458
+ <meta charset="UTF-8">
459
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
460
+ <title>${applicationName}</title>
461
+ </head>
462
+ <body>
463
+ <div id="root"></div>
464
+ <script type="module" src="/src/index${framework === 'react' ? '.tsx' : '.js'}"></script>
465
+ </body>
466
+ </html>
467
+ `;
468
+ fs.writeFileSync(path.join(projectDir, 'index.html'), indexHtml);
469
+ // Create .env.example
470
+ const envExample = `# FeltDB Configuration
471
+ FELTDB_API_KEY=
472
+ FELTDB_URL=http://localhost:7700
473
+ NODE_ENV=development
474
+ `;
475
+ fs.writeFileSync(path.join(projectDir, '.env.example'), envExample);
476
+ // Create .gitignore
477
+ const gitignore = `node_modules/
478
+ dist/
479
+ build/
480
+ .env
481
+ .env.local
482
+ .env.*.local
483
+ *.log
484
+ .DS_Store
485
+ .feltdb/keys.json
486
+ .feltdb/connection.json
487
+ `;
488
+ fs.writeFileSync(path.join(projectDir, '.gitignore'), gitignore);
489
+ // Create README
490
+ const readme = `# ${applicationName}
491
+
492
+ A FeltDB distributed application with agents and capabilities.
493
+
494
+ ## Quick Start
495
+
496
+ \`\`\`bash
497
+ npm install
498
+ npm run dev
499
+ \`\`\`
500
+
501
+ ## Project Structure
502
+
503
+ \`\`\`
504
+ ${applicationName}/
505
+ ├── feltdb/
506
+ │ ├── agents/ # Agent definitions
507
+ │ ├── capabilities/ # Capability implementations
508
+ │ ├── workflows/ # Workflow definitions
509
+ │ └── schema/ # Data schemas
510
+ ├── src/
511
+ │ ├── App.${framework === 'react' ? 'tsx' : 'js'}
512
+ │ ├── feltdb.ts
513
+ │ └── index.${framework === 'react' ? 'tsx' : 'js'}
514
+ ├── public/
515
+ ├── index.html
516
+ ├── .feltdb/ # Local FeltDB configuration
517
+ ├── feltdb.config.json
518
+ ├── .env.example
519
+ ├── package.json
520
+ ├── tsconfig.json
521
+ └── README.md
522
+ \`\`\`
523
+
524
+ ## Configuration
525
+
526
+ Configuration is in \`feltdb.config.json\`:
527
+ - \`runtime\`: ${runtime} (browser|node|self-hosted)
528
+ - \`storage\`: ${runtime === 'browser' ? 'opfs' : 'durable'}
529
+ - \`distributed\`: ${distributed}
530
+ - \`agents.enabled\`: ${hasAgents}
531
+ - \`capabilities\`: ${capabilities}
532
+
533
+ ## Development
534
+
535
+ ### Start Development Server
536
+ \`\`\`bash
537
+ npm run dev
538
+ \`\`\`
539
+
540
+ ### Build for Production
541
+ \`\`\`bash
542
+ npm run build
543
+ \`\`\`
544
+
545
+ ### Connect to Remote Server
546
+ \`\`\`bash
547
+ feltdb connect http://localhost:7700
548
+ \`\`\`
549
+
550
+ ### Create API Key
551
+ \`\`\`bash
552
+ feltdb keys create --name development --scope '*'
553
+ \`\`\`
554
+
555
+ ## Agents
556
+
557
+ ${hasAgents ? `The \`researcher\` agent demonstrates distributed execution:
558
+ - Resolves document references
559
+ - Discovers capabilities across peers
560
+ - Executes on compatible peers
561
+ - Creates workflows
562
+ - Publishes results` : 'No agents configured'}
563
+
564
+ ## Capabilities
565
+
566
+ ${capabilities}
567
+
568
+ ## Learn More
569
+
570
+ Visit [FeltDB Documentation](https://github.com/rkendel1/feltdb) to learn more.
571
+ `;
572
+ fs.writeFileSync(path.join(projectDir, 'README.md'), readme);
573
+ }
package/dist/index.js ADDED
@@ -0,0 +1,4 @@
1
+ /**
2
+ * create-feltdb - Main exports
3
+ */
4
+ export * from './create';
@@ -0,0 +1,4 @@
1
+ // One release train keeps generated applications installable. The repository
2
+ // validation script checks these values against every workspace manifest.
3
+ export const FELTDB_PACKAGE_VERSION = '0.2.0';
4
+ export const feltdbPackageRange = `^${FELTDB_PACKAGE_VERSION}`;
package/package.json ADDED
@@ -0,0 +1,39 @@
1
+ {
2
+ "name": "create-feltdb",
3
+ "version": "0.2.0",
4
+ "description": "Create a new FeltDB application with one command",
5
+ "license": "MIT",
6
+ "bin": {
7
+ "create-feltdb": "bin/create-feltdb.js"
8
+ },
9
+ "main": "dist/index.js",
10
+ "type": "module",
11
+ "files": [
12
+ "dist/",
13
+ "bin/",
14
+ "templates/"
15
+ ],
16
+ "scripts": {
17
+ "build": "rm -rf dist && tsc",
18
+ "dev": "node dist/cli.js"
19
+ },
20
+ "devDependencies": {
21
+ "typescript": "^5.0.0",
22
+ "@types/node": "^20.0.0"
23
+ },
24
+ "engines": {
25
+ "node": ">=14"
26
+ },
27
+ "repository": {
28
+ "type": "git",
29
+ "url": "git+https://github.com/rkendel1/feltdb.git",
30
+ "directory": "tools/create-feltdb"
31
+ },
32
+ "keywords": [
33
+ "feltdb",
34
+ "database",
35
+ "scaffold",
36
+ "template",
37
+ "cli"
38
+ ]
39
+ }