@mneme-ai/core 2.19.31 → 2.19.33
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/dist/autonomic_scheduler/b4_context_shift.test.d.ts +12 -0
- package/dist/autonomic_scheduler/b4_context_shift.test.d.ts.map +1 -0
- package/dist/autonomic_scheduler/b4_context_shift.test.js +213 -0
- package/dist/autonomic_scheduler/b4_context_shift.test.js.map +1 -0
- package/dist/autonomic_scheduler/index.d.ts +44 -0
- package/dist/autonomic_scheduler/index.d.ts.map +1 -1
- package/dist/autonomic_scheduler/index.js +68 -1
- package/dist/autonomic_scheduler/index.js.map +1 -1
- package/dist/consciousness_fork/consciousness_fork.test.d.ts +2 -0
- package/dist/consciousness_fork/consciousness_fork.test.d.ts.map +1 -0
- package/dist/consciousness_fork/consciousness_fork.test.js +177 -0
- package/dist/consciousness_fork/consciousness_fork.test.js.map +1 -0
- package/dist/consciousness_fork/index.d.ts +129 -0
- package/dist/consciousness_fork/index.d.ts.map +1 -0
- package/dist/consciousness_fork/index.js +227 -0
- package/dist/consciousness_fork/index.js.map +1 -0
- package/dist/conversation_compiler/b1_extract_decisions.test.d.ts +2 -0
- package/dist/conversation_compiler/b1_extract_decisions.test.d.ts.map +1 -0
- package/dist/conversation_compiler/b1_extract_decisions.test.js +150 -0
- package/dist/conversation_compiler/b1_extract_decisions.test.js.map +1 -0
- package/dist/conversation_compiler/index.d.ts +19 -1
- package/dist/conversation_compiler/index.d.ts.map +1 -1
- package/dist/conversation_compiler/index.js +128 -39
- package/dist/conversation_compiler/index.js.map +1 -1
- package/dist/cosmic/aurelian_v1932.test.d.ts +2 -0
- package/dist/cosmic/aurelian_v1932.test.d.ts.map +1 -0
- package/dist/cosmic/aurelian_v1932.test.js +83 -0
- package/dist/cosmic/aurelian_v1932.test.js.map +1 -0
- package/dist/cosmic/aurelian_v1933.test.d.ts +2 -0
- package/dist/cosmic/aurelian_v1933.test.d.ts.map +1 -0
- package/dist/cosmic/aurelian_v1933.test.js +82 -0
- package/dist/cosmic/aurelian_v1933.test.js.map +1 -0
- package/dist/cosmic/v1933_integration.test.d.ts +2 -0
- package/dist/cosmic/v1933_integration.test.d.ts.map +1 -0
- package/dist/cosmic/v1933_integration.test.js +128 -0
- package/dist/cosmic/v1933_integration.test.js.map +1 -0
- package/dist/handoff_pwa/handoff_pwa.test.d.ts +2 -0
- package/dist/handoff_pwa/handoff_pwa.test.d.ts.map +1 -0
- package/dist/handoff_pwa/handoff_pwa.test.js +119 -0
- package/dist/handoff_pwa/handoff_pwa.test.js.map +1 -0
- package/dist/handoff_pwa/index.d.ts +81 -0
- package/dist/handoff_pwa/index.d.ts.map +1 -0
- package/dist/handoff_pwa/index.js +312 -0
- package/dist/handoff_pwa/index.js.map +1 -0
- package/dist/handoff_snapshot/handoff_snapshot.test.d.ts +2 -0
- package/dist/handoff_snapshot/handoff_snapshot.test.d.ts.map +1 -0
- package/dist/handoff_snapshot/handoff_snapshot.test.js +147 -0
- package/dist/handoff_snapshot/handoff_snapshot.test.js.map +1 -0
- package/dist/handoff_snapshot/index.d.ts +156 -0
- package/dist/handoff_snapshot/index.d.ts.map +1 -0
- package/dist/handoff_snapshot/index.js +261 -0
- package/dist/handoff_snapshot/index.js.map +1 -0
- package/dist/handoff_snapshot/system_e2e.test.d.ts +8 -0
- package/dist/handoff_snapshot/system_e2e.test.d.ts.map +1 -0
- package/dist/handoff_snapshot/system_e2e.test.js +211 -0
- package/dist/handoff_snapshot/system_e2e.test.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +14 -0
- package/dist/index.js.map +1 -1
- package/dist/pair_code/index.d.ts +107 -0
- package/dist/pair_code/index.d.ts.map +1 -0
- package/dist/pair_code/index.js +226 -0
- package/dist/pair_code/index.js.map +1 -0
- package/dist/pair_code/pair_code.test.d.ts +2 -0
- package/dist/pair_code/pair_code.test.d.ts.map +1 -0
- package/dist/pair_code/pair_code.test.js +197 -0
- package/dist/pair_code/pair_code.test.js.map +1 -0
- package/dist/tool_browser/index.d.ts +128 -0
- package/dist/tool_browser/index.d.ts.map +1 -0
- package/dist/tool_browser/index.js +218 -0
- package/dist/tool_browser/index.js.map +1 -0
- package/dist/tool_browser/tool_browser.test.d.ts +2 -0
- package/dist/tool_browser/tool_browser.test.d.ts.map +1 -0
- package/dist/tool_browser/tool_browser.test.js +167 -0
- package/dist/tool_browser/tool_browser.test.js.map +1 -0
- package/dist/tool_tier/index.d.ts.map +1 -1
- package/dist/tool_tier/index.js +23 -5
- package/dist/tool_tier/index.js.map +1 -1
- package/dist/truth_sensor_pack/index.d.ts +105 -0
- package/dist/truth_sensor_pack/index.d.ts.map +1 -0
- package/dist/truth_sensor_pack/index.js +201 -0
- package/dist/truth_sensor_pack/index.js.map +1 -0
- package/dist/truth_sensor_pack/truth_sensor_pack.test.d.ts +2 -0
- package/dist/truth_sensor_pack/truth_sensor_pack.test.d.ts.map +1 -0
- package/dist/truth_sensor_pack/truth_sensor_pack.test.js +153 -0
- package/dist/truth_sensor_pack/truth_sensor_pack.test.js.map +1 -0
- package/dist/whats_new.d.ts.map +1 -1
- package/dist/whats_new.js +16 -0
- package/dist/whats_new.js.map +1 -1
- package/dist/wrapper_genesis/index.d.ts.map +1 -1
- package/dist/wrapper_genesis/index.js +37 -0
- package/dist/wrapper_genesis/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* v2.19.32 — MNEME HANDOFF PWA (the device-adaptive page the scanner lands on)
|
|
3
|
+
*
|
|
4
|
+
* "PWA ปลายทาง — Smart, Detect device. หน้าเดียว ฉลาดพอจะปรับตัว
|
|
5
|
+
* ตาม scanner: Android phone → Share to Gemini; Desktop → Open in
|
|
6
|
+
* Cursor / VS Code / Claude Code; iOS → Copy + Shortcut; Tablet →
|
|
7
|
+
* เหมือน Phone" — user spec, 2026-05-17
|
|
8
|
+
*
|
|
9
|
+
* v2.19.32 ships a pure-function HTML GENERATOR. Caller (BEACON HTTP
|
|
10
|
+
* server) embeds the envelope text + SAS emoji + pair code into a
|
|
11
|
+
* self-contained HTML page (no external CDN — works offline on LAN).
|
|
12
|
+
* The embedded JavaScript detects user-agent and renders the right
|
|
13
|
+
* set of action buttons.
|
|
14
|
+
*
|
|
15
|
+
* Action buttons by device:
|
|
16
|
+
*
|
|
17
|
+
* 📱 Android Phone:
|
|
18
|
+
* [📤 Share to Gemini app] (Web Share API → any AI app installed)
|
|
19
|
+
* [📤 Share to ChatGPT app]
|
|
20
|
+
* [📤 Share to Claude app]
|
|
21
|
+
* [📋 Copy to clipboard]
|
|
22
|
+
*
|
|
23
|
+
* 📱 iOS Phone (Web Share API limited):
|
|
24
|
+
* [📋 Copy to clipboard]
|
|
25
|
+
* [📲 Open Shortcut] (mneme://receive deep link)
|
|
26
|
+
*
|
|
27
|
+
* 💻 Desktop browser:
|
|
28
|
+
* [💻 Open in Cursor] (cursor:// deep link)
|
|
29
|
+
* [💻 Open in VS Code] (vscode:// deep link)
|
|
30
|
+
* [💻 Open in Claude Code] (claude-code:// deep link)
|
|
31
|
+
* [💻 Save to .mneme/] (download .json — CLI auto-detects)
|
|
32
|
+
* [📋 Copy to clipboard]
|
|
33
|
+
*
|
|
34
|
+
* 📱 Tablet: phone-like
|
|
35
|
+
*
|
|
36
|
+
* All buttons gracefully degrade: if Web Share unsupported → clipboard;
|
|
37
|
+
* if deep link unsupported → download .json + instructions.
|
|
38
|
+
*
|
|
39
|
+
* Composes onto:
|
|
40
|
+
* - v2.19.32 HANDOFF SNAPSHOT (envelope to embed)
|
|
41
|
+
* - v2.19.32 PAIR CODE (code displayed + SAS emoji)
|
|
42
|
+
* - v2.9 BEACON server (HTTP transport)
|
|
43
|
+
*
|
|
44
|
+
* Honest scope:
|
|
45
|
+
* - PURE FUNCTION HTML emitter. Single string returned.
|
|
46
|
+
* - No external CSS / JS / fonts — fully self-contained.
|
|
47
|
+
* - All user-supplied text HTML-escaped (defends against the v2.19.31
|
|
48
|
+
* XSS-via-payload class — reuses beacon's escape logic).
|
|
49
|
+
* - 24/7 safe: empty / missing fields render placeholders, never throw.
|
|
50
|
+
*/
|
|
51
|
+
const PROTOCOL_VERSION = 1;
|
|
52
|
+
function escapeHtml(s) {
|
|
53
|
+
return String(s).replace(/[&<>"']/g, (c) => ({
|
|
54
|
+
"&": "&",
|
|
55
|
+
"<": "<",
|
|
56
|
+
">": ">",
|
|
57
|
+
"\"": """,
|
|
58
|
+
"'": "'",
|
|
59
|
+
}[c]));
|
|
60
|
+
}
|
|
61
|
+
const LS_RE = new RegExp("
", "g");
|
|
62
|
+
const PS_RE = new RegExp("
", "g");
|
|
63
|
+
function escapeJs(s) {
|
|
64
|
+
// For embedding into <script> string literal — escape backslash, quote,
|
|
65
|
+
// line terminators (\n / \r / U+2028 / U+2029) and </ to prevent
|
|
66
|
+
// </script> closure attack.
|
|
67
|
+
return String(s)
|
|
68
|
+
.replace(/\\/g, "\\\\")
|
|
69
|
+
.replace(/'/g, "\\'")
|
|
70
|
+
.replace(/\n/g, "\\n")
|
|
71
|
+
.replace(/\r/g, "\\r")
|
|
72
|
+
.replace(LS_RE, "\\u2028")
|
|
73
|
+
.replace(PS_RE, "\\u2029")
|
|
74
|
+
.replace(/<\//g, "<\\/");
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Render a self-contained HTML page the BEACON server can serve at
|
|
78
|
+
* GET /pair/<code>. No external requests — works offline on LAN.
|
|
79
|
+
*/
|
|
80
|
+
export function generateHandoffPwaHtml(input) {
|
|
81
|
+
const title = escapeHtml(input.title ?? "Mneme Handoff");
|
|
82
|
+
const pairCode = escapeHtml(input.pairCode);
|
|
83
|
+
const emoji = (Array.isArray(input.sasEmoji) && input.sasEmoji.length === 4)
|
|
84
|
+
? input.sasEmoji.map(escapeHtml).join(" ")
|
|
85
|
+
: "❓ ❓ ❓ ❓";
|
|
86
|
+
const body = escapeJs(input.body ?? "");
|
|
87
|
+
const parent = escapeHtml(input.parentDeviceId ?? "anonymous");
|
|
88
|
+
const expiresIn = Number.isFinite(input.expiresInMs) ? Math.max(0, Math.floor(input.expiresInMs / 1000)) : 0;
|
|
89
|
+
const shareTargets = (Array.isArray(input.shareTargets) && input.shareTargets.length > 0)
|
|
90
|
+
? input.shareTargets
|
|
91
|
+
: ["Gemini", "ChatGPT", "Claude"];
|
|
92
|
+
const shareTargetsJs = JSON.stringify(shareTargets.map(escapeJs));
|
|
93
|
+
return `<!DOCTYPE html>
|
|
94
|
+
<html lang="en">
|
|
95
|
+
<head>
|
|
96
|
+
<meta charset="utf-8">
|
|
97
|
+
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1">
|
|
98
|
+
<meta name="theme-color" content="#0f172a">
|
|
99
|
+
<title>${title}</title>
|
|
100
|
+
<style>
|
|
101
|
+
:root {
|
|
102
|
+
--bg: #0f172a;
|
|
103
|
+
--card: #1e293b;
|
|
104
|
+
--border: #334155;
|
|
105
|
+
--text: #e2e8f0;
|
|
106
|
+
--muted: #94a3b8;
|
|
107
|
+
--accent: #22d3ee;
|
|
108
|
+
--ok: #4ade80;
|
|
109
|
+
--warn: #fbbf24;
|
|
110
|
+
}
|
|
111
|
+
* { box-sizing: border-box; }
|
|
112
|
+
body { margin: 0; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
|
113
|
+
background: var(--bg); color: var(--text); min-height: 100vh; padding: 16px; }
|
|
114
|
+
.wrap { max-width: 720px; margin: 0 auto; }
|
|
115
|
+
h1 { font-size: 1.4rem; margin: 8px 0 4px; }
|
|
116
|
+
.sub { color: var(--muted); font-size: 0.85rem; margin-bottom: 16px; }
|
|
117
|
+
.card { background: var(--card); border: 1px solid var(--border); border-radius: 12px;
|
|
118
|
+
padding: 16px; margin: 12px 0; }
|
|
119
|
+
.pair { text-align: center; padding: 24px 16px; }
|
|
120
|
+
.pair-code { font-size: 2.6rem; letter-spacing: 0.15em; font-weight: 700;
|
|
121
|
+
color: var(--accent); margin: 8px 0; user-select: all; }
|
|
122
|
+
.sas { font-size: 2.2rem; letter-spacing: 0.2em; margin: 8px 0; }
|
|
123
|
+
.sas-label { color: var(--muted); font-size: 0.8rem; }
|
|
124
|
+
.countdown { color: var(--warn); font-weight: 600; }
|
|
125
|
+
.actions { display: grid; gap: 8px; margin-top: 12px; }
|
|
126
|
+
.btn { display: block; padding: 14px 16px; border-radius: 10px; border: 1px solid var(--border);
|
|
127
|
+
background: #0b1220; color: var(--text); text-decoration: none; cursor: pointer;
|
|
128
|
+
font-size: 1rem; text-align: left; transition: background 0.15s; }
|
|
129
|
+
.btn:hover { background: #172033; }
|
|
130
|
+
.btn-primary { background: var(--accent); color: #001821; border-color: var(--accent); font-weight: 600; }
|
|
131
|
+
.btn-primary:hover { filter: brightness(1.1); }
|
|
132
|
+
.body-preview { background: #020617; border: 1px solid var(--border); border-radius: 8px;
|
|
133
|
+
padding: 12px; font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
|
|
134
|
+
font-size: 0.8rem; white-space: pre-wrap; word-break: break-word; max-height: 260px;
|
|
135
|
+
overflow-y: auto; }
|
|
136
|
+
.toast { position: fixed; bottom: 24px; left: 50%; transform: translateX(-50%);
|
|
137
|
+
background: var(--ok); color: #001821; padding: 12px 20px; border-radius: 8px;
|
|
138
|
+
font-weight: 600; opacity: 0; transition: opacity 0.2s; pointer-events: none; }
|
|
139
|
+
.toast.show { opacity: 1; }
|
|
140
|
+
.footer { color: var(--muted); font-size: 0.75rem; text-align: center; margin-top: 24px; }
|
|
141
|
+
.footer a { color: var(--accent); }
|
|
142
|
+
</style>
|
|
143
|
+
</head>
|
|
144
|
+
<body>
|
|
145
|
+
<div class="wrap">
|
|
146
|
+
<h1>🧬 ${title}</h1>
|
|
147
|
+
<div class="sub">From parent: <strong>${parent}</strong></div>
|
|
148
|
+
|
|
149
|
+
<div class="card pair">
|
|
150
|
+
<div class="sas-label">Verify parent & child show SAME emoji:</div>
|
|
151
|
+
<div class="sas">${emoji}</div>
|
|
152
|
+
<div style="border-top: 1px solid var(--border); margin: 16px 0; padding-top: 12px;">
|
|
153
|
+
<div class="sas-label">Pair code (one-shot):</div>
|
|
154
|
+
<div class="pair-code">${pairCode}</div>
|
|
155
|
+
<div>⏱ expires in <span class="countdown" id="countdown">${expiresIn}s</span></div>
|
|
156
|
+
</div>
|
|
157
|
+
</div>
|
|
158
|
+
|
|
159
|
+
<div class="card">
|
|
160
|
+
<h2 style="margin-top: 0;">Send the handoff to your AI tool</h2>
|
|
161
|
+
<div class="actions" id="actions">
|
|
162
|
+
<button class="btn" onclick="copyBody()">📋 Copy handoff to clipboard</button>
|
|
163
|
+
</div>
|
|
164
|
+
</div>
|
|
165
|
+
|
|
166
|
+
<div class="card">
|
|
167
|
+
<h2 style="margin-top: 0;">Preview</h2>
|
|
168
|
+
<div class="body-preview" id="preview"></div>
|
|
169
|
+
</div>
|
|
170
|
+
|
|
171
|
+
<div class="footer">
|
|
172
|
+
Mneme HANDOFF v${PROTOCOL_VERSION} · local-first · no external requests<br>
|
|
173
|
+
<a href="https://www.npmjs.com/package/mneme-ai">npmjs.com/mneme-ai</a>
|
|
174
|
+
</div>
|
|
175
|
+
</div>
|
|
176
|
+
|
|
177
|
+
<div class="toast" id="toast">Copied</div>
|
|
178
|
+
|
|
179
|
+
<script>
|
|
180
|
+
(function() {
|
|
181
|
+
var BODY = '${body}';
|
|
182
|
+
var PAIR_CODE = '${escapeJs(input.pairCode)}';
|
|
183
|
+
var SHARE_TARGETS = ${shareTargetsJs};
|
|
184
|
+
|
|
185
|
+
var pre = document.getElementById('preview');
|
|
186
|
+
if (pre) pre.textContent = BODY;
|
|
187
|
+
|
|
188
|
+
var sec = ${expiresIn};
|
|
189
|
+
var cd = document.getElementById('countdown');
|
|
190
|
+
var timer = setInterval(function() {
|
|
191
|
+
sec--;
|
|
192
|
+
if (cd) cd.textContent = sec + 's';
|
|
193
|
+
if (sec <= 0) {
|
|
194
|
+
clearInterval(timer);
|
|
195
|
+
if (cd) { cd.textContent = 'EXPIRED'; cd.style.color = '#ef4444'; }
|
|
196
|
+
}
|
|
197
|
+
}, 1000);
|
|
198
|
+
|
|
199
|
+
var ua = (navigator.userAgent || '').toLowerCase();
|
|
200
|
+
var isAndroid = /android/.test(ua);
|
|
201
|
+
var isIOS = /iphone|ipad|ipod/.test(ua);
|
|
202
|
+
var isMobile = isAndroid || isIOS || /mobile/.test(ua);
|
|
203
|
+
var isTablet = /tablet|ipad/.test(ua);
|
|
204
|
+
var hasWebShare = typeof navigator.share === 'function';
|
|
205
|
+
var hasClipboard = !!(navigator.clipboard && navigator.clipboard.writeText);
|
|
206
|
+
|
|
207
|
+
var actions = document.getElementById('actions');
|
|
208
|
+
if (actions) actions.innerHTML = '';
|
|
209
|
+
|
|
210
|
+
function addBtn(label, onclick, primary) {
|
|
211
|
+
var b = document.createElement('button');
|
|
212
|
+
b.className = 'btn' + (primary ? ' btn-primary' : '');
|
|
213
|
+
b.textContent = label;
|
|
214
|
+
b.onclick = onclick;
|
|
215
|
+
if (actions) actions.appendChild(b);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
function showToast(msg, color) {
|
|
219
|
+
var t = document.getElementById('toast');
|
|
220
|
+
if (!t) return;
|
|
221
|
+
t.textContent = msg;
|
|
222
|
+
if (color) t.style.background = color;
|
|
223
|
+
t.classList.add('show');
|
|
224
|
+
setTimeout(function() { t.classList.remove('show'); }, 1800);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
window.copyBody = function() {
|
|
228
|
+
if (hasClipboard) {
|
|
229
|
+
navigator.clipboard.writeText(BODY).then(function() {
|
|
230
|
+
showToast('✓ Copied — paste into your AI tool');
|
|
231
|
+
}).catch(function() {
|
|
232
|
+
fallbackCopy();
|
|
233
|
+
});
|
|
234
|
+
} else {
|
|
235
|
+
fallbackCopy();
|
|
236
|
+
}
|
|
237
|
+
};
|
|
238
|
+
|
|
239
|
+
function fallbackCopy() {
|
|
240
|
+
var ta = document.createElement('textarea');
|
|
241
|
+
ta.value = BODY;
|
|
242
|
+
ta.style.position = 'fixed'; ta.style.opacity = '0';
|
|
243
|
+
document.body.appendChild(ta);
|
|
244
|
+
ta.select();
|
|
245
|
+
try { document.execCommand('copy'); showToast('✓ Copied'); }
|
|
246
|
+
catch (e) { showToast('Copy failed — long-press preview', '#ef4444'); }
|
|
247
|
+
document.body.removeChild(ta);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
if (isMobile && hasWebShare) {
|
|
251
|
+
addBtn('📤 Share to AI app (Gemini / ChatGPT / Claude)', function() {
|
|
252
|
+
navigator.share({
|
|
253
|
+
title: 'Mneme Handoff',
|
|
254
|
+
text: BODY,
|
|
255
|
+
}).then(function() {
|
|
256
|
+
showToast('✓ Shared');
|
|
257
|
+
}).catch(function(err) {
|
|
258
|
+
if (err && err.name === 'AbortError') return;
|
|
259
|
+
showToast('Share failed — copy fallback', '#ef4444');
|
|
260
|
+
});
|
|
261
|
+
}, true);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
if (!isMobile) {
|
|
265
|
+
var deeplinks = [
|
|
266
|
+
{ label: '💻 Open in Cursor', url: 'cursor://anysphere.cursor-deeplink/prompt?text=' + encodeURIComponent(BODY) },
|
|
267
|
+
{ label: '💻 Open in VS Code', url: 'vscode://file//?text=' + encodeURIComponent(BODY) },
|
|
268
|
+
{ label: '💻 Open in Claude Code', url: 'claude-code://open?text=' + encodeURIComponent(BODY) },
|
|
269
|
+
{ label: '🧠 Open in Mneme CLI', url: 'mneme://receive?code=' + encodeURIComponent(PAIR_CODE) },
|
|
270
|
+
];
|
|
271
|
+
for (var i = 0; i < deeplinks.length; i++) {
|
|
272
|
+
(function(d) {
|
|
273
|
+
addBtn(d.label, function() {
|
|
274
|
+
window.location.href = d.url;
|
|
275
|
+
setTimeout(function() {
|
|
276
|
+
showToast('Opened deep link — if nothing happened, click Copy below', '#fbbf24');
|
|
277
|
+
}, 800);
|
|
278
|
+
});
|
|
279
|
+
})(deeplinks[i]);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
addBtn('💾 Download handoff.json', function() {
|
|
284
|
+
var blob = new Blob([BODY], { type: 'text/plain' });
|
|
285
|
+
var url = URL.createObjectURL(blob);
|
|
286
|
+
var a = document.createElement('a');
|
|
287
|
+
a.href = url;
|
|
288
|
+
a.download = 'mneme-handoff-' + PAIR_CODE + '.txt';
|
|
289
|
+
document.body.appendChild(a);
|
|
290
|
+
a.click();
|
|
291
|
+
document.body.removeChild(a);
|
|
292
|
+
URL.revokeObjectURL(url);
|
|
293
|
+
showToast('✓ Downloaded');
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
addBtn('📋 Copy to clipboard', window.copyBody, !isMobile);
|
|
297
|
+
})();
|
|
298
|
+
</script>
|
|
299
|
+
</body>
|
|
300
|
+
</html>`;
|
|
301
|
+
}
|
|
302
|
+
export function computePwaStats(input, html) {
|
|
303
|
+
return {
|
|
304
|
+
htmlBytes: html.length,
|
|
305
|
+
hasEmoji: Array.isArray(input.sasEmoji) && input.sasEmoji.length === 4,
|
|
306
|
+
embeddedBodyBytes: (input.body ?? "").length,
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
export const HANDOFF_PWA_TUNABLES = Object.freeze({
|
|
310
|
+
PROTOCOL_VERSION,
|
|
311
|
+
});
|
|
312
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/handoff_pwa/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handoff_snapshot.test.d.ts","sourceRoot":"","sources":["../../src/handoff_snapshot/handoff_snapshot.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { captureSnapshot, verifyEnvelope, freshnessCheck, renderForChildVendor, computeSnapshotStats, formatSnapshotLine, HANDOFF_SNAPSHOT_TUNABLES, } from "./index.js";
|
|
3
|
+
const SECRET = "handoff-test-secret-77";
|
|
4
|
+
describe("v2.19.32 HANDOFF SNAPSHOT -- pure-function envelope composer", () => {
|
|
5
|
+
it("captureSnapshot returns a valid HMAC-signed envelope from minimal input", () => {
|
|
6
|
+
const env = captureSnapshot({
|
|
7
|
+
parentDeviceId: "parent-pc",
|
|
8
|
+
nowMs: 1_700_000_000_000,
|
|
9
|
+
secret: SECRET,
|
|
10
|
+
});
|
|
11
|
+
expect(env.v).toBe(HANDOFF_SNAPSHOT_TUNABLES.PROTOCOL_VERSION);
|
|
12
|
+
expect(env.envelopeId).toMatch(/^[0-9a-f]{16}$/);
|
|
13
|
+
expect(env.sig).toMatch(/^[0-9a-f]{64}$/);
|
|
14
|
+
expect(env.parentDeviceId).toBe("parent-pc");
|
|
15
|
+
expect(env.snapshotAtMs).toBe(1_700_000_000_000);
|
|
16
|
+
expect(verifyEnvelope(env, SECRET)).toBe(true);
|
|
17
|
+
});
|
|
18
|
+
it("captureSnapshot is deterministic: same input + secret -> same sig", () => {
|
|
19
|
+
const input = {
|
|
20
|
+
parentDeviceId: "p1",
|
|
21
|
+
conversation: [{ role: "user", text: "hello", ts: 1000 }],
|
|
22
|
+
nowMs: 5000,
|
|
23
|
+
secret: SECRET,
|
|
24
|
+
};
|
|
25
|
+
const a = captureSnapshot(input);
|
|
26
|
+
const b = captureSnapshot(input);
|
|
27
|
+
expect(a.sig).toBe(b.sig);
|
|
28
|
+
expect(a.envelopeId).toBe(b.envelopeId);
|
|
29
|
+
});
|
|
30
|
+
it("captureSnapshot embeds conversation + git state + activity", () => {
|
|
31
|
+
const env = captureSnapshot({
|
|
32
|
+
parentDeviceId: "p1",
|
|
33
|
+
conversation: [
|
|
34
|
+
{ role: "user", text: "fix beacon bug", ts: 1000 },
|
|
35
|
+
{ role: "assistant", text: "found it on line 216", ts: 2000 },
|
|
36
|
+
],
|
|
37
|
+
activeIntent: "fixing BEACON BUG #1",
|
|
38
|
+
gitState: { branch: "main", dirty: " M beacon/index.ts", recentCommits: ["fix: bug #1"] },
|
|
39
|
+
recentActivity: [{ action: "mneme.truth.forensic", ts: 1500 }],
|
|
40
|
+
capabilities: { mnemeVersion: "2.19.32", toolFamilies: ["beacon", "synapse"] },
|
|
41
|
+
voiceDirective: "concise + technical",
|
|
42
|
+
mnemeDictionary: { "BEACON": "QR transfer subsystem" },
|
|
43
|
+
nowMs: 3000,
|
|
44
|
+
secret: SECRET,
|
|
45
|
+
});
|
|
46
|
+
expect(env.conversation.length).toBe(2);
|
|
47
|
+
expect(env.activeIntent).toBe("fixing BEACON BUG #1");
|
|
48
|
+
expect(env.gitState.branch).toBe("main");
|
|
49
|
+
expect(env.recentActivity.length).toBe(1);
|
|
50
|
+
expect(env.capabilities.mnemeVersion).toBe("2.19.32");
|
|
51
|
+
expect(env.voiceDirective).toBe("concise + technical");
|
|
52
|
+
expect(env.mnemeDictionary["BEACON"]).toBe("QR transfer subsystem");
|
|
53
|
+
expect(verifyEnvelope(env, SECRET)).toBe(true);
|
|
54
|
+
});
|
|
55
|
+
it("captureSnapshot is DEFENSIVE: bad input never throws", () => {
|
|
56
|
+
const bad = [
|
|
57
|
+
undefined, null, {}, { parentDeviceId: 123 }, { conversation: "not-an-array" },
|
|
58
|
+
{ conversation: [{ role: "alien", text: 99, ts: "x" }] },
|
|
59
|
+
{ gitState: "not-an-object" },
|
|
60
|
+
{ recentActivity: [null, undefined, "x", { action: 1 }] },
|
|
61
|
+
{ capabilities: 99 },
|
|
62
|
+
{ mnemeDictionary: "x" },
|
|
63
|
+
];
|
|
64
|
+
for (const b of bad) {
|
|
65
|
+
const env = captureSnapshot((b ?? {}));
|
|
66
|
+
expect(env.sig).toMatch(/^[0-9a-f]{64}$/);
|
|
67
|
+
expect(verifyEnvelope(env)).toBe(true);
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
it("verifyEnvelope rejects tampered envelopes (one char change in sig)", () => {
|
|
71
|
+
const env = captureSnapshot({ parentDeviceId: "p", nowMs: 1, secret: SECRET });
|
|
72
|
+
const tampered = { ...env, sig: env.sig.slice(0, -1) + (env.sig.endsWith("a") ? "b" : "a") };
|
|
73
|
+
expect(verifyEnvelope(tampered, SECRET)).toBe(false);
|
|
74
|
+
});
|
|
75
|
+
it("verifyEnvelope rejects field mutation", () => {
|
|
76
|
+
const env = captureSnapshot({ parentDeviceId: "p", nowMs: 1, secret: SECRET });
|
|
77
|
+
const tampered = { ...env, parentDeviceId: "attacker" };
|
|
78
|
+
expect(verifyEnvelope(tampered, SECRET)).toBe(false);
|
|
79
|
+
});
|
|
80
|
+
it("verifyEnvelope rejects wrong secret", () => {
|
|
81
|
+
const env = captureSnapshot({ parentDeviceId: "p", nowMs: 1, secret: SECRET });
|
|
82
|
+
expect(verifyEnvelope(env, "wrong-secret")).toBe(false);
|
|
83
|
+
});
|
|
84
|
+
it("verifyEnvelope rejects malformed envelopes", () => {
|
|
85
|
+
expect(verifyEnvelope(null)).toBe(false);
|
|
86
|
+
expect(verifyEnvelope({})).toBe(false);
|
|
87
|
+
expect(verifyEnvelope({ v: 99, sig: "x".repeat(64) })).toBe(false);
|
|
88
|
+
});
|
|
89
|
+
it("freshnessCheck: fresh / stale / expired / future_clock_skew bands", () => {
|
|
90
|
+
const env = captureSnapshot({ parentDeviceId: "p", nowMs: 1_000_000, secret: SECRET });
|
|
91
|
+
expect(freshnessCheck(env, 1_000_500).reason).toBe("fresh"); // 0.5s old
|
|
92
|
+
expect(freshnessCheck(env, 1_000_000 + 4 * 60 * 1000 + 30 * 1000).reason).toBe("stale"); // 4.5min
|
|
93
|
+
expect(freshnessCheck(env, 1_000_000 + 6 * 60 * 1000).reason).toBe("expired"); // 6min
|
|
94
|
+
expect(freshnessCheck(env, 1_000_000 - 5_000).reason).toBe("future_clock_skew"); // child behind 5s
|
|
95
|
+
});
|
|
96
|
+
it("renderForChildVendor produces valid markdown the receiving AI can paste", () => {
|
|
97
|
+
const env = captureSnapshot({
|
|
98
|
+
parentDeviceId: "macbook",
|
|
99
|
+
conversation: [{ role: "user", text: "what about phase D?", ts: 1000 }],
|
|
100
|
+
activeIntent: "discussing cross-device sync",
|
|
101
|
+
gitState: { branch: "main", recentCommits: ["feat: v2.19.31"] },
|
|
102
|
+
capabilities: { mnemeVersion: "2.19.32", toolFamilies: ["synapse"] },
|
|
103
|
+
nowMs: 2000,
|
|
104
|
+
secret: SECRET,
|
|
105
|
+
});
|
|
106
|
+
const md = renderForChildVendor(env);
|
|
107
|
+
expect(md).toContain("Mneme Handoff");
|
|
108
|
+
expect(md).toContain("macbook");
|
|
109
|
+
expect(md).toContain("phase D");
|
|
110
|
+
expect(md).toContain("discussing cross-device sync");
|
|
111
|
+
expect(md).toContain("feat: v2.19.31");
|
|
112
|
+
expect(md).toContain(env.envelopeId);
|
|
113
|
+
expect(md.length).toBeGreaterThan(100);
|
|
114
|
+
});
|
|
115
|
+
it("computeSnapshotStats reports byte size + turn count + age", () => {
|
|
116
|
+
const env = captureSnapshot({
|
|
117
|
+
parentDeviceId: "p",
|
|
118
|
+
conversation: [{ role: "user", text: "hi", ts: 1 }],
|
|
119
|
+
nowMs: 1000,
|
|
120
|
+
secret: SECRET,
|
|
121
|
+
});
|
|
122
|
+
const s = computeSnapshotStats(env, 5000);
|
|
123
|
+
expect(s.conversationTurns).toBe(1);
|
|
124
|
+
expect(s.totalBytes).toBeGreaterThan(0);
|
|
125
|
+
expect(s.ageMs).toBe(4000);
|
|
126
|
+
const line = formatSnapshotLine(s);
|
|
127
|
+
expect(line).toContain("SNAPSHOT");
|
|
128
|
+
expect(line).toContain(env.envelopeId);
|
|
129
|
+
});
|
|
130
|
+
it("24/7 RESILIENCE: 1000 random snapshots never crash", () => {
|
|
131
|
+
const rand = (n) => Math.floor(Math.random() * n);
|
|
132
|
+
for (let i = 0; i < 1000; i++) {
|
|
133
|
+
const env = captureSnapshot({
|
|
134
|
+
parentDeviceId: `p-${rand(100)}`,
|
|
135
|
+
conversation: Array.from({ length: rand(5) }, (_, j) => ({
|
|
136
|
+
role: ["user", "assistant", "system"][rand(3)],
|
|
137
|
+
text: `msg-${rand(10000)}`,
|
|
138
|
+
ts: rand(1_000_000),
|
|
139
|
+
})),
|
|
140
|
+
nowMs: rand(1_000_000),
|
|
141
|
+
secret: `s-${rand(50)}`,
|
|
142
|
+
});
|
|
143
|
+
expect(verifyEnvelope(env, env.parentDeviceId === "" ? undefined : undefined)).toBeDefined();
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
});
|
|
147
|
+
//# sourceMappingURL=handoff_snapshot.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handoff_snapshot.test.js","sourceRoot":"","sources":["../../src/handoff_snapshot/handoff_snapshot.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* v2.19.32 — MNEME HANDOFF SNAPSHOT (the brain you hand to your child device)
|
|
3
|
+
*
|
|
4
|
+
* User mandate (2026-05-17):
|
|
5
|
+
* "อยากให้ลูก mneme เก่งสุดๆ และรู้จักการเอาตัวรอดได้ทุกสถานการณ์ ...
|
|
6
|
+
* BEACON ทำมานานแล้วแต่ไม่เคยใช้ได้เลยผมเครียดมากๆๆ ... ทุก handoff =
|
|
7
|
+
* fresh snapshot. ไม่ใช่ pre-baked file. child ได้ context เดียวกับ
|
|
8
|
+
* parent ตอนนั้นเป๊ะ"
|
|
9
|
+
*
|
|
10
|
+
* Diagnosis: prior BEACON shipped a "soul prompt" that was generic +
|
|
11
|
+
* stale — same paragraph every release, no actual conversation context.
|
|
12
|
+
* When user scanned QR on phone, they got a paragraph about Mneme's
|
|
13
|
+
* features, not "we were debugging the auth bypass on line 216 of
|
|
14
|
+
* beacon/index.ts." That's why BEACON has never been used in anger.
|
|
15
|
+
*
|
|
16
|
+
* v2.19.32 HANDOFF SNAPSHOT is the pure-function COMPOSER: caller
|
|
17
|
+
* supplies the live conversation + git state + activity (caller has the
|
|
18
|
+
* I/O), this module canonicalises + HMAC-signs + ages it. The result
|
|
19
|
+
* is a HandoffEnvelope the BEACON server can serve to whoever scans the
|
|
20
|
+
* QR code, and the child device's `mneme receive` can verify + ingest.
|
|
21
|
+
*
|
|
22
|
+
* What's NEW vs prior soul prompt:
|
|
23
|
+
* - LIVE conversation (caller passes last N turns from MCP session)
|
|
24
|
+
* - GIT STATE (branch / dirty / last N commits) at SNAPSHOT time
|
|
25
|
+
* - RECENT ACTIVITY (tail of .mneme/cli-activity.jsonl)
|
|
26
|
+
* - ACTIVE INTENT (what the user was just asking about)
|
|
27
|
+
* - CAPABILITIES (mneme version + tool families) for child compatibility
|
|
28
|
+
* - FRESHNESS TIMESTAMP — receiver enforces 5-min staleness gate
|
|
29
|
+
*
|
|
30
|
+
* Composes onto:
|
|
31
|
+
* - v2.9 BEACON (the QR + local HTTP server that carries this)
|
|
32
|
+
* - v2.19.31 BUG #1 fix (token-required transport — no auth bypass)
|
|
33
|
+
* - v2.19.32 PAIR CODE (6-char human-friendly handle bound to envelope)
|
|
34
|
+
* - v2.19.32 CONSCIOUSNESS FORK (HMAC parent/child lineage record)
|
|
35
|
+
*
|
|
36
|
+
* Honest scope:
|
|
37
|
+
* - PURE FUNCTION composer. Caller has the I/O (read git, tail jsonl,
|
|
38
|
+
* get conversation). This makes it testable + vendor-neutral.
|
|
39
|
+
* - HMAC-SHA256 signed for tamper detection at the receiver.
|
|
40
|
+
* - Defensive: empty conversation OK, missing git OK, malformed input
|
|
41
|
+
* returns minimal-but-valid envelope rather than throw.
|
|
42
|
+
* - Freshness gate: receiver checks freshnessMs against TTL.
|
|
43
|
+
* - 24/7 safe: never throws on bad input; 1000 random snapshots in a
|
|
44
|
+
* row never crashes (measured in test suite).
|
|
45
|
+
*/
|
|
46
|
+
declare const PROTOCOL_VERSION: 2;
|
|
47
|
+
export interface ConversationTurn {
|
|
48
|
+
role: "user" | "assistant" | "system";
|
|
49
|
+
/** UTF-8 text. Caller may pre-trim to budget. */
|
|
50
|
+
text: string;
|
|
51
|
+
/** ms since epoch. */
|
|
52
|
+
ts: number;
|
|
53
|
+
}
|
|
54
|
+
export interface GitState {
|
|
55
|
+
branch?: string;
|
|
56
|
+
/** Output of `git status --short` (already truncated by caller). */
|
|
57
|
+
dirty?: string;
|
|
58
|
+
/** Last N commit subject lines. */
|
|
59
|
+
recentCommits?: string[];
|
|
60
|
+
}
|
|
61
|
+
export interface ActivityRecord {
|
|
62
|
+
/** Tool name OR free-form action (caller picks). */
|
|
63
|
+
action: string;
|
|
64
|
+
/** ms since epoch. */
|
|
65
|
+
ts: number;
|
|
66
|
+
/** Optional structured metadata (must be JSON-serialisable). */
|
|
67
|
+
meta?: Record<string, unknown>;
|
|
68
|
+
}
|
|
69
|
+
export interface CapabilitiesSnapshot {
|
|
70
|
+
mnemeVersion: string;
|
|
71
|
+
/** MCP tool family names (e.g. ["synapse", "truth", "soul"]). */
|
|
72
|
+
toolFamilies: string[];
|
|
73
|
+
/** Tools whose presence the receiver should require for full fidelity. */
|
|
74
|
+
requiredTools?: string[];
|
|
75
|
+
}
|
|
76
|
+
export interface HandoffSnapshotInput {
|
|
77
|
+
/** Last N conversation turns. Caller trims to budget. */
|
|
78
|
+
conversation?: ConversationTurn[];
|
|
79
|
+
/** Free-form one-line current intent inferred from conversation tail. */
|
|
80
|
+
activeIntent?: string;
|
|
81
|
+
gitState?: GitState;
|
|
82
|
+
/** Tail of cli-activity.jsonl (caller pre-reads + parses). */
|
|
83
|
+
recentActivity?: ActivityRecord[];
|
|
84
|
+
capabilities?: CapabilitiesSnapshot;
|
|
85
|
+
/** Optional voice directive — agent-tone instructions. */
|
|
86
|
+
voiceDirective?: string;
|
|
87
|
+
/** Optional shared dictionary for cross-vendor term consistency. */
|
|
88
|
+
mnemeDictionary?: Record<string, string>;
|
|
89
|
+
/** Parent device fingerprint (e.g. host hash). */
|
|
90
|
+
parentDeviceId?: string;
|
|
91
|
+
/** ms since epoch. Default Date.now(). */
|
|
92
|
+
nowMs?: number;
|
|
93
|
+
secret?: string;
|
|
94
|
+
}
|
|
95
|
+
export interface HandoffEnvelope {
|
|
96
|
+
v: typeof PROTOCOL_VERSION;
|
|
97
|
+
/** Stable deterministic id derived from (parentDeviceId, snapshotAt, content hash). */
|
|
98
|
+
envelopeId: string;
|
|
99
|
+
parentDeviceId: string;
|
|
100
|
+
snapshotAtMs: number;
|
|
101
|
+
/** TTL the receiver should enforce. */
|
|
102
|
+
freshnessTtlMs: number;
|
|
103
|
+
conversation: ConversationTurn[];
|
|
104
|
+
activeIntent: string;
|
|
105
|
+
gitState: Required<GitState>;
|
|
106
|
+
recentActivity: ActivityRecord[];
|
|
107
|
+
capabilities: CapabilitiesSnapshot;
|
|
108
|
+
voiceDirective: string;
|
|
109
|
+
mnemeDictionary: Record<string, string>;
|
|
110
|
+
/** HMAC-SHA256 over canonical body. */
|
|
111
|
+
sig: string;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Compose a fresh handoff envelope. Defensive at every boundary:
|
|
115
|
+
* - missing fields filled with sane defaults
|
|
116
|
+
* - bad types coerced or dropped
|
|
117
|
+
* - HMAC always computed (never empty sig)
|
|
118
|
+
* - return value ALWAYS valid; never throws
|
|
119
|
+
*/
|
|
120
|
+
export declare function captureSnapshot(input: HandoffSnapshotInput): HandoffEnvelope;
|
|
121
|
+
/** Verify envelope HMAC. Returns false on shape mismatch / tampered sig. */
|
|
122
|
+
export declare function verifyEnvelope(envelope: HandoffEnvelope, secret?: string): boolean;
|
|
123
|
+
/**
|
|
124
|
+
* Receiver-side freshness gate. Returns age in ms; caller compares to TTL.
|
|
125
|
+
* Stale envelope = receiver should refuse to ingest + ask parent to refresh.
|
|
126
|
+
*/
|
|
127
|
+
export interface FreshnessResult {
|
|
128
|
+
ageMs: number;
|
|
129
|
+
isFresh: boolean;
|
|
130
|
+
isExpired: boolean;
|
|
131
|
+
reason: "fresh" | "stale" | "expired" | "future_clock_skew";
|
|
132
|
+
}
|
|
133
|
+
export declare function freshnessCheck(envelope: HandoffEnvelope, nowMs?: number): FreshnessResult;
|
|
134
|
+
/**
|
|
135
|
+
* Render an envelope as the AI-ingestible text the child will paste into
|
|
136
|
+
* its new vendor session (Gemini / GPT / Claude / etc). Deterministic,
|
|
137
|
+
* vendor-neutral, safe to display in clear text — the SIG is what gives
|
|
138
|
+
* tamper-evidence, not secrecy. (For confidentiality wrap in ECDH at the
|
|
139
|
+
* transport layer; out of scope for this composer.)
|
|
140
|
+
*/
|
|
141
|
+
export declare function renderForChildVendor(envelope: HandoffEnvelope): string;
|
|
142
|
+
export interface SnapshotStats {
|
|
143
|
+
envelopeId: string;
|
|
144
|
+
conversationTurns: number;
|
|
145
|
+
activityRecords: number;
|
|
146
|
+
totalBytes: number;
|
|
147
|
+
ageMs: number;
|
|
148
|
+
}
|
|
149
|
+
export declare function computeSnapshotStats(envelope: HandoffEnvelope, nowMs?: number): SnapshotStats;
|
|
150
|
+
export declare function formatSnapshotLine(s: SnapshotStats): string;
|
|
151
|
+
export declare const HANDOFF_SNAPSHOT_TUNABLES: Readonly<{
|
|
152
|
+
PROTOCOL_VERSION: 2;
|
|
153
|
+
DEFAULT_FRESHNESS_TTL_MS: number;
|
|
154
|
+
}>;
|
|
155
|
+
export {};
|
|
156
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/handoff_snapshot/index.ts"],"names":[],"mappings":"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"}
|