nlm-memory 0.4.1 → 0.5.0

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.
Files changed (90) hide show
  1. package/dist/cli/nlm.js +221 -32
  2. package/dist/cli/nlm.js.map +1 -1
  3. package/dist/core/adapters/cursor.d.ts +45 -0
  4. package/dist/core/adapters/cursor.js +397 -0
  5. package/dist/core/adapters/cursor.js.map +1 -0
  6. package/dist/core/adapters/from-source.js +10 -0
  7. package/dist/core/adapters/from-source.js.map +1 -1
  8. package/dist/core/adapters/windsurf.d.ts +44 -0
  9. package/dist/core/adapters/windsurf.js +299 -0
  10. package/dist/core/adapters/windsurf.js.map +1 -0
  11. package/dist/core/hook/claude-settings.d.ts +12 -5
  12. package/dist/core/hook/claude-settings.js +21 -6
  13. package/dist/core/hook/claude-settings.js.map +1 -1
  14. package/dist/core/sources/source-registry.d.ts +1 -1
  15. package/dist/core/sources/source-registry.js +18 -0
  16. package/dist/core/sources/source-registry.js.map +1 -1
  17. package/dist/core/storage/sqlite-session-store.d.ts +2 -0
  18. package/dist/core/storage/sqlite-session-store.js +38 -2
  19. package/dist/core/storage/sqlite-session-store.js.map +1 -1
  20. package/dist/hook/hook-auth.d.ts +13 -0
  21. package/dist/hook/hook-auth.js +19 -0
  22. package/dist/hook/hook-auth.js.map +1 -0
  23. package/dist/hook/prompt-recall-hook.js +7 -1
  24. package/dist/hook/prompt-recall-hook.js.map +1 -1
  25. package/dist/hook/session-start-hook.js +4 -1
  26. package/dist/hook/session-start-hook.js.map +1 -1
  27. package/dist/hook/stop-hook.js +4 -1
  28. package/dist/hook/stop-hook.js.map +1 -1
  29. package/dist/http/app.d.ts +2 -0
  30. package/dist/http/app.js +74 -0
  31. package/dist/http/app.js.map +1 -1
  32. package/dist/install/claude-code.js +1 -1
  33. package/dist/install/claude-code.js.map +1 -1
  34. package/dist/install/cursor.d.ts +25 -0
  35. package/dist/install/cursor.js +43 -0
  36. package/dist/install/cursor.js.map +1 -0
  37. package/dist/install/nlm-dir-perms.d.ts +19 -0
  38. package/dist/install/nlm-dir-perms.js +43 -0
  39. package/dist/install/nlm-dir-perms.js.map +1 -0
  40. package/dist/install/ollama.d.ts +18 -1
  41. package/dist/install/ollama.js +68 -10
  42. package/dist/install/ollama.js.map +1 -1
  43. package/dist/install/setup.d.ts +4 -0
  44. package/dist/install/setup.js +141 -18
  45. package/dist/install/setup.js.map +1 -1
  46. package/dist/install/windsurf.d.ts +25 -0
  47. package/dist/install/windsurf.js +43 -0
  48. package/dist/install/windsurf.js.map +1 -0
  49. package/dist/shared/types.d.ts +4 -0
  50. package/dist/ui/assets/{index-BA6IpU8g.css → index-C8cpwbYJ.css} +1 -1
  51. package/dist/ui/assets/index-CB50QnL-.js +69 -0
  52. package/dist/ui/index.html +2 -2
  53. package/logs/CHANGELOG/CHANGELOG-2026.md +186 -0
  54. package/logs/CHANGELOG/CHANGELOG.md +107 -235
  55. package/migrations/014_sources_cursor.sql +30 -0
  56. package/migrations/015_sources_windsurf.sql +30 -0
  57. package/package.json +1 -1
  58. package/plugin/scripts/prompt-recall-hook.mjs +55 -4
  59. package/plugin/scripts/stop-hook.mjs +57 -6
  60. package/src/cli/nlm.ts +224 -31
  61. package/src/core/adapters/cursor.ts +486 -0
  62. package/src/core/adapters/from-source.ts +10 -0
  63. package/src/core/adapters/windsurf.ts +386 -0
  64. package/src/core/hook/claude-settings.ts +30 -9
  65. package/src/core/sources/source-registry.ts +19 -1
  66. package/src/core/storage/sqlite-session-store.ts +46 -1
  67. package/src/hook/hook-auth.ts +18 -0
  68. package/src/hook/prompt-recall-hook.ts +7 -1
  69. package/src/hook/session-start-hook.ts +4 -1
  70. package/src/hook/stop-hook.ts +4 -1
  71. package/src/http/app.ts +78 -0
  72. package/src/install/claude-code.ts +1 -1
  73. package/src/install/cursor.ts +68 -0
  74. package/src/install/nlm-dir-perms.ts +55 -0
  75. package/src/install/ollama.ts +86 -10
  76. package/src/install/setup.ts +138 -17
  77. package/src/install/windsurf.ts +68 -0
  78. package/src/shared/types.ts +4 -0
  79. package/src/ui/components/SessionDrawer.tsx +97 -34
  80. package/src/ui/pages/River.tsx +90 -44
  81. package/src/ui/pages/Search.tsx +357 -64
  82. package/src/ui/pages/Thread.tsx +267 -56
  83. package/src/ui/styles.css +129 -5
  84. package/tests/integration/getbyids-sqlite.test.ts +40 -0
  85. package/tests/integration/hook-claude-settings.test.ts +14 -1
  86. package/tests/integration/mcp.test.ts +12 -0
  87. package/tests/integration/source-registry.test.ts +5 -3
  88. package/tests/unit/core/adapters/cursor.test.ts +485 -0
  89. package/tests/unit/core/adapters/windsurf.test.ts +416 -0
  90. package/dist/ui/assets/index-B_qIVV0k.js +0 -69
