@mnemahq/cli 0.1.0 → 0.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/README.md CHANGED
@@ -15,8 +15,15 @@ The package is `@mnemahq/cli`; the command it installs is **`mnema`**. (The unsc
15
15
  name `mnema` is blocked on npm — its typosquat filter rejects it as too close to the
16
16
  existing package `mem`.)
17
17
 
18
- You'll be asked for your **workspace id** and a **hook token** (both in *Settings Developer*), and
19
- optionally an **API key** for search. `init` installs the capture hook, stores your secrets in the OS
18
+ Run `mnema login` first and the workspace is filled in automatically. Otherwise you'll be asked
19
+ for two values, which live on **two different settings pages**:
20
+
21
+ | value | where |
22
+ | --- | --- |
23
+ | Workspace id | **Settings → Workspace** |
24
+ | Hook token | **Settings → Access** → *Session capture* → **Generate token** |
25
+
26
+ Optionally an **API key** for search. `init` installs the capture hook, stores your secrets in the OS
20
27
  keychain, and writes a `.mnema/config.json` (safe to commit — it holds no secrets).
21
28
 
22
29
  Start a Claude Code session and it appears under **Sessions** with its cost.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mnemahq/cli",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Mnema CLI — connect a repo to your Mnema workspace: install session capture, sweep past sessions, and search from the terminal.",
5
5
  "type": "module",
6
6
  "bin": {
package/src/cli.mjs CHANGED
@@ -11,9 +11,9 @@
11
11
  */
12
12
 
13
13
  import { existsSync } from 'node:fs';
14
- import { cmdLogin, cmdLogout } from './login.mjs';
14
+ import { cmdLogin, cmdLogout, accessToken } from './login.mjs';
15
15
  import {
16
- DEFAULT_ORIGIN, c, gitInfo, canonicalRepo, readConfig, writeConfig, removeConfigDir,
16
+ DEFAULT_ORIGIN, DEFAULT_APP_URL, c, gitInfo, canonicalRepo, readConfig, writeConfig, removeConfigDir,
17
17
  apiFetch, prompt, promptHidden, localSessionsForRepo,
18
18
  } from './util.mjs';
19
19
  import { getSecret, setSecret, deleteSecrets, backendName, usingFallback } from './secrets.mjs';
@@ -57,6 +57,33 @@ function fmtAge(mtimeMs) {
57
57
 
58
58
  // ── init ───────────────────────────────────────────────────────────────────────
59
59
 
60
+ /**
61
+ * The workspace this login already belongs to.
62
+ *
63
+ * ⭐ THE CLI WAS ASKING FOR SOMETHING IT COULD LOOK UP. `init` prompted "Workspace
64
+ * id:" with no hint, and the id lives on a different settings page from the hook
65
+ * token — so the first thing a new user did was go hunting for a UUID the tool
66
+ * could have read from their own session. If they have run `mnema login`, /api/me
67
+ * answers it.
68
+ *
69
+ * Returns null on any failure. This is a convenience, never a requirement: not
70
+ * logged in, offline, or an unexpected body all fall through to the prompt.
71
+ */
72
+ async function workspaceFromSession(origin) {
73
+ try {
74
+ const token = await accessToken();
75
+ if (!token) return null;
76
+ const res = await fetch(`${origin}/api/me`, { headers: { Authorization: `Bearer ${token}` } });
77
+ if (!res.ok) return null;
78
+ const body = await res.json();
79
+ if (!body?.workspace_id) return null;
80
+ console.log(c.green(`\u2713 Workspace: ${body.workspace_name || body.workspace_id} (from your login)`));
81
+ return body.workspace_id;
82
+ } catch {
83
+ return null;
84
+ }
85
+ }
86
+
60
87
  async function cmdInit(flags) {
61
88
  const git = gitInfo();
62
89
  const root = git.root || process.cwd();
@@ -66,11 +93,24 @@ async function cmdInit(flags) {
66
93
  const existing = readConfig(root);
67
94
 
68
95
  let workspaceId = flags.workspace || process.env.MNEMA_WORKSPACE_ID || existing?.workspaceId;
69
- if (!workspaceId) workspaceId = await prompt('Workspace id: ');
96
+ if (!workspaceId) workspaceId = await workspaceFromSession(origin);
97
+ if (!workspaceId) {
98
+ console.log(` Workspace id — ${c.dim('Settings \u2192 Workspace')} ${c.dim(`${DEFAULT_APP_URL}/app/settings/workspace`)}`);
99
+ console.log(` ${c.dim('(or run `mnema login` first and this is filled in for you)')}`);
100
+ workspaceId = await prompt('Workspace id: ');
101
+ }
70
102
  if (!workspaceId) { console.error(c.red('A workspace id is required.')); process.exit(1); }
71
103
 
72
104
  let hookToken = process.env.MNEMA_HOOK_TOKEN || getSecret(workspaceId, 'hook-token');
73
- if (!hookToken) hookToken = await promptHidden('Hook token (Settings → Developer): ');
105
+ if (!hookToken) {
106
+ // ⚠️ NOT "Settings → Developer". That page does not exist and never did in
107
+ // this shape — the hook token moved to the Access page when tokens were
108
+ // consolidated there, and the id lives on Workspace. The old prompt sent
109
+ // every new user looking for a page that was not in the app.
110
+ console.log(` Hook token — ${c.dim('Settings \u2192 Access \u2192 "Session capture" \u2192 Generate token')}`);
111
+ console.log(` ${c.dim(`${DEFAULT_APP_URL}/app/settings/access`)}`);
112
+ hookToken = await promptHidden('Hook token: ');
113
+ }
74
114
  if (!hookToken) { console.error(c.red('A hook token is required.')); process.exit(1); }
75
115
 
76
116
  let apiKey = process.env.MNEMA_API_KEY || getSecret(workspaceId, 'api-key') || '';
package/src/util.mjs CHANGED
@@ -18,6 +18,16 @@ import { createInterface } from 'node:readline';
18
18
  // capture hook uses.
19
19
  export const DEFAULT_ORIGIN = process.env.MNEMA_API_ORIGIN || 'https://api.theboringpeople.in';
20
20
 
21
+ /**
22
+ * ⭐ THE APP, NOT THE API — a SEPARATE host, and the reason this constant exists.
23
+ * Everything the CLI asks a human to fetch lives in the web app at
24
+ * mnema.theboringpeople.in, while every request it makes goes to
25
+ * api.theboringpeople.in. Deriving one from the other is not possible, and
26
+ * printing the API origin in a "go here and copy this" message sends people to a
27
+ * host with no UI on it.
28
+ */
29
+ export const DEFAULT_APP_URL = process.env.MNEMA_APP_URL || 'https://mnema.theboringpeople.in';
30
+
21
31
  export const c = {
22
32
  dim: (s) => `\x1b[2m${s}\x1b[0m`,
23
33
  green: (s) => `\x1b[32m${s}\x1b[0m`,