modular-studio 1.0.4 → 1.0.5
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 +101 -20
- package/dist/assets/Badge-22Ai0eyi.js +1 -0
- package/dist/assets/Input-Bgp734xs.js +1 -0
- package/dist/assets/KnowledgeTab-DABxirZh.js +4 -0
- package/dist/assets/MemoryTab-DZeYElIT.js +16 -0
- package/dist/assets/QualificationTab-Dfpy3J30.js +1 -0
- package/dist/assets/ReviewTab-SD8lQuCc.js +103 -0
- package/dist/assets/Section-DoJrmytO.js +1 -0
- package/dist/assets/TestTab-PDyMF8Fw.js +33 -0
- package/dist/assets/ToolsTab-B83qGCmG.js +1 -0
- package/dist/assets/conversationStore-CkfEU2eV.js +1 -0
- package/dist/assets/icons-C2EV-le6.js +1 -0
- package/dist/assets/index-DkpMAxX7.css +1 -0
- package/dist/assets/index-q24ug5Qs.js +143 -0
- package/dist/assets/{jszip.min-BK6ZQWkj.js → jszip.min-wf-D3Ix_.js} +1 -1
- package/dist/assets/markdown-DWF7F0i0.js +29 -0
- package/dist/assets/services-BaKotDf0.js +343 -0
- package/dist/assets/stores-CeKWz7ou.js +1 -0
- package/dist/assets/vendor-D1h_O76p.js +9 -0
- package/dist/index.html +8 -4
- package/dist-server/bin/modular-mcp.js +0 -1
- package/dist-server/bin/modular-studio.js +0 -1
- package/dist-server/server/config.js +0 -1
- package/dist-server/server/data/mcp-tokens.json +3 -3
- package/dist-server/server/index.d.ts.map +1 -1
- package/dist-server/server/index.js +2 -1
- package/dist-server/server/mcp/manager.js +0 -1
- package/dist-server/server/mcp/modular-server.js +0 -1
- package/dist-server/server/mcp/transport.js +0 -1
- package/dist-server/server/routes/agent-sdk.js +0 -1
- package/dist-server/server/routes/agents.d.ts +9 -5
- package/dist-server/server/routes/agents.d.ts.map +1 -1
- package/dist-server/server/routes/agents.js +81 -8
- package/dist-server/server/routes/auth-codex.js +0 -1
- package/dist-server/server/routes/capabilities.js +0 -1
- package/dist-server/server/routes/claude-config.js +0 -1
- package/dist-server/server/routes/connectors.d.ts.map +1 -1
- package/dist-server/server/routes/connectors.js +194 -1
- package/dist-server/server/routes/conversations.js +0 -1
- package/dist-server/server/routes/embeddings.js +0 -1
- package/dist-server/server/routes/health.js +0 -1
- package/dist-server/server/routes/knowledge.js +0 -1
- package/dist-server/server/routes/llm.js +0 -1
- package/dist-server/server/routes/mcp-oauth.js +0 -1
- package/dist-server/server/routes/mcp.js +0 -1
- package/dist-server/server/routes/memory.d.ts +3 -0
- package/dist-server/server/routes/memory.d.ts.map +1 -0
- package/dist-server/server/routes/memory.js +283 -0
- package/dist-server/server/routes/pipeline.js +0 -1
- package/dist-server/server/routes/providers.js +0 -1
- package/dist-server/server/routes/qualification.d.ts.map +1 -1
- package/dist-server/server/routes/qualification.js +382 -74
- package/dist-server/server/routes/repo-index.js +0 -1
- package/dist-server/server/routes/runtime.js +0 -1
- package/dist-server/server/routes/skills-search.d.ts.map +1 -1
- package/dist-server/server/routes/skills-search.js +39 -5
- package/dist-server/server/routes/worktrees.js +0 -1
- package/dist-server/server/services/__tests__/embeddingService.test.js +0 -1
- package/dist-server/server/services/adapters/postgresAdapter.d.ts +29 -0
- package/dist-server/server/services/adapters/postgresAdapter.d.ts.map +1 -0
- package/dist-server/server/services/adapters/postgresAdapter.js +224 -0
- package/dist-server/server/services/adapters/sqliteAdapter.d.ts +28 -0
- package/dist-server/server/services/adapters/sqliteAdapter.d.ts.map +1 -0
- package/dist-server/server/services/adapters/sqliteAdapter.js +219 -0
- package/dist-server/server/services/adapters/storageAdapter.d.ts +22 -0
- package/dist-server/server/services/adapters/storageAdapter.d.ts.map +1 -0
- package/dist-server/server/services/adapters/storageAdapter.js +1 -0
- package/dist-server/server/services/agentRunner.js +0 -1
- package/dist-server/server/services/agentStore.d.ts +18 -3
- package/dist-server/server/services/agentStore.d.ts.map +1 -1
- package/dist-server/server/services/agentStore.js +116 -23
- package/dist-server/server/services/contentStore.js +0 -1
- package/dist-server/server/services/embeddingService.d.ts +2 -0
- package/dist-server/server/services/embeddingService.d.ts.map +1 -1
- package/dist-server/server/services/embeddingService.js +30 -19
- package/dist-server/server/services/factExtractor.js +0 -1
- package/dist-server/server/services/githubIndexer.js +0 -1
- package/dist-server/server/services/mcpOAuth.js +0 -1
- package/dist-server/server/services/memoryScorer.js +0 -1
- package/dist-server/server/services/repoIndexer.js +0 -1
- package/dist-server/server/services/sqliteStore.js +0 -1
- package/dist-server/server/services/teamRunner.js +0 -1
- package/dist-server/server/services/worktreeManager.js +0 -1
- package/dist-server/server/types.d.ts +5 -0
- package/dist-server/server/types.d.ts.map +1 -1
- package/dist-server/server/types.js +0 -1
- package/dist-server/server/utils/pathSecurity.js +0 -1
- package/dist-server/src/services/budgetAllocator.js +0 -1
- package/dist-server/src/services/contradictionDetector.js +0 -1
- package/dist-server/src/services/treeIndexer.js +0 -1
- package/dist-server/src/store/knowledgeBase.d.ts +10 -0
- package/dist-server/src/store/knowledgeBase.d.ts.map +1 -1
- package/dist-server/src/store/knowledgeBase.js +13 -1
- package/dist-server/src/store/memoryStore.d.ts +107 -0
- package/dist-server/src/store/memoryStore.d.ts.map +1 -0
- package/dist-server/src/store/memoryStore.js +263 -0
- package/dist-server/tsconfig.server.tsbuildinfo +1 -1
- package/package.json +104 -97
- package/dist/assets/graphPopulator-B3rQxb5A.js +0 -1
- package/dist/assets/index-BA_J-aHx.js +0 -686
- package/dist/assets/index-C7vpqKVZ.css +0 -1
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
import { Router } from 'express';
|
|
2
|
+
import { SqliteAdapter } from '../services/adapters/sqliteAdapter.js';
|
|
3
|
+
import { PostgresAdapter } from '../services/adapters/postgresAdapter.js';
|
|
4
|
+
import { extractFacts, extractFactsWithLlm } from '../services/factExtractor.js';
|
|
5
|
+
import { rankFacts } from '../services/memoryScorer.js';
|
|
6
|
+
import { readConfig, writeConfig } from '../config.js';
|
|
7
|
+
const router = Router();
|
|
8
|
+
// Global state for the current adapter
|
|
9
|
+
let currentAdapter = null;
|
|
10
|
+
let currentBackend = 'local_sqlite';
|
|
11
|
+
let connectionString = null;
|
|
12
|
+
async function getAdapter() {
|
|
13
|
+
if (!currentAdapter) {
|
|
14
|
+
const config = readConfig();
|
|
15
|
+
const memoryConfig = config.memory || { backend: 'local_sqlite' };
|
|
16
|
+
currentBackend = memoryConfig.backend || 'local_sqlite';
|
|
17
|
+
connectionString = memoryConfig.connectionString || null;
|
|
18
|
+
if (currentBackend === 'postgres' && connectionString) {
|
|
19
|
+
currentAdapter = new PostgresAdapter(connectionString);
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
currentAdapter = new SqliteAdapter();
|
|
23
|
+
}
|
|
24
|
+
await currentAdapter.initialize();
|
|
25
|
+
}
|
|
26
|
+
return currentAdapter;
|
|
27
|
+
}
|
|
28
|
+
async function switchAdapter(backend, connStr) {
|
|
29
|
+
if (currentAdapter) {
|
|
30
|
+
await currentAdapter.close();
|
|
31
|
+
currentAdapter = null;
|
|
32
|
+
}
|
|
33
|
+
currentBackend = backend;
|
|
34
|
+
connectionString = connStr || null;
|
|
35
|
+
if (backend === 'postgres' && connStr) {
|
|
36
|
+
currentAdapter = new PostgresAdapter(connStr);
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
currentAdapter = new SqliteAdapter();
|
|
40
|
+
}
|
|
41
|
+
await currentAdapter.initialize();
|
|
42
|
+
// Save config
|
|
43
|
+
const config = readConfig();
|
|
44
|
+
config.memory = {
|
|
45
|
+
...config.memory,
|
|
46
|
+
backend,
|
|
47
|
+
...(connStr && { connectionString: connStr })
|
|
48
|
+
};
|
|
49
|
+
writeConfig(config);
|
|
50
|
+
}
|
|
51
|
+
// GET /api/memory/facts - list facts (with pagination, domain filter)
|
|
52
|
+
router.get('/facts', async (req, res) => {
|
|
53
|
+
try {
|
|
54
|
+
const { domain, limit, offset } = req.query;
|
|
55
|
+
const adapter = await getAdapter();
|
|
56
|
+
const options = {};
|
|
57
|
+
if (domain)
|
|
58
|
+
options.domain = domain;
|
|
59
|
+
if (limit)
|
|
60
|
+
options.limit = parseInt(limit);
|
|
61
|
+
if (offset)
|
|
62
|
+
options.offset = parseInt(offset);
|
|
63
|
+
const facts = await adapter.getFacts(options);
|
|
64
|
+
res.json({ status: 'success', facts });
|
|
65
|
+
}
|
|
66
|
+
catch (error) {
|
|
67
|
+
console.error('[Memory] Failed to get facts:', error);
|
|
68
|
+
res.status(500).json({
|
|
69
|
+
status: 'error',
|
|
70
|
+
error: error instanceof Error ? error.message : 'Unknown error'
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
// POST /api/memory/facts - create fact
|
|
75
|
+
router.post('/facts', async (req, res) => {
|
|
76
|
+
try {
|
|
77
|
+
const fact = req.body;
|
|
78
|
+
if (!fact.id || !fact.content) {
|
|
79
|
+
return res.status(400).json({
|
|
80
|
+
status: 'error',
|
|
81
|
+
error: 'Missing required fields: id, content'
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
const adapter = await getAdapter();
|
|
85
|
+
await adapter.storeFact(fact);
|
|
86
|
+
res.json({ status: 'success' });
|
|
87
|
+
}
|
|
88
|
+
catch (error) {
|
|
89
|
+
console.error('[Memory] Failed to create fact:', error);
|
|
90
|
+
res.status(500).json({
|
|
91
|
+
status: 'error',
|
|
92
|
+
error: error instanceof Error ? error.message : 'Unknown error'
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
// PUT /api/memory/facts/:id - update fact
|
|
97
|
+
router.put('/facts/:id', async (req, res) => {
|
|
98
|
+
try {
|
|
99
|
+
const { id } = req.params;
|
|
100
|
+
const patch = req.body;
|
|
101
|
+
const adapter = await getAdapter();
|
|
102
|
+
await adapter.updateFact(id, patch);
|
|
103
|
+
res.json({ status: 'success' });
|
|
104
|
+
}
|
|
105
|
+
catch (error) {
|
|
106
|
+
console.error('[Memory] Failed to update fact:', error);
|
|
107
|
+
res.status(500).json({
|
|
108
|
+
status: 'error',
|
|
109
|
+
error: error instanceof Error ? error.message : 'Unknown error'
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
// DELETE /api/memory/facts/:id - delete fact
|
|
114
|
+
router.delete('/facts/:id', async (req, res) => {
|
|
115
|
+
try {
|
|
116
|
+
const { id } = req.params;
|
|
117
|
+
const adapter = await getAdapter();
|
|
118
|
+
await adapter.deleteFact(id);
|
|
119
|
+
res.json({ status: 'success' });
|
|
120
|
+
}
|
|
121
|
+
catch (error) {
|
|
122
|
+
console.error('[Memory] Failed to delete fact:', error);
|
|
123
|
+
res.status(500).json({
|
|
124
|
+
status: 'error',
|
|
125
|
+
error: error instanceof Error ? error.message : 'Unknown error'
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
// POST /api/memory/search - semantic search
|
|
130
|
+
router.post('/search', async (req, res) => {
|
|
131
|
+
try {
|
|
132
|
+
const { query, k } = req.body;
|
|
133
|
+
if (!query) {
|
|
134
|
+
return res.status(400).json({
|
|
135
|
+
status: 'error',
|
|
136
|
+
error: 'Missing required field: query'
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
const adapter = await getAdapter();
|
|
140
|
+
const results = await adapter.searchFacts(query, k || 5);
|
|
141
|
+
res.json({ status: 'success', results });
|
|
142
|
+
}
|
|
143
|
+
catch (error) {
|
|
144
|
+
console.error('[Memory] Failed to search facts:', error);
|
|
145
|
+
res.status(500).json({
|
|
146
|
+
status: 'error',
|
|
147
|
+
error: error instanceof Error ? error.message : 'Unknown error'
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
// POST /api/memory/extract - call factExtractor on input text
|
|
152
|
+
router.post('/extract', async (req, res) => {
|
|
153
|
+
try {
|
|
154
|
+
const { text, agentId, useLlm, providerId, model } = req.body;
|
|
155
|
+
if (!text || !agentId) {
|
|
156
|
+
return res.status(400).json({
|
|
157
|
+
status: 'error',
|
|
158
|
+
error: 'Missing required fields: text, agentId'
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
let facts;
|
|
162
|
+
if (useLlm && providerId && model) {
|
|
163
|
+
facts = await extractFactsWithLlm(text, agentId, providerId, model);
|
|
164
|
+
}
|
|
165
|
+
else {
|
|
166
|
+
facts = extractFacts(text, agentId);
|
|
167
|
+
}
|
|
168
|
+
res.json({ status: 'success', facts });
|
|
169
|
+
}
|
|
170
|
+
catch (error) {
|
|
171
|
+
console.error('[Memory] Failed to extract facts:', error);
|
|
172
|
+
res.status(500).json({
|
|
173
|
+
status: 'error',
|
|
174
|
+
error: error instanceof Error ? error.message : 'Unknown error'
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
// POST /api/memory/score - call memoryScorer on facts
|
|
179
|
+
router.post('/score', async (req, res) => {
|
|
180
|
+
try {
|
|
181
|
+
const { facts, query, limit } = req.body;
|
|
182
|
+
if (!facts || !Array.isArray(facts)) {
|
|
183
|
+
return res.status(400).json({
|
|
184
|
+
status: 'error',
|
|
185
|
+
error: 'Missing or invalid required field: facts (array)'
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
const scored = rankFacts(facts, query || '', limit);
|
|
189
|
+
res.json({ status: 'success', facts: scored });
|
|
190
|
+
}
|
|
191
|
+
catch (error) {
|
|
192
|
+
console.error('[Memory] Failed to score facts:', error);
|
|
193
|
+
res.status(500).json({
|
|
194
|
+
status: 'error',
|
|
195
|
+
error: error instanceof Error ? error.message : 'Unknown error'
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
// GET /api/memory/config - get current backend config
|
|
200
|
+
router.get('/config', (_req, res) => {
|
|
201
|
+
try {
|
|
202
|
+
const config = readConfig();
|
|
203
|
+
const memoryConfig = config.memory || { backend: 'local_sqlite' };
|
|
204
|
+
res.json({
|
|
205
|
+
status: 'success',
|
|
206
|
+
config: {
|
|
207
|
+
...memoryConfig,
|
|
208
|
+
backend: currentBackend,
|
|
209
|
+
connectionString: currentBackend === 'postgres' ? connectionString : undefined
|
|
210
|
+
}
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
catch (error) {
|
|
214
|
+
console.error('[Memory] Failed to get config:', error);
|
|
215
|
+
res.status(500).json({
|
|
216
|
+
status: 'error',
|
|
217
|
+
error: error instanceof Error ? error.message : 'Unknown error'
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
});
|
|
221
|
+
// POST /api/memory/config - set backend config (store type, connection string)
|
|
222
|
+
router.post('/config', async (req, res) => {
|
|
223
|
+
try {
|
|
224
|
+
const { backend, connectionString: connStr } = req.body;
|
|
225
|
+
if (!backend) {
|
|
226
|
+
return res.status(400).json({
|
|
227
|
+
status: 'error',
|
|
228
|
+
error: 'Missing required field: backend'
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
if (backend === 'postgres' && !connStr) {
|
|
232
|
+
return res.status(400).json({
|
|
233
|
+
status: 'error',
|
|
234
|
+
error: 'PostgreSQL backend requires connectionString'
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
// Test connection before switching
|
|
238
|
+
let testAdapter;
|
|
239
|
+
if (backend === 'postgres') {
|
|
240
|
+
testAdapter = new PostgresAdapter(connStr);
|
|
241
|
+
}
|
|
242
|
+
else {
|
|
243
|
+
testAdapter = new SqliteAdapter();
|
|
244
|
+
}
|
|
245
|
+
try {
|
|
246
|
+
await testAdapter.initialize();
|
|
247
|
+
await testAdapter.getHealth();
|
|
248
|
+
await testAdapter.close();
|
|
249
|
+
}
|
|
250
|
+
catch (testError) {
|
|
251
|
+
return res.status(400).json({
|
|
252
|
+
status: 'error',
|
|
253
|
+
error: `Failed to connect to ${backend}: ${testError instanceof Error ? testError.message : 'Unknown error'}`
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
await switchAdapter(backend, connStr);
|
|
257
|
+
res.json({ status: 'success' });
|
|
258
|
+
}
|
|
259
|
+
catch (error) {
|
|
260
|
+
console.error('[Memory] Failed to set config:', error);
|
|
261
|
+
res.status(500).json({
|
|
262
|
+
status: 'error',
|
|
263
|
+
error: error instanceof Error ? error.message : 'Unknown error'
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
});
|
|
267
|
+
// GET /api/memory/health - backend health check (never 500 — always returns a health object)
|
|
268
|
+
router.get('/health', async (_req, res) => {
|
|
269
|
+
try {
|
|
270
|
+
const adapter = await getAdapter();
|
|
271
|
+
const health = await adapter.getHealth();
|
|
272
|
+
res.json({ status: 'success', health, backend: currentBackend });
|
|
273
|
+
}
|
|
274
|
+
catch (error) {
|
|
275
|
+
// Return 200 with degraded health — don't 500 or the frontend will loop
|
|
276
|
+
res.json({
|
|
277
|
+
status: 'success',
|
|
278
|
+
health: { status: 'unavailable', factCount: 0, error: error instanceof Error ? error.message : 'Adapter init failed' },
|
|
279
|
+
backend: currentBackend
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
});
|
|
283
|
+
export default router;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"qualification.d.ts","sourceRoot":"","sources":["../../../server/routes/qualification.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"qualification.d.ts","sourceRoot":"","sources":["../../../server/routes/qualification.ts"],"names":[],"mappings":"AAKA,QAAA,MAAM,MAAM,4CAAW,CAAC;AAijBxB,eAAe,MAAM,CAAC"}
|