@jhizzard/termdeck 1.0.14 → 1.1.1
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 +1 -1
- package/packages/cli/src/init-mnestra.js +50 -10
- package/packages/client/public/app.js +57 -0
- package/packages/server/src/index.js +19 -1
- package/packages/server/src/setup/migrations.js +514 -1
- package/packages/server/src/setup/mnestra-migrations/001_mnestra_tables.sql +2 -2
- package/packages/server/src/setup/mnestra-migrations/002_mnestra_search_function.sql +1 -1
- package/packages/server/src/setup/mnestra-migrations/009_memory_relationship_metadata.sql +1 -1
- package/packages/server/src/setup/mnestra-migrations/011_project_tag_backfill.sql +7 -3
- package/packages/server/src/setup/mnestra-migrations/012_project_tag_re_taxonomy.sql +2 -2
- package/packages/server/src/setup/mnestra-migrations/014_explicit_grants.sql +3 -3
- package/packages/server/src/setup/mnestra-migrations/016_mnestra_doctor_probes.sql +3 -3
- package/packages/server/src/setup/mnestra-migrations/017_memory_sessions_session_metadata.sql +5 -5
- package/packages/server/src/setup/mnestra-migrations/018_rumen_processed_at.sql +1 -1
- package/packages/server/src/setup/mnestra-migrations/019_security_hardening.sql +190 -0
- package/packages/server/src/setup/mnestra-migrations/020_migration_tracking.sql +57 -0
- package/packages/server/src/setup/mnestra-migrations/021_project_tag_canonicalize_claimguard.sql +175 -0
- package/packages/server/src/setup/mnestra-migrations/022_source_agent_backfill.sql +182 -0
- package/packages/server/src/setup/rumen/functions/rumen-tick/index.ts +0 -30
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jhizzard/termdeck",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.1",
|
|
4
4
|
"description": "Browser-based terminal multiplexer with metadata overlays, panel flashback memory recall, and AI-aware session management",
|
|
5
5
|
"bin": {
|
|
6
6
|
"termdeck": "./packages/cli/src/index.js"
|
|
@@ -332,23 +332,63 @@ async function promptSecretWithValidation(validator) {
|
|
|
332
332
|
throw new Error('Too many invalid attempts — cancelling.');
|
|
333
333
|
}
|
|
334
334
|
|
|
335
|
+
// Sprint 61 T2 — collapsed fresh-install / upgrade paths. Pre-Sprint-61, the
|
|
336
|
+
// wizard re-applied every bundled mnestra migration on every invocation,
|
|
337
|
+
// relying on per-file IF NOT EXISTS / CREATE OR REPLACE idempotency. That
|
|
338
|
+
// works for fresh installs but doesn't tell the wizard which migrations the
|
|
339
|
+
// live database has actually received — so a user running
|
|
340
|
+
// `npm install -g @latest` against an existing project lands in Class A
|
|
341
|
+
// (schema drift on package upgrade): the npm package files upgrade, the
|
|
342
|
+
// database stays at first-kickstart state. Brad reported this 2026-05-02.
|
|
343
|
+
//
|
|
344
|
+
// applyPendingMigrations (migrations.js) replaces the loop with a tracker-
|
|
345
|
+
// aware diff: SELECT applied filenames from public.mnestra_migrations, run
|
|
346
|
+
// only the bundled-but-unapplied ones, INSERT a tracker row per apply.
|
|
347
|
+
// Pre-020 installs trigger a one-time backfill probe pass that seeds the
|
|
348
|
+
// tracker for migrations whose schema artifacts are already present.
|
|
335
349
|
async function applyMigrations(client, dryRun) {
|
|
336
350
|
const files = migrations.listMnestraMigrations();
|
|
337
351
|
if (files.length === 0) {
|
|
338
352
|
throw new Error('No Mnestra migrations found. TermDeck install looks corrupted.');
|
|
339
353
|
}
|
|
340
354
|
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
ok(
|
|
348
|
-
} else {
|
|
349
|
-
fail(result.error);
|
|
350
|
-
throw new Error(`Migration failed: ${base}`);
|
|
355
|
+
if (dryRun) {
|
|
356
|
+
// Preserve the per-file dry-run banner so the user sees the planned
|
|
357
|
+
// sequence without touching the database.
|
|
358
|
+
for (const file of files) {
|
|
359
|
+
const base = path.basename(file);
|
|
360
|
+
step(`Applying migration ${base}...`);
|
|
361
|
+
ok('(dry-run)');
|
|
351
362
|
}
|
|
363
|
+
return;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
step('Running tracker-aware diff-and-apply (skips already-applied migrations)...');
|
|
367
|
+
const summary = await migrations.applyPendingMigrations(client);
|
|
368
|
+
|
|
369
|
+
if (summary.errored) {
|
|
370
|
+
fail(`${summary.errored.file}: ${summary.errored.error}`);
|
|
371
|
+
throw new Error(`Migration failed: ${summary.errored.file}`);
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
ok(
|
|
375
|
+
`(applied ${summary.applied.length}, backfilled ${summary.backfilled.length}, ` +
|
|
376
|
+
`skipped ${summary.skipped.length})`
|
|
377
|
+
);
|
|
378
|
+
|
|
379
|
+
for (const f of summary.applied) {
|
|
380
|
+
process.stdout.write(` ✓ applied ${f}\n`);
|
|
381
|
+
}
|
|
382
|
+
for (const f of summary.backfilled) {
|
|
383
|
+
process.stdout.write(` ◇ backfilled ${f} (schema already present, recorded in tracker)\n`);
|
|
384
|
+
}
|
|
385
|
+
for (const w of summary.warnings) {
|
|
386
|
+
const tracked = (w.trackedChecksum || '').slice(0, 12) || '<empty>';
|
|
387
|
+
const bundled = (w.bundledChecksum || '').slice(0, 12) || '<empty>';
|
|
388
|
+
process.stdout.write(
|
|
389
|
+
` ! checksum drift on ${w.file}: tracked=${tracked}, bundled=${bundled} ` +
|
|
390
|
+
`(no auto-overwrite — investigate before re-running)\n`
|
|
391
|
+
);
|
|
352
392
|
}
|
|
353
393
|
}
|
|
354
394
|
|
|
@@ -129,6 +129,12 @@
|
|
|
129
129
|
// Sprint 37 T1: orchestrator Guide right-rail. Lazy — fetches the doc
|
|
130
130
|
// on first expand to keep page load light.
|
|
131
131
|
setupGuideRail();
|
|
132
|
+
|
|
133
|
+
// 2026-05-08 hotfix: document-level capture-phase image-paste handler.
|
|
134
|
+
// Intercepts Cmd+V image data before xterm-helper-textarea consumes it
|
|
135
|
+
// (xterm reads only text/plain, drops images silently). See comment on
|
|
136
|
+
// setupGlobalImagePaste() near uploadFilesAndType() for details.
|
|
137
|
+
setupGlobalImagePaste();
|
|
132
138
|
}
|
|
133
139
|
|
|
134
140
|
// ===== Drag/drop reorder of PTY panels (Sprint 42 T4) =====
|
|
@@ -275,6 +281,57 @@
|
|
|
275
281
|
}
|
|
276
282
|
}
|
|
277
283
|
|
|
284
|
+
// Document-level capture-phase image paste handler.
|
|
285
|
+
//
|
|
286
|
+
// The Sprint 59 per-panel `paste` listener at line 218 is bubble-phase, but
|
|
287
|
+
// xterm.js@5.5.0's hidden helper-textarea has its own `paste` handler that
|
|
288
|
+
// reads only `clipboardData.getData('text/plain')`. Image data lives in
|
|
289
|
+
// `clipboardData.items` with `kind: 'file'` and never reaches xterm's
|
|
290
|
+
// text path — and the panel-level bubble-phase handler runs after xterm's,
|
|
291
|
+
// by which point xterm has already returned (silently dropping the image).
|
|
292
|
+
// Net: pre-fix, Cmd+V'ing a screenshot into a focused TermDeck panel did
|
|
293
|
+
// nothing. Joshua reported this on 2026-05-08 (post-v1.1.0 upgrade).
|
|
294
|
+
//
|
|
295
|
+
// Fix: document-level listener with `{capture: true}` runs in capture
|
|
296
|
+
// phase BEFORE the event reaches xterm-helper-textarea. If the event
|
|
297
|
+
// target is inside a `.term-panel` AND the clipboard contains image
|
|
298
|
+
// files, we preventDefault + stopPropagation (so xterm + the bubble-phase
|
|
299
|
+
// panel handler don't see it) and route through `uploadFilesAndType`.
|
|
300
|
+
// For text paste (no image files) we let the event continue normally.
|
|
301
|
+
//
|
|
302
|
+
// Idempotent: setupGlobalImagePaste() is called once from init().
|
|
303
|
+
let _globalImagePasteSetup = false;
|
|
304
|
+
function setupGlobalImagePaste() {
|
|
305
|
+
if (_globalImagePasteSetup) return;
|
|
306
|
+
_globalImagePasteSetup = true;
|
|
307
|
+
document.addEventListener('paste', (e) => {
|
|
308
|
+
const target = e.target;
|
|
309
|
+
if (!(target instanceof Element)) return;
|
|
310
|
+
const panel = target.closest('.term-panel');
|
|
311
|
+
if (!panel) return;
|
|
312
|
+
const items = (e.clipboardData && e.clipboardData.items) || [];
|
|
313
|
+
const blobs = [];
|
|
314
|
+
for (const item of items) {
|
|
315
|
+
if (item.kind === 'file' && item.type && item.type.startsWith('image/')) {
|
|
316
|
+
const blob = item.getAsFile();
|
|
317
|
+
if (blob) blobs.push(blob);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
if (blobs.length === 0) return;
|
|
321
|
+
e.preventDefault();
|
|
322
|
+
e.stopPropagation();
|
|
323
|
+
const ts = new Date().toISOString().replace(/[:.]/g, '-');
|
|
324
|
+
const named = blobs.map((b, i) => {
|
|
325
|
+
const ext = (b.type.split('/')[1] || 'png').replace(/[^a-z0-9]/gi, '');
|
|
326
|
+
const name = b.name && b.name.length > 0
|
|
327
|
+
? b.name
|
|
328
|
+
: `pasted-${ts}${blobs.length > 1 ? '-' + i : ''}.${ext}`;
|
|
329
|
+
return new File([b], name, { type: b.type });
|
|
330
|
+
});
|
|
331
|
+
uploadFilesAndType(panel, named);
|
|
332
|
+
}, { capture: true });
|
|
333
|
+
}
|
|
334
|
+
|
|
278
335
|
// ===== Create Terminal Panel =====
|
|
279
336
|
function createTerminalPanel(sessionData) {
|
|
280
337
|
const id = sessionData.id;
|
|
@@ -16,7 +16,25 @@ const { createCachedLookup, createFailureLogger } = require('./rumen-pool-resili
|
|
|
16
16
|
// Conditional imports (graceful fallback if not installed yet)
|
|
17
17
|
let pty, Database, pg;
|
|
18
18
|
try { pty = require('@homebridge/node-pty-prebuilt-multiarch'); } catch { pty = null; }
|
|
19
|
-
try {
|
|
19
|
+
try {
|
|
20
|
+
Database = require('better-sqlite3');
|
|
21
|
+
} catch (err) {
|
|
22
|
+
// Brad Heath 2026-05-11: distinguish a native-ABI mismatch (Node upgraded
|
|
23
|
+
// after install) from "package not installed yet." ABI mismatch leaves
|
|
24
|
+
// Database=null and cascades into a null-handle storm downstream that
|
|
25
|
+
// masquerades as "Mnestra unreachable / DB timeout" in health probes.
|
|
26
|
+
// Fail fast with the actionable rebuild hint instead.
|
|
27
|
+
const msg = err && err.message ? String(err.message) : '';
|
|
28
|
+
if (err && err.code === 'ERR_DLOPEN_FAILED' && /NODE_MODULE_VERSION/.test(msg)) {
|
|
29
|
+
console.error('[db] better-sqlite3 native ABI mismatch (Node was upgraded after install).');
|
|
30
|
+
console.error('[db] TermDeck cannot serve memory features without a working SQLite.');
|
|
31
|
+
console.error('[db] Fix:');
|
|
32
|
+
console.error(' cd "$(npm root -g)/@jhizzard/termdeck" && npm rebuild better-sqlite3');
|
|
33
|
+
console.error('[db] Then restart TermDeck. Aborting.');
|
|
34
|
+
process.exit(1);
|
|
35
|
+
}
|
|
36
|
+
Database = null;
|
|
37
|
+
}
|
|
20
38
|
try { pg = require('pg'); } catch { pg = null; }
|
|
21
39
|
|
|
22
40
|
// Module-level singleton Postgres pool for rumen_insights (petvetbid DB).
|