@phren/cli 0.0.10 → 0.0.12

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 (100) hide show
  1. package/README.md +11 -17
  2. package/mcp/dist/capabilities/cli.js +1 -1
  3. package/mcp/dist/capabilities/mcp.js +1 -1
  4. package/mcp/dist/capabilities/vscode.js +1 -1
  5. package/mcp/dist/capabilities/web-ui.js +1 -1
  6. package/mcp/dist/cli-actions.js +58 -71
  7. package/mcp/dist/cli-config.js +337 -131
  8. package/mcp/dist/cli-extract.js +3 -2
  9. package/mcp/dist/cli-govern.js +35 -63
  10. package/mcp/dist/cli-graph.js +19 -4
  11. package/mcp/dist/cli-hooks-globs.js +2 -1
  12. package/mcp/dist/cli-hooks-output.js +4 -4
  13. package/mcp/dist/cli-hooks-session.js +1 -1
  14. package/mcp/dist/cli-hooks.js +44 -35
  15. package/mcp/dist/cli-namespaces.js +15 -5
  16. package/mcp/dist/cli-search.js +2 -2
  17. package/mcp/dist/cli.js +1 -1
  18. package/mcp/dist/content-archive.js +23 -14
  19. package/mcp/dist/content-citation.js +13 -2
  20. package/mcp/dist/content-dedup.js +9 -9
  21. package/mcp/dist/content-learning.js +6 -4
  22. package/mcp/dist/content-metadata.js +10 -0
  23. package/mcp/dist/core-finding.js +1 -1
  24. package/mcp/dist/data-access.js +10 -31
  25. package/mcp/dist/data-tasks.js +5 -26
  26. package/mcp/dist/embedding.js +7 -8
  27. package/mcp/dist/entrypoint.js +133 -102
  28. package/mcp/dist/finding-impact.js +1 -32
  29. package/mcp/dist/finding-journal.js +1 -1
  30. package/mcp/dist/finding-lifecycle.js +2 -7
  31. package/mcp/dist/governance-locks.js +12 -5
  32. package/mcp/dist/governance-policy.js +156 -9
  33. package/mcp/dist/governance-scores.js +4 -10
  34. package/mcp/dist/hooks.js +62 -18
  35. package/mcp/dist/index.js +4 -4
  36. package/mcp/dist/init-config.js +4 -25
  37. package/mcp/dist/init-preferences.js +1 -1
  38. package/mcp/dist/init-setup.js +6 -55
  39. package/mcp/dist/init-shared.js +53 -1
  40. package/mcp/dist/init.js +191 -29
  41. package/mcp/dist/link-checksums.js +3 -2
  42. package/mcp/dist/link-context.js +2 -2
  43. package/mcp/dist/link-doctor.js +14 -57
  44. package/mcp/dist/link-skills.js +98 -12
  45. package/mcp/dist/link.js +16 -75
  46. package/mcp/dist/machine-identity.js +1 -9
  47. package/mcp/dist/mcp-config.js +247 -42
  48. package/mcp/dist/mcp-data.js +9 -9
  49. package/mcp/dist/mcp-extract-facts.js +12 -7
  50. package/mcp/dist/mcp-extract.js +2 -2
  51. package/mcp/dist/mcp-finding.js +16 -20
  52. package/mcp/dist/mcp-graph.js +12 -12
  53. package/mcp/dist/mcp-hooks.js +1 -1
  54. package/mcp/dist/mcp-ops.js +18 -18
  55. package/mcp/dist/mcp-search.js +11 -16
  56. package/mcp/dist/mcp-session.js +12 -2
  57. package/mcp/dist/memory-ui-assets.js +1 -36
  58. package/mcp/dist/memory-ui-graph.js +152 -50
  59. package/mcp/dist/memory-ui-page.js +30 -5
  60. package/mcp/dist/memory-ui-scripts.js +252 -63
  61. package/mcp/dist/memory-ui-server.js +115 -3
  62. package/mcp/dist/phren-core.js +2 -0
  63. package/mcp/dist/phren-paths.js +8 -9
  64. package/mcp/dist/proactivity.js +5 -5
  65. package/mcp/dist/profile-store.js +2 -2
  66. package/mcp/dist/project-config.js +64 -17
  67. package/mcp/dist/provider-adapters.js +1 -1
  68. package/mcp/dist/query-correlation.js +22 -19
  69. package/mcp/dist/session-checkpoints.js +14 -14
  70. package/mcp/dist/session-utils.js +3 -2
  71. package/mcp/dist/shared-data-utils.js +28 -0
  72. package/mcp/dist/shared-fragment-graph.js +22 -21
  73. package/mcp/dist/shared-governance.js +1 -1
  74. package/mcp/dist/shared-index.js +144 -105
  75. package/mcp/dist/shared-retrieval.js +21 -23
  76. package/mcp/dist/shared-search-fallback.js +15 -25
  77. package/mcp/dist/shared-sqljs.js +3 -2
  78. package/mcp/dist/shared.js +5 -6
  79. package/mcp/dist/shell-entry.js +1 -1
  80. package/mcp/dist/shell-input.js +63 -53
  81. package/mcp/dist/shell-palette.js +6 -1
  82. package/mcp/dist/shell-render.js +9 -5
  83. package/mcp/dist/shell-state-store.js +2 -5
  84. package/mcp/dist/shell-view.js +7 -6
  85. package/mcp/dist/shell.js +5 -55
  86. package/mcp/dist/skill-files.js +4 -10
  87. package/mcp/dist/skill-registry.js +3 -0
  88. package/mcp/dist/status.js +43 -21
  89. package/mcp/dist/task-hygiene.js +1 -1
  90. package/mcp/dist/telemetry.js +5 -4
  91. package/mcp/dist/update.js +1 -1
  92. package/mcp/dist/utils.js +4 -4
  93. package/package.json +2 -3
  94. package/skills/docs.md +11 -11
  95. package/starter/README.md +1 -1
  96. package/starter/global/CLAUDE.md +2 -2
  97. package/starter/global/skills/audit.md +106 -0
  98. package/mcp/dist/cli-hooks-retrieval.js +0 -2
  99. package/mcp/dist/impact-scoring.js +0 -22
  100. package/mcp/dist/shared-paths.js +0 -1
