@feltdb/core 0.4.4 → 0.4.6

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 (143) hide show
  1. package/README.md +22 -0
  2. package/bin/create-feltdb.js +3 -0
  3. package/bin/feltdb.js +3 -0
  4. package/dist/analytics-backend.js +1 -1
  5. package/dist/cli/api-client.js +236 -0
  6. package/dist/cli/cli.js +18 -0
  7. package/dist/cli/commands.js +795 -0
  8. package/dist/cli/config.js +66 -0
  9. package/dist/cli/index.js +399 -0
  10. package/dist/create/application-identity.js +132 -0
  11. package/dist/create/cli-scripts-generator.js +211 -0
  12. package/dist/create/cli.js +202 -0
  13. package/dist/create/create.js +638 -0
  14. package/dist/create/docker-compose-generator.js +258 -0
  15. package/dist/create/index.js +4 -0
  16. package/dist/create/package-versions.js +4 -0
  17. package/dist/create/runtime-templates.js +272 -0
  18. package/dist/index-backend.js +1 -1
  19. package/dist/migrate/analyzer/index.d.ts +2 -0
  20. package/dist/migrate/analyzer/index.js +34 -0
  21. package/dist/migrate/benchmark/index.d.ts +13 -0
  22. package/dist/migrate/benchmark/index.js +8 -0
  23. package/dist/migrate/capability-gate/index.d.ts +3 -0
  24. package/dist/migrate/capability-gate/index.js +3 -0
  25. package/dist/migrate/classifier/index.d.ts +3 -0
  26. package/dist/migrate/classifier/index.js +53 -0
  27. package/dist/migrate/cli/index.d.ts +2 -0
  28. package/dist/migrate/cli/index.js +201 -0
  29. package/dist/migrate/domain-model/index.d.ts +2 -0
  30. package/dist/migrate/domain-model/index.js +4 -0
  31. package/dist/migrate/generator/index.d.ts +2 -0
  32. package/dist/migrate/generator/index.js +21 -0
  33. package/dist/migrate/index.d.ts +16 -0
  34. package/dist/migrate/index.js +16 -0
  35. package/dist/migrate/measurement/index.d.ts +7 -0
  36. package/dist/migrate/measurement/index.js +1 -0
  37. package/dist/migrate/migrator/index.d.ts +2 -0
  38. package/dist/migrate/migrator/index.js +35 -0
  39. package/dist/migrate/planner/index.d.ts +2 -0
  40. package/dist/migrate/planner/index.js +12 -0
  41. package/dist/migrate/prover/index.d.ts +9 -0
  42. package/dist/migrate/prover/index.js +3 -0
  43. package/dist/migrate/reporter/index.d.ts +4 -0
  44. package/dist/migrate/reporter/index.js +1 -0
  45. package/dist/migrate/runtime-dependencies/index.d.ts +13 -0
  46. package/dist/migrate/runtime-dependencies/index.js +112 -0
  47. package/dist/migrate/state-contract/index.d.ts +13 -0
  48. package/dist/migrate/state-contract/index.js +49 -0
  49. package/dist/migrate/types/index.d.ts +228 -0
  50. package/dist/migrate/types/index.js +1 -0
  51. package/dist/migrate/ui-wiring/index.d.ts +18 -0
  52. package/dist/migrate/ui-wiring/index.js +2 -0
  53. package/dist/migrate/util.d.ts +5 -0
  54. package/dist/migrate/util.js +10 -0
  55. package/dist/react/index.d.ts +7 -0
  56. package/dist/react/index.d.ts.map +1 -0
  57. package/dist/react/index.js +6 -0
  58. package/dist/react/useCapability.d.ts +11 -0
  59. package/dist/react/useCapability.d.ts.map +1 -0
  60. package/dist/react/useCapability.js +30 -0
  61. package/dist/react/useCollection.d.ts +17 -0
  62. package/dist/react/useCollection.d.ts.map +1 -0
  63. package/dist/react/useCollection.js +69 -0
  64. package/dist/react/useFeltDB.d.ts +136 -0
  65. package/dist/react/useFeltDB.d.ts.map +1 -0
  66. package/dist/react/useFeltDB.js +350 -0
  67. package/dist/studio/.gitkeep +1 -0
  68. package/dist/studio/KeyManagementPanel-BOvWTRyH.js +246 -0
  69. package/dist/studio/app.d.ts +10 -0
  70. package/dist/studio/app.d.ts.map +1 -0
  71. package/dist/studio/components/AgentExplorer.d.ts +9 -0
  72. package/dist/studio/components/AgentExplorer.d.ts.map +1 -0
  73. package/dist/studio/components/ApplicationDesigner.d.ts +11 -0
  74. package/dist/studio/components/ApplicationDesigner.d.ts.map +1 -0
  75. package/dist/studio/components/CapabilityExplorer.d.ts +9 -0
  76. package/dist/studio/components/CapabilityExplorer.d.ts.map +1 -0
  77. package/dist/studio/components/ConflictExplorer.d.ts +9 -0
  78. package/dist/studio/components/ConflictExplorer.d.ts.map +1 -0
  79. package/dist/studio/components/ExecutionViewer.d.ts +9 -0
  80. package/dist/studio/components/ExecutionViewer.d.ts.map +1 -0
  81. package/dist/studio/components/GlobalSearch.d.ts +10 -0
  82. package/dist/studio/components/GlobalSearch.d.ts.map +1 -0
  83. package/dist/studio/components/HealthCenter.d.ts +9 -0
  84. package/dist/studio/components/HealthCenter.d.ts.map +1 -0
  85. package/dist/studio/components/KeyManagementPanel.d.ts +9 -0
  86. package/dist/studio/components/KeyManagementPanel.d.ts.map +1 -0
  87. package/dist/studio/components/KeyManagementPanel.js +2 -0
  88. package/dist/studio/components/ManagedInstancePanel.d.ts +4 -0
  89. package/dist/studio/components/ManagedInstancePanel.d.ts.map +1 -0
  90. package/dist/studio/components/ManagedInstancePanel.js +281 -0
  91. package/dist/studio/components/OperationsExplorer.d.ts +10 -0
  92. package/dist/studio/components/OperationsExplorer.d.ts.map +1 -0
  93. package/dist/studio/components/OverviewDashboard.d.ts +8 -0
  94. package/dist/studio/components/OverviewDashboard.d.ts.map +1 -0
  95. package/dist/studio/components/PeerMap.d.ts +8 -0
  96. package/dist/studio/components/PeerMap.d.ts.map +1 -0
  97. package/dist/studio/components/ProvenanceViewer.d.ts +11 -0
  98. package/dist/studio/components/ProvenanceViewer.d.ts.map +1 -0
  99. package/dist/studio/components/ReferenceExplorer.d.ts +10 -0
  100. package/dist/studio/components/ReferenceExplorer.d.ts.map +1 -0
  101. package/dist/studio/components/SettingsPanel.d.ts +7 -0
  102. package/dist/studio/components/SettingsPanel.d.ts.map +1 -0
  103. package/dist/studio/components/StateExplorer.d.ts +10 -0
  104. package/dist/studio/components/StateExplorer.d.ts.map +1 -0
  105. package/dist/studio/components/WorkflowVisualizer.d.ts +9 -0
  106. package/dist/studio/components/WorkflowVisualizer.d.ts.map +1 -0
  107. package/dist/studio/components/index.d.ts +24 -0
  108. package/dist/studio/components/index.d.ts.map +1 -0
  109. package/dist/studio/components/index.js +4 -0
  110. package/dist/studio/components-BRYUceo9.js +1711 -0
  111. package/dist/studio/hooks/index.d.ts +37 -0
  112. package/dist/studio/hooks/index.d.ts.map +1 -0
  113. package/dist/studio/index.d.ts +27 -0
  114. package/dist/studio/index.d.ts.map +1 -0
  115. package/dist/studio/index.html +30 -0
  116. package/dist/studio/index.js +236 -0
  117. package/dist/studio/main.d.ts +1 -0
  118. package/dist/studio/main.d.ts.map +1 -0
  119. package/dist/studio/studio.css +2 -0
  120. package/dist/studio/types/index.d.ts +133 -0
  121. package/dist/studio/types/index.d.ts.map +1 -0
  122. package/dist/studio/utils/api.d.ts +27 -0
  123. package/dist/studio/utils/api.d.ts.map +1 -0
  124. package/dist/studio/utils/format.d.ts +24 -0
  125. package/dist/studio/utils/format.d.ts.map +1 -0
  126. package/dist/studio/utils/index.d.ts +7 -0
  127. package/dist/studio/utils/index.d.ts.map +1 -0
  128. package/dist/studio/utils/index.js +75 -0
  129. package/dist/studio/utils/managed-instance.d.ts +40 -0
  130. package/dist/studio/utils/managed-instance.d.ts.map +1 -0
  131. package/dist/studio/utils/managed-instance.js +51 -0
  132. package/dist/studio-app/.gitkeep +1 -0
  133. package/dist/studio-app/assets/feltdb_wasm-BXMn9UxO.js +1 -0
  134. package/dist/studio-app/assets/feltdb_wasm_bg-bYYbZeRM.wasm +0 -0
  135. package/dist/studio-app/assets/index-B-lZjdtI.js +28 -0
  136. package/dist/studio-app/assets/index-CB-Eed9V.css +1 -0
  137. package/dist/studio-app/index.html +3 -0
  138. package/dist/wasm/feltdb_wasm.d.ts +461 -0
  139. package/dist/wasm/feltdb_wasm.js +1690 -0
  140. package/dist/wasm/feltdb_wasm_bg.wasm +0 -0
  141. package/dist/wasm/feltdb_wasm_bg.wasm.d.ts +84 -0
  142. package/dist/wasm/package.json +16 -0
  143. package/package.json +40 -5
