opencode-fractal-memory 0.6.8 → 0.6.10
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.
|
@@ -93,32 +93,6 @@ export function queryNodes(scope) {
|
|
|
93
93
|
db.close();
|
|
94
94
|
return rows.map((r) => rowToNode(r));
|
|
95
95
|
}
|
|
96
|
-
export function queryPlaybooks(scope) {
|
|
97
|
-
const db = openDb(scope);
|
|
98
|
-
if (!db)
|
|
99
|
-
return [];
|
|
100
|
-
const rows = db.query(`
|
|
101
|
-
SELECT id, label, content, metadata, times_used, usefulness_score
|
|
102
|
-
FROM memory_nodes
|
|
103
|
-
WHERE type = 'playbook' AND scope = ?
|
|
104
|
-
ORDER BY label
|
|
105
|
-
`).all(scope);
|
|
106
|
-
db.close();
|
|
107
|
-
return rows.map((r) => {
|
|
108
|
-
const meta = r.metadata ? JSON.parse(r.metadata) : {};
|
|
109
|
-
return {
|
|
110
|
-
id: r.id,
|
|
111
|
-
name: r.label || "",
|
|
112
|
-
description: r.content || "",
|
|
113
|
-
steps: meta.steps || [],
|
|
114
|
-
triggers: meta.triggers || [],
|
|
115
|
-
tags: meta.tags || [],
|
|
116
|
-
executionCount: meta.executionCount ?? r.times_used ?? 0,
|
|
117
|
-
avgDurationMs: meta.avgDurationMs ?? null,
|
|
118
|
-
lastExecutedAt: meta.lastExecutedAt ?? null,
|
|
119
|
-
};
|
|
120
|
-
});
|
|
121
|
-
}
|
|
122
96
|
export function cosineSimilarity(a, b) {
|
|
123
97
|
let dot = 0, normA = 0, normB = 0;
|
|
124
98
|
for (let i = 0; i < a.length && i < b.length; i++) {
|
|
@@ -177,6 +151,7 @@ export const TYPE_SHAPES = {
|
|
|
177
151
|
improvement: "sphere",
|
|
178
152
|
howto: "sphere",
|
|
179
153
|
skill: "icosahedron",
|
|
154
|
+
playbook: "torus",
|
|
180
155
|
unknown: "sphere",
|
|
181
156
|
};
|
|
182
157
|
export const CUSTOM_TYPE_SHAPES = {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { memLog } from "../logging";
|
|
2
2
|
import { generateEmbedding } from "../embeddings";
|
|
3
|
-
import { queryNodes,
|
|
3
|
+
import { queryNodes, getAvailableScopes, extractLinks, computeStats, readProjectConfig, writeProjectConfig, rowToNode, withDb, jsonResponse, cosineSimilarity, } from "./helpers";
|
|
4
4
|
function handleScopes() {
|
|
5
5
|
return jsonResponse(getAvailableScopes());
|
|
6
6
|
}
|
|
@@ -15,9 +15,6 @@ function handleStats(ctx) {
|
|
|
15
15
|
const nodes = queryNodes(ctx.scope);
|
|
16
16
|
return jsonResponse(computeStats(nodes));
|
|
17
17
|
}
|
|
18
|
-
function handlePlaybooks(ctx) {
|
|
19
|
-
return jsonResponse(queryPlaybooks(ctx.scope));
|
|
20
|
-
}
|
|
21
18
|
function handleConfigGet() {
|
|
22
19
|
return jsonResponse(readProjectConfig());
|
|
23
20
|
}
|
|
@@ -189,7 +186,6 @@ export function registerRoutes(router) {
|
|
|
189
186
|
router.get(/^\/api\/nodes$/, (_, ctx) => handleNodes(ctx));
|
|
190
187
|
router.get(/^\/api\/links$/, (_, ctx) => handleLinks(ctx));
|
|
191
188
|
router.get(/^\/api\/stats$/, (_, ctx) => handleStats(ctx));
|
|
192
|
-
router.get(/^\/api\/playbooks$/, (_, ctx) => handlePlaybooks(ctx));
|
|
193
189
|
router.get(/^\/api\/config$/, () => handleConfigGet());
|
|
194
190
|
router.put(/^\/api\/config$/, (req) => handleConfigSave(req));
|
|
195
191
|
router.post(/^\/api\/config$/, (req) => handleConfigSave(req));
|
package/management/public/app.js
CHANGED
|
@@ -715,21 +715,12 @@ function setupEventListeners() {
|
|
|
715
715
|
btn.classList.add("active");
|
|
716
716
|
const tab = btn.dataset.tab;
|
|
717
717
|
const visualizePanel = document.getElementById("visualize-panel");
|
|
718
|
-
const playbooksPanel = document.getElementById("playbooks-panel");
|
|
719
718
|
const settingsPanel = document.getElementById("settings-panel");
|
|
720
719
|
if (visualizePanel) visualizePanel.classList.toggle("active", tab === "visualize");
|
|
721
|
-
if (playbooksPanel) playbooksPanel.classList.toggle("active", tab === "playbooks");
|
|
722
720
|
if (settingsPanel) settingsPanel.classList.toggle("active", tab === "settings");
|
|
723
721
|
if (tab === "settings") loadSettings();
|
|
724
|
-
if (tab === "playbooks") loadPlaybooks();
|
|
725
722
|
});
|
|
726
723
|
});
|
|
727
|
-
|
|
728
|
-
// Playbook search input
|
|
729
|
-
const pbSearch = document.getElementById("playbook-search-input");
|
|
730
|
-
if (pbSearch) {
|
|
731
|
-
pbSearch.addEventListener("input", () => renderPlaybooks(playbookData));
|
|
732
|
-
}
|
|
733
724
|
}
|
|
734
725
|
|
|
735
726
|
// ==================== Data Loading ====================
|
|
@@ -1298,111 +1289,6 @@ async function performServerSearch(query) {
|
|
|
1298
1289
|
}
|
|
1299
1290
|
}
|
|
1300
1291
|
|
|
1301
|
-
// ==================== Playbooks ====================
|
|
1302
|
-
|
|
1303
|
-
let playbookData = [];
|
|
1304
|
-
|
|
1305
|
-
async function loadPlaybooks() {
|
|
1306
|
-
const container = document.getElementById('playbook-list');
|
|
1307
|
-
container.innerHTML = '<div style="color:#888;font-size:12px;text-align:center;padding:20px;">Loading playbooks...</div>';
|
|
1308
|
-
|
|
1309
|
-
try {
|
|
1310
|
-
const res = await fetch(`/api/playbooks?scope=${currentScope}`);
|
|
1311
|
-
if (!res.ok) {
|
|
1312
|
-
container.innerHTML = '<div style="color:#f44;font-size:12px;text-align:center;padding:20px;">Failed to load playbooks</div>';
|
|
1313
|
-
return;
|
|
1314
|
-
}
|
|
1315
|
-
playbookData = await res.json();
|
|
1316
|
-
renderPlaybooks(playbookData);
|
|
1317
|
-
} catch (e) {
|
|
1318
|
-
container.innerHTML = `<div style="color:#f44;font-size:12px;text-align:center;padding:20px;">Error: ${e.message}</div>`;
|
|
1319
|
-
}
|
|
1320
|
-
}
|
|
1321
|
-
|
|
1322
|
-
function renderPlaybooks(playbooks) {
|
|
1323
|
-
const container = document.getElementById('playbook-list');
|
|
1324
|
-
const searchQ = (document.getElementById('playbook-search-input').value || '').toLowerCase();
|
|
1325
|
-
|
|
1326
|
-
const filtered = searchQ
|
|
1327
|
-
? playbooks.filter(p =>
|
|
1328
|
-
p.name.toLowerCase().includes(searchQ) ||
|
|
1329
|
-
p.description.toLowerCase().includes(searchQ) ||
|
|
1330
|
-
(p.tags || []).some(t => t.toLowerCase().includes(searchQ))
|
|
1331
|
-
)
|
|
1332
|
-
: playbooks;
|
|
1333
|
-
|
|
1334
|
-
if (filtered.length === 0) {
|
|
1335
|
-
container.innerHTML = '<div style="color:#888;font-size:12px;text-align:center;padding:20px;">No playbooks found.</div>';
|
|
1336
|
-
return;
|
|
1337
|
-
}
|
|
1338
|
-
|
|
1339
|
-
container.innerHTML = filtered.map(renderPlaybookCard).join('');
|
|
1340
|
-
|
|
1341
|
-
// Wire delete buttons after render
|
|
1342
|
-
container.querySelectorAll('.pb-delete-btn').forEach(btn => {
|
|
1343
|
-
btn.addEventListener('click', () => deletePlaybook(btn.dataset.pbId));
|
|
1344
|
-
});
|
|
1345
|
-
}
|
|
1346
|
-
|
|
1347
|
-
function renderPlaybookCard(pb) {
|
|
1348
|
-
const tags = (pb.tags || []).map(t => `<span class="pb-tag">${t}</span>`).join('');
|
|
1349
|
-
const steps = (pb.steps || []).map(s =>
|
|
1350
|
-
`<div class="pb-step">
|
|
1351
|
-
<span class="step-tool">${s.toolName}</span>
|
|
1352
|
-
${s.critical ? '<span class="step-critical">\u26a0</span>' : ''}
|
|
1353
|
-
<span>${s.description}</span>
|
|
1354
|
-
</div>`
|
|
1355
|
-
).join('');
|
|
1356
|
-
const triggers = (pb.triggers || []).map(t => {
|
|
1357
|
-
if (t.type === 'task_keyword') return `<div class="pb-trigger">\ud83d\udd11 ${(t.keywords || []).join(', ')}</div>`;
|
|
1358
|
-
if (t.type === 'tool_sequence') return `<div class="pb-trigger">\ud83d\udd27 ${(t.pattern || []).join(' \u2192 ')}</div>`;
|
|
1359
|
-
return `<div class="pb-trigger">\ud83d\udccb ${t.type}</div>`;
|
|
1360
|
-
}).join('');
|
|
1361
|
-
|
|
1362
|
-
return `<div class="playbook-card">
|
|
1363
|
-
<div class="pb-header">
|
|
1364
|
-
<div>
|
|
1365
|
-
<div class="pb-name">${pb.name}</div>
|
|
1366
|
-
<div class="pb-desc">${pb.description}</div>
|
|
1367
|
-
</div>
|
|
1368
|
-
<button class="pb-delete-btn" data-pb-id="${pb.id}">Delete</button>
|
|
1369
|
-
</div>
|
|
1370
|
-
<div class="pb-meta">
|
|
1371
|
-
<span>\u26a1 ${pb.executionCount || 0} runs</span>
|
|
1372
|
-
${pb.avgDurationMs ? `<span>\u23f1 ${(pb.avgDurationMs / 1000).toFixed(1)}s avg</span>` : ''}
|
|
1373
|
-
${pb.lastExecutedAt ? `<span>\ud83d\udd50 ${new Date(pb.lastExecutedAt).toLocaleDateString()}</span>` : ''}
|
|
1374
|
-
</div>
|
|
1375
|
-
${triggers ? `<div class="pb-triggers">${triggers}</div>` : ''}
|
|
1376
|
-
<div class="pb-steps">${steps}</div>
|
|
1377
|
-
${tags ? `<div class="pb-tags">${tags}</div>` : ''}
|
|
1378
|
-
</div>`;
|
|
1379
|
-
}
|
|
1380
|
-
|
|
1381
|
-
async function deletePlaybook(id) {
|
|
1382
|
-
if (!confirm('Delete this playbook?')) return;
|
|
1383
|
-
try {
|
|
1384
|
-
const res = await fetch(`/api/playbooks/${id}?scope=${currentScope}`, { method: 'DELETE' });
|
|
1385
|
-
if (res.ok) {
|
|
1386
|
-
playbookData = playbookData.filter(p => p.id !== id);
|
|
1387
|
-
renderPlaybooks(playbookData);
|
|
1388
|
-
} else {
|
|
1389
|
-
alert('Failed to delete playbook');
|
|
1390
|
-
}
|
|
1391
|
-
} catch (e) {
|
|
1392
|
-
alert('Error: ' + e.message);
|
|
1393
|
-
}
|
|
1394
|
-
}
|
|
1395
|
-
|
|
1396
|
-
// Playbook search input
|
|
1397
|
-
document.addEventListener('DOMContentLoaded', () => {
|
|
1398
|
-
const searchInput = document.getElementById('playbook-search-input');
|
|
1399
|
-
if (searchInput) {
|
|
1400
|
-
searchInput.addEventListener('input', () => {
|
|
1401
|
-
renderPlaybooks(playbookData);
|
|
1402
|
-
});
|
|
1403
|
-
}
|
|
1404
|
-
});
|
|
1405
|
-
|
|
1406
1292
|
// ==================== Animation Loop ====================
|
|
1407
1293
|
|
|
1408
1294
|
function animate() {
|
|
@@ -1413,19 +1299,6 @@ function animate() {
|
|
|
1413
1299
|
// ==================== Settings ====================
|
|
1414
1300
|
|
|
1415
1301
|
document.addEventListener('DOMContentLoaded', () => {
|
|
1416
|
-
document.querySelectorAll('.tab-btn').forEach(btn => {
|
|
1417
|
-
btn.addEventListener('click', () => {
|
|
1418
|
-
document.querySelectorAll('.tab-btn').forEach(b => b.classList.remove('active'));
|
|
1419
|
-
btn.classList.add('active');
|
|
1420
|
-
const tab = btn.dataset.tab;
|
|
1421
|
-
document.getElementById('visualize-panel').classList.toggle('active', tab === 'visualize');
|
|
1422
|
-
document.getElementById('playbooks-panel').classList.toggle('active', tab === 'playbooks');
|
|
1423
|
-
document.getElementById('settings-panel').classList.toggle('active', tab === 'settings');
|
|
1424
|
-
if (tab === 'settings') loadSettings();
|
|
1425
|
-
if (tab === 'playbooks') loadPlaybooks();
|
|
1426
|
-
});
|
|
1427
|
-
});
|
|
1428
|
-
|
|
1429
1302
|
document.getElementById('save-config').addEventListener('click', saveSettings);
|
|
1430
1303
|
});
|
|
1431
1304
|
|
|
@@ -182,44 +182,6 @@
|
|
|
182
182
|
.save-btn:hover { background: rgba(100, 150, 255, 0.5); }
|
|
183
183
|
.save-message { font-size: 11px; color: #4f4; margin-top: 8px; text-align: center; }
|
|
184
184
|
|
|
185
|
-
/* Playbook styles */
|
|
186
|
-
.playbook-card {
|
|
187
|
-
background: rgba(255,255,255,0.03); border-radius: 8px; padding: 12px;
|
|
188
|
-
margin-bottom: 10px; border: 1px solid rgba(255,255,255,0.08);
|
|
189
|
-
transition: border-color 0.2s;
|
|
190
|
-
}
|
|
191
|
-
.playbook-card:hover { border-color: rgba(100,150,255,0.3); }
|
|
192
|
-
.playbook-card .pb-header { display: flex; justify-content: space-between; align-items: flex-start; }
|
|
193
|
-
.playbook-card .pb-name { font-size: 14px; color: #fff; font-weight: 500; }
|
|
194
|
-
.playbook-card .pb-desc { font-size: 11px; color: #888; margin-top: 2px; }
|
|
195
|
-
.playbook-card .pb-meta { font-size: 10px; color: #666; margin-top: 6px; }
|
|
196
|
-
.playbook-card .pb-meta span { display: inline-block; margin-right: 12px; }
|
|
197
|
-
.playbook-card .pb-tags { margin-top: 6px; display: flex; flex-wrap: wrap; gap: 4px; }
|
|
198
|
-
.playbook-card .pb-tag {
|
|
199
|
-
padding: 2px 8px; border-radius: 10px; background: rgba(100,150,255,0.15);
|
|
200
|
-
color: rgba(100,150,255,0.8); font-size: 10px;
|
|
201
|
-
}
|
|
202
|
-
.playbook-card .pb-steps { margin-top: 8px; }
|
|
203
|
-
.playbook-card .pb-step {
|
|
204
|
-
padding: 4px 8px; margin: 2px 0; border-radius: 4px;
|
|
205
|
-
background: rgba(255,255,255,0.03); font-size: 11px; color: #aaa;
|
|
206
|
-
display: flex; align-items: center; gap: 6px;
|
|
207
|
-
}
|
|
208
|
-
.playbook-card .pb-step .step-tool {
|
|
209
|
-
padding: 1px 6px; border-radius: 4px; background: rgba(100,150,255,0.2);
|
|
210
|
-
color: #4a9eff; font-size: 10px; font-weight: 500;
|
|
211
|
-
}
|
|
212
|
-
.playbook-card .pb-step .step-critical {
|
|
213
|
-
color: #f66; font-size: 10px; font-weight: 700;
|
|
214
|
-
}
|
|
215
|
-
.playbook-card .pb-delete-btn {
|
|
216
|
-
background: none; border: 1px solid rgba(255,60,60,0.3); color: #f66;
|
|
217
|
-
padding: 2px 10px; border-radius: 4px; font-size: 11px; cursor: pointer;
|
|
218
|
-
}
|
|
219
|
-
.playbook-card .pb-delete-btn:hover { background: rgba(255,60,60,0.2); }
|
|
220
|
-
.playbook-card .pb-triggers { margin-top: 6px; }
|
|
221
|
-
.playbook-card .pb-trigger { font-size: 10px; color: #888; font-style: italic; }
|
|
222
|
-
|
|
223
185
|
#node-list {
|
|
224
186
|
max-height: 40vh; overflow-y: auto; border: 1px solid rgba(255,255,255,0.1);
|
|
225
187
|
border-radius: 6px;
|
|
@@ -245,7 +207,6 @@
|
|
|
245
207
|
|
|
246
208
|
<div class="tab-buttons">
|
|
247
209
|
<button class="tab-btn active" data-tab="visualize">Visualize</button>
|
|
248
|
-
<button class="tab-btn" data-tab="playbooks">Playbooks</button>
|
|
249
210
|
<button class="tab-btn" data-tab="settings">Settings</button>
|
|
250
211
|
</div>
|
|
251
212
|
|
|
@@ -304,17 +265,6 @@
|
|
|
304
265
|
</div>
|
|
305
266
|
</div>
|
|
306
267
|
|
|
307
|
-
<!-- Playbooks Panel -->
|
|
308
|
-
<div id="playbooks-panel" class="settings-panel">
|
|
309
|
-
<div class="section">
|
|
310
|
-
<h3>Playbooks</h3>
|
|
311
|
-
<div style="margin-bottom: 10px;">
|
|
312
|
-
<input type="text" id="playbook-search-input" placeholder="Search playbooks..." style="width:100%;padding:6px 10px;border-radius:6px;border:1px solid rgba(255,255,255,0.2);background:rgba(255,255,255,0.05);color:#fff;font-size:12px;outline:none;">
|
|
313
|
-
</div>
|
|
314
|
-
<div id="playbook-list"></div>
|
|
315
|
-
</div>
|
|
316
|
-
</div>
|
|
317
|
-
|
|
318
268
|
<!-- Settings Panel -->
|
|
319
269
|
<div id="settings-panel" class="settings-panel">
|
|
320
270
|
<div class="section">
|