@@ -43,7 +43,7 @@ export function installClaudeCodeHooks(opts) {
43
43
  const installed = [];
44
44
  for (const spec of opts.hooks) {
45
45
  try {
46
- const command = opts.buildHookCommand(opts.nodeExecPath, spec.script, "shadow");
46
+ const command = opts.buildHookCommand(opts.nodeExecPath, spec.script, "live");
47
47
  opts.addHook(opts.settingsPath, command, spec.event);
48
48
  const smoke = opts.smokeTestHookCommand(command, opts.hookLogPath);
49
49
  if (!smoke.ok) {
@@ -1 +1 @@
1
- {"version":3,"file":"claude-code.js","sourceRoot":"","sources":["../../src/install/claude-code.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"claude-code.js","sourceRoot":"","sources":["../../src/install/claude-code.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * `nlm connect cursor` / `nlm disconnect cursor` — registers or removes the
3
+ * Cursor adapter source in the NLM source registry.
4
+ *
5
+ * Unlike plugin-based runtimes (hermes-agent, codex), Cursor needs no file
6
+ * to be installed. NLM reads Cursor's existing state.vscdb directly. The
7
+ * connect operation only registers the source row so the daemon scans it.
8
+ */
9
+ import type { SourceRegistry } from "../core/sources/source-registry.js";
10
+ export interface ConnectCursorOptions {
11
+ readonly dbPath?: string;
12
+ readonly dryRun?: boolean;
13
+ }
14
+ export interface ConnectCursorReport {
15
+ readonly adapterDbPath: string;
16
+ readonly adapterExists: boolean;
17
+ readonly action: "created" | "enabled" | "already-active" | "dry-run";
18
+ }
19
+ export interface DisconnectCursorReport {
20
+ readonly action: "disabled" | "not-found" | "dry-run";
21
+ }
22
+ export declare function connectCursor(registry: SourceRegistry, opts?: ConnectCursorOptions): ConnectCursorReport;
23
+ export declare function disconnectCursor(registry: SourceRegistry, opts?: {
24
+ dryRun?: boolean;
25
+ }): DisconnectCursorReport;
@@ -0,0 +1,43 @@
1
+ /**
2
+ * `nlm connect cursor` / `nlm disconnect cursor` — registers or removes the
3
+ * Cursor adapter source in the NLM source registry.
4
+ *
5
+ * Unlike plugin-based runtimes (hermes-agent, codex), Cursor needs no file
6
+ * to be installed. NLM reads Cursor's existing state.vscdb directly. The
7
+ * connect operation only registers the source row so the daemon scans it.
8
+ */
9
+ import { existsSync } from "node:fs";
10
+ import { defaultDbPath } from "../core/adapters/cursor.js";
11
+ export function connectCursor(registry, opts = {}) {
12
+ const adapterDbPath = opts.dbPath ?? defaultDbPath();
13
+ const adapterExists = existsSync(adapterDbPath);
14
+ if (opts.dryRun) {
15
+ return { adapterDbPath, adapterExists, action: "dry-run" };
16
+ }
17
+ const existing = registry.getByName("Cursor");
18
+ if (existing) {
19
+ if (existing.enabled && existing.pathOrUrl === adapterDbPath) {
20
+ return { adapterDbPath, adapterExists, action: "already-active" };
21
+ }
22
+ registry.update(existing.id, { enabled: true, pathOrUrl: adapterDbPath });
23
+ return { adapterDbPath, adapterExists, action: "enabled" };
24
+ }
25
+ registry.insert({
26
+ kind: "cursor",
27
+ name: "Cursor",
28
+ pathOrUrl: adapterDbPath,
29
+ runtimeLabel: "cursor/1.0",
30
+ enabled: adapterExists,
31
+ });
32
+ return { adapterDbPath, adapterExists, action: "created" };
33
+ }
34
+ export function disconnectCursor(registry, opts = {}) {
35
+ if (opts.dryRun)
36
+ return { action: "dry-run" };
37
+ const existing = registry.getByName("Cursor");
38
+ if (!existing)
39
+ return { action: "not-found" };
40
+ registry.update(existing.id, { enabled: false });
41
+ return { action: "disabled" };
42
+ }
43
+ //# sourceMappingURL=cursor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cursor.js","sourceRoot":"","sources":["../../src/install/cursor.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAkB3D,MAAM,UAAU,aAAa,CAC3B,QAAwB,EACxB,OAA6B,EAAE;IAE/B,MAAM,aAAa,GAAG,IAAI,CAAC,MAAM,IAAI,aAAa,EAAE,CAAC;IACrD,MAAM,aAAa,GAAG,UAAU,CAAC,aAAa,CAAC,CAAC;IAEhD,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;QAChB,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;IAC7D,CAAC;IAED,MAAM,QAAQ,GAAG,QAAQ,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;IAC9C,IAAI,QAAQ,EAAE,CAAC;QACb,IAAI,QAAQ,CAAC,OAAO,IAAI,QAAQ,CAAC,SAAS,KAAK,aAAa,EAAE,CAAC;YAC7D,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,EAAE,gBAAgB,EAAE,CAAC;QACpE,CAAC;QACD,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,aAAa,EAAE,CAAC,CAAC;QAC1E,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;IAC7D,CAAC;IAED,QAAQ,CAAC,MAAM,CAAC;QACd,IAAI,EAAE,QAAQ;QACd,IAAI,EAAE,QAAQ;QACd,SAAS,EAAE,aAAa;QACxB,YAAY,EAAE,YAAY;QAC1B,OAAO,EAAE,aAAa;KACvB,CAAC,CAAC;IACH,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;AAC7D,CAAC;AAED,MAAM,UAAU,gBAAgB,CAC9B,QAAwB,EACxB,OAA6B,EAAE;IAE/B,IAAI,IAAI,CAAC,MAAM;QAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;IAC9C,MAAM,QAAQ,GAAG,QAAQ,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;IAC9C,IAAI,CAAC,QAAQ;QAAE,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC;IAC9C,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;IACjD,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC;AAChC,CAAC"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Idempotent permission hardening for ~/.nlm/.
3
+ *
4
+ * Recursively sets owner-only perms on the daemon's working directory:
5
+ * directories → 0o700
6
+ * files → 0o600
7
+ *
8
+ * Run at every `nlm setup`, `nlm install`, and `nlm start` so installs
9
+ * predating v0.4.2 (when explicit chmod was added) self-heal on next
10
+ * launch. No-op on Windows — ACLs are the POSIX equivalent and out of
11
+ * scope here.
12
+ */
13
+ export interface PermsHardenResult {
14
+ readonly nlmDir: string;
15
+ readonly filesHardened: number;
16
+ readonly dirsHardened: number;
17
+ readonly skipped: number;
18
+ }
19
+ export declare function hardenNlmDirPermissions(nlmDir?: string): PermsHardenResult;
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Idempotent permission hardening for ~/.nlm/.
3
+ *
4
+ * Recursively sets owner-only perms on the daemon's working directory:
5
+ * directories → 0o700
6
+ * files → 0o600
7
+ *
8
+ * Run at every `nlm setup`, `nlm install`, and `nlm start` so installs
9
+ * predating v0.4.2 (when explicit chmod was added) self-heal on next
10
+ * launch. No-op on Windows — ACLs are the POSIX equivalent and out of
11
+ * scope here.
12
+ */
13
+ import { chmodSync, existsSync, readdirSync, statSync } from "node:fs";
14
+ import { homedir } from "node:os";
15
+ import { join } from "node:path";
16
+ export function hardenNlmDirPermissions(nlmDir = join(homedir(), ".nlm")) {
17
+ const result = { nlmDir, filesHardened: 0, dirsHardened: 0, skipped: 0 };
18
+ if (process.platform === "win32")
19
+ return result;
20
+ if (!existsSync(nlmDir))
21
+ return result;
22
+ walk(nlmDir, result);
23
+ return result;
24
+ }
25
+ function walk(path, r) {
26
+ try {
27
+ const s = statSync(path);
28
+ if (s.isDirectory()) {
29
+ chmodSync(path, 0o700);
30
+ r.dirsHardened += 1;
31
+ for (const name of readdirSync(path))
32
+ walk(join(path, name), r);
33
+ }
34
+ else if (s.isFile()) {
35
+ chmodSync(path, 0o600);
36
+ r.filesHardened += 1;
37
+ }
38
+ }
39
+ catch {
40
+ r.skipped += 1;
41
+ }
42
+ }
43
+ //# sourceMappingURL=nlm-dir-perms.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nlm-dir-perms.js","sourceRoot":"","sources":["../../src/install/nlm-dir-perms.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACvE,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AASjC,MAAM,UAAU,uBAAuB,CACrC,SAAiB,IAAI,CAAC,OAAO,EAAE,EAAE,MAAM,CAAC;IAExC,MAAM,MAAM,GAAG,EAAE,MAAM,EAAE,aAAa,EAAE,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;IACzE,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO;QAAE,OAAO,MAAM,CAAC;IAChD,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC;QAAE,OAAO,MAAM,CAAC;IACvC,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrB,OAAO,MAAM,CAAC;AAChB,CAAC;AAQD,SAAS,IAAI,CAAC,IAAY,EAAE,CAAgB;IAC1C,IAAI,CAAC;QACH,MAAM,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;QACzB,IAAI,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC;YACpB,SAAS,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;YACvB,CAAC,CAAC,YAAY,IAAI,CAAC,CAAC;YACpB,KAAK,MAAM,IAAI,IAAI,WAAW,CAAC,IAAI,CAAC;gBAAE,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;QAClE,CAAC;aAAM,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC;YACtB,SAAS,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;YACvB,CAAC,CAAC,aAAa,IAAI,CAAC,CAAC;QACvB,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC;IACjB,CAAC;AACH,CAAC"}
@@ -47,8 +47,25 @@ export declare function waitForOllamaServer(maxAttempts?: number, intervalMs?: n
47
47
  */
48
48
  export declare function pullEmbeddingModel(): OllamaResult;
49
49
  export type ClassifierChoice = "deepseek" | "ollama-offline";
50
+ export interface ClassifierConfigInput {
51
+ readonly choice: ClassifierChoice;
52
+ readonly model?: string;
53
+ readonly apiKey?: string;
54
+ }
50
55
  /**
51
56
  * Write classifier config to ~/.nlm/.env. Merges into the existing file —
52
57
  * only the lines we manage are updated; anything the user added by hand stays.
58
+ *
59
+ * Manages three keys: DEEPSEEK_API_KEY, NLM_CLASSIFIER, NLM_CLASSIFIER_MODEL.
60
+ * Backwards-compatible: passing positional (choice, apiKey) still works.
61
+ */
62
+ export declare function writeClassifierConfig(choiceOrInput: ClassifierChoice | ClassifierConfigInput, apiKey?: string): void;
63
+ /**
64
+ * Generate and persist an NLM_MCP_TOKEN if one isn't already set. Returns
65
+ * the token that's active for this process. Called during setup and on
66
+ * `nlm start` so installs that pre-date token-gated /api/* still get
67
+ * Bearer-protected without operator intervention.
68
+ *
69
+ * Token is hex-encoded crypto.randomBytes — 64 chars, 256 bits of entropy.
53
70
  */
54
- export declare function writeClassifierConfig(choice: ClassifierChoice, apiKey?: string): void;
71
+ export declare function ensureMcpToken(): string;
@@ -11,10 +11,11 @@
11
11
  * Linux — official install.sh / systemctl / detached spawn
12
12
  * Windows — winget install / detached spawn
13
13
  */
14
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
14
+ import { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
15
15
  import { homedir, platform } from "node:os";
16
16
  import { join } from "node:path";
17
17
  import { spawnSync, spawn } from "node:child_process";
18
+ import { randomBytes } from "node:crypto";
18
19
  export const EMBEDDING_MODEL = "nomic-embed-text";
19
20
  const OS = platform();
20
21
  // ── Detection ─────────────────────────────────────────────────────────────
@@ -154,25 +155,82 @@ export function pullEmbeddingModel() {
154
155
  /**
155
156
  * Write classifier config to ~/.nlm/.env. Merges into the existing file —
156
157
  * only the lines we manage are updated; anything the user added by hand stays.
158
+ *
159
+ * Manages three keys: DEEPSEEK_API_KEY, NLM_CLASSIFIER, NLM_CLASSIFIER_MODEL.
160
+ * Backwards-compatible: passing positional (choice, apiKey) still works.
157
161
  */
158
- export function writeClassifierConfig(choice, apiKey) {
162
+ export function writeClassifierConfig(choiceOrInput, apiKey) {
163
+ const input = typeof choiceOrInput === "string"
164
+ ? { choice: choiceOrInput, ...(apiKey !== undefined ? { apiKey } : {}) }
165
+ : choiceOrInput;
159
166
  const envPath = join(homedir(), ".nlm", ".env");
160
- mkdirSync(join(homedir(), ".nlm"), { recursive: true });
167
+ const nlmDir = join(homedir(), ".nlm");
168
+ mkdirSync(nlmDir, { recursive: true, mode: 0o700 });
169
+ chmodSync(nlmDir, 0o700);
161
170
  const existing = existsSync(envPath) ? readFileSync(envPath, "utf8") : "";
162
171
  const kept = existing
163
172
  .split("\n")
164
- .filter((l) => !l.startsWith("DEEPSEEK_API_KEY=") && !l.startsWith("NLM_CLASSIFIER="))
173
+ .filter((l) => !l.startsWith("DEEPSEEK_API_KEY=") &&
174
+ !l.startsWith("NLM_CLASSIFIER=") &&
175
+ !l.startsWith("NLM_CLASSIFIER_MODEL="))
165
176
  .join("\n")
166
177
  .replace(/\n{3,}/g, "\n\n")
167
178
  .trim();
168
179
  const additions = [];
169
- if (choice === "deepseek" && apiKey) {
170
- // Strip newlines that clipboard paste can introduce.
171
- const sanitized = apiKey.replace(/[\r\n]/g, "").trim();
172
- additions.push(`DEEPSEEK_API_KEY=${sanitized}`);
180
+ if (input.choice === "deepseek") {
181
+ additions.push("NLM_CLASSIFIER=deepseek");
182
+ if (input.apiKey) {
183
+ // Strip newlines that clipboard paste can introduce.
184
+ const sanitized = input.apiKey.replace(/[\r\n]/g, "").trim();
185
+ additions.push(`DEEPSEEK_API_KEY=${sanitized}`);
186
+ }
173
187
  }
174
- if (choice === "ollama-offline")
188
+ if (input.choice === "ollama-offline")
175
189
  additions.push("NLM_CLASSIFIER=ollama");
176
- writeFileSync(envPath, [kept, ...additions].filter(Boolean).join("\n") + "\n", "utf8");
190
+ if (input.model)
191
+ additions.push(`NLM_CLASSIFIER_MODEL=${input.model}`);
192
+ writeFileSync(envPath, [kept, ...additions].filter(Boolean).join("\n") + "\n", { mode: 0o600 });
193
+ chmodSync(envPath, 0o600);
194
+ }
195
+ const TOKEN_BYTES = 32;
196
+ /**
197
+ * Generate and persist an NLM_MCP_TOKEN if one isn't already set. Returns
198
+ * the token that's active for this process. Called during setup and on
199
+ * `nlm start` so installs that pre-date token-gated /api/* still get
200
+ * Bearer-protected without operator intervention.
201
+ *
202
+ * Token is hex-encoded crypto.randomBytes — 64 chars, 256 bits of entropy.
203
+ */
204
+ export function ensureMcpToken() {
205
+ const existing = process.env["NLM_MCP_TOKEN"];
206
+ if (existing)
207
+ return existing;
208
+ const token = randomBytes(TOKEN_BYTES).toString("hex");
209
+ const envPath = join(homedir(), ".nlm", ".env");
210
+ const nlmDir = join(homedir(), ".nlm");
211
+ mkdirSync(nlmDir, { recursive: true, mode: 0o700 });
212
+ chmodSync(nlmDir, 0o700);
213
+ const fileExisting = existsSync(envPath) ? readFileSync(envPath, "utf8") : "";
214
+ // Idempotent re-read: another setup run could have written the token
215
+ // between our env check and now. Prefer the persisted value.
216
+ for (const line of fileExisting.split("\n")) {
217
+ if (line.startsWith("NLM_MCP_TOKEN=")) {
218
+ const persisted = line.slice("NLM_MCP_TOKEN=".length).trim();
219
+ if (persisted) {
220
+ process.env["NLM_MCP_TOKEN"] = persisted;
221
+ return persisted;
222
+ }
223
+ }
224
+ }
225
+ const kept = fileExisting
226
+ .split("\n")
227
+ .filter((l) => !l.startsWith("NLM_MCP_TOKEN="))
228
+ .join("\n")
229
+ .replace(/\n{3,}/g, "\n\n")
230
+ .trim();
231
+ writeFileSync(envPath, [kept, `NLM_MCP_TOKEN=${token}`].filter(Boolean).join("\n") + "\n", { mode: 0o600 });
232
+ chmodSync(envPath, 0o600);
233
+ process.env["NLM_MCP_TOKEN"] = token;
234
+ return token;
177
235
  }
178
236
  //# sourceMappingURL=ollama.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ollama.js","sourceRoot":"","sources":["../../src/install/ollama.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ollama.js","sourceRoot":"","sources":["../../src/install/ollama.ts"],"names":[],"mappings":"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"}
@@ -19,6 +19,10 @@ export interface SetupOptions {
19
19
  readonly launchAgentLabel: string;
20
20
  readonly launchAgentPlist: string;
21
21
  readonly buildPlist: (nodeExec: string, binPath: string) => string;
22
+ readonly linuxSystemdUnitName: string;
23
+ readonly linuxSystemdUnitPath: string;
24
+ readonly buildSystemdUnit: (nodeExec: string, binPath: string) => string;
25
+ readonly linuxSystemdUserAvailable: () => boolean;
22
26
  readonly claudeSettingsPath: string;
23
27
  readonly allHooks: ReadonlyArray<{
24
28
  event: ClaudeHookEvent;
@@ -12,15 +12,41 @@
12
12
  import { existsSync, mkdirSync, writeFileSync } from "node:fs";
13
13
  import { execFileSync } from "node:child_process";
14
14
  import { homedir, platform } from "node:os";
15
- import { join } from "node:path";
15
+ import { dirname, join } from "node:path";
16
16
  import { cancel, confirm, intro, isCancel, log, multiselect, outro, password, select, spinner, } from "@clack/prompts";
17
17
  import { connectClaudeCode } from "./claude-code.js";
18
18
  import { connectHermes } from "./hermes.js";
19
19
  import { codexBinaryAvailable, connectCodex, pluginScriptsDir } from "./codex.js";
20
20
  import { defaultDbPath as openCodeDefaultDbPath } from "../core/adapters/opencode.js";
21
- import { EMBEDDING_MODEL, embeddingModelPresent, installOllama, ollamaBinaryAvailable, ollamaServerRunning, pullEmbeddingModel, startOllamaServer, waitForOllamaServer, writeClassifierConfig, } from "./ollama.js";
21
+ import { EMBEDDING_MODEL, embeddingModelPresent, ensureMcpToken, installOllama, ollamaBinaryAvailable, ollamaServerRunning, pullEmbeddingModel, startOllamaServer, waitForOllamaServer, writeClassifierConfig, } from "./ollama.js";
22
22
  import { installClaudeCodeHooks } from "./claude-code.js";
23
+ import { hardenNlmDirPermissions } from "./nlm-dir-perms.js";
23
24
  const OS = platform();
25
+ // Embedding-only tags shouldn't be offered as classifier models — they
26
+ // can't run chat completions and the call would fail at first ingest.
27
+ const EMBEDDING_MODEL_PREFIXES = ["nomic-embed", "mxbai-embed", "snowflake-arctic-embed", "bge-"];
28
+ async function fetchOllamaChatModels(timeoutMs = 5000) {
29
+ const baseUrl = process.env["NLM_OLLAMA_URL"] ?? "http://localhost:11434";
30
+ const controller = new AbortController();
31
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
32
+ try {
33
+ const res = await fetch(`${baseUrl}/api/tags`, { signal: controller.signal });
34
+ if (!res.ok)
35
+ return [];
36
+ const data = (await res.json());
37
+ return (data.models ?? [])
38
+ .map((m) => m.name)
39
+ .filter((n) => typeof n === "string")
40
+ .filter((n) => !EMBEDDING_MODEL_PREFIXES.some((p) => n.startsWith(p)))
41
+ .sort();
42
+ }
43
+ catch {
44
+ return [];
45
+ }
46
+ finally {
47
+ clearTimeout(timer);
48
+ }
49
+ }
24
50
  function detectRuntimes() {
25
51
  const claudeProjectsPath = process.env["NLM_CLAUDE_PROJECTS_PATH"]
26
52
  ?? join(homedir(), ".claude", "projects");
@@ -151,18 +177,28 @@ export async function runSetup(opts) {
151
177
  if (ollamaBinaryAvailable() && embeddingModelPresent()) {
152
178
  log.success(`Ollama ready — ${EMBEDDING_MODEL} present`);
153
179
  }
154
- // ── Step 3: classifier API key ────────────────────────────────────────
155
- const wantKey = await confirm({ message: "Add a classifier API key? (enables accurate session tagging; DeepSeek is ~$0.002/session)" });
156
- if (isCancel(wantKey)) {
180
+ // ── Step 3: classifier (provider + model + key) ───────────────────────
181
+ const wantConfigure = await confirm({
182
+ message: "Configure the session classifier? (controls how new sessions are tagged)",
183
+ });
184
+ if (isCancel(wantConfigure)) {
157
185
  cancel("Setup cancelled.");
158
186
  process.exit(0);
159
187
  }
160
- if (wantKey) {
188
+ if (wantConfigure) {
161
189
  const classifierChoice = await select({
162
- message: "Which classifier?",
190
+ message: "Which classifier provider?",
163
191
  options: [
164
- { value: "deepseek", label: "DeepSeek", hint: "recommended — fast, cheap, needs DEEPSEEK_API_KEY" },
165
- { value: "ollama-offline", label: "Ollama (offline)", hint: "free, no API key, slower and less accurate" },
192
+ {
193
+ value: "deepseek",
194
+ label: "DeepSeek (cloud)",
195
+ hint: "fast, cheap (~$0.002/session). Transcripts are sent to api.deepseek.com.",
196
+ },
197
+ {
198
+ value: "ollama-offline",
199
+ label: "Ollama (local)",
200
+ hint: "private — runs on this machine via your local Ollama. Slower; needs a chat model pulled.",
201
+ },
166
202
  ],
167
203
  });
168
204
  if (isCancel(classifierChoice)) {
@@ -170,24 +206,71 @@ export async function runSetup(opts) {
170
206
  process.exit(0);
171
207
  }
172
208
  if (classifierChoice === "deepseek") {
209
+ log.info("Heads up: DeepSeek classification sends up to 30K chars of each session transcript to api.deepseek.com.");
210
+ log.info(" Anything in a transcript (pasted keys, client names, internal URLs) leaves this machine.");
211
+ log.info(" Pick Ollama (local) above if that's not acceptable.");
212
+ const model = await select({
213
+ message: "Which DeepSeek model?",
214
+ options: [
215
+ { value: "deepseek-v4-flash", label: "deepseek-v4-flash", hint: "recommended — fast + cheap, ~$0.002/session" },
216
+ { value: "deepseek-v4-pro", label: "deepseek-v4-pro", hint: "higher quality, ~10× cost" },
217
+ { value: "deepseek-chat", label: "deepseek-chat", hint: "legacy chat model" },
218
+ ],
219
+ });
220
+ if (isCancel(model)) {
221
+ cancel("Setup cancelled.");
222
+ process.exit(0);
223
+ }
173
224
  const key = await password({ message: "DeepSeek API key (get one at platform.deepseek.com):" });
174
225
  if (isCancel(key)) {
175
226
  cancel("Setup cancelled.");
176
227
  process.exit(0);
177
228
  }
178
- if (key && key.trim()) {
179
- writeClassifierConfig("deepseek", key.trim());
180
- log.success("DeepSeek API key saved to ~/.nlm/.env");
229
+ const apiKey = key && key.trim() ? key.trim() : undefined;
230
+ writeClassifierConfig(apiKey !== undefined
231
+ ? { choice: "deepseek", model: model, apiKey }
232
+ : { choice: "deepseek", model: model });
233
+ if (apiKey) {
234
+ log.success(`DeepSeek (${model}) configured — credentials saved to ~/.nlm/.env`);
181
235
  }
182
236
  else {
183
- log.warn("No key entered — set DEEPSEEK_API_KEY in ~/.nlm/.env later.");
237
+ log.warn(`DeepSeek (${model}) configured — set DEEPSEEK_API_KEY in ~/.nlm/.env before running.`);
184
238
  }
185
239
  }
186
240
  else {
187
- writeClassifierConfig("ollama-offline");
188
- log.success("Classifier set to Ollama offline (saved to ~/.nlm/.env)");
241
+ const ollamaModels = await fetchOllamaChatModels();
242
+ let modelValue = "phi4-mini:latest";
243
+ if (ollamaModels.length > 0) {
244
+ const model = await select({
245
+ message: "Which Ollama chat model?",
246
+ options: ollamaModels.map((m) => ({
247
+ value: m,
248
+ label: m,
249
+ hint: m === "phi4-mini:latest" ? "recommended default — small, fast" : undefined,
250
+ })),
251
+ });
252
+ if (isCancel(model)) {
253
+ cancel("Setup cancelled.");
254
+ process.exit(0);
255
+ }
256
+ modelValue = model;
257
+ }
258
+ else {
259
+ log.warn("No Ollama chat models detected. Defaulting to phi4-mini:latest.");
260
+ log.warn(" Pull a model with: ollama pull phi4-mini (or any chat model you prefer)");
261
+ }
262
+ writeClassifierConfig({ choice: "ollama-offline", model: modelValue });
263
+ log.success(`Ollama classifier (${modelValue}) saved to ~/.nlm/.env`);
189
264
  }
190
265
  }
266
+ // ── Step 3.5: HTTP API auth token ─────────────────────────────────────
267
+ // Generate a token if one isn't set so /api/* gets Bearer-protected for
268
+ // non-browser callers (curl, port-forwarded clients). The UI still works
269
+ // because browsers send Origin and we exempt loopback origins.
270
+ const token = ensureMcpToken();
271
+ if (token === process.env["NLM_MCP_TOKEN"] && token.length === 64) {
272
+ log.success("HTTP API auth token saved to ~/.nlm/.env (NLM_MCP_TOKEN)");
273
+ }
191
274
  // ── Step 4: migrations ────────────────────────────────────────────────
192
275
  const ms = spinner();
193
276
  ms.start("Running database migrations");
@@ -202,6 +285,13 @@ export async function runSetup(opts) {
202
285
  log.error(`${e instanceof Error ? e.message : String(e)}`);
203
286
  process.exit(1);
204
287
  }
288
+ // ── Step 4.5: harden ~/.nlm permissions ────────────────────────────────
289
+ // Idempotent. Covers upgrade from pre-v0.4.2 installs where files were
290
+ // written without explicit chmod, leaving secrets world-readable.
291
+ const perms = hardenNlmDirPermissions();
292
+ if (perms.filesHardened + perms.dirsHardened > 0) {
293
+ log.success(`Hardened perms on ${perms.dirsHardened} dirs and ${perms.filesHardened} files in ${perms.nlmDir}`);
294
+ }
205
295
  // ── Step 5: daemon ────────────────────────────────────────────────────
206
296
  if (OS === "darwin") {
207
297
  const installDaemon = await confirm({ message: "Install macOS LaunchAgent (auto-start on login)?" });
@@ -233,9 +323,38 @@ export async function runSetup(opts) {
233
323
  }
234
324
  }
235
325
  else if (OS === "linux") {
236
- log.info("Linux daemon: add `nlm start` to your init system to auto-start on boot.");
237
- log.info(" systemd example: sudo systemctl enable --now nlm (after creating a unit file)");
238
- log.info(" Quick start now: nlm start &");
326
+ if (opts.linuxSystemdUserAvailable()) {
327
+ const installDaemon = await confirm({ message: "Install systemd user unit (auto-start on login)?" });
328
+ if (isCancel(installDaemon)) {
329
+ cancel("Setup cancelled.");
330
+ process.exit(0);
331
+ }
332
+ if (installDaemon) {
333
+ const ds = spinner();
334
+ ds.start("Installing systemd user unit");
335
+ try {
336
+ mkdirSync(dirname(opts.linuxSystemdUnitPath), { recursive: true });
337
+ mkdirSync(join(homedir(), ".nlm", "logs"), { recursive: true });
338
+ writeFileSync(opts.linuxSystemdUnitPath, opts.buildSystemdUnit(opts.nodeExecPath, opts.nlmBinPath), "utf8");
339
+ execFileSync("systemctl", ["--user", "daemon-reload"]);
340
+ execFileSync("systemctl", ["--user", "enable", "--now", opts.linuxSystemdUnitName]);
341
+ ds.stop("systemd user unit installed — daemon running");
342
+ log.info(` Status: systemctl --user status ${opts.linuxSystemdUnitName}`);
343
+ log.info(" Headless? Run `sudo loginctl enable-linger $USER` so the daemon survives logout.");
344
+ }
345
+ catch (e) {
346
+ ds.stop("systemd install failed");
347
+ log.error(`${e instanceof Error ? e.message : String(e)}`);
348
+ log.warn("Run `nlm install` manually later, or start now with: nlm start &");
349
+ }
350
+ }
351
+ }
352
+ else {
353
+ log.info("systemd user instance not available (no XDG_RUNTIME_DIR or `systemctl --user`).");
354
+ log.info(" Common on headless servers — start manually with: nlm start &");
355
+ log.info(" Or enable lingering, then re-run `nlm install`:");
356
+ log.info(" sudo loginctl enable-linger $USER");
357
+ }
239
358
  }
240
359
  else if (OS === "win32") {
241
360
  log.info("Windows daemon: run `nlm start` at login via Task Scheduler.");
@@ -324,6 +443,10 @@ export async function runSetup(opts) {
324
443
  case "pi":
325
444
  log.success("pi.dev: session scanning enabled (passive — no extra config needed)");
326
445
  break;
446
+ default: {
447
+ const _ = id;
448
+ log.warn(`Unknown runtime: ${_} — skipping.`);
449
+ }
327
450
  }
328
451
  }
329
452
  // ── Summary ───────────────────────────────────────────────────────────