@@ -0,0 +1,638 @@
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
+ typescript: '^5.0.0',
57
+ '@types/node': '^20.0.0',
58
+ vite: '^8.2.1',
59
+ },
60
+ };
61
+ if (framework === 'react') {
62
+ packageJson.dependencies['react'] = '^18.0.0';
63
+ packageJson.dependencies['react-dom'] = '^18.0.0';
64
+ packageJson.devDependencies['@types/react'] = '^18.0.0';
65
+ packageJson.devDependencies['@types/react-dom'] = '^18.0.0';
66
+ }
67
+ if (hasAgents) {
68
+ packageJson.dependencies['@feltdb/webllm'] = feltdbPackageRange;
69
+ }
70
+ fs.writeFileSync(path.join(projectDir, 'package.json'), JSON.stringify(packageJson, null, 2));
71
+ // Create feltdb.config.json
72
+ const feltdbConfig = {
73
+ namespace: applicationName,
74
+ runtime,
75
+ storage: runtime === 'browser' ? 'opfs' : 'durable',
76
+ distributed,
77
+ agents: {
78
+ enabled: hasAgents,
79
+ },
80
+ capabilities: {},
81
+ };
82
+ if (capabilities.includes('search')) {
83
+ feltdbConfig.capabilities.search = true;
84
+ }
85
+ if (capabilities.includes('vector')) {
86
+ feltdbConfig.capabilities['vector-search'] = true;
87
+ }
88
+ fs.writeFileSync(path.join(projectDir, 'feltdb.config.json'), JSON.stringify(feltdbConfig, null, 2));
89
+ const appName = applicationName.replace(/[^A-Za-z0-9_]/g, '_').replace(/^[^A-Za-z_]/, 'App_');
90
+ const flowSpec = `app ${appName} {
91
+ collection Document {
92
+ title: text
93
+ content: text
94
+ createdAt: datetime
95
+ index search using fulltext(content)
96
+ }
97
+
98
+ collection Report {
99
+ title: text
100
+ content: text
101
+ document: ref Document
102
+ }
103
+
104
+ capability Research {
105
+ read Document
106
+ write Report
107
+ }
108
+
109
+ agent Researcher {
110
+ capability Research
111
+ workflow ResearchDocument
112
+ }
113
+
114
+ workflow ResearchDocument(document: Document) {
115
+ step search {
116
+ input document.content
117
+ }
118
+ step identity {
119
+ input search.output
120
+ }
121
+ }
122
+
123
+ trigger on Document.created {
124
+ workflow ResearchDocument(document)
125
+ }
126
+
127
+ policy Document {
128
+ read: authenticated
129
+ write: authenticated
130
+ }
131
+ }
132
+ `;
133
+ fs.writeFileSync(path.join(projectDir, 'feltdb.flow'), flowSpec);
134
+ // Create tsconfig.json
135
+ const tsconfig = {
136
+ compilerOptions: {
137
+ target: 'ES2020',
138
+ module: 'ESNext',
139
+ lib: ['ES2020', 'DOM'],
140
+ declaration: true,
141
+ outDir: './dist',
142
+ rootDir: './src',
143
+ strict: true,
144
+ esModuleInterop: true,
145
+ skipLibCheck: true,
146
+ forceConsistentCasingInFileNames: true,
147
+ moduleResolution: 'node',
148
+ },
149
+ include: ['src/**/*'],
150
+ exclude: ['node_modules'],
151
+ };
152
+ if (framework === 'react') {
153
+ tsconfig.compilerOptions.jsx = 'react-jsx';
154
+ }
155
+ fs.writeFileSync(path.join(projectDir, 'tsconfig.json'), JSON.stringify(tsconfig, null, 2));
156
+ // Create main application files
157
+ const runtimeOptions = runtime === 'browser'
158
+ ? "{ namespace: '" + applicationName + "', browser: true }"
159
+ : runtime === 'self-hosted'
160
+ ? "{ namespace: '" + applicationName + "', server: { url: import.meta.env.VITE_FELTDB_URL || 'http://localhost:7700', token: import.meta.env.VITE_FELTDB_API_KEY || '' } }"
161
+ : "{ namespace: '" + applicationName + "', memory: true }";
162
+ const feltdbTs = `import { createFeltDB } from '@feltdb/core';
163
+
164
+ export const db = createFeltDB(${runtimeOptions});
165
+
166
+ // Collections
167
+ export const documents = db.collection('documents');
168
+ export const reports = db.collection('reports');
169
+ `;
170
+ fs.writeFileSync(path.join(srcDir, 'feltdb.ts'), feltdbTs);
171
+ // Create a real local-inference agent for browser projects.
172
+ if (hasAgents) {
173
+ const agentTs = `import { WebLLMProvider } from '@feltdb/webllm';
174
+ import { db, reports } from '../../src/feltdb';
175
+
176
+ /**
177
+ * Researcher metadata is registered in FeltDB; inference runs privately in
178
+ * the browser through WebLLM and its worker.
179
+ */
180
+ export const researcher = db.defineAgent({
181
+ name: 'researcher',
182
+ version: 1,
183
+ description: 'Analyze documents with private, on-device inference',
184
+ capabilities: [
185
+ 'document-read',
186
+ 'report-write'
187
+ ],
188
+ goals: ['Summarize documents without sending prompts off-device'],
189
+ constraints: { maxIterations: 1 },
190
+ });
191
+
192
+ let provider: WebLLMProvider | undefined;
193
+
194
+ export async function runResearcher(
195
+ prompt: string,
196
+ onProgress?: (message: string) => void,
197
+ ) {
198
+ provider ??= new WebLLMProvider({
199
+ onProgress: ({ progress, text }) =>
200
+ onProgress?.(\`${'${Math.round(progress * 100)}'}% ${'${text}'}\`),
201
+ });
202
+ const content = await provider.generate([
203
+ { role: 'system', content: 'You are a concise research assistant. Keep all reasoning local.' },
204
+ { role: 'user', content: prompt },
205
+ ]);
206
+ await reports.insert({
207
+ title: prompt.slice(0, 80) || 'Local research',
208
+ content,
209
+ createdAt: new Date(),
210
+ });
211
+ return content;
212
+ }
213
+ `;
214
+ fs.writeFileSync(path.join(feltdbDir, 'agents', 'researcher.ts'), agentTs);
215
+ }
216
+ // Create capabilities index
217
+ const capabilitiesTs = `/**
218
+ * Capabilities
219
+ *
220
+ * Define capabilities that can be executed by agents
221
+ * across distributed peers
222
+ */
223
+
224
+ export const capabilities = {
225
+ 'document-read': {
226
+ enabled: true,
227
+ scope: ['documents:read'],
228
+ },
229
+ 'vector-search': {
230
+ enabled: ${capabilities.includes('vector')},
231
+ scope: ['documents:read', 'capabilities:execute'],
232
+ },
233
+ 'report-write': {
234
+ enabled: true,
235
+ scope: ['reports:write'],
236
+ },
237
+ };
238
+ `;
239
+ fs.writeFileSync(path.join(feltdbDir, 'capabilities', 'index.ts'), capabilitiesTs);
240
+ // Create main application file based on framework
241
+ if (framework === 'react') {
242
+ const agentImport = hasAgents
243
+ ? "import { runResearcher } from '../feltdb/agents/researcher';"
244
+ : '';
245
+ const agentState = hasAgents
246
+ ? ` const [prompt, setPrompt] = useState('Summarize why local-first applications are useful.');
247
+ const [answer, setAnswer] = useState('');
248
+ const [modelStatus, setModelStatus] = useState('Model not loaded');
249
+ const [generating, setGenerating] = useState(false);`
250
+ : '';
251
+ const agentHandler = hasAgents
252
+ ? `
253
+ const handleResearch = async () => {
254
+ setGenerating(true);
255
+ setAnswer('');
256
+ try {
257
+ setAnswer(await runResearcher(prompt, setModelStatus));
258
+ setModelStatus('Ready — inference stayed in this browser');
259
+ } catch (error) {
260
+ setModelStatus(error instanceof Error ? error.message : String(error));
261
+ } finally {
262
+ setGenerating(false);
263
+ }
264
+ };
265
+ `
266
+ : '';
267
+ const agentMarkup = hasAgents
268
+ ? `
269
+ <section className="researcher">
270
+ <h2>Private WebLLM Researcher</h2>
271
+ <p>{modelStatus}</p>
272
+ <textarea value={prompt} onChange={event => setPrompt(event.target.value)} rows={4} />
273
+ <button onClick={handleResearch} disabled={generating || !prompt.trim()}>
274
+ {generating ? 'Running locally…' : 'Run researcher'}
275
+ </button>
276
+ {answer && <article><h3>Result</h3><p>{answer}</p></article>}
277
+ </section>`
278
+ : '';
279
+ const appTsx = `import React, { useState, useEffect } from 'react';
280
+ import { db, documents } from './feltdb';
281
+ ${agentImport}
282
+
283
+ export function App() {
284
+ const [docs, setDocs] = useState<any[]>([]);
285
+ const [loading, setLoading] = useState(true);
286
+ ${agentState}
287
+
288
+ useEffect(() => {
289
+ const loadDocs = async () => {
290
+ try {
291
+ const allDocs = await documents.find({});
292
+ setDocs(allDocs);
293
+ } catch (err) {
294
+ console.error('Error loading documents:', err);
295
+ } finally {
296
+ setLoading(false);
297
+ }
298
+ };
299
+
300
+ loadDocs();
301
+ }, []);
302
+
303
+ const handleAddDocument = async () => {
304
+ try {
305
+ await documents.insert({
306
+ title: 'New Document',
307
+ content: 'Enter content here',
308
+ createdAt: new Date(),
309
+ });
310
+ // Reload documents
311
+ const allDocs = await documents.find({});
312
+ setDocs(allDocs);
313
+ } catch (err) {
314
+ console.error('Error adding document:', err);
315
+ }
316
+ };
317
+ ${agentHandler}
318
+
319
+ return (
320
+ <div className="app">
321
+ <header>
322
+ <h1>🌊 FeltDB Research App</h1>
323
+ <p>Distributed document management with agents and capabilities</p>
324
+ </header>
325
+
326
+ <main>
327
+ <section className="stats">
328
+ <div className="stat">
329
+ <span className="label">Documents:</span>
330
+ <span className="value">{docs.length}</span>
331
+ </div>
332
+ <div className="stat">
333
+ <span className="label">Runtime:</span>
334
+ <span className="value">${runtime}</span>
335
+ </div>
336
+ <div className="stat">
337
+ <span className="label">Distributed:</span>
338
+ <span className="value">${distributed ? '✓' : '✗'}</span>
339
+ </div>
340
+ </section>
341
+
342
+ <section className="documents">
343
+ <h2>Documents</h2>
344
+ {loading ? (
345
+ <p>Loading...</p>
346
+ ) : docs.length === 0 ? (
347
+ <p>No documents yet</p>
348
+ ) : (
349
+ <ul>
350
+ {docs.map((doc: any) => (
351
+ <li key={doc.id}>
352
+ <h3>{doc.title}</h3>
353
+ <p>{doc.content}</p>
354
+ </li>
355
+ ))}
356
+ </ul>
357
+ )}
358
+ <button onClick={handleAddDocument}>Add Document</button>
359
+ </section>
360
+ ${agentMarkup}
361
+ </main>
362
+
363
+ <style>{\`
364
+ body {
365
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto;
366
+ margin: 0;
367
+ padding: 0;
368
+ background: #f5f5f5;
369
+ }
370
+
371
+ .app {
372
+ max-width: 1200px;
373
+ margin: 0 auto;
374
+ padding: 20px;
375
+ }
376
+
377
+ header {
378
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
379
+ color: white;
380
+ padding: 30px;
381
+ border-radius: 8px;
382
+ margin-bottom: 30px;
383
+ }
384
+
385
+ header h1 {
386
+ margin: 0 0 10px 0;
387
+ font-size: 28px;
388
+ }
389
+
390
+ header p {
391
+ margin: 0;
392
+ opacity: 0.9;
393
+ }
394
+
395
+ main {
396
+ background: white;
397
+ padding: 20px;
398
+ border-radius: 8px;
399
+ box-shadow: 0 2px 8px rgba(0,0,0,0.1);
400
+ }
401
+
402
+ .stats {
403
+ display: grid;
404
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
405
+ gap: 20px;
406
+ margin-bottom: 30px;
407
+ }
408
+
409
+ .stat {
410
+ padding: 15px;
411
+ background: #f9f9f9;
412
+ border-radius: 4px;
413
+ border-left: 3px solid #667eea;
414
+ }
415
+
416
+ .stat .label {
417
+ display: block;
418
+ color: #666;
419
+ font-size: 12px;
420
+ text-transform: uppercase;
421
+ margin-bottom: 5px;
422
+ }
423
+
424
+ .stat .value {
425
+ display: block;
426
+ font-size: 24px;
427
+ font-weight: bold;
428
+ color: #333;
429
+ }
430
+
431
+ .documents h2 {
432
+ margin-top: 0;
433
+ }
434
+
435
+ .documents ul {
436
+ list-style: none;
437
+ padding: 0;
438
+ margin: 0 0 20px 0;
439
+ }
440
+
441
+ .documents li {
442
+ padding: 15px;
443
+ background: #f9f9f9;
444
+ border-radius: 4px;
445
+ margin-bottom: 10px;
446
+ }
447
+
448
+ .documents h3 {
449
+ margin: 0 0 10px 0;
450
+ color: #333;
451
+ }
452
+
453
+ .documents p {
454
+ margin: 0;
455
+ color: #666;
456
+ font-size: 14px;
457
+ }
458
+
459
+ button {
460
+ background: #667eea;
461
+ color: white;
462
+ border: none;
463
+ padding: 10px 20px;
464
+ border-radius: 4px;
465
+ cursor: pointer;
466
+ font-size: 14px;
467
+ font-weight: 500;
468
+ }
469
+
470
+ button:hover {
471
+ background: #5568d3;
472
+ }
473
+
474
+ textarea {
475
+ box-sizing: border-box;
476
+ display: block;
477
+ margin: 12px 0;
478
+ padding: 10px;
479
+ width: 100%;
480
+ }
481
+
482
+ .researcher {
483
+ border-top: 1px solid #eee;
484
+ margin-top: 30px;
485
+ padding-top: 20px;
486
+ }
487
+ \`}</style>
488
+ </div>
489
+ );
490
+ }
491
+ `;
492
+ fs.writeFileSync(path.join(srcDir, 'App.tsx'), appTsx);
493
+ const indexTsx = `import React from 'react';
494
+ import ReactDOM from 'react-dom/client';
495
+ import { App } from './App';
496
+
497
+ const root = ReactDOM.createRoot(document.getElementById('root')!);
498
+ root.render(
499
+ <React.StrictMode>
500
+ <App />
501
+ </React.StrictMode>
502
+ );
503
+ `;
504
+ fs.writeFileSync(path.join(srcDir, 'index.tsx'), indexTsx);
505
+ }
506
+ else {
507
+ // Create vanilla JS app
508
+ const indexJs = `import { db, documents } from './feltdb';
509
+
510
+ async function main() {
511
+ console.log('🌊 FeltDB Research App');
512
+ console.log('Runtime: ${runtime}');
513
+ console.log('Distributed: ${distributed}');
514
+ }
515
+
516
+ main().catch(console.error);
517
+ `;
518
+ fs.writeFileSync(path.join(srcDir, 'index.js'), indexJs);
519
+ }
520
+ // Create index.html
521
+ const indexHtml = `<!DOCTYPE html>
522
+ <html lang="en">
523
+ <head>
524
+ <meta charset="UTF-8">
525
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
526
+ <title>${applicationName}</title>
527
+ </head>
528
+ <body>
529
+ <div id="root"></div>
530
+ <script type="module" src="/src/index${framework === 'react' ? '.tsx' : '.js'}"></script>
531
+ </body>
532
+ </html>
533
+ `;
534
+ fs.writeFileSync(path.join(projectDir, 'index.html'), indexHtml);
535
+ // Create .env.example
536
+ const envExample = `# FeltDB Configuration
537
+ VITE_FELTDB_API_KEY=
538
+ VITE_FELTDB_URL=http://localhost:7700
539
+ # Override the versioned self-hosted container when needed:
540
+ FELTDB_IMAGE=
541
+ NODE_ENV=development
542
+ `;
543
+ fs.writeFileSync(path.join(projectDir, '.env.example'), envExample);
544
+ // Create .gitignore
545
+ const gitignore = `node_modules/
546
+ dist/
547
+ build/
548
+ .env
549
+ .env.local
550
+ .env.*.local
551
+ *.log
552
+ .DS_Store
553
+ .feltdb/keys.json
554
+ .feltdb/connection.json
555
+ `;
556
+ fs.writeFileSync(path.join(projectDir, '.gitignore'), gitignore);
557
+ // Create README
558
+ const readme = `# ${applicationName}
559
+
560
+ A FeltDB distributed application with agents and capabilities.
561
+
562
+ ## Quick Start
563
+
564
+ \`\`\`bash
565
+ npm install
566
+ npm run dev
567
+ \`\`\`
568
+
569
+ ## Project Structure
570
+
571
+ \`\`\`
572
+ ${applicationName}/
573
+ ├── feltdb/
574
+ │ ├── agents/ # Agent definitions
575
+ │ ├── capabilities/ # Capability implementations
576
+ │ ├── workflows/ # Workflow definitions
577
+ │ └── schema/ # Data schemas
578
+ ├── src/
579
+ │ ├── App.${framework === 'react' ? 'tsx' : 'js'}
580
+ │ ├── feltdb.ts
581
+ │ └── index.${framework === 'react' ? 'tsx' : 'js'}
582
+ ├── public/
583
+ ├── index.html
584
+ ├── .feltdb/ # Local FeltDB configuration
585
+ ├── feltdb.config.json
586
+ ├── .env.example
587
+ ├── package.json
588
+ ├── tsconfig.json
589
+ └── README.md
590
+ \`\`\`
591
+
592
+ ## Configuration
593
+
594
+ Configuration is in \`feltdb.config.json\`:
595
+ - \`runtime\`: ${runtime} (browser|node|self-hosted)
596
+ - \`storage\`: ${runtime === 'browser' ? 'opfs' : 'durable'}
597
+ - \`distributed\`: ${distributed}
598
+ - \`agents.enabled\`: ${hasAgents}
599
+ - \`capabilities\`: ${capabilities}
600
+
601
+ ## Development
602
+
603
+ ### Start Development Server
604
+ \`\`\`bash
605
+ npm run dev
606
+ \`\`\`
607
+
608
+ ### Build for Production
609
+ \`\`\`bash
610
+ npm run build
611
+ \`\`\`
612
+
613
+ ### Connect to Remote Server
614
+ \`\`\`bash
615
+ feltdb connect http://localhost:7700
616
+ \`\`\`
617
+
618
+ ### Create API Key
619
+ \`\`\`bash
620
+ feltdb keys create --name development --scope '*'
621
+ \`\`\`
622
+
623
+ ## Agents
624
+
625
+ ${hasAgents ? `The \`researcher\` agent runs real private inference with
626
+ \`@feltdb/webllm\`. The model downloads on first use, runs in a Web Worker, and
627
+ caches its artifacts in the browser. Generated reports are stored in FeltDB.` : 'No agents configured'}
628
+
629
+ ## Capabilities
630
+
631
+ ${capabilities}
632
+
633
+ ## Learn More
634
+
635
+ Visit [FeltDB Documentation](https://github.com/rkendel1/feltdb) to learn more.
636
+ `;
637
+ fs.writeFileSync(path.join(projectDir, 'README.md'), readme);
638
+ }