mcp-memory-bucket 0.1.0 → 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 +40 -14
- package/dist/client/assets/index-CXe_noum.js +344 -0
- package/dist/client/index.html +1 -1
- package/dist/src/config.js +77 -10
- package/dist/src/memory/repository.js +51 -7
- package/dist/src/memory/tools.js +11 -5
- package/dist/src/server.js +17 -9
- package/dist/src/shared/relocate-tool.js +2 -1
- package/dist/src/shared/relocate.js +2 -1
- package/dist/src/skills/builtin/memory-bucket-authoring/SKILL.md +24 -0
- package/dist/src/skills/repository.js +67 -13
- package/dist/src/skills/tools.js +12 -6
- package/dist/src/store/db.js +11 -0
- package/dist/src/store/sync.js +43 -10
- package/dist/src/web/routes.js +119 -7
- package/package.json +2 -2
- package/dist/client/assets/index-CxhInmjj.js +0 -150
package/dist/src/web/routes.js
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import os from 'node:os';
|
|
3
|
+
import path from 'node:path';
|
|
1
4
|
import express from 'express';
|
|
5
|
+
import { saveRoot, removeRoot as removeRootFromConfig } from '../config.js';
|
|
2
6
|
function asArray(v) {
|
|
3
7
|
if (v === undefined)
|
|
4
8
|
return [];
|
|
@@ -17,6 +21,7 @@ function queryEntries(db, req) {
|
|
|
17
21
|
const owners = asArray(req.query.owner);
|
|
18
22
|
const docTypes = asArray(req.query.doc_type);
|
|
19
23
|
const keyTypes = asArray(req.query.key_type);
|
|
24
|
+
const roots = asArray(req.query.root);
|
|
20
25
|
const q = req.query.q?.trim();
|
|
21
26
|
const matchedIds = q
|
|
22
27
|
? matchSearch(db, q)
|
|
@@ -26,10 +31,10 @@ function queryEntries(db, req) {
|
|
|
26
31
|
}
|
|
27
32
|
const results = [];
|
|
28
33
|
if (type === 'skill' || type === 'all') {
|
|
29
|
-
results.push(...queryTable(db, 'skills', { tags, statuses, owners, docTypes: [], keyTypes: [] }, matchedIds?.skills));
|
|
34
|
+
results.push(...queryTable(db, 'skills', { tags, statuses, owners, docTypes: [], keyTypes: [], roots }, matchedIds?.skills));
|
|
30
35
|
}
|
|
31
36
|
if (type === 'memory' || type === 'all') {
|
|
32
|
-
results.push(...queryTable(db, 'memory_docs', { tags, statuses, owners: [], docTypes, keyTypes }, matchedIds?.memory_docs));
|
|
37
|
+
results.push(...queryTable(db, 'memory_docs', { tags, statuses, owners: [], docTypes, keyTypes, roots }, matchedIds?.memory_docs));
|
|
33
38
|
}
|
|
34
39
|
const sort = req.query.sort ?? 'mtime_desc';
|
|
35
40
|
results.sort((a, b) => {
|
|
@@ -65,13 +70,17 @@ function queryTable(db, table, filters, restrictToIds) {
|
|
|
65
70
|
where += ` AND key_type IN (${filters.keyTypes.map(() => '?').join(', ')})`;
|
|
66
71
|
params.push(...filters.keyTypes);
|
|
67
72
|
}
|
|
73
|
+
if (filters.roots.length > 0) {
|
|
74
|
+
where += ` AND root IN (${filters.roots.map(() => '?').join(', ')})`;
|
|
75
|
+
params.push(...filters.roots);
|
|
76
|
+
}
|
|
68
77
|
if (restrictToIds) {
|
|
69
78
|
where += ` AND id IN (${[...restrictToIds].map(() => '?').join(', ')})`;
|
|
70
79
|
params.push(...restrictToIds);
|
|
71
80
|
}
|
|
72
81
|
if (table === 'skills') {
|
|
73
82
|
const rows = db
|
|
74
|
-
.prepare(`SELECT id, description, owner, status, tags, mtime_ms FROM skills WHERE ${where}`)
|
|
83
|
+
.prepare(`SELECT id, description, owner, status, tags, root, mtime_ms FROM skills WHERE ${where}`)
|
|
75
84
|
.all(...params);
|
|
76
85
|
return rows.map((r) => ({
|
|
77
86
|
_table: 'skills',
|
|
@@ -83,11 +92,12 @@ function queryTable(db, table, filters, restrictToIds) {
|
|
|
83
92
|
owner: r.owner,
|
|
84
93
|
doc_type: null,
|
|
85
94
|
key_type: null,
|
|
95
|
+
root: r.root,
|
|
86
96
|
mtime_ms: r.mtime_ms,
|
|
87
97
|
}));
|
|
88
98
|
}
|
|
89
99
|
const rows = db
|
|
90
|
-
.prepare(`SELECT id, key, description, doc_type, key_type, status, tags, mtime_ms FROM memory_docs WHERE ${where}`)
|
|
100
|
+
.prepare(`SELECT id, key, description, doc_type, key_type, status, tags, root, mtime_ms FROM memory_docs WHERE ${where}`)
|
|
91
101
|
.all(...params);
|
|
92
102
|
return rows.map((r) => ({
|
|
93
103
|
_table: 'memory_docs',
|
|
@@ -99,6 +109,7 @@ function queryTable(db, table, filters, restrictToIds) {
|
|
|
99
109
|
owner: null,
|
|
100
110
|
doc_type: r.doc_type,
|
|
101
111
|
key_type: r.key_type,
|
|
112
|
+
root: r.root,
|
|
102
113
|
mtime_ms: r.mtime_ms,
|
|
103
114
|
}));
|
|
104
115
|
}
|
|
@@ -127,22 +138,27 @@ function buildFacets(db, type) {
|
|
|
127
138
|
const owners = new Set();
|
|
128
139
|
const docTypes = new Set();
|
|
129
140
|
const keyTypes = new Set();
|
|
141
|
+
const roots = new Set();
|
|
130
142
|
if (type === 'skill' || type === 'all') {
|
|
131
|
-
const rows = db.prepare(`SELECT tags, status, owner FROM skills`).all();
|
|
143
|
+
const rows = db.prepare(`SELECT tags, status, owner, root FROM skills`).all();
|
|
132
144
|
for (const r of rows) {
|
|
133
145
|
JSON.parse(r.tags).forEach((t) => tags.add(t));
|
|
134
146
|
statuses.add(r.status);
|
|
135
147
|
if (r.owner)
|
|
136
148
|
owners.add(r.owner);
|
|
149
|
+
if (r.root)
|
|
150
|
+
roots.add(r.root);
|
|
137
151
|
}
|
|
138
152
|
}
|
|
139
153
|
if (type === 'memory' || type === 'all') {
|
|
140
|
-
const rows = db.prepare(`SELECT tags, status, doc_type, key_type FROM memory_docs`).all();
|
|
154
|
+
const rows = db.prepare(`SELECT tags, status, doc_type, key_type, root FROM memory_docs`).all();
|
|
141
155
|
for (const r of rows) {
|
|
142
156
|
JSON.parse(r.tags).forEach((t) => tags.add(t));
|
|
143
157
|
statuses.add(r.status);
|
|
144
158
|
docTypes.add(r.doc_type);
|
|
145
159
|
keyTypes.add(r.key_type);
|
|
160
|
+
if (r.root)
|
|
161
|
+
roots.add(r.root);
|
|
146
162
|
}
|
|
147
163
|
}
|
|
148
164
|
return {
|
|
@@ -151,6 +167,7 @@ function buildFacets(db, type) {
|
|
|
151
167
|
owners: [...owners].sort(),
|
|
152
168
|
doc_types: [...docTypes].sort(),
|
|
153
169
|
key_types: [...keyTypes].sort(),
|
|
170
|
+
roots: [...roots].sort(),
|
|
154
171
|
};
|
|
155
172
|
}
|
|
156
173
|
function buildHealth(db) {
|
|
@@ -173,7 +190,16 @@ function buildHealth(db) {
|
|
|
173
190
|
.map((m) => m.id);
|
|
174
191
|
return { danglingExtends, danglingRelatedTo, emptyTriggerPhrases, staleActiveMemoryDocs };
|
|
175
192
|
}
|
|
176
|
-
|
|
193
|
+
/** Lowercase-hyphenate a folder-derived root name, same shape as skill names. */
|
|
194
|
+
function sanitizeRootName(raw) {
|
|
195
|
+
return raw
|
|
196
|
+
.trim()
|
|
197
|
+
.toLowerCase()
|
|
198
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
199
|
+
.replace(/^-+|-+$/g, '')
|
|
200
|
+
.slice(0, 64);
|
|
201
|
+
}
|
|
202
|
+
export function buildWebRouter(db, config, skillRepo, memoryRepo) {
|
|
177
203
|
const router = express.Router();
|
|
178
204
|
router.get('/api/entries', (req, res) => {
|
|
179
205
|
res.json(queryEntries(db, req));
|
|
@@ -200,5 +226,91 @@ export function buildWebRouter(db) {
|
|
|
200
226
|
router.get('/api/health', (_req, res) => {
|
|
201
227
|
res.json(buildHealth(db));
|
|
202
228
|
});
|
|
229
|
+
router.get('/api/roots', (_req, res) => {
|
|
230
|
+
res.json({
|
|
231
|
+
skill: skillRepo.listRoots().map((r) => ({ ...r, kind: 'skill' })),
|
|
232
|
+
memory: memoryRepo.listRoots().map((r) => ({ ...r, kind: 'memory' })),
|
|
233
|
+
});
|
|
234
|
+
});
|
|
235
|
+
router.post('/api/roots', (req, res) => {
|
|
236
|
+
const { kind, name, path: dirPath } = req.body;
|
|
237
|
+
if (kind !== 'skill' && kind !== 'memory') {
|
|
238
|
+
res.status(400).json({ error: 'kind must be "skill" or "memory"' });
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
if (!dirPath || !path.isAbsolute(dirPath)) {
|
|
242
|
+
res.status(400).json({ error: 'path must be an absolute directory path' });
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
if (!fs.existsSync(dirPath) || !fs.statSync(dirPath).isDirectory()) {
|
|
246
|
+
res.status(400).json({ error: `not a directory: ${dirPath}` });
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
const rootName = sanitizeRootName(name || path.basename(dirPath));
|
|
250
|
+
if (!rootName) {
|
|
251
|
+
res.status(400).json({ error: 'could not derive a valid root name — provide one explicitly' });
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
const repo = kind === 'skill' ? skillRepo : memoryRepo;
|
|
255
|
+
try {
|
|
256
|
+
repo.addRoot({ name: rootName, path: dirPath });
|
|
257
|
+
saveRoot(config, kind, { name: rootName, path: dirPath });
|
|
258
|
+
res.json({ name: rootName, path: dirPath, kind });
|
|
259
|
+
}
|
|
260
|
+
catch (err) {
|
|
261
|
+
res.status(409).json({ error: err.message });
|
|
262
|
+
}
|
|
263
|
+
});
|
|
264
|
+
router.delete('/api/roots/:kind/:name', (req, res) => {
|
|
265
|
+
const { kind, name } = req.params;
|
|
266
|
+
if (kind !== 'skill' && kind !== 'memory') {
|
|
267
|
+
res.status(400).json({ error: 'kind must be "skill" or "memory"' });
|
|
268
|
+
return;
|
|
269
|
+
}
|
|
270
|
+
if (!name) {
|
|
271
|
+
res.status(400).json({ error: 'root name is required' });
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
const repo = kind === 'skill' ? skillRepo : memoryRepo;
|
|
275
|
+
try {
|
|
276
|
+
repo.removeRoot(name);
|
|
277
|
+
removeRootFromConfig(config, kind, name);
|
|
278
|
+
res.json({ removed: name, kind });
|
|
279
|
+
}
|
|
280
|
+
catch (err) {
|
|
281
|
+
res.status(404).json({ error: err.message });
|
|
282
|
+
}
|
|
283
|
+
});
|
|
284
|
+
router.get('/api/fs/list', (req, res) => {
|
|
285
|
+
const requested = req.query.path?.trim();
|
|
286
|
+
const dirPath = requested ? path.resolve(requested) : os.homedir();
|
|
287
|
+
let stat;
|
|
288
|
+
try {
|
|
289
|
+
stat = fs.statSync(dirPath);
|
|
290
|
+
}
|
|
291
|
+
catch {
|
|
292
|
+
res.status(400).json({ error: `path not found: ${dirPath}` });
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
if (!stat.isDirectory()) {
|
|
296
|
+
res.status(400).json({ error: `not a directory: ${dirPath}` });
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
299
|
+
let dirents;
|
|
300
|
+
try {
|
|
301
|
+
dirents = fs.readdirSync(dirPath, { withFileTypes: true });
|
|
302
|
+
}
|
|
303
|
+
catch (err) {
|
|
304
|
+
res.status(403).json({ error: err.message });
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
const showHidden = req.query.hidden === '1' || req.query.hidden === 'true';
|
|
308
|
+
const entries = dirents
|
|
309
|
+
.filter((d) => d.isDirectory() && (showHidden || !d.name.startsWith('.')))
|
|
310
|
+
.map((d) => ({ name: d.name, path: path.join(dirPath, d.name) }))
|
|
311
|
+
.sort((a, b) => a.name.localeCompare(b.name));
|
|
312
|
+
const parent = path.dirname(dirPath) !== dirPath ? path.dirname(dirPath) : null;
|
|
313
|
+
res.json({ path: dirPath, parent, entries });
|
|
314
|
+
});
|
|
203
315
|
return router;
|
|
204
316
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mcp-memory-bucket",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "MCP server exposing skill_* (reusable coding patterns) and memory_* (point-in-time working context) tools over a markdown+frontmatter source, cached into SQLite at runtime.",
|
|
6
6
|
"repository": {
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
},
|
|
11
11
|
"license": "MIT",
|
|
12
12
|
"bin": {
|
|
13
|
-
"mcp-memory-bucket": "
|
|
13
|
+
"mcp-memory-bucket": "bin/mcp-memory-bucket.js"
|
|
14
14
|
},
|
|
15
15
|
"main": "dist/src/server.js",
|
|
16
16
|
"files": [
|
|
@@ -1,150 +0,0 @@
|
|
|
1
|
-
(function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const i of document.querySelectorAll('link[rel="modulepreload"]'))s(i);new MutationObserver(i=>{for(const o of i)if(o.type==="childList")for(const n of o.addedNodes)n.tagName==="LINK"&&n.rel==="modulepreload"&&s(n)}).observe(document,{childList:!0,subtree:!0});function e(i){const o={};return i.integrity&&(o.integrity=i.integrity),i.referrerPolicy&&(o.referrerPolicy=i.referrerPolicy),i.crossOrigin==="use-credentials"?o.credentials="include":i.crossOrigin==="anonymous"?o.credentials="omit":o.credentials="same-origin",o}function s(i){if(i.ep)return;i.ep=!0;const o=e(i);fetch(i.href,o)}})();/**
|
|
2
|
-
* @license
|
|
3
|
-
* Copyright 2019 Google LLC
|
|
4
|
-
* SPDX-License-Identifier: BSD-3-Clause
|
|
5
|
-
*/const T=globalThis,L=T.ShadowRoot&&(T.ShadyCSS===void 0||T.ShadyCSS.nativeShadow)&&"adoptedStyleSheets"in Document.prototype&&"replace"in CSSStyleSheet.prototype,D=Symbol(),F=new WeakMap;let rt=class{constructor(t,e,s){if(this._$cssResult$=!0,s!==D)throw Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead.");this.cssText=t,this.t=e}get styleSheet(){let t=this.o;const e=this.t;if(L&&t===void 0){const s=e!==void 0&&e.length===1;s&&(t=F.get(e)),t===void 0&&((this.o=t=new CSSStyleSheet).replaceSync(this.cssText),s&&F.set(e,t))}return t}toString(){return this.cssText}};const pt=r=>new rt(typeof r=="string"?r:r+"",void 0,D),I=(r,...t)=>{const e=r.length===1?r[0]:t.reduce((s,i,o)=>s+(n=>{if(n._$cssResult$===!0)return n.cssText;if(typeof n=="number")return n;throw Error("Value passed to 'css' function must be a 'css' function result: "+n+". Use 'unsafeCSS' to pass non-literal values, but take care to ensure page security.")})(i)+r[o+1],r[0]);return new rt(e,r,D)},dt=(r,t)=>{if(L)r.adoptedStyleSheets=t.map(e=>e instanceof CSSStyleSheet?e:e.styleSheet);else for(const e of t){const s=document.createElement("style"),i=T.litNonce;i!==void 0&&s.setAttribute("nonce",i),s.textContent=e.cssText,r.appendChild(s)}},K=L?r=>r:r=>r instanceof CSSStyleSheet?(t=>{let e="";for(const s of t.cssRules)e+=s.cssText;return pt(e)})(r):r;/**
|
|
6
|
-
* @license
|
|
7
|
-
* Copyright 2017 Google LLC
|
|
8
|
-
* SPDX-License-Identifier: BSD-3-Clause
|
|
9
|
-
*/const{is:ut,defineProperty:ft,getOwnPropertyDescriptor:$t,getOwnPropertyNames:gt,getOwnPropertySymbols:_t,getPrototypeOf:mt}=Object,N=globalThis,Z=N.trustedTypes,yt=Z?Z.emptyScript:"",vt=N.reactiveElementPolyfillSupport,E=(r,t)=>r,j={toAttribute(r,t){switch(t){case Boolean:r=r?yt:null;break;case Object:case Array:r=r==null?r:JSON.stringify(r)}return r},fromAttribute(r,t){let e=r;switch(t){case Boolean:e=r!==null;break;case Number:e=r===null?null:Number(r);break;case Object:case Array:try{e=JSON.parse(r)}catch{e=null}}return e}},ot=(r,t)=>!ut(r,t),J={attribute:!0,type:String,converter:j,reflect:!1,useDefault:!1,hasChanged:ot};Symbol.metadata??=Symbol("metadata"),N.litPropertyMetadata??=new WeakMap;let A=class extends HTMLElement{static addInitializer(t){this._$Ei(),(this.l??=[]).push(t)}static get observedAttributes(){return this.finalize(),this._$Eh&&[...this._$Eh.keys()]}static createProperty(t,e=J){if(e.state&&(e.attribute=!1),this._$Ei(),this.prototype.hasOwnProperty(t)&&((e=Object.create(e)).wrapped=!0),this.elementProperties.set(t,e),!e.noAccessor){const s=Symbol(),i=this.getPropertyDescriptor(t,s,e);i!==void 0&&ft(this.prototype,t,i)}}static getPropertyDescriptor(t,e,s){const{get:i,set:o}=$t(this.prototype,t)??{get(){return this[e]},set(n){this[e]=n}};return{get:i,set(n){const h=i?.call(this);o?.call(this,n),this.requestUpdate(t,h,s)},configurable:!0,enumerable:!0}}static getPropertyOptions(t){return this.elementProperties.get(t)??J}static _$Ei(){if(this.hasOwnProperty(E("elementProperties")))return;const t=mt(this);t.finalize(),t.l!==void 0&&(this.l=[...t.l]),this.elementProperties=new Map(t.elementProperties)}static finalize(){if(this.hasOwnProperty(E("finalized")))return;if(this.finalized=!0,this._$Ei(),this.hasOwnProperty(E("properties"))){const e=this.properties,s=[...gt(e),..._t(e)];for(const i of s)this.createProperty(i,e[i])}const t=this[Symbol.metadata];if(t!==null){const e=litPropertyMetadata.get(t);if(e!==void 0)for(const[s,i]of e)this.elementProperties.set(s,i)}this._$Eh=new Map;for(const[e,s]of this.elementProperties){const i=this._$Eu(e,s);i!==void 0&&this._$Eh.set(i,e)}this.elementStyles=this.finalizeStyles(this.styles)}static finalizeStyles(t){const e=[];if(Array.isArray(t)){const s=new Set(t.flat(1/0).reverse());for(const i of s)e.unshift(K(i))}else t!==void 0&&e.push(K(t));return e}static _$Eu(t,e){const s=e.attribute;return s===!1?void 0:typeof s=="string"?s:typeof t=="string"?t.toLowerCase():void 0}constructor(){super(),this._$Ep=void 0,this.isUpdatePending=!1,this.hasUpdated=!1,this._$Em=null,this._$Ev()}_$Ev(){this._$ES=new Promise(t=>this.enableUpdating=t),this._$AL=new Map,this._$E_(),this.requestUpdate(),this.constructor.l?.forEach(t=>t(this))}addController(t){(this._$EO??=new Set).add(t),this.renderRoot!==void 0&&this.isConnected&&t.hostConnected?.()}removeController(t){this._$EO?.delete(t)}_$E_(){const t=new Map,e=this.constructor.elementProperties;for(const s of e.keys())this.hasOwnProperty(s)&&(t.set(s,this[s]),delete this[s]);t.size>0&&(this._$Ep=t)}createRenderRoot(){const t=this.shadowRoot??this.attachShadow(this.constructor.shadowRootOptions);return dt(t,this.constructor.elementStyles),t}connectedCallback(){this.renderRoot??=this.createRenderRoot(),this.enableUpdating(!0),this._$EO?.forEach(t=>t.hostConnected?.())}enableUpdating(t){}disconnectedCallback(){this._$EO?.forEach(t=>t.hostDisconnected?.())}attributeChangedCallback(t,e,s){this._$AK(t,s)}_$ET(t,e){const s=this.constructor.elementProperties.get(t),i=this.constructor._$Eu(t,s);if(i!==void 0&&s.reflect===!0){const o=(s.converter?.toAttribute!==void 0?s.converter:j).toAttribute(e,s.type);this._$Em=t,o==null?this.removeAttribute(i):this.setAttribute(i,o),this._$Em=null}}_$AK(t,e){const s=this.constructor,i=s._$Eh.get(t);if(i!==void 0&&this._$Em!==i){const o=s.getPropertyOptions(i),n=typeof o.converter=="function"?{fromAttribute:o.converter}:o.converter?.fromAttribute!==void 0?o.converter:j;this._$Em=i;const h=n.fromAttribute(e,o.type);this[i]=h??this._$Ej?.get(i)??h,this._$Em=null}}requestUpdate(t,e,s,i=!1,o){if(t!==void 0){const n=this.constructor;if(i===!1&&(o=this[t]),s??=n.getPropertyOptions(t),!((s.hasChanged??ot)(o,e)||s.useDefault&&s.reflect&&o===this._$Ej?.get(t)&&!this.hasAttribute(n._$Eu(t,s))))return;this.C(t,e,s)}this.isUpdatePending===!1&&(this._$ES=this._$EP())}C(t,e,{useDefault:s,reflect:i,wrapped:o},n){s&&!(this._$Ej??=new Map).has(t)&&(this._$Ej.set(t,n??e??this[t]),o!==!0||n!==void 0)||(this._$AL.has(t)||(this.hasUpdated||s||(e=void 0),this._$AL.set(t,e)),i===!0&&this._$Em!==t&&(this._$Eq??=new Set).add(t))}async _$EP(){this.isUpdatePending=!0;try{await this._$ES}catch(e){Promise.reject(e)}const t=this.scheduleUpdate();return t!=null&&await t,!this.isUpdatePending}scheduleUpdate(){return this.performUpdate()}performUpdate(){if(!this.isUpdatePending)return;if(!this.hasUpdated){if(this.renderRoot??=this.createRenderRoot(),this._$Ep){for(const[i,o]of this._$Ep)this[i]=o;this._$Ep=void 0}const s=this.constructor.elementProperties;if(s.size>0)for(const[i,o]of s){const{wrapped:n}=o,h=this[i];n!==!0||this._$AL.has(i)||h===void 0||this.C(i,void 0,o,h)}}let t=!1;const e=this._$AL;try{t=this.shouldUpdate(e),t?(this.willUpdate(e),this._$EO?.forEach(s=>s.hostUpdate?.()),this.update(e)):this._$EM()}catch(s){throw t=!1,this._$EM(),s}t&&this._$AE(e)}willUpdate(t){}_$AE(t){this._$EO?.forEach(e=>e.hostUpdated?.()),this.hasUpdated||(this.hasUpdated=!0,this.firstUpdated(t)),this.updated(t)}_$EM(){this._$AL=new Map,this.isUpdatePending=!1}get updateComplete(){return this.getUpdateComplete()}getUpdateComplete(){return this._$ES}shouldUpdate(t){return!0}update(t){this._$Eq&&=this._$Eq.forEach(e=>this._$ET(e,this[e])),this._$EM()}updated(t){}firstUpdated(t){}};A.elementStyles=[],A.shadowRootOptions={mode:"open"},A[E("elementProperties")]=new Map,A[E("finalized")]=new Map,vt?.({ReactiveElement:A}),(N.reactiveElementVersions??=[]).push("2.1.2");/**
|
|
10
|
-
* @license
|
|
11
|
-
* Copyright 2017 Google LLC
|
|
12
|
-
* SPDX-License-Identifier: BSD-3-Clause
|
|
13
|
-
*/const B=globalThis,Q=r=>r,M=B.trustedTypes,Y=M?M.createPolicy("lit-html",{createHTML:r=>r}):void 0,nt="$lit$",_=`lit$${Math.random().toFixed(9).slice(2)}$`,at="?"+_,bt=`<${at}>`,b=document,C=()=>b.createComment(""),P=r=>r===null||typeof r!="object"&&typeof r!="function",q=Array.isArray,At=r=>q(r)||typeof r?.[Symbol.iterator]=="function",R=`[
|
|
14
|
-
\f\r]`,S=/<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g,G=/-->/g,X=/>/g,m=RegExp(`>|${R}(?:([^\\s"'>=/]+)(${R}*=${R}*(?:[^
|
|
15
|
-
\f\r"'\`<>=]|("|')|))|$)`,"g"),tt=/'/g,et=/"/g,lt=/^(?:script|style|textarea|title)$/i,wt=r=>(t,...e)=>({_$litType$:r,strings:t,values:e}),f=wt(1),w=Symbol.for("lit-noChange"),c=Symbol.for("lit-nothing"),st=new WeakMap,y=b.createTreeWalker(b,129);function ht(r,t){if(!q(r)||!r.hasOwnProperty("raw"))throw Error("invalid template strings array");return Y!==void 0?Y.createHTML(t):t}const xt=(r,t)=>{const e=r.length-1,s=[];let i,o=t===2?"<svg>":t===3?"<math>":"",n=S;for(let h=0;h<e;h++){const a=r[h];let p,d,l=-1,$=0;for(;$<a.length&&(n.lastIndex=$,d=n.exec(a),d!==null);)$=n.lastIndex,n===S?d[1]==="!--"?n=G:d[1]!==void 0?n=X:d[2]!==void 0?(lt.test(d[2])&&(i=RegExp("</"+d[2],"g")),n=m):d[3]!==void 0&&(n=m):n===m?d[0]===">"?(n=i??S,l=-1):d[1]===void 0?l=-2:(l=n.lastIndex-d[2].length,p=d[1],n=d[3]===void 0?m:d[3]==='"'?et:tt):n===et||n===tt?n=m:n===G||n===X?n=S:(n=m,i=void 0);const g=n===m&&r[h+1].startsWith("/>")?" ":"";o+=n===S?a+bt:l>=0?(s.push(p),a.slice(0,l)+nt+a.slice(l)+_+g):a+_+(l===-2?h:g)}return[ht(r,o+(r[e]||"<?>")+(t===2?"</svg>":t===3?"</math>":"")),s]};class k{constructor({strings:t,_$litType$:e},s){let i;this.parts=[];let o=0,n=0;const h=t.length-1,a=this.parts,[p,d]=xt(t,e);if(this.el=k.createElement(p,s),y.currentNode=this.el.content,e===2||e===3){const l=this.el.content.firstChild;l.replaceWith(...l.childNodes)}for(;(i=y.nextNode())!==null&&a.length<h;){if(i.nodeType===1){if(i.hasAttributes())for(const l of i.getAttributeNames())if(l.endsWith(nt)){const $=d[n++],g=i.getAttribute(l).split(_),O=/([.?@])?(.*)/.exec($);a.push({type:1,index:o,name:O[2],strings:g,ctor:O[1]==="."?Et:O[1]==="?"?Ct:O[1]==="@"?Pt:H}),i.removeAttribute(l)}else l.startsWith(_)&&(a.push({type:6,index:o}),i.removeAttribute(l));if(lt.test(i.tagName)){const l=i.textContent.split(_),$=l.length-1;if($>0){i.textContent=M?M.emptyScript:"";for(let g=0;g<$;g++)i.append(l[g],C()),y.nextNode(),a.push({type:2,index:++o});i.append(l[$],C())}}}else if(i.nodeType===8)if(i.data===at)a.push({type:2,index:o});else{let l=-1;for(;(l=i.data.indexOf(_,l+1))!==-1;)a.push({type:7,index:o}),l+=_.length-1}o++}}static createElement(t,e){const s=b.createElement("template");return s.innerHTML=t,s}}function x(r,t,e=r,s){if(t===w)return t;let i=s!==void 0?e._$Co?.[s]:e._$Cl;const o=P(t)?void 0:t._$litDirective$;return i?.constructor!==o&&(i?._$AO?.(!1),o===void 0?i=void 0:(i=new o(r),i._$AT(r,e,s)),s!==void 0?(e._$Co??=[])[s]=i:e._$Cl=i),i!==void 0&&(t=x(r,i._$AS(r,t.values),i,s)),t}class St{constructor(t,e){this._$AV=[],this._$AN=void 0,this._$AD=t,this._$AM=e}get parentNode(){return this._$AM.parentNode}get _$AU(){return this._$AM._$AU}u(t){const{el:{content:e},parts:s}=this._$AD,i=(t?.creationScope??b).importNode(e,!0);y.currentNode=i;let o=y.nextNode(),n=0,h=0,a=s[0];for(;a!==void 0;){if(n===a.index){let p;a.type===2?p=new U(o,o.nextSibling,this,t):a.type===1?p=new a.ctor(o,a.name,a.strings,this,t):a.type===6&&(p=new kt(o,this,t)),this._$AV.push(p),a=s[++h]}n!==a?.index&&(o=y.nextNode(),n++)}return y.currentNode=b,i}p(t){let e=0;for(const s of this._$AV)s!==void 0&&(s.strings!==void 0?(s._$AI(t,s,e),e+=s.strings.length-2):s._$AI(t[e])),e++}}class U{get _$AU(){return this._$AM?._$AU??this._$Cv}constructor(t,e,s,i){this.type=2,this._$AH=c,this._$AN=void 0,this._$AA=t,this._$AB=e,this._$AM=s,this.options=i,this._$Cv=i?.isConnected??!0}get parentNode(){let t=this._$AA.parentNode;const e=this._$AM;return e!==void 0&&t?.nodeType===11&&(t=e.parentNode),t}get startNode(){return this._$AA}get endNode(){return this._$AB}_$AI(t,e=this){t=x(this,t,e),P(t)?t===c||t==null||t===""?(this._$AH!==c&&this._$AR(),this._$AH=c):t!==this._$AH&&t!==w&&this._(t):t._$litType$!==void 0?this.$(t):t.nodeType!==void 0?this.T(t):At(t)?this.k(t):this._(t)}O(t){return this._$AA.parentNode.insertBefore(t,this._$AB)}T(t){this._$AH!==t&&(this._$AR(),this._$AH=this.O(t))}_(t){this._$AH!==c&&P(this._$AH)?this._$AA.nextSibling.data=t:this.T(b.createTextNode(t)),this._$AH=t}$(t){const{values:e,_$litType$:s}=t,i=typeof s=="number"?this._$AC(t):(s.el===void 0&&(s.el=k.createElement(ht(s.h,s.h[0]),this.options)),s);if(this._$AH?._$AD===i)this._$AH.p(e);else{const o=new St(i,this),n=o.u(this.options);o.p(e),this.T(n),this._$AH=o}}_$AC(t){let e=st.get(t.strings);return e===void 0&&st.set(t.strings,e=new k(t)),e}k(t){q(this._$AH)||(this._$AH=[],this._$AR());const e=this._$AH;let s,i=0;for(const o of t)i===e.length?e.push(s=new U(this.O(C()),this.O(C()),this,this.options)):s=e[i],s._$AI(o),i++;i<e.length&&(this._$AR(s&&s._$AB.nextSibling,i),e.length=i)}_$AR(t=this._$AA.nextSibling,e){for(this._$AP?.(!1,!0,e);t!==this._$AB;){const s=Q(t).nextSibling;Q(t).remove(),t=s}}setConnected(t){this._$AM===void 0&&(this._$Cv=t,this._$AP?.(t))}}class H{get tagName(){return this.element.tagName}get _$AU(){return this._$AM._$AU}constructor(t,e,s,i,o){this.type=1,this._$AH=c,this._$AN=void 0,this.element=t,this.name=e,this._$AM=i,this.options=o,s.length>2||s[0]!==""||s[1]!==""?(this._$AH=Array(s.length-1).fill(new String),this.strings=s):this._$AH=c}_$AI(t,e=this,s,i){const o=this.strings;let n=!1;if(o===void 0)t=x(this,t,e,0),n=!P(t)||t!==this._$AH&&t!==w,n&&(this._$AH=t);else{const h=t;let a,p;for(t=o[0],a=0;a<o.length-1;a++)p=x(this,h[s+a],e,a),p===w&&(p=this._$AH[a]),n||=!P(p)||p!==this._$AH[a],p===c?t=c:t!==c&&(t+=(p??"")+o[a+1]),this._$AH[a]=p}n&&!i&&this.j(t)}j(t){t===c?this.element.removeAttribute(this.name):this.element.setAttribute(this.name,t??"")}}class Et extends H{constructor(){super(...arguments),this.type=3}j(t){this.element[this.name]=t===c?void 0:t}}class Ct extends H{constructor(){super(...arguments),this.type=4}j(t){this.element.toggleAttribute(this.name,!!t&&t!==c)}}class Pt extends H{constructor(t,e,s,i,o){super(t,e,s,i,o),this.type=5}_$AI(t,e=this){if((t=x(this,t,e,0)??c)===w)return;const s=this._$AH,i=t===c&&s!==c||t.capture!==s.capture||t.once!==s.once||t.passive!==s.passive,o=t!==c&&(s===c||i);i&&this.element.removeEventListener(this.name,this,s),o&&this.element.addEventListener(this.name,this,t),this._$AH=t}handleEvent(t){typeof this._$AH=="function"?this._$AH.call(this.options?.host??this.element,t):this._$AH.handleEvent(t)}}class kt{constructor(t,e,s){this.element=t,this.type=6,this._$AN=void 0,this._$AM=e,this.options=s}get _$AU(){return this._$AM._$AU}_$AI(t){x(this,t)}}const Ut=B.litHtmlPolyfillSupport;Ut?.(k,U),(B.litHtmlVersions??=[]).push("3.3.3");const Ot=(r,t,e)=>{const s=e?.renderBefore??t;let i=s._$litPart$;if(i===void 0){const o=e?.renderBefore??null;s._$litPart$=i=new U(t.insertBefore(C(),o),o,void 0,e??{})}return i._$AI(r),i};/**
|
|
16
|
-
* @license
|
|
17
|
-
* Copyright 2017 Google LLC
|
|
18
|
-
* SPDX-License-Identifier: BSD-3-Clause
|
|
19
|
-
*/const W=globalThis;class v extends A{constructor(){super(...arguments),this.renderOptions={host:this},this._$Do=void 0}createRenderRoot(){const t=super.createRenderRoot();return this.renderOptions.renderBefore??=t.firstChild,t}update(t){const e=this.render();this.hasUpdated||(this.renderOptions.isConnected=this.isConnected),super.update(t),this._$Do=Ot(e,this.renderRoot,this.renderOptions)}connectedCallback(){super.connectedCallback(),this._$Do?.setConnected(!0)}disconnectedCallback(){super.disconnectedCallback(),this._$Do?.setConnected(!1)}render(){return w}}v._$litElement$=!0,v.finalized=!0,W.litElementHydrateSupport?.({LitElement:v});const Tt=W.litElementPolyfillSupport;Tt?.({LitElement:v});(W.litElementVersions??=[]).push("4.2.2");var ct;let z=0;const it=new Set;function Mt(r){z++;try{r()}finally{z--,z===0&&Nt()}}function Nt(){const r=new Set(it);it.clear();for(const t of r)t()}function Ht(r,t){return r!=r?t==t:r!==t||r&&typeof r=="object"||typeof r=="function"}function Rt(r){return r&&typeof r.deref=="function"}class V{static#e=0;#t;#s;#i=new Set;#r=ct.#e++;name;constructor(t,e){this.#t=t,this.#s=t,this.name=e}_get(){return u.activeConsumer&&u.activeConsumer.track(this),this.#t}_set(t){return Ht(t,this.#t)?(this.#s=this.#t,this.#t=t,this._notify(),!0):!1}subscribe(t,e=!1){let s=t;return e&&(s=new WeakRef(t)),this.#i.add(s),()=>this.#i.delete(s)}_notify(){const t=[...this.#i];for(const e of t){let s;if(Rt(e)){if(s=e.deref(),!s){this.#i.delete(e);continue}}else s=e;s()}}get id(){return this.#r}get previousValue(){return this.#s}toString(){return this.name?`${this.constructor.name}(${this.name})`:`${this.constructor.name}#${this.id}`}}ct=V;class u extends V{static#e=[];constructor(t,e){super(t,e)}static get activeConsumer(){return this.#e[this.#e.length-1]}static push(t){this.#e.push(t)}static pop(){this.#e.pop()}get(){return this._get()}set(t){Mt(()=>{this._set(t)})}get value(){return this.get()}set value(t){this.set(t)}update(t){this.set(t(this.get()))}}class zt extends V{#e;#t=!0;#s=!1;#i=new Map;_debugParent;#r;#o=()=>{this.#t||(this.#t=!0,this._notify())};constructor(t,e,s){super(void 0,e),this.#e=t,this.#r=s?.weak??!0}track(t){if(this.#i.has(t))return;const e=t.subscribe(this.#o,this.#r);this.#i.set(t,e)}dispose(){this.#n()}#n(){for(const t of this.#i.values())t();this.#i.clear()}get(){if(u.activeConsumer&&u.activeConsumer.track(this),!this.#t)return this._get();if(this.#s)throw new Error(`Cycle detected in ${this}
|
|
20
|
-
↳ while computing ${this._debugParent??"root"}`);this.#s=!0,this.#n(),u.push(this);try{const t=this.#e();this._set(t)}finally{u.pop(),this.#t=!1,this.#s=!1}return this._get()}get value(){return this.get()}set value(t){throw new Error(`Cannot set value of Computed ${this}. Computed values are read-only.`)}subscribe(t,e=!1){const s=super.subscribe(t,e);return u.activeConsumer||this.get(),s}}class jt{#e;#t=new Map;_debugParent;constructor(t){this.#e=t,t.addController(this);const e=t,s=e.update,i=this;e.update=function(o){u.push(i);try{s.call(this,o)}finally{u.pop()}}}track(t){this.#t.has(t)||this.#t.set(t,t.subscribe(this.#s,!0))}#s=()=>{this.#e.requestUpdate()};hostUpdate(){for(const t of this.#t.values())t();this.#t.clear()}hostDisconnected(){for(const t of this.#t.values())t();this.#t.clear()}toString(){const t=this.#e;return`SignalWatcher(${t?.localName??t?.tagName??t?.constructor?.name??"unknown"})`}}class Lt extends v{static{this.properties={results:{attribute:!1},onSelect:{attribute:!1}}}static{this.styles=I`
|
|
21
|
-
:host { display: block; }
|
|
22
|
-
.row { padding: 10px 14px; border-bottom: 1px solid #8882; cursor: pointer; }
|
|
23
|
-
.row:hover { background: #8881; }
|
|
24
|
-
.top { display: flex; justify-content: space-between; gap: 8px; font-size: 13px; }
|
|
25
|
-
.name { font-weight: 600; }
|
|
26
|
-
.meta { opacity: 0.65; font-size: 11px; white-space: nowrap; }
|
|
27
|
-
.desc { font-size: 12px; opacity: 0.8; margin-top: 3px; }
|
|
28
|
-
.tags { margin-top: 4px; display: flex; gap: 4px; flex-wrap: wrap; }
|
|
29
|
-
.tag { font-size: 10px; border: 1px solid #8886; border-radius: 999px; padding: 1px 6px; }
|
|
30
|
-
.type-badge { font-size: 10px; text-transform: uppercase; opacity: 0.6; }
|
|
31
|
-
.empty { padding: 24px; opacity: 0.6; font-size: 13px; }
|
|
32
|
-
`}render(){return!this.results||this.results.length===0?f`<div class="empty">No results.</div>`:f`
|
|
33
|
-
${this.results.map(t=>f`
|
|
34
|
-
<div class="row" @click=${()=>this.onSelect(t)}>
|
|
35
|
-
<div class="top">
|
|
36
|
-
<span class="name">${t.name}</span>
|
|
37
|
-
<span class="meta">${t.owner??"—"} · ${t.status}</span>
|
|
38
|
-
</div>
|
|
39
|
-
<div class="desc">${t.description}</div>
|
|
40
|
-
<div class="tags">
|
|
41
|
-
<span class="type-badge">${t._table==="skills"?"skill":"memory"}</span>
|
|
42
|
-
${t.tags.map(e=>f`<span class="tag">${e}</span>`)}
|
|
43
|
-
</div>
|
|
44
|
-
</div>
|
|
45
|
-
`)}
|
|
46
|
-
`}}customElements.define("result-list",Lt);class Dt extends v{static{this.properties={selected:{attribute:!1},_doc:{state:!0}}}static{this.styles=I`
|
|
47
|
-
:host { display: block; padding: 16px; }
|
|
48
|
-
h2 { margin: 0 0 4px; font-size: 16px; }
|
|
49
|
-
.meta { font-size: 12px; opacity: 0.7; margin-bottom: 12px; }
|
|
50
|
-
.source-path {
|
|
51
|
-
font-family: monospace;
|
|
52
|
-
font-size: 11px;
|
|
53
|
-
opacity: 0.6;
|
|
54
|
-
cursor: pointer;
|
|
55
|
-
word-break: break-all;
|
|
56
|
-
}
|
|
57
|
-
pre {
|
|
58
|
-
white-space: pre-wrap;
|
|
59
|
-
font-size: 12px;
|
|
60
|
-
background: #8881;
|
|
61
|
-
padding: 12px;
|
|
62
|
-
border-radius: 6px;
|
|
63
|
-
max-height: 60vh;
|
|
64
|
-
overflow-y: auto;
|
|
65
|
-
}
|
|
66
|
-
.empty { opacity: 0.5; font-size: 13px; }
|
|
67
|
-
`}updated(t){t.has("selected")&&this.selected&&this.#e()}async#e(){const{table:t,id:e}=this.selected,s=await fetch(`/api/entries/${t}/${encodeURIComponent(e)}`);this._doc=s.ok?await s.json():null}#t(){this._doc?.source_path&&navigator.clipboard?.writeText(this._doc.source_path)}render(){if(!this.selected)return f`<div class="empty">Select an entry to view its details.</div>`;if(!this._doc)return c;const t=this._doc;return f`
|
|
68
|
-
<h2>${t.name??t.key??t.id}</h2>
|
|
69
|
-
<div class="meta">
|
|
70
|
-
${t.tags?.join(", ")||"no tags"} · ${t.status}${t.owner?` · owner: ${t.owner}`:""}
|
|
71
|
-
</div>
|
|
72
|
-
<div class="meta">${t.description}</div>
|
|
73
|
-
<pre>${t.body}</pre>
|
|
74
|
-
<div class="source-path" title="click to copy" @click=${()=>this.#t()}>${t.source_path}</div>
|
|
75
|
-
`}}customElements.define("detail-panel",Dt);const It=[{value:"all",label:"All"},{value:"skill",label:"Skills"},{value:"memory",label:"Memories"}],Bt={tags:[],statuses:[],owners:[],doc_types:[],key_types:[]};class qt extends v{static{this.styles=I`
|
|
76
|
-
:host { display: block; height: 100vh; }
|
|
77
|
-
.filters {
|
|
78
|
-
padding: 12px 16px;
|
|
79
|
-
border-bottom: 1px solid #8883;
|
|
80
|
-
display: flex;
|
|
81
|
-
flex-direction: column;
|
|
82
|
-
gap: 8px;
|
|
83
|
-
}
|
|
84
|
-
.filters input[type='search'] {
|
|
85
|
-
font-size: 14px;
|
|
86
|
-
padding: 8px 10px;
|
|
87
|
-
width: 100%;
|
|
88
|
-
max-width: 480px;
|
|
89
|
-
box-sizing: border-box;
|
|
90
|
-
}
|
|
91
|
-
.row { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
|
|
92
|
-
.chip {
|
|
93
|
-
border: 1px solid #8886;
|
|
94
|
-
border-radius: 999px;
|
|
95
|
-
padding: 3px 10px;
|
|
96
|
-
font-size: 12px;
|
|
97
|
-
cursor: pointer;
|
|
98
|
-
background: none;
|
|
99
|
-
color: inherit;
|
|
100
|
-
}
|
|
101
|
-
.chip.active { background: #2563eb; border-color: #2563eb; color: white; }
|
|
102
|
-
.type-toggle button {
|
|
103
|
-
border: 1px solid #8886;
|
|
104
|
-
background: none;
|
|
105
|
-
color: inherit;
|
|
106
|
-
padding: 5px 12px;
|
|
107
|
-
font-size: 13px;
|
|
108
|
-
cursor: pointer;
|
|
109
|
-
}
|
|
110
|
-
.type-toggle button.active { background: #2563eb; border-color: #2563eb; color: white; }
|
|
111
|
-
.type-toggle button:first-child { border-radius: 6px 0 0 6px; }
|
|
112
|
-
.type-toggle button:last-child { border-radius: 0 6px 6px 0; }
|
|
113
|
-
.body-region { display: flex; height: calc(100vh - 130px); }
|
|
114
|
-
result-list { flex: 1 1 40%; overflow-y: auto; border-right: 1px solid #8883; }
|
|
115
|
-
detail-panel { flex: 1 1 60%; overflow-y: auto; }
|
|
116
|
-
label.small { font-size: 12px; opacity: 0.7; }
|
|
117
|
-
`}#e=new u("");#t=new u("all");#s=new u([]);#i=new u([]);#r=new u(Bt);#o=new u(null);constructor(){super(),new jt(this)}#n=new zt(()=>{const t=new URLSearchParams;this.#t.value!=="all"&&t.set("type",this.#t.value),this.#e.value.trim()&&t.set("q",this.#e.value.trim());for(const e of this.#s.value)t.append("tag",e);return t.toString()});connectedCallback(){super.connectedCallback(),this.#a(),this.#l()}async#a(){const t=await fetch(`/api/entries?${this.#n.value}`);this.#i.set(await t.json())}async#l(){const t=this.#t.value==="all"?"":`?type=${this.#t.value}`,e=await fetch(`/api/facets${t}`);this.#r.set(await e.json())}#h(t){this.#t.set(t),this.#s.set([]),this.#l(),this.#a()}#c(t){const e=this.#s.value;this.#s.set(e.includes(t)?e.filter(s=>s!==t):[...e,t]),this.#a()}#p(t){this.#e.set(t.target.value),this.#a()}#d(t){this.#o.set({table:t._table,id:t.id})}render(){const t=this.#r.value;return f`
|
|
118
|
-
<div class="filters">
|
|
119
|
-
<input
|
|
120
|
-
type="search"
|
|
121
|
-
placeholder="Search descriptions, bodies, tags..."
|
|
122
|
-
.value=${this.#e.value}
|
|
123
|
-
@input=${e=>this.#p(e)}
|
|
124
|
-
/>
|
|
125
|
-
<div class="row type-toggle">
|
|
126
|
-
${It.map(e=>f`
|
|
127
|
-
<button
|
|
128
|
-
class=${this.#t.value===e.value?"active":""}
|
|
129
|
-
@click=${()=>this.#h(e.value)}
|
|
130
|
-
>
|
|
131
|
-
${e.label}
|
|
132
|
-
</button>
|
|
133
|
-
`)}
|
|
134
|
-
</div>
|
|
135
|
-
<div class="row">
|
|
136
|
-
${t.tags.length===0?f`<label class="small">no tags yet</label>`:t.tags.map(e=>f`
|
|
137
|
-
<button
|
|
138
|
-
class="chip ${this.#s.value.includes(e)?"active":""}"
|
|
139
|
-
@click=${()=>this.#c(e)}
|
|
140
|
-
>
|
|
141
|
-
${e}
|
|
142
|
-
</button>
|
|
143
|
-
`)}
|
|
144
|
-
</div>
|
|
145
|
-
</div>
|
|
146
|
-
<div class="body-region">
|
|
147
|
-
<result-list .results=${this.#i.value} .onSelect=${e=>this.#d(e)}></result-list>
|
|
148
|
-
<detail-panel .selected=${this.#o.value}></detail-panel>
|
|
149
|
-
</div>
|
|
150
|
-
`}}customElements.define("mem-bucket-app",qt);
|