package/README.md CHANGED
@@ -5,10 +5,12 @@
5
5
  <p align="center">
6
6
  <a href="https://www.npmjs.com/package/@phren/cli"><img src="https://img.shields.io/npm/v/%40phren%2Fcli?style=flat&labelColor=0D0D0D&color=7C3AED" alt="npm version"></a>
7
7
  <a href="https://github.com/alaarab/phren/blob/main/LICENSE"><img src="https://img.shields.io/github/license/alaarab/phren?style=flat&labelColor=0D0D0D&color=7C3AED" alt="license"></a>
8
+ <a href="https://alaarab.github.io/phren/"><img src="https://img.shields.io/badge/docs-alaarab.github.io%2Fphren-7C3AED?style=flat&labelColor=0D0D0D" alt="docs"></a>
9
+ <a href="https://alaarab.github.io/phren/whitepaper.pdf"><img src="https://img.shields.io/badge/whitepaper-PDF-7C3AED?style=flat&labelColor=0D0D0D" alt="whitepaper"></a>
8
10
  </p>
9
11
 
10
12
  <p align="center">
11
- Every time you start a new session, your AI agent forgets everything it learned. Phren fixes that — findings, decisions, and patterns persist as markdown in a git repo you control. No database, no hosted service, no vendor lock-in. Works across sessions, projects, and machines.
13
+ Every time you start a new session, your AI agent forgets everything it learned. Phren fixes that. Findings, decisions, and patterns persist as markdown in a git repo you control. No database, no hosted service, no vendor lock-in.
12
14
  </p>
13
15
 
14
16
  ---
@@ -23,18 +25,18 @@ That single command creates `~/.phren`, wires up MCP, installs hooks, and gives
23
25
 
24
26
  ## What phren tracks
25
27
 
26
- - **Findings** bugs hit, patterns discovered, decisions and their reasoning. Tagged by type (`[pattern]`, `[decision]`, `[pitfall]`, `[observation]`) with per-type decay rates
27
- - **Fragments** named concepts (auth, build, React) that connect findings across projects. When you search for a topic, phren pulls in everything linked to that fragment
28
- - **Tasks** work items that persist across sessions with priority, pinning, and GitHub issue linking
29
- - **Sessions** conversation boundaries with summaries and checkpoints, so the next session picks up where this one left off
30
- - **Skills** reusable slash commands you teach phren. Drop them in `~/.phren/global/skills/` and they work everywhere
28
+ - **Findings**: bugs hit, patterns discovered, decisions and their reasoning. Tagged by type (`[pattern]`, `[decision]`, `[pitfall]`, `[observation]`) with per-type decay rates
29
+ - **Fragments**: named concepts (auth, build, React) that connect findings across projects. Search for a topic and phren pulls in everything linked to that fragment
30
+ - **Tasks**: work items that persist across sessions with priority, pinning, and GitHub issue linking
31
+ - **Sessions**: conversation boundaries with summaries and checkpoints, so the next session picks up where the last one left off
32
+ - **Skills**: reusable slash commands you teach phren. Drop them in `~/.phren/global/skills/` and they work everywhere
31
33
 
