@mneme-ai/xray 3.17.0 → 3.19.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/package.json +2 -2
- package/public/index.html +4 -0
- package/public/thymos.html +120 -105
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mneme-ai/xray",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.19.0",
|
|
4
4
|
"description": "Mneme Repo X-Ray — a signed, raw-free, deterministic X-Ray of any repo. Every number is reproducible from git/AST/metadata and sealed with an offline-verifiable NOTARY receipt. No source code ever leaves the machine; no LLM guesses anything.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
"mneme"
|
|
48
48
|
],
|
|
49
49
|
"dependencies": {
|
|
50
|
-
"@mneme-ai/core": "3.
|
|
50
|
+
"@mneme-ai/core": "3.19.0"
|
|
51
51
|
},
|
|
52
52
|
"optionalDependencies": {
|
|
53
53
|
"@resvg/resvg-js": "^2.6.2"
|
package/public/index.html
CHANGED
|
@@ -53,6 +53,9 @@
|
|
|
53
53
|
button:hover{background:#22232c}
|
|
54
54
|
button:active{transform:scale(.98)}
|
|
55
55
|
button:disabled{opacity:.5;cursor:default}
|
|
56
|
+
.thymoslink{display:inline-flex;align-items:center;gap:8px;margin:16px auto 0;padding:9px 16px;border:1px solid var(--line);border-radius:999px;color:var(--ink2);text-decoration:none;font-size:13.5px;font-weight:560;background:var(--soft);transition:border-color .15s,transform .1s}
|
|
57
|
+
.thymoslink:hover{border-color:#d9b8c6;transform:translateY(-1px)}
|
|
58
|
+
.thymoswrap{text-align:center}
|
|
56
59
|
.hint{color:var(--sub);font-size:13.5px;text-align:center;line-height:1.6}
|
|
57
60
|
.hint b{color:var(--ink2);font-weight:560}
|
|
58
61
|
.err{color:var(--red);text-align:center;margin-top:18px;font-size:14.5px}
|
|
@@ -477,6 +480,7 @@ document.querySelectorAll(".fontpick button").forEach(function(b){b.addEventList
|
|
|
477
480
|
<span><b>X-Ray</b> — instant health report: dependencies, secrets, risk & who-to-ask.</span>
|
|
478
481
|
<span><b>📦 AI Pack</b> — bundle the whole repo into one text to paste into any AI chat.</span>
|
|
479
482
|
</div>
|
|
483
|
+
<div class="thymoswrap"><a class="thymoslink" href="/thymos" title="THYMOS — a semantic attention filter that runs in your browser">💗 THYMOS — drowning in a pile? pull what matters to the top (real semantics, in your browser) →</a></div>
|
|
480
484
|
<p class="hint">Every number is <b>reproducible</b> from git, code & package metadata and sealed with an <b>offline-verifiable</b> signature. <span class="muted">Private repo or a local folder with no public URL? Run <code>npx @mneme-ai/xray bridge</code> on your machine — a <b>Scan a local folder</b> box appears here + your code never leaves your computer.</span></p>
|
|
481
485
|
<details class="keybox">
|
|
482
486
|
<summary>🔖 Optional — save your reports</summary>
|
package/public/thymos.html
CHANGED
|
@@ -3,130 +3,145 @@
|
|
|
3
3
|
<head>
|
|
4
4
|
<meta charset="utf-8">
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
6
|
-
<title>THYMOS —
|
|
7
|
-
<meta name="description" content="
|
|
6
|
+
<title>THYMOS — pull what matters out of a messy pile · Mneme</title>
|
|
7
|
+
<meta name="description" content="A filter for your attention. Tell THYMOS your goal, paste a messy pile of notes/tasks/links, and it pulls what matters to the top — using a real sentence model that runs 100% in your browser. Nothing is uploaded.">
|
|
8
|
+
<link rel="icon" href="/favicon.svg">
|
|
8
9
|
<style>
|
|
9
|
-
:root
|
|
10
|
-
*
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
.
|
|
17
|
-
|
|
18
|
-
.
|
|
19
|
-
|
|
20
|
-
.
|
|
21
|
-
|
|
22
|
-
.
|
|
23
|
-
.
|
|
24
|
-
.
|
|
25
|
-
|
|
26
|
-
.
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
.
|
|
10
|
+
:root{--bg:#ffffff;--soft:#f7f8fa;--ink:#111317;--ink2:#33353c;--sub:#6b7280;--line:#e7e9ee;--pink:#e0316f;--pinks:#fdeef4;--grn:#0a9d62;--blu:#2563eb;--gold:#b7791f;--r:16px;--rs:11px}
|
|
11
|
+
*{box-sizing:border-box}
|
|
12
|
+
html{-webkit-font-smoothing:antialiased}
|
|
13
|
+
body{margin:0;background:var(--bg);color:var(--ink);font:15.5px/1.6 -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif}
|
|
14
|
+
.wrap{max-width:760px;margin:0 auto;padding:26px 20px 90px}
|
|
15
|
+
.back{display:inline-block;color:var(--sub);text-decoration:none;font-size:13px;margin-bottom:18px}.back:hover{color:var(--ink)}
|
|
16
|
+
h1{font-size:30px;line-height:1.15;margin:0 0 6px;letter-spacing:-.6px}h1 .h{color:var(--pink)}
|
|
17
|
+
.tag{color:var(--sub);font-size:17px;margin:0 0 22px;max-width:560px}
|
|
18
|
+
/* explainer */
|
|
19
|
+
.explain{background:var(--soft);border:1px solid var(--line);border-radius:var(--r);padding:18px 20px;margin:0 0 22px}
|
|
20
|
+
.explain h2{font-size:14px;letter-spacing:.02em;text-transform:uppercase;color:var(--sub);margin:0 0 8px}
|
|
21
|
+
.explain p{margin:0 0 14px;color:var(--ink2)}
|
|
22
|
+
.steps{display:grid;grid-template-columns:repeat(3,1fr);gap:12px}@media(max-width:620px){.steps{grid-template-columns:1fr}}
|
|
23
|
+
.step{display:flex;gap:10px;align-items:flex-start}
|
|
24
|
+
.num{flex:none;width:24px;height:24px;border-radius:50%;background:var(--pink);color:#fff;font-weight:700;font-size:13px;display:grid;place-items:center}
|
|
25
|
+
.step b{display:block;font-size:14px}.step span{color:var(--sub);font-size:13px}
|
|
26
|
+
/* engine */
|
|
27
|
+
.engine{display:inline-flex;align-items:center;gap:8px;font-size:12.5px;color:var(--sub);border:1px solid var(--line);border-radius:999px;padding:5px 12px;margin:0 0 18px;background:#fff}
|
|
28
|
+
.engine .led{width:8px;height:8px;border-radius:50%;background:var(--gold)}.engine.ready .led{background:var(--grn)}.engine.fb .led{background:var(--pink)}
|
|
29
|
+
/* form */
|
|
30
|
+
.grid{display:grid;grid-template-columns:1fr 1fr;gap:14px}@media(max-width:620px){.grid{grid-template-columns:1fr}}
|
|
31
|
+
label{display:block;font-size:13px;color:var(--ink2);margin:0 0 6px;font-weight:600}
|
|
32
|
+
textarea{width:100%;background:#fff;border:1px solid var(--line);color:var(--ink);border-radius:var(--rs);padding:12px 14px;font:inherit;resize:vertical;transition:border-color .15s,box-shadow .15s}
|
|
33
|
+
textarea:focus{outline:0;border-color:var(--pink);box-shadow:0 0 0 3px var(--pinks)}
|
|
34
|
+
#goal{height:74px}#pile{height:210px}
|
|
35
|
+
.row{display:flex;gap:12px;align-items:center;margin:16px 0 4px;flex-wrap:wrap}
|
|
36
|
+
button{height:48px;padding:0 24px;border:0;border-radius:var(--rs);background:var(--pink);color:#fff;font-weight:700;font-size:15px;cursor:pointer;transition:transform .1s,filter .15s}
|
|
37
|
+
button:hover{filter:brightness(1.05)}button:active{transform:scale(.98)}button:disabled{opacity:.5;cursor:default}
|
|
38
|
+
.ghost{background:#fff;border:1px solid var(--line);color:var(--ink2);font-weight:600}
|
|
39
|
+
.thr{display:flex;align-items:center;gap:8px;color:var(--sub);font-size:13px;margin-left:auto}
|
|
40
|
+
input[type=range]{accent-color:var(--pink)}
|
|
41
|
+
.ex{color:var(--sub);font-size:13px;margin-top:8px}.ex a{color:var(--blu);cursor:pointer;text-decoration:none}.ex a:hover{text-decoration:underline}
|
|
42
|
+
.mono{font-family:ui-monospace,SFMono-Regular,Menlo,monospace}
|
|
43
|
+
/* results */
|
|
44
|
+
.summary{margin:24px 0 10px;font-size:15.5px;min-height:22px}.summary b{font-size:19px}
|
|
45
|
+
.item{display:flex;align-items:center;gap:13px;background:#fff;border:1px solid var(--line);border-radius:var(--rs);padding:12px 15px;margin:9px 0}
|
|
46
|
+
.item.keep{border-color:#cfead9;background:#fbfefc}.item.drop{opacity:.62}
|
|
47
|
+
.bar{flex:none;width:56px;height:6px;border-radius:99px;background:#eef0f4;overflow:hidden}
|
|
48
|
+
.bar i{display:block;height:100%;background:linear-gradient(90deg,var(--blu),var(--pink))}
|
|
49
|
+
.txt{flex:1;min-width:0;overflow-wrap:anywhere}
|
|
50
|
+
.verdict{flex:none;font-size:12px;font-weight:700;padding:3px 10px;border-radius:999px}
|
|
51
|
+
.keepv{background:#e6f6ee;color:var(--grn)}.letv{background:#f1f2f5;color:var(--sub)}
|
|
52
|
+
.sc{flex:none;color:var(--sub);font-size:12px;font-family:ui-monospace,monospace;width:32px;text-align:right}
|
|
53
|
+
.honest{border-left:3px solid var(--gold);padding:11px 15px;background:#fdf8ee;border-radius:0 10px 10px 0;color:#7a5b14;font-size:13px;margin-top:28px}
|
|
54
|
+
.foot{color:var(--sub);font-size:12.5px;margin-top:30px;text-align:center}.foot a{color:var(--blu);text-decoration:none}
|
|
55
|
+
.spin{width:13px;height:13px;border:2px solid var(--line);border-top-color:var(--blu);border-radius:50%;display:inline-block;animation:s .8s linear infinite;vertical-align:-2px}@keyframes s{to{transform:rotate(360deg)}}
|
|
30
56
|
</style>
|
|
31
57
|
</head>
|
|
32
58
|
<body>
|
|
33
59
|
<div class="wrap">
|
|
34
|
-
<
|
|
35
|
-
<
|
|
60
|
+
<a class="back" href="/">← Mneme · Repo X-Ray</a>
|
|
61
|
+
<h1>💗 <span class="h">THYMOS</span></h1>
|
|
62
|
+
<p class="tag">A filter for your attention — it pulls what matters out of a messy pile.</p>
|
|
36
63
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
<
|
|
40
|
-
<
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
<
|
|
44
|
-
<span><span class="dot" style="background:var(--gold)"></span>salience 0.5 — a normal note</span>
|
|
45
|
-
<span><span class="dot" style="background:var(--pink)"></span>salience 0.15 — a throwaway log line</span>
|
|
64
|
+
<div class="explain">
|
|
65
|
+
<h2>What it is & what it's for</h2>
|
|
66
|
+
<p>Got a long, messy list — notes, tasks, links, search results — and a goal? THYMOS reads the <b>meaning</b> of each line and surfaces the ones that actually matter for your goal, so you can ignore the rest. It’s a focus tool: less scrolling, less noise.</p>
|
|
67
|
+
<div class="steps">
|
|
68
|
+
<div class="step"><div class="num">1</div><div><b>Say your goal</b><span>what you’re trying to do right now</span></div></div>
|
|
69
|
+
<div class="step"><div class="num">2</div><div><b>Paste the pile</b><span>one item per line</span></div></div>
|
|
70
|
+
<div class="step"><div class="num">3</div><div><b>Hit Triage</b><span>keep the 🧲, drop the rest</span></div></div>
|
|
46
71
|
</div>
|
|
47
72
|
</div>
|
|
48
73
|
|
|
49
|
-
|
|
50
|
-
<div class="card">
|
|
51
|
-
<h2>② Resonance — the core attracts</h2>
|
|
52
|
-
<p class="k">Type your <b>vision</b>, then inbound items. Each item is pulled toward the core by its <b>resonance</b> (cosine over words) — high resonance is magnetised in, noise is repelled. Same math as <span class="mono">mneme thymos resonate</span>.</p>
|
|
53
|
-
<div class="row"><input id="core" type="text" value="local-first trust and memory for AI agents" placeholder="your core vision"></div>
|
|
54
|
-
<div class="row"><input id="items" type="text" value="signed memory for agents, vendor-neutral trust, cheap flights to tokyo, offline governance proof" placeholder="comma-separated inbound items"></div>
|
|
55
|
-
<canvas id="magnet" height="320"></canvas>
|
|
56
|
-
<div class="legend"><span><span class="dot" style="background:var(--grn)"></span>pulled in (resonance ≥ 0.12)</span><span><span class="dot" style="background:var(--mut)"></span>repelled</span></div>
|
|
57
|
-
</div>
|
|
74
|
+
<div class="engine" id="engine"><span class="led"></span><span id="engtext">semantic engine: loading… (≈25 MB once, then cached)</span></div>
|
|
58
75
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
<
|
|
62
|
-
<p class="k">Strong feeling either way sticks — praise <em>and</em> correction. Type anything.</p>
|
|
63
|
-
<div class="row"><input id="affect" type="text" value="งานนี้เยี่ยมมาก ขอบคุณ!" placeholder="type EN or Thai…"></div>
|
|
64
|
-
<div class="row" style="margin-top:14px">
|
|
65
|
-
<div>valence <span id="val" class="big mono">—</span></div>
|
|
66
|
-
<div style="margin-left:24px">intensity <span id="inten" class="big mono">—</span></div>
|
|
67
|
-
<div style="margin-left:24px">→ salience <span id="sal" class="pill" style="background:#1d2838;color:var(--blu)">—</span></div>
|
|
68
|
-
</div>
|
|
76
|
+
<div class="grid">
|
|
77
|
+
<div><label>① Your goal / focus right now</label><textarea id="goal" placeholder="e.g. ship the local-first trust layer for AI agents this week"></textarea></div>
|
|
78
|
+
<div><label>② The pile — one item per line</label><textarea id="pile" placeholder="refactor the auth module reply to the recruiter benchmark the signed-memory protocol buy cat food draft the launch post random cooking video"></textarea></div>
|
|
69
79
|
</div>
|
|
80
|
+
<div class="row">
|
|
81
|
+
<button id="run">🧲 Triage</button>
|
|
82
|
+
<button id="copy" class="ghost">Copy the keepers</button>
|
|
83
|
+
<span class="thr">let-go below <input id="thr" type="range" min="10" max="50" value="22"> <span id="thrv" class="mono">0.22</span></span>
|
|
84
|
+
</div>
|
|
85
|
+
<p class="ex">no idea? <a id="demo">load an example</a> — then hit Triage. <span class="mono">⌘/Ctrl + Enter</span> in the pile also runs it.</p>
|
|
70
86
|
|
|
71
|
-
<div
|
|
87
|
+
<div id="summary" class="summary"></div>
|
|
88
|
+
<div id="out"></div>
|
|
72
89
|
|
|
73
|
-
<
|
|
74
|
-
</div>
|
|
90
|
+
<div class="honest" id="honest">★ <b>How it works, honestly:</b> THYMOS turns your goal and each line into a real 384-dimension embedding with <b>all-MiniLM-L6-v2</b> (a small sentence model) running <b>100% in your browser</b> — only the model downloads once from a CDN; <b>your text is never uploaded</b>, there’s no server and no API key. It ranks by the similarity of meaning (it gets synonyms & paraphrase, not just shared words). It surfaces what fits <em>your stated goal</em> — it doesn’t read your mind, and it’s a small fast model, not a giant one.</div>
|
|
75
91
|
|
|
76
|
-
<
|
|
77
|
-
|
|
78
|
-
const clamp=(n,lo,hi)=>Math.max(lo,Math.min(hi,n||0));
|
|
79
|
-
const DAY=86400000;
|
|
80
|
-
function halfLifeMs(sal){ return (0.5 + clamp(sal,0,1)**2 * 547) * DAY; }
|
|
81
|
-
function strengthAt(sal, elapsedMs){ return clamp(Math.pow(0.5, elapsedMs/halfLifeMs(sal)),0,1); }
|
|
82
|
-
function bag(t){ const m={}; for(const w of (t||'').toLowerCase().split(/[^a-z0-9-]+/).filter(x=>x.length>1)) m[w]=(m[w]||0)+1; return m; }
|
|
83
|
-
function resonance(core,item){ const a=bag(core),b=bag(item); let dot=0; for(const k in a) dot+=a[k]*(b[k]||0); const mag=o=>Math.sqrt(Object.values(o).reduce((s,v)=>s+v*v,0)); const d=mag(a)*mag(b); return d?clamp(dot/d,0,1):0; }
|
|
84
|
-
const POS=["love","great","excellent","important","amazing","thank","perfect","brilliant","awesome","beautiful","ชอบ","รัก","เยี่ยม","สุดยอด","ดีมาก","สำคัญ","ประทับใจ","ขอบคุณ","เจ๋ง","ปลื้ม"];
|
|
85
|
-
const NEG=["wrong","bad","hate","broken","bug","terrible","angry","sad","awful","fail","ผิด","แย่","เกลียด","ไม่ชอบ","เสียใจ","โกรธ","พัง","บั๊ก","ห่วย","เซ็ง"];
|
|
86
|
-
const BOOST=["very","so","most","really","extremely","มาก","สุด","ที่สุด","โคตร","สุดๆ"];
|
|
87
|
-
function readAffect(t){ t=(t||'').toLowerCase(); const c=w=>w.reduce((n,x)=>n+(t.includes(x)?1:0),0); const pos=c(POS),neg=c(NEG),boost=c(BOOST),bangs=(t.match(/!|ที่สุด/g)||[]).length; const hits=pos+neg; if(!hits&&!boost&&!bangs)return{valence:0,intensity:0}; const valence=hits?clamp((pos-neg)/hits,-1,1):0; const intensity=clamp(hits*0.34+boost*0.18+bangs*0.12,0,1); return{valence:Math.round(valence*100)/100,intensity:Math.round(intensity*100)/100}; }
|
|
88
|
-
function salience(recalls,valence,consequence){ const reuse=recalls/(recalls+3); return Math.round(clamp(0.12+0.34*reuse+0.27*Math.abs(valence)+0.27*consequence,0,1)*1000)/1000; }
|
|
89
|
-
const css=v=>getComputedStyle(document.documentElement).getPropertyValue(v).trim();
|
|
92
|
+
<p class="foot">Part of <a href="/">Mneme</a> · the local-first trust & memory layer · <span class="mono">npm i -g mneme-ai</span></p>
|
|
93
|
+
</div>
|
|
90
94
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
for(const d of [0,100,200,300,400]){ x.fillText(d+'d',X(d)-8,h-6); }
|
|
97
|
-
const series=[[0.9,css('--grn')],[0.5,css('--gold')],[0.15,css('--pink')]];
|
|
98
|
-
for(const [sal,col] of series){ x.strokeStyle=col; x.lineWidth=2.4; x.beginPath(); for(let d=0; d<=days; d+=2){ const s=strengthAt(sal, d*DAY); const px=X(d),py=Y(s); d===0?x.moveTo(px,py):x.lineTo(px,py);} x.stroke(); }
|
|
99
|
-
// forget floor
|
|
100
|
-
x.strokeStyle='rgba(255,93,143,.5)'; x.setLineDash([4,4]); x.beginPath(); x.moveTo(pad,Y(0.18)); x.lineTo(w-10,Y(0.18)); x.stroke(); x.setLineDash([]); x.fillStyle='rgba(255,93,143,.8)'; x.fillText('forget floor 0.18',w-130,Y(0.18)-5);
|
|
101
|
-
}
|
|
95
|
+
<script type="module">
|
|
96
|
+
const $=id=>document.getElementById(id);
|
|
97
|
+
let THR=0.22, extractor=null, loading=null, MODE="semantic";
|
|
98
|
+
const eng=$('engine');
|
|
99
|
+
function setEng(t,cls){ $('engtext').innerHTML=t; eng.className="engine"+(cls?" "+cls:""); }
|
|
102
100
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
x.fillStyle = p.pulled ? css('--grn') : css('--mut'); x.beginPath(); x.arc(p.cxp,p.cyp,p.pulled?7:5,0,7); x.fill();
|
|
117
|
-
x.fillStyle=css('--ink'); x.font='12px system-ui'; x.textAlign='center'; const lbl=p.label.length>26?p.label.slice(0,24)+'…':p.label; x.fillText(lbl + ' ('+p.r.toFixed(2)+')', p.cxp, p.cyp-12);
|
|
118
|
-
}
|
|
119
|
-
raf=requestAnimationFrame(drawMagnet);
|
|
101
|
+
async function loadEngine(){
|
|
102
|
+
if(extractor) return extractor;
|
|
103
|
+
if(loading) return loading;
|
|
104
|
+
loading=(async()=>{
|
|
105
|
+
setEng('<span class="spin"></span> loading semantic engine (MiniLM, ≈25 MB once)…');
|
|
106
|
+
const { pipeline, env } = await import('https://cdn.jsdelivr.net/npm/@xenova/transformers@2.17.2');
|
|
107
|
+
env.allowLocalModels=false;
|
|
108
|
+
const ex = await pipeline('feature-extraction','Xenova/all-MiniLM-L6-v2',{ quantized:true,
|
|
109
|
+
progress_callback:(p)=>{ if(p&&p.status==='progress'&&p.file&&/onnx|model/.test(p.file)) setEng('<span class="spin"></span> downloading model… '+Math.round(p.progress||0)+'%'); } });
|
|
110
|
+
extractor=ex; MODE="semantic"; setEng('✓ semantic engine ready · all-MiniLM-L6-v2 · 100% in your browser','ready');
|
|
111
|
+
return ex;
|
|
112
|
+
})().catch(()=>{ extractor=null; MODE="fallback"; setEng('⚠ semantic engine unavailable — using an approximate keyword match','fb'); return null; });
|
|
113
|
+
return loading;
|
|
120
114
|
}
|
|
115
|
+
function cos(a,b){ let d=0; for(let i=0;i<a.length;i++) d+=a[i]*b[i]; return d; }
|
|
116
|
+
function bag(t){const m={};for(const w of (t||'').toLowerCase().split(/[^a-z0-9-]+/).filter(x=>x.length>1))m[w]=(m[w]||0)+1;return m}
|
|
117
|
+
function tokRes(c,i){const a=bag(c),b=bag(i);let d=0;for(const k in a)d+=a[k]*(b[k]||0);const mg=o=>Math.sqrt(Object.values(o).reduce((s,v)=>s+v*v,0));const dn=mg(a)*mg(b);return dn?d/dn:0}
|
|
121
118
|
|
|
122
|
-
|
|
123
|
-
|
|
119
|
+
$('thr').addEventListener('input',()=>{THR=$('thr').value/100;$('thrv').textContent=THR.toFixed(2);if($('out').children.length)run()});
|
|
120
|
+
$('demo').addEventListener('click',()=>{$('goal').value="ship the local-first trust layer for AI agents this week";$('pile').value="harden the agent governance gate\nreply to the recruiter from xAI\nmeasure how fast the signed memory protocol verifies\nbuy cat food\nwrite the announcement for the offline-proof feature\nwatch a random cooking video\nfix the disconnected-ops charter bug\nrepaint the bedroom someday";run()});
|
|
124
121
|
|
|
125
|
-
function
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
122
|
+
async function run(){
|
|
123
|
+
const goal=$('goal').value.trim();
|
|
124
|
+
const lines=$('pile').value.split('\n').map(s=>s.trim()).filter(Boolean);
|
|
125
|
+
if(!goal||!lines.length){$('summary').innerHTML='<span style="color:var(--sub)">enter a goal + a few lines, then hit Triage.</span>';$('out').innerHTML='';return}
|
|
126
|
+
$('run').disabled=true; $('summary').innerHTML='<span class="spin"></span> reading meaning + ranking…';
|
|
127
|
+
let scores;
|
|
128
|
+
try{
|
|
129
|
+
const ex=await loadEngine();
|
|
130
|
+
if(ex){ const t=await ex([goal,...lines],{pooling:'mean',normalize:true}); const v=t.tolist(); const g=v[0]; scores=lines.map((t,i)=>Math.max(0,cos(g,v[i+1]))); }
|
|
131
|
+
else { scores=lines.map(t=>tokRes(goal,t)); }
|
|
132
|
+
}catch(e){ MODE="fallback"; setEng('⚠ engine error — approximate keyword match','fb'); scores=lines.map(t=>tokRes(goal,t)); }
|
|
133
|
+
const eff = MODE==="semantic" ? THR : Math.min(THR,0.12);
|
|
134
|
+
const scored=lines.map((t,i)=>({t,score:Math.round(scores[i]*100)/100,keep:scores[i]>=eff})).sort((a,b)=>b.score-a.score);
|
|
135
|
+
const keep=scored.filter(s=>s.keep),drop=scored.filter(s=>!s.keep);
|
|
136
|
+
$('summary').innerHTML='🧲 Focus on <b style="color:var(--grn)">'+keep.length+'</b> · 〰 let go of <b>'+drop.length+'</b>'+(keep.length?' — <span style="color:var(--sub)">top: '+keep.slice(0,2).map(k=>'“'+esc(k.t.slice(0,46))+'”').join(', ')+'</span>':'')+(MODE==='fallback'?' <span style="color:var(--pink)">· approximate (keyword) mode</span>':'');
|
|
137
|
+
$('out').innerHTML=scored.map(s=>'<div class="item '+(s.keep?'keep':'drop')+'"><div class="bar"><i style="width:'+Math.round(s.score*100)+'%"></i></div><div class="txt">'+esc(s.t)+'</div><span class="sc">'+s.score.toFixed(2)+'</span><span class="verdict '+(s.keep?'keepv':'letv')+'">'+(s.keep?'🧲 KEEP':'〰 let go')+'</span></div>').join('');
|
|
138
|
+
window._keepers=keep.map(k=>k.t); $('run').disabled=false;
|
|
139
|
+
}
|
|
140
|
+
function esc(s){return String(s).replace(/[&<>]/g,c=>({'&':'&','<':'<','>':'>'}[c]))}
|
|
141
|
+
$('run').addEventListener('click',run);
|
|
142
|
+
$('copy').addEventListener('click',()=>{const k=(window._keepers||[]);if(!k.length)return;navigator.clipboard&&navigator.clipboard.writeText(k.join('\n'));$('copy').textContent='✓ copied '+k.length;setTimeout(()=>$('copy').textContent='Copy the keepers',1400)});
|
|
143
|
+
$('pile').addEventListener('keydown',e=>{if((e.metaKey||e.ctrlKey)&&e.key==='Enter')run()});
|
|
144
|
+
loadEngine();
|
|
130
145
|
</script>
|
|
131
146
|
</body>
|
|
132
147
|
</html>
|