@jhizzard/termdeck 0.2.2 → 0.2.3
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/index.js +4 -4
- package/packages/cli/src/{init-engram.js → init-mnestra.js} +15 -15
- package/packages/cli/src/init-rumen.js +6 -6
- package/packages/server/src/setup/migrations.js +9 -9
- package/packages/server/src/setup/{engram-migrations/001_engram_tables.sql → mnestra-migrations/001_mnestra_tables.sql} +4 -4
- package/packages/server/src/setup/{engram-migrations/002_engram_search_function.sql → mnestra-migrations/002_mnestra_search_function.sql} +1 -1
- package/packages/server/src/setup/{engram-migrations/003_engram_event_webhook.sql → mnestra-migrations/003_mnestra_event_webhook.sql} +2 -2
- package/packages/server/src/setup/{engram-migrations/004_engram_match_count_cap_and_explain.sql → mnestra-migrations/004_mnestra_match_count_cap_and_explain.sql} +5 -5
- package/packages/server/src/setup/{engram-migrations → mnestra-migrations}/005_v0_1_to_v0_2_upgrade.sql +3 -3
- package/packages/server/src/setup/{engram-migrations → mnestra-migrations}/006_memory_status_rpc.sql +1 -1
- package/packages/server/src/setup/prompts.js +1 -1
- package/packages/server/src/setup/rumen/migrations/001_rumen_tables.sql +1 -1
- package/packages/server/src/setup/supabase-url.js +1 -1
- package/packages/server/src/setup/yaml-io.js +3 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jhizzard/termdeck",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.3",
|
|
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"
|
|
@@ -7,9 +7,9 @@
|
|
|
7
7
|
// termdeck init --rumen [flags] # Tier 3 async learning deploy
|
|
8
8
|
//
|
|
9
9
|
// Note (Sprint 3): the `--mnestra` flag name matches the current init-mnestra.js
|
|
10
|
-
// filename. When the main orchestrator completes the Mnestra →
|
|
10
|
+
// filename. When the main orchestrator completes the Mnestra → Mnestra rename
|
|
11
11
|
// sweep over this repo, both the flag name and the filename should flip to
|
|
12
|
-
// `--
|
|
12
|
+
// `--mnestra` / `init-mnestra.js` together.
|
|
13
13
|
|
|
14
14
|
const path = require('path');
|
|
15
15
|
const { execSync } = require('child_process');
|
|
@@ -43,7 +43,7 @@ if (args[0] === 'init') {
|
|
|
43
43
|
return;
|
|
44
44
|
}
|
|
45
45
|
console.error('Usage: termdeck init --mnestra | --rumen');
|
|
46
|
-
console.error(' termdeck init --mnestra Configure Tier 2 memory (Supabase +
|
|
46
|
+
console.error(' termdeck init --mnestra Configure Tier 2 memory (Supabase + Mnestra)');
|
|
47
47
|
console.error(' termdeck init --rumen Deploy Tier 3 async learning (Rumen)');
|
|
48
48
|
process.exit(1);
|
|
49
49
|
}
|
|
@@ -66,7 +66,7 @@ for (let i = 0; i < args.length; i++) {
|
|
|
66
66
|
termdeck --port 8080 Start on custom port
|
|
67
67
|
termdeck --no-open Don't auto-open browser
|
|
68
68
|
termdeck --session-logs Write per-session markdown logs to ~/.termdeck/sessions/
|
|
69
|
-
termdeck init --mnestra Configure Tier 2 memory (Supabase +
|
|
69
|
+
termdeck init --mnestra Configure Tier 2 memory (Supabase + Mnestra)
|
|
70
70
|
termdeck init --rumen Deploy Tier 3 async learning (Rumen)
|
|
71
71
|
|
|
72
72
|
Keyboard shortcuts (in browser):
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
// `termdeck init --
|
|
4
|
-
// layer. Wraps the six manual
|
|
3
|
+
// `termdeck init --mnestra` — interactive wizard for TermDeck's Tier 2 memory
|
|
4
|
+
// layer. Wraps the six manual Mnestra setup steps into one command.
|
|
5
5
|
//
|
|
6
6
|
// Steps:
|
|
7
7
|
// 1. Collect Supabase URL, service_role key, direct DB URL, OpenAI + Anthropic keys
|
|
8
8
|
// 2. Connect via `pg` using the direct URL
|
|
9
|
-
// 3. Apply the six bundled
|
|
9
|
+
// 3. Apply the six bundled Mnestra migrations in order
|
|
10
10
|
// 4. Write ~/.termdeck/secrets.env (merge-aware, preserves existing values)
|
|
11
11
|
// 5. Update ~/.termdeck/config.yaml to enable RAG + point at ${VAR} refs
|
|
12
12
|
// 6. Verify with a memory_status_aggregation() call
|
|
@@ -35,9 +35,9 @@ const {
|
|
|
35
35
|
|
|
36
36
|
const HELP = [
|
|
37
37
|
'',
|
|
38
|
-
'TermDeck
|
|
38
|
+
'TermDeck Mnestra Setup',
|
|
39
39
|
'',
|
|
40
|
-
'Usage: termdeck init --
|
|
40
|
+
'Usage: termdeck init --mnestra [flags]',
|
|
41
41
|
'',
|
|
42
42
|
'Flags:',
|
|
43
43
|
' --help Print this message and exit',
|
|
@@ -48,10 +48,10 @@ const HELP = [
|
|
|
48
48
|
'What this does:',
|
|
49
49
|
' 1. Prompts for Supabase URL, service_role key, direct Postgres connection',
|
|
50
50
|
' string, OpenAI API key, and (optional) Anthropic API key.',
|
|
51
|
-
' 2. Applies the six
|
|
51
|
+
' 2. Applies the six Mnestra schema + RPC migrations via node-postgres.',
|
|
52
52
|
' 3. Writes ~/.termdeck/secrets.env (merge-aware, preserves existing values).',
|
|
53
53
|
' 4. Updates ~/.termdeck/config.yaml to enable RAG and reference ${VAR} keys.',
|
|
54
|
-
' 5. Verifies the
|
|
54
|
+
' 5. Verifies the Mnestra store is reachable via memory_status_aggregation().',
|
|
55
55
|
'',
|
|
56
56
|
'Every secret stays on your machine. Nothing is ever printed once entered.',
|
|
57
57
|
''
|
|
@@ -70,10 +70,10 @@ function parseFlags(argv) {
|
|
|
70
70
|
|
|
71
71
|
function printBanner() {
|
|
72
72
|
process.stdout.write(`
|
|
73
|
-
TermDeck
|
|
73
|
+
TermDeck Mnestra Setup
|
|
74
74
|
─────────────────────
|
|
75
75
|
|
|
76
|
-
This wizard configures TermDeck's Tier 2 memory layer (
|
|
76
|
+
This wizard configures TermDeck's Tier 2 memory layer (Mnestra) by:
|
|
77
77
|
1. Asking for your Supabase URL and service_role key
|
|
78
78
|
2. Asking for a direct Postgres connection string
|
|
79
79
|
3. Applying six SQL migrations to the database
|
|
@@ -166,9 +166,9 @@ async function promptSecretWithValidation(validator) {
|
|
|
166
166
|
}
|
|
167
167
|
|
|
168
168
|
async function applyMigrations(client, dryRun) {
|
|
169
|
-
const files = migrations.
|
|
169
|
+
const files = migrations.listMnestraMigrations();
|
|
170
170
|
if (files.length === 0) {
|
|
171
|
-
throw new Error('No
|
|
171
|
+
throw new Error('No Mnestra migrations found. TermDeck install looks corrupted.');
|
|
172
172
|
}
|
|
173
173
|
|
|
174
174
|
for (const file of files) {
|
|
@@ -257,7 +257,7 @@ function writeLocalConfig(inputs, dryRun) {
|
|
|
257
257
|
|
|
258
258
|
function printNextSteps() {
|
|
259
259
|
process.stdout.write(`
|
|
260
|
-
|
|
260
|
+
Mnestra is configured.
|
|
261
261
|
|
|
262
262
|
Next steps:
|
|
263
263
|
1. Restart TermDeck: termdeck
|
|
@@ -280,7 +280,7 @@ async function main(argv) {
|
|
|
280
280
|
try {
|
|
281
281
|
inputs = await collectInputs({ yes: flags.yes });
|
|
282
282
|
} catch (err) {
|
|
283
|
-
process.stderr.write(`\n[init --
|
|
283
|
+
process.stderr.write(`\n[init --mnestra] ${err.message}\n`);
|
|
284
284
|
return 2;
|
|
285
285
|
}
|
|
286
286
|
|
|
@@ -322,7 +322,7 @@ async function main(argv) {
|
|
|
322
322
|
}
|
|
323
323
|
}
|
|
324
324
|
} catch (err) {
|
|
325
|
-
process.stderr.write(`\n[init --
|
|
325
|
+
process.stderr.write(`\n[init --mnestra] ${err.message}\n`);
|
|
326
326
|
return 5;
|
|
327
327
|
} finally {
|
|
328
328
|
try { await client.end(); } catch (_err) { /* ignore */ }
|
|
@@ -336,7 +336,7 @@ if (require.main === module) {
|
|
|
336
336
|
main(process.argv.slice(2))
|
|
337
337
|
.then((code) => process.exit(code || 0))
|
|
338
338
|
.catch((err) => {
|
|
339
|
-
process.stderr.write(`\n[init --
|
|
339
|
+
process.stderr.write(`\n[init --mnestra] unexpected error: ${err && err.stack || err}\n`);
|
|
340
340
|
process.exit(1);
|
|
341
341
|
});
|
|
342
342
|
}
|
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
// `termdeck init --rumen` — interactive wizard for deploying Rumen as a
|
|
4
4
|
// Supabase Edge Function + pg_cron schedule against the same Supabase
|
|
5
|
-
// project that holds the
|
|
5
|
+
// project that holds the Mnestra store.
|
|
6
6
|
//
|
|
7
7
|
// Requirements checked at runtime:
|
|
8
8
|
// - `supabase` CLI on PATH
|
|
9
9
|
// - `deno` on PATH
|
|
10
10
|
// - `~/.termdeck/secrets.env` with SUPABASE_URL + SUPABASE_SERVICE_ROLE_KEY +
|
|
11
|
-
// DATABASE_URL + ANTHROPIC_API_KEY populated (run `termdeck init --
|
|
11
|
+
// DATABASE_URL + ANTHROPIC_API_KEY populated (run `termdeck init --mnestra` first)
|
|
12
12
|
//
|
|
13
13
|
// Steps:
|
|
14
14
|
// 1. Preflight: which supabase, which deno, read secrets.env
|
|
@@ -47,7 +47,7 @@ const HELP = [
|
|
|
47
47
|
' --skip-schedule Deploy the function but do not install the pg_cron schedule',
|
|
48
48
|
'',
|
|
49
49
|
'Requires: Supabase CLI and Deno already installed.',
|
|
50
|
-
'Requires: `termdeck init --
|
|
50
|
+
'Requires: `termdeck init --mnestra` has already run (needs secrets.env).',
|
|
51
51
|
''
|
|
52
52
|
].join('\n');
|
|
53
53
|
|
|
@@ -112,14 +112,14 @@ function preflight() {
|
|
|
112
112
|
}
|
|
113
113
|
ok();
|
|
114
114
|
|
|
115
|
-
step('Reading
|
|
115
|
+
step('Reading Mnestra config from ~/.termdeck/secrets.env...');
|
|
116
116
|
const secrets = dotenv.readSecrets();
|
|
117
117
|
const required = ['SUPABASE_URL', 'SUPABASE_SERVICE_ROLE_KEY', 'DATABASE_URL', 'ANTHROPIC_API_KEY'];
|
|
118
118
|
const missing = required.filter((k) => !secrets[k]);
|
|
119
119
|
if (missing.length > 0) {
|
|
120
120
|
fail(`missing keys: ${missing.join(', ')}`);
|
|
121
121
|
process.stderr.write(
|
|
122
|
-
'\nRun `termdeck init --
|
|
122
|
+
'\nRun `termdeck init --mnestra` first — it writes the keys this wizard needs.\n'
|
|
123
123
|
);
|
|
124
124
|
return null;
|
|
125
125
|
}
|
|
@@ -363,7 +363,7 @@ Next steps:
|
|
|
363
363
|
1. Monitor: psql "$DATABASE_URL" -c "SELECT * FROM rumen_jobs ORDER BY started_at DESC LIMIT 5"
|
|
364
364
|
2. Store the service_role key in Supabase Vault as \`rumen_service_role_key\`
|
|
365
365
|
so the cron call in migrations/002_pg_cron_schedule.sql can authenticate.
|
|
366
|
-
3. Rumen insights flow back into
|
|
366
|
+
3. Rumen insights flow back into Mnestra's memory_items via rumen_insights.
|
|
367
367
|
4. TermDeck's Flashback will surface cross-project patterns automatically.
|
|
368
368
|
`);
|
|
369
369
|
}
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
// Discover the SQL migration files that ship bundled inside the TermDeck
|
|
2
|
-
// package. Both init wizards call this — init-
|
|
2
|
+
// package. Both init wizards call this — init-mnestra for the six Mnestra
|
|
3
3
|
// migrations, init-rumen for the two Rumen migrations.
|
|
4
4
|
//
|
|
5
|
-
// The wizards intentionally do NOT fall back to a sibling `../../
|
|
5
|
+
// The wizards intentionally do NOT fall back to a sibling `../../mnestra`
|
|
6
6
|
// working copy. Resolution order:
|
|
7
7
|
//
|
|
8
|
-
// 1. Files bundled at `packages/server/src/setup/
|
|
8
|
+
// 1. Files bundled at `packages/server/src/setup/mnestra-migrations/*.sql`
|
|
9
9
|
// (this directory is covered by the root package.json `files` glob).
|
|
10
|
-
// 2. Files at `node_modules/@jhizzard/
|
|
10
|
+
// 2. Files at `node_modules/@jhizzard/mnestra/migrations/*.sql` if that
|
|
11
11
|
// package is installed alongside TermDeck (future-proof path — shipping
|
|
12
|
-
// `@jhizzard/
|
|
12
|
+
// `@jhizzard/mnestra` as an optional peer would let us drop the bundled
|
|
13
13
|
// copy).
|
|
14
14
|
|
|
15
15
|
const fs = require('fs');
|
|
@@ -44,10 +44,10 @@ function tryNodeModules(packageName, migrationSubdir = 'migrations') {
|
|
|
44
44
|
}
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
function
|
|
48
|
-
const fromNm = tryNodeModules('@jhizzard/
|
|
47
|
+
function listMnestraMigrations() {
|
|
48
|
+
const fromNm = tryNodeModules('@jhizzard/mnestra');
|
|
49
49
|
if (fromNm.length > 0) return fromNm;
|
|
50
|
-
return listBundled('
|
|
50
|
+
return listBundled('mnestra-migrations');
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
function listRumenMigrations() {
|
|
@@ -73,7 +73,7 @@ function readFile(filepath) {
|
|
|
73
73
|
}
|
|
74
74
|
|
|
75
75
|
module.exports = {
|
|
76
|
-
|
|
76
|
+
listMnestraMigrations,
|
|
77
77
|
listRumenMigrations,
|
|
78
78
|
rumenFunctionDir,
|
|
79
79
|
readFile
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
--
|
|
1
|
+
-- Mnestra v0.1 — core tables
|
|
2
2
|
--
|
|
3
3
|
-- Run against a Postgres 15+ database that has pgvector installed
|
|
4
4
|
-- (Supabase already ships with it). Apply in order:
|
|
5
|
-
--
|
|
6
|
-
--
|
|
7
|
-
--
|
|
5
|
+
-- 001_mnestra_tables.sql
|
|
6
|
+
-- 002_mnestra_search_function.sql
|
|
7
|
+
-- 003_mnestra_event_webhook.sql
|
|
8
8
|
|
|
9
9
|
create extension if not exists "vector";
|
|
10
10
|
create extension if not exists "pg_trgm";
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
--
|
|
1
|
+
-- Mnestra v0.1 — real-time event webhook (Fix 6)
|
|
2
2
|
--
|
|
3
3
|
-- Fix 6 from RAG-MEMORY-IMPROVEMENTS-AND-TERMDECK-STRATEGY.md is a
|
|
4
4
|
-- real-time event intake path so TermDeck (or any other client) can
|
|
5
5
|
-- POST terminal events — "server started on :8080", "tests failing",
|
|
6
6
|
-- "error detected" — and have them land in memory immediately.
|
|
7
7
|
--
|
|
8
|
-
-- That intake is implemented as an HTTP endpoint inside the
|
|
8
|
+
-- That intake is implemented as an HTTP endpoint inside the Mnestra MCP
|
|
9
9
|
-- server process, not as a SQL trigger. This file exists as a placeholder
|
|
10
10
|
-- so the migration history is explicit and future database-side changes
|
|
11
11
|
-- (e.g. an events queue table for async ingestion) have a home.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
--
|
|
1
|
+
-- Mnestra v0.2 — match_count cap + EXPLAIN variant
|
|
2
2
|
--
|
|
3
3
|
-- Two changes to the search surface:
|
|
4
4
|
--
|
|
@@ -6,13 +6,13 @@
|
|
|
6
6
|
-- Default cap: 200. The original function was unbounded, which risks
|
|
7
7
|
-- runaway queries at scale (10k+ rows pulled per call).
|
|
8
8
|
--
|
|
9
|
-
-- Override per-database: ALTER DATABASE your_db SET
|
|
10
|
-
-- Override per-session: SET
|
|
9
|
+
-- Override per-database: ALTER DATABASE your_db SET mnestra.max_match_count = 500;
|
|
10
|
+
-- Override per-session: SET mnestra.max_match_count = 500;
|
|
11
11
|
-- Leave unset: cap defaults to 200.
|
|
12
12
|
--
|
|
13
13
|
-- 2. A new function `memory_hybrid_search_explain` that returns
|
|
14
14
|
-- EXPLAIN (ANALYZE, BUFFERS) output for an equivalent call. Used by
|
|
15
|
-
-- `
|
|
15
|
+
-- `mnestra diagnose` to troubleshoot slow recall queries.
|
|
16
16
|
--
|
|
17
17
|
-- Rerun-safe: CREATE OR REPLACE on both.
|
|
18
18
|
|
|
@@ -140,7 +140,7 @@ from scored s
|
|
|
140
140
|
order by s.score desc
|
|
141
141
|
limit least(
|
|
142
142
|
greatest(match_count, 1),
|
|
143
|
-
coalesce(nullif(current_setting('
|
|
143
|
+
coalesce(nullif(current_setting('mnestra.max_match_count', true), '')::int, 200)
|
|
144
144
|
);
|
|
145
145
|
$$;
|
|
146
146
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
--
|
|
1
|
+
-- Mnestra v0.2 — minimal additive delta for stores provisioned against the
|
|
2
2
|
-- original rag-system schema.
|
|
3
3
|
--
|
|
4
4
|
-- This migration is idempotent and non-destructive:
|
|
5
|
-
-- • adds only the single column (`archived`) that
|
|
5
|
+
-- • adds only the single column (`archived`) that Mnestra v0.2 reads/writes
|
|
6
6
|
-- but which is absent from the original rag-system `memory_items` table;
|
|
7
7
|
-- • re-creates the two partial indexes under v2 names so they cannot
|
|
8
8
|
-- collide with any pre-existing same-named index that uses a different
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
-- other SQL function — those remain on their production versions.
|
|
12
12
|
--
|
|
13
13
|
-- Apply once, in the Supabase SQL editor, against any existing store that
|
|
14
|
-
-- pre-dates
|
|
14
|
+
-- pre-dates Mnestra v0.2's `archived` soft-delete column.
|
|
15
15
|
|
|
16
16
|
alter table memory_items
|
|
17
17
|
add column if not exists archived boolean not null default false;
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
// hangs. The event-driven path works for both TTY and piped input, which lets
|
|
9
9
|
// us drive the wizard non-interactively in tests:
|
|
10
10
|
//
|
|
11
|
-
// printf 'a\nb\nc\n' | termdeck init --
|
|
11
|
+
// printf 'a\nb\nc\n' | termdeck init --mnestra --dry-run
|
|
12
12
|
//
|
|
13
13
|
// Secret prompts still mute stdout echo when TTY is attached; on non-TTY
|
|
14
14
|
// stdin they fall back to visible input so piped test runs work.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
-- Rumen v0.1 schema
|
|
2
2
|
-- Non-destructive: creates three new tables under the rumen_ namespace.
|
|
3
|
-
-- Does NOT modify or reference
|
|
3
|
+
-- Does NOT modify or reference Mnestra's existing memory_items / memory_sessions tables.
|
|
4
4
|
--
|
|
5
5
|
-- Apply with:
|
|
6
6
|
-- psql "$DIRECT_URL" -f migrations/001_rumen_tables.sql
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Parse + validate Supabase URLs and derive what we can from them without the
|
|
2
2
|
// database password. Useful for both init wizards:
|
|
3
3
|
//
|
|
4
|
-
// - init-
|
|
4
|
+
// - init-mnestra needs the project ref to show in status output and also
|
|
5
5
|
// needs a full DATABASE_URL to apply migrations; since the DB password
|
|
6
6
|
// cannot be derived from the project URL alone, the wizard prompts for
|
|
7
7
|
// the direct connection string separately.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Targeted writer for ~/.termdeck/config.yaml that the `init --
|
|
1
|
+
// Targeted writer for ~/.termdeck/config.yaml that the `init --mnestra` wizard
|
|
2
2
|
// uses to flip `rag.enabled: true` and point secret fields at `${VAR}` refs
|
|
3
3
|
// instead of inline values.
|
|
4
4
|
//
|
|
@@ -56,8 +56,8 @@ function updateRagConfig(updates) {
|
|
|
56
56
|
openaiApiKey: updates.openaiApiKey || rag.openaiApiKey || '${OPENAI_API_KEY}',
|
|
57
57
|
anthropicApiKey: updates.anthropicApiKey || rag.anthropicApiKey || '${ANTHROPIC_API_KEY}',
|
|
58
58
|
syncIntervalMs: rag.syncIntervalMs != null ? rag.syncIntervalMs : 10000,
|
|
59
|
-
|
|
60
|
-
|
|
59
|
+
mnestraMode: rag.mnestraMode || 'direct',
|
|
60
|
+
mnestraWebhookUrl: rag.mnestraWebhookUrl || 'http://localhost:37778/mnestra'
|
|
61
61
|
};
|
|
62
62
|
|
|
63
63
|
// Preserve any fields we didn't explicitly handle (e.g. tables, developerId).
|