32
34
  ## How it works
33
35
 
34
36
  - **Surfaces relevant context on every prompt** via hooks. Agents build on what they know instead of starting fresh
35
- - **Trust scores decay over time** old findings lose confidence. Decisions never decay. Observations expire in 14 days
37
+ - **Trust scores decay over time.** Old findings lose confidence. Decisions never decay. Observations expire in 14 days
36
38
  - **Syncs across machines** through git push/pull. No coordination service
37
- - **Works with Claude Code, Copilot, Cursor, and Codex** one memory, every agent
39
+ - **Works with Claude Code, Copilot, Cursor, and Codex.** One store, every agent
38
40
  - **Shell and web UI** for browsing, searching, and triaging (`phren` or `phren web-ui`)
39
41
 
40
42
  ## Quick start
@@ -43,18 +45,10 @@ That single command creates `~/.phren`, wires up MCP, installs hooks, and gives
43
45
  npx @phren/cli init # set up phren (interactive walkthrough)
44
46
  ```
45
47
 
46
- Init detects your tools, registers MCP servers, and installs lifecycle hooks. After it finishes, open a prompt in any tracked project phren is already injecting context.
48
+ Init detects your tools, registers MCP servers, and installs lifecycle hooks. After it finishes, open a prompt in any tracked project. Phren is already injecting context.
47
49
 
48
50
  To add a project later, run `phren add` from that directory. To browse what phren knows, run `phren` to open the interactive shell.
49
51
 
50
- ## Learn more
51
-
52
- - [Documentation site](https://alaarab.github.io/phren/)
53
- - [Whitepaper (PDF)](https://alaarab.github.io/phren/whitepaper.pdf)
54
- - [Architecture](docs/architecture.md) — how retrieval, governance, and persistence fit together
55
- - [Contributing](CONTRIBUTING.md) — how to add tools, skills, and tests
56
- - [Security](SECURITY.md)
57
-
58
52
  ---
59
53
 
60
54
  MIT License. Made by [Ala Arab](https://github.com/alaarab).
@@ -1,6 +1,6 @@
1
1
  export const cliManifest = {
2
2
  surface: "cli",
3
- version: "1.31.1",
3
+ version: "0.0.12",
4
4
  actions: {
5
5
  // Finding management
6
6
  "finding.add": { implemented: true, handler: "cli-actions.ts:handleAddFinding" },
@@ -1,6 +1,6 @@
1
1
  export const mcpManifest = {
2
2
  surface: "mcp",
3
- version: "1.31.1",
3
+ version: "0.0.12",
4
4
  actions: {
5
5
  // Finding management
6
6
  "finding.add": { implemented: true, handler: "index.ts:add_finding" },
@@ -1,6 +1,6 @@
1
1
  export const vscodeManifest = {
2
2
  surface: "vscode",
3
- version: "1.31.1",
3
+ version: "0.0.12",
4
4
  actions: {
5
5
  // Finding management
6
6
  "finding.add": { implemented: true, handler: "extension.ts:phren.addFinding" },
@@ -1,6 +1,6 @@
1
1
  export const webUiManifest = {
2
2
  surface: "web-ui",
3
- version: "1.31.1",
3
+ version: "0.0.12",
4
4
  actions: {
5
5
  // Finding management
6
6
  "finding.add": { implemented: false, reason: "Web UI is read-only for findings (review queue only)" },
@@ -14,35 +14,27 @@ import { runSearch, runFragmentSearch, parseFragmentSearchArgs, runRelatedDocs,
14
14
  import { resolveRuntimeProfile } from "./runtime-profile.js";
15
15
  import { getProjectConsolidationStatus, CONSOLIDATION_ENTRY_THRESHOLD } from "./content-validate.js";
16
16
  import { listAllSessions } from "./mcp-session.js";
17
- export async function handleSearch(opts, profile) {
18
- const result = await runSearch(opts, getPhrenPath(), profile);
19
- if (result.lines.length > 0) {
17
+ async function runAndPrint(fn) {
18
+ const result = await fn();
19
+ if (result.lines.length > 0)
20
20
  console.log(result.lines.join("\n"));
21
- }
22
21
  if (result.exitCode !== 0)
23
22
  process.exit(result.exitCode);
24
23
  }
24
+ export async function handleSearch(opts, profile) {
25
+ await runAndPrint(() => runSearch(opts, getPhrenPath(), profile));
26
+ }
25
27
  export async function handleFragmentSearch(args, profile) {
26
28
  const opts = parseFragmentSearchArgs(args);
27
29
  if (!opts)
28
30
  return;
29
- const result = await runFragmentSearch(opts.query, getPhrenPath(), profile, opts);
30
- if (result.lines.length > 0) {
31
- console.log(result.lines.join("\n"));
32
- }
33
- if (result.exitCode !== 0)
34
- process.exit(result.exitCode);
31
+ await runAndPrint(() => runFragmentSearch(opts.query, getPhrenPath(), profile, opts));
35
32
  }
36
33
  export async function handleRelatedDocs(args, profile) {
37
34
  const opts = parseRelatedDocsArgs(args);
38
35
  if (!opts)
39
36
  return;
40
- const result = await runRelatedDocs(opts.entity, getPhrenPath(), profile, opts);
41
- if (result.lines.length > 0) {
42
- console.log(result.lines.join("\n"));
43
- }
44
- if (result.exitCode !== 0)
45
- process.exit(result.exitCode);
37
+ await runAndPrint(() => runRelatedDocs(opts.entity, getPhrenPath(), profile, opts));
46
38
  }
47
39
  export async function handleAddFinding(project, learning) {
48
40
  if (!project || !learning) {
@@ -58,7 +50,7 @@ export async function handleAddFinding(project, learning) {
58
50
  console.log(result.message);
59
51
  }
60
52
  catch (err) {
61
- console.error(err instanceof Error ? err.message : String(err));
53
+ console.error(errorMessage(err));
62
54
  process.exit(1);
63
55
  }
64
56
  }
@@ -164,7 +156,7 @@ export async function handleDoctor(args) {
164
156
  }
165
157
  }
166
158
  catch (err) {
167
- if ((process.env.PHREN_DEBUG || process.env.PHREN_DEBUG))
159
+ if ((process.env.PHREN_DEBUG))
168
160
  process.stderr.write(`[phren] doctor searchMissParse: ${errorMessage(err)}\n`);
169
161
  }
170
162
  }
@@ -181,44 +173,49 @@ export async function handleDoctor(args) {
181
173
  }
182
174
  }
183
175
  catch (err) {
184
- if ((process.env.PHREN_DEBUG || process.env.PHREN_DEBUG))
176
+ if ((process.env.PHREN_DEBUG))
185
177
  process.stderr.write(`[phren] doctor searchMissAnalysis: ${errorMessage(err)}\n`);
186
178
  }
179
+ const semStatus = await getSemanticSearchStatus(getPhrenPath(), profile || undefined);
180
+ if (!semStatus.ollamaUrl) {
181
+ console.log("- ok semantic-search: disabled (optional; enable for fuzzy/paraphrase-heavy retrieval)");
182
+ }
183
+ else if (!semStatus.available) {
184
+ console.log(`- warn semantic-search: Ollama not running at ${semStatus.ollamaUrl} (start Ollama or set PHREN_OLLAMA_URL=off to disable)`);
185
+ }
186
+ else if (!semStatus.modelReady) {
187
+ console.log(`- warn semantic-search: model ${semStatus.model} not pulled (run: ollama pull ${semStatus.model})`);
188
+ }
189
+ else {
190
+ console.log(`- ok semantic-search: ${semStatus.model} ready, ${semStatus.coverage}`);
191
+ }
192
+ process.exit(result.ok ? 0 : 1);
193
+ }
194
+ async function getSemanticSearchStatus(phrenPath, profile) {
187
195
  try {
188
196
  const { checkOllamaAvailable, checkModelAvailable, getOllamaUrl, getEmbeddingModel } = await import("./shared-ollama.js");
189
197
  const { getEmbeddingCache, formatEmbeddingCoverage } = await import("./shared-embedding-cache.js");
190
198
  const { listIndexedDocumentPaths } = await import("./shared-index.js");
191
199
  const ollamaUrl = getOllamaUrl();
192
- if (!ollamaUrl) {
193
- console.log("- ok semantic-search: disabled (optional; enable for fuzzy/paraphrase-heavy retrieval)");
194
- }
195
- else {
196
- const available = await checkOllamaAvailable();
197
- if (!available) {
198
- console.log(`- warn semantic-search: Ollama not running at ${ollamaUrl} (start Ollama or set PHREN_OLLAMA_URL=off to disable)`);
199
- }
200
- else {
201
- const model = getEmbeddingModel();
202
- const modelReady = await checkModelAvailable();
203
- if (!modelReady) {
204
- console.log(`- warn semantic-search: model ${model} not pulled (run: ollama pull ${model})`);
205
- }
206
- else {
207
- const phrenPath = getPhrenPath();
208
- const cache = getEmbeddingCache(phrenPath);
209
- await cache.load().catch(() => { });
210
- const allPaths = listIndexedDocumentPaths(phrenPath, profile || undefined);
211
- const coverage = cache.coverage(allPaths);
212
- console.log(`- ok semantic-search: ${model} ready, ${formatEmbeddingCoverage(coverage)}`);
213
- }
214
- }
215
- }
200
+ if (!ollamaUrl)
201
+ return { ollamaUrl: null };
202
+ const available = await checkOllamaAvailable();
203
+ if (!available)
204
+ return { ollamaUrl, available: false };
205
+ const model = getEmbeddingModel();
206
+ const modelReady = await checkModelAvailable();
207
+ if (!modelReady)
208
+ return { ollamaUrl, available: true, modelReady: false, model };
209
+ const cache = getEmbeddingCache(phrenPath);
210
+ await cache.load().catch(() => { });
211
+ const coverage = formatEmbeddingCoverage(cache.coverage(listIndexedDocumentPaths(phrenPath, profile)));
212
+ return { ollamaUrl, available: true, modelReady: true, model, coverage };
216
213
  }
217
214
  catch (err) {
218
- if ((process.env.PHREN_DEBUG || process.env.PHREN_DEBUG))
219
- process.stderr.write(`[phren] doctor ollamaStatus: ${errorMessage(err)}\n`);
215
+ if ((process.env.PHREN_DEBUG))
216
+ process.stderr.write(`[phren] getSemanticSearchStatus: ${errorMessage(err)}\n`);
217
+ return { ollamaUrl: null, status: "error", error: errorMessage(err) };
220
218
  }
221
- process.exit(result.ok ? 0 : 1);
222
219
  }
223
220
  export async function handleStatus() {
224
221
  const phrenPath = getPhrenPath();
@@ -231,34 +228,24 @@ export async function handleStatus() {
231
228
  console.log(`unsynced commits: ${runtime.lastSync?.unsyncedCommits ?? 0}`);
232
229
  if (runtime.lastSync?.lastPushDetail)
233
230
  console.log(`push detail: ${runtime.lastSync.lastPushDetail}`);
234
- try {
235
- const { getOllamaUrl, checkOllamaAvailable, checkModelAvailable, getEmbeddingModel } = await import("./shared-ollama.js");
236
- const { getEmbeddingCache, formatEmbeddingCoverage } = await import("./shared-embedding-cache.js");
237
- const { listIndexedDocumentPaths } = await import("./shared-index.js");
238
- const ollamaUrl = getOllamaUrl();
239
- if (!ollamaUrl) {
240
- console.log("semantic-search: disabled (optional)");
241
- return;
242
- }
243
- const available = await checkOllamaAvailable();
244
- if (!available) {
245
- console.log(`semantic-search: offline (${ollamaUrl})`);
246
- return;
231
+ const semStatus = await getSemanticSearchStatus(phrenPath, profile || undefined);
232
+ if (!semStatus.ollamaUrl) {
233
+ const errStatus = semStatus;
234
+ if (errStatus.status === "error") {
235
+ console.log(`semantic-search: error (${errStatus.error ?? "unknown"})`);
247
236
  }
248
- const model = getEmbeddingModel();
249
- const modelReady = await checkModelAvailable();
250
- if (!modelReady) {
251
- console.log(`semantic-search: model missing (${model})`);
252
- return;
237
+ else {
238
+ console.log("semantic-search: disabled (optional)");
253
239
  }
254
- const cache = getEmbeddingCache(phrenPath);
255
- await cache.load().catch(() => { });
256
- const coverage = cache.coverage(listIndexedDocumentPaths(phrenPath, profile || undefined));
257
- console.log(`semantic-search: ${model} ready, ${formatEmbeddingCoverage(coverage)}`);
258
240
  }
259
- catch (err) {
260
- if ((process.env.PHREN_DEBUG || process.env.PHREN_DEBUG))
261
- process.stderr.write(`[phren] handleStatus semanticSearch: ${errorMessage(err)}\n`);
241
+ else if (!semStatus.available) {
242
+ console.log(`semantic-search: offline (${semStatus.ollamaUrl})`);
243
+ }
244
+ else if (!semStatus.modelReady) {
245
+ console.log(`semantic-search: model missing (${semStatus.model})`);
246
+ }
247
+ else {
248
+ console.log(`semantic-search: ${semStatus.model} ready, ${semStatus.coverage}`);
262
249
  }
263
250
  }
264
251
  export async function handleQualityFeedback(args) {