@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.
- package/README.md +22 -0
- package/bin/create-feltdb.js +3 -0
- package/bin/feltdb.js +3 -0
- package/dist/analytics-backend.js +1 -1
- package/dist/cli/api-client.js +236 -0
- package/dist/cli/cli.js +18 -0
- package/dist/cli/commands.js +795 -0
- package/dist/cli/config.js +66 -0
- package/dist/cli/index.js +399 -0
- package/dist/create/application-identity.js +132 -0
- package/dist/create/cli-scripts-generator.js +211 -0
- package/dist/create/cli.js +202 -0
- package/dist/create/create.js +638 -0
- package/dist/create/docker-compose-generator.js +258 -0
- package/dist/create/index.js +4 -0
- package/dist/create/package-versions.js +4 -0
- package/dist/create/runtime-templates.js +272 -0
- package/dist/index-backend.js +1 -1
- package/dist/migrate/analyzer/index.d.ts +2 -0
- package/dist/migrate/analyzer/index.js +34 -0
- package/dist/migrate/benchmark/index.d.ts +13 -0
- package/dist/migrate/benchmark/index.js +8 -0
- package/dist/migrate/capability-gate/index.d.ts +3 -0
- package/dist/migrate/capability-gate/index.js +3 -0
- package/dist/migrate/classifier/index.d.ts +3 -0
- package/dist/migrate/classifier/index.js +53 -0
- package/dist/migrate/cli/index.d.ts +2 -0
- package/dist/migrate/cli/index.js +201 -0
- package/dist/migrate/domain-model/index.d.ts +2 -0
- package/dist/migrate/domain-model/index.js +4 -0
- package/dist/migrate/generator/index.d.ts +2 -0
- package/dist/migrate/generator/index.js +21 -0
- package/dist/migrate/index.d.ts +16 -0
- package/dist/migrate/index.js +16 -0
- package/dist/migrate/measurement/index.d.ts +7 -0
- package/dist/migrate/measurement/index.js +1 -0
- package/dist/migrate/migrator/index.d.ts +2 -0
- package/dist/migrate/migrator/index.js +35 -0
- package/dist/migrate/planner/index.d.ts +2 -0
- package/dist/migrate/planner/index.js +12 -0
- package/dist/migrate/prover/index.d.ts +9 -0
- package/dist/migrate/prover/index.js +3 -0
- package/dist/migrate/reporter/index.d.ts +4 -0
- package/dist/migrate/reporter/index.js +1 -0
- package/dist/migrate/runtime-dependencies/index.d.ts +13 -0
- package/dist/migrate/runtime-dependencies/index.js +112 -0
- package/dist/migrate/state-contract/index.d.ts +13 -0
- package/dist/migrate/state-contract/index.js +49 -0
- package/dist/migrate/types/index.d.ts +228 -0
- package/dist/migrate/types/index.js +1 -0
- package/dist/migrate/ui-wiring/index.d.ts +18 -0
- package/dist/migrate/ui-wiring/index.js +2 -0
- package/dist/migrate/util.d.ts +5 -0
- package/dist/migrate/util.js +10 -0
- package/dist/react/index.d.ts +7 -0
- package/dist/react/index.d.ts.map +1 -0
- package/dist/react/index.js +6 -0
- package/dist/react/useCapability.d.ts +11 -0
- package/dist/react/useCapability.d.ts.map +1 -0
- package/dist/react/useCapability.js +30 -0
- package/dist/react/useCollection.d.ts +17 -0
- package/dist/react/useCollection.d.ts.map +1 -0
- package/dist/react/useCollection.js +69 -0
- package/dist/react/useFeltDB.d.ts +136 -0
- package/dist/react/useFeltDB.d.ts.map +1 -0
- package/dist/react/useFeltDB.js +350 -0
- package/dist/studio/.gitkeep +1 -0
- package/dist/studio/KeyManagementPanel-BOvWTRyH.js +246 -0
- package/dist/studio/app.d.ts +10 -0
- package/dist/studio/app.d.ts.map +1 -0
- package/dist/studio/components/AgentExplorer.d.ts +9 -0
- package/dist/studio/components/AgentExplorer.d.ts.map +1 -0
- package/dist/studio/components/ApplicationDesigner.d.ts +11 -0
- package/dist/studio/components/ApplicationDesigner.d.ts.map +1 -0
- package/dist/studio/components/CapabilityExplorer.d.ts +9 -0
- package/dist/studio/components/CapabilityExplorer.d.ts.map +1 -0
- package/dist/studio/components/ConflictExplorer.d.ts +9 -0
- package/dist/studio/components/ConflictExplorer.d.ts.map +1 -0
- package/dist/studio/components/ExecutionViewer.d.ts +9 -0
- package/dist/studio/components/ExecutionViewer.d.ts.map +1 -0
- package/dist/studio/components/GlobalSearch.d.ts +10 -0
- package/dist/studio/components/GlobalSearch.d.ts.map +1 -0
- package/dist/studio/components/HealthCenter.d.ts +9 -0
- package/dist/studio/components/HealthCenter.d.ts.map +1 -0
- package/dist/studio/components/KeyManagementPanel.d.ts +9 -0
- package/dist/studio/components/KeyManagementPanel.d.ts.map +1 -0
- package/dist/studio/components/KeyManagementPanel.js +2 -0
- package/dist/studio/components/ManagedInstancePanel.d.ts +4 -0
- package/dist/studio/components/ManagedInstancePanel.d.ts.map +1 -0
- package/dist/studio/components/ManagedInstancePanel.js +281 -0
- package/dist/studio/components/OperationsExplorer.d.ts +10 -0
- package/dist/studio/components/OperationsExplorer.d.ts.map +1 -0
- package/dist/studio/components/OverviewDashboard.d.ts +8 -0
- package/dist/studio/components/OverviewDashboard.d.ts.map +1 -0
- package/dist/studio/components/PeerMap.d.ts +8 -0
- package/dist/studio/components/PeerMap.d.ts.map +1 -0
- package/dist/studio/components/ProvenanceViewer.d.ts +11 -0
- package/dist/studio/components/ProvenanceViewer.d.ts.map +1 -0
- package/dist/studio/components/ReferenceExplorer.d.ts +10 -0
- package/dist/studio/components/ReferenceExplorer.d.ts.map +1 -0
- package/dist/studio/components/SettingsPanel.d.ts +7 -0
- package/dist/studio/components/SettingsPanel.d.ts.map +1 -0
- package/dist/studio/components/StateExplorer.d.ts +10 -0
- package/dist/studio/components/StateExplorer.d.ts.map +1 -0
- package/dist/studio/components/WorkflowVisualizer.d.ts +9 -0
- package/dist/studio/components/WorkflowVisualizer.d.ts.map +1 -0
- package/dist/studio/components/index.d.ts +24 -0
- package/dist/studio/components/index.d.ts.map +1 -0
- package/dist/studio/components/index.js +4 -0
- package/dist/studio/components-BRYUceo9.js +1711 -0
- package/dist/studio/hooks/index.d.ts +37 -0
- package/dist/studio/hooks/index.d.ts.map +1 -0
- package/dist/studio/index.d.ts +27 -0
- package/dist/studio/index.d.ts.map +1 -0
- package/dist/studio/index.html +30 -0
- package/dist/studio/index.js +236 -0
- package/dist/studio/main.d.ts +1 -0
- package/dist/studio/main.d.ts.map +1 -0
- package/dist/studio/studio.css +2 -0
- package/dist/studio/types/index.d.ts +133 -0
- package/dist/studio/types/index.d.ts.map +1 -0
- package/dist/studio/utils/api.d.ts +27 -0
- package/dist/studio/utils/api.d.ts.map +1 -0
- package/dist/studio/utils/format.d.ts +24 -0
- package/dist/studio/utils/format.d.ts.map +1 -0
- package/dist/studio/utils/index.d.ts +7 -0
- package/dist/studio/utils/index.d.ts.map +1 -0
- package/dist/studio/utils/index.js +75 -0
- package/dist/studio/utils/managed-instance.d.ts +40 -0
- package/dist/studio/utils/managed-instance.d.ts.map +1 -0
- package/dist/studio/utils/managed-instance.js +51 -0
- package/dist/studio-app/.gitkeep +1 -0
- package/dist/studio-app/assets/feltdb_wasm-BXMn9UxO.js +1 -0
- package/dist/studio-app/assets/feltdb_wasm_bg-bYYbZeRM.wasm +0 -0
- package/dist/studio-app/assets/index-B-lZjdtI.js +28 -0
- package/dist/studio-app/assets/index-CB-Eed9V.css +1 -0
- package/dist/studio-app/index.html +3 -0
- package/dist/wasm/feltdb_wasm.d.ts +461 -0
- package/dist/wasm/feltdb_wasm.js +1690 -0
- package/dist/wasm/feltdb_wasm_bg.wasm +0 -0
- package/dist/wasm/feltdb_wasm_bg.wasm.d.ts +84 -0
- package/dist/wasm/package.json +16 -0
- 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
|
+
}
|