memex-mvp 0.10.9 → 0.10.10

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/ingest.js CHANGED
@@ -293,6 +293,21 @@ async function cmdInstall() {
293
293
  console.log('');
294
294
  console.log(`config: ${CONFIG_PATH} (auto-created on first edit)`);
295
295
  console.log(`status: npx memex-sync status`);
296
+
297
+ // v0.10.10: surface the new web dashboard so manual installers actually
298
+ // discover it. (curl-bash flow has its own [Y/n] prompt in install.sh —
299
+ // it suppresses this output via `>/dev/null 2>&1`, so this callout is
300
+ // for the `memex-sync install` direct-call path only.)
301
+ console.log('');
302
+ console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
303
+ console.log('🌐 NEW in v0.10.8: open your memory in a browser');
304
+ console.log('');
305
+ console.log(' memex web --open');
306
+ console.log('');
307
+ console.log('5 pages, read-only, localhost-only. Every captured');
308
+ console.log('conversation, verbatim — not summarized. Ctrl+C to stop.');
309
+ console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
310
+
296
311
  process.exit(0);
297
312
  }
298
313
 
package/lib/cli/index.js CHANGED
@@ -150,20 +150,41 @@ function maybePrintTelegramTip(opts = {}, currentSubcommand = '') {
150
150
  async function afterCommand(opts = {}, currentSubcommand = '') {
151
151
  if (opts.json) return;
152
152
  if (currentSubcommand === 'telegram') return;
153
+ if (currentSubcommand === 'web') return; // web command holds the loop; tip would never print anyway
154
+ // `context` output IS the SessionStart hook payload — it gets injected
155
+ // verbatim into Claude Code's session header. Tips would corrupt that
156
+ // (and bust the --budget-tokens cap that the hook contract relies on).
157
+ if (currentSubcommand === 'context') return;
153
158
  if (process.env.MEMEX_TIP_SUPPRESS === '1') return;
154
159
  try {
155
- const { listPending } = await import('../telegram-pending.js');
156
- const list = listPending();
157
- if (!list || list.length === 0) return;
158
160
  const notify = await import('../telegram-notify.js');
159
161
  const state = notify.loadNotifyState();
160
- if (!notify.cliTipDue(state)) return;
161
- const showTitles = state.notifications.show_titles !== false;
162
- const tip = notify.formatTelegramTip(list, { showTitles });
163
- if (tip) {
164
- console.log(tip);
165
- notify.markCliTipShown(state);
166
- notify.saveNotifyState(state);
162
+
163
+ // Channel B priority: TG-pending tip first (it's actionable — there's
164
+ // a real export waiting). Dashboard tip is "nice to know", so only
165
+ // show it when the TG channel has nothing to surface.
166
+ const { listPending } = await import('../telegram-pending.js');
167
+ const list = listPending();
168
+ const hasPending = list && list.length > 0;
169
+
170
+ if (hasPending && notify.cliTipDue(state)) {
171
+ const showTitles = state.notifications.show_titles !== false;
172
+ const tip = notify.formatTelegramTip(list, { showTitles });
173
+ if (tip) {
174
+ console.log(tip);
175
+ notify.markCliTipShown(state);
176
+ notify.saveNotifyState(state);
177
+ return;
178
+ }
179
+ }
180
+
181
+ if (!hasPending && notify.dashboardTipDue(state)) {
182
+ const tip = notify.formatDashboardTip();
183
+ if (tip) {
184
+ console.log(c.dim(tip));
185
+ notify.markDashboardTipShown(state);
186
+ notify.saveNotifyState(state);
187
+ }
167
188
  }
168
189
  } catch (_) {
169
190
  /* never break a command because of a tip */
@@ -1737,6 +1758,18 @@ Examples:
1737
1758
 
1738
1759
  const { startServer } = await import('../web/index.js');
1739
1760
  await startServer(opts);
1761
+
1762
+ // First successful start ever → silence the discovery tip forever.
1763
+ // User has clearly found the feature; no need to keep nagging.
1764
+ try {
1765
+ const notify = await import('../telegram-notify.js');
1766
+ const state = notify.loadNotifyState();
1767
+ if (!state.dashboard_ever_opened) {
1768
+ notify.markDashboardEverOpened(state);
1769
+ notify.saveNotifyState(state);
1770
+ }
1771
+ } catch (_) { /* never break server start on notify-state write */ }
1772
+
1740
1773
  // The HTTP server now holds the event loop open. Park on an unsettled
1741
1774
  // promise so cmdWeb never returns to the dispatcher — that way server.js
1742
1775
  // doesn't reach process.exit(0) below or fall through to MCP-mode init.
@@ -47,6 +47,13 @@ const DEFAULT_STATE = () => ({
47
47
  version: 1,
48
48
  cli_tip_last_shown_at: null,
49
49
  notif_shown_for_ids: [],
50
+ // v0.10.10: dashboard discovery throttle. Three-strike pattern so the tip
51
+ // appears on a few different terminal sessions in the first days after
52
+ // install, then quiets down. Becomes permanently silent once the user
53
+ // actually opens the dashboard at least once.
54
+ dashboard_tip_shown_count: 0,
55
+ dashboard_tip_last_shown_at: null,
56
+ dashboard_ever_opened: false,
50
57
  notifications: {
51
58
  enabled: false, // privacy-first: opt-in for macOS notification
52
59
  show_titles: false, // even when on, don't leak chat names by default
@@ -105,6 +112,49 @@ export function markCliTipShown(state, now = new Date()) {
105
112
  return state;
106
113
  }
107
114
 
115
+ // ---------------------- Dashboard discovery tip (v0.10.10) ----------------------
116
+
117
+ /**
118
+ * Whether the "try memex web" tip should fire on the next CLI command.
119
+ *
120
+ * - Hard-stop once the user has actually run `memex web` (any duration)
121
+ * - Cap at maxShows (default 3) total reveals
122
+ * - Cooldown cooldownHours (default 12) between reveals so it doesn't
123
+ * stack with the TG-pending tip on the same minute
124
+ */
125
+ export function dashboardTipDue(state, opts = {}) {
126
+ const { maxShows = 3, cooldownHours = 12 } = opts;
127
+ if (state.dashboard_ever_opened) return false;
128
+ if ((state.dashboard_tip_shown_count || 0) >= maxShows) return false;
129
+ if (!state.dashboard_tip_last_shown_at) return true;
130
+ const last = Date.parse(state.dashboard_tip_last_shown_at);
131
+ if (isNaN(last)) return true;
132
+ return Date.now() - last >= cooldownHours * ONE_HOUR_MS;
133
+ }
134
+
135
+ export function markDashboardTipShown(state, now = new Date()) {
136
+ state.dashboard_tip_shown_count = (state.dashboard_tip_shown_count || 0) + 1;
137
+ state.dashboard_tip_last_shown_at = now.toISOString();
138
+ return state;
139
+ }
140
+
141
+ /**
142
+ * Permanently silence the dashboard tip — call this the first time the user
143
+ * actually runs `memex web`. They've discovered it; no need to keep nagging.
144
+ */
145
+ export function markDashboardEverOpened(state) {
146
+ state.dashboard_ever_opened = true;
147
+ return state;
148
+ }
149
+
150
+ /**
151
+ * The tip text itself. Plain string (no ANSI) — the caller decides whether
152
+ * to dim it. Returns null if there is genuinely nothing to say (defensive).
153
+ */
154
+ export function formatDashboardTip() {
155
+ return '💡 New: try `memex web --open` — browse your memory in a browser (read-only, localhost only).';
156
+ }
157
+
108
158
  // ---------------------- Notification dedup ----------------------
109
159
 
110
160
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "memex-mvp",
3
- "version": "0.10.9",
3
+ "version": "0.10.10",
4
4
  "description": "Local-first MCP server for cross-agent AI memory. One SQLite + FTS5 corpus across Claude Code, Cowork, Cursor, Continue, Zed, Obsidian, and Telegram — passively captured, verbatim, searchable from any MCP-compatible client.",
5
5
  "type": "module",
6
6
  "main": "server.js",
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: install-memex
3
3
  description: Make Claude, Cursor, Cline, Continue, and Zed remember every AI conversation forever — one local SQLite corpus shared across all of them. Installs memex (local-first MCP server) in ~60 seconds via curl one-liner. Includes auto-capture daemon for Claude Code / Cowork / Cursor / Obsidian; v0.10 Telegram auto-detect (export from Desktop → memex stages it → AI proactively asks which to import, privacy-first per-chat consent); v0.8 SessionStart hook for the Brian Chesky moment ("Claude already knows what you were doing"); URL / Perplexity / AI chat share capture via memex_store_document. 18 MCP tools, no cloud, no account, verbatim storage. Use when the user says "install memex", "set up memex", "add memory to my AI", "make my agent remember across sessions", "сохрани мои чаты", or similar.
4
- version: 1.4.0
4
+ version: 1.4.1
5
5
  metadata:
6
6
  openclaw:
7
7
  emoji: "📚"
@@ -290,15 +290,19 @@ If the user declines Telegram setup ("not now" / "skip"): say "OK, I'll skip Tel
290
290
 
291
291
  Tell the user to fully quit and reopen the MCP client (Cmd+Q on macOS) so it picks up the new memex tools.
292
292
 
293
- After restart, suggest they try any of:
293
+ **🌟 FIRST, STRONGLY RECOMMEND THIS (v0.10.8+):** offer to run `memex web --open` for them right now. It's the single most magical post-install moment — a local browser tab opens at `http://127.0.0.1:8765` with 5 pages showing every conversation memex has captured, dialogue rendered as chat-bubbles, full-text searchable. Verbatim — not AI-summarized. Read-only, localhost-only, Ctrl+C to stop. Phrase it naturally, e.g.:
294
+
295
+ > "I can open a local web dashboard that lets you actually *see* what memex captured — every message, in chat-bubble form, searchable. It's just a browser tab on `localhost:8765`. Run it now? It's a way better demo than asking me search queries blind."
296
+
297
+ Then run `memex web --open` (in a backgrounded shell if your shell wrapper supports it — otherwise tell the user to run it themselves in another terminal). Wait for them to react before continuing.
298
+
299
+ **After that, suggest other ways to confirm end-to-end:**
294
300
  - "show me what memex has in memory" → triggers `memex_overview`
295
301
  - "what projects has memex captured" → triggers `memex_list_projects`
296
302
  - "search memex for [recent topic]" → triggers `memex_search`
297
303
  - "save https://en.wikipedia.org/wiki/As_We_May_Think to memex" → triggers `memex_store_document` and teaches the user that URL-saving exists (v0.6+)
298
304
  - **Open Claude Code in any project the user worked on recently** — the SessionStart auto-context (v0.8+) should kick in and Claude will mention prior work _before_ the user types anything. This is the "Brian Chesky moment" — the magical-first-impression of memex.
299
-
300
305
  - **(if Telegram was set up)** `memex telegram check` — confirms daemon's Telegram-Downloads watcher is active and shows the user's full capture pipeline state.
301
- - **(v0.10.8+)** `memex web --open` — opens the local read-only web dashboard at `http://127.0.0.1:8765`. 5 pages: corpus stats, FTS5-searchable conversations list, verbatim chat-bubble transcripts, pending Telegram review with checkboxes, settings/daemon status. Useful for the user to *see* their memory with their own eyes — and a strong demo moment ("look at the actual messages verbatim, not an AI summary"). Localhost-only by default; Ctrl+C to stop.
302
306
 
303
307
  These confirm everything works end-to-end.
304
308