@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.
- package/README.md +11 -17
- package/mcp/dist/capabilities/cli.js +1 -1
- package/mcp/dist/capabilities/mcp.js +1 -1
- package/mcp/dist/capabilities/vscode.js +1 -1
- package/mcp/dist/capabilities/web-ui.js +1 -1
- package/mcp/dist/cli-actions.js +58 -71
- package/mcp/dist/cli-config.js +337 -131
- package/mcp/dist/cli-extract.js +3 -2
- package/mcp/dist/cli-govern.js +35 -63
- package/mcp/dist/cli-graph.js +19 -4
- package/mcp/dist/cli-hooks-globs.js +2 -1
- package/mcp/dist/cli-hooks-output.js +4 -4
- package/mcp/dist/cli-hooks-session.js +1 -1
- package/mcp/dist/cli-hooks.js +44 -35
- package/mcp/dist/cli-namespaces.js +15 -5
- package/mcp/dist/cli-search.js +2 -2
- package/mcp/dist/cli.js +1 -1
- package/mcp/dist/content-archive.js +23 -14
- package/mcp/dist/content-citation.js +13 -2
- package/mcp/dist/content-dedup.js +9 -9
- package/mcp/dist/content-learning.js +6 -4
- package/mcp/dist/content-metadata.js +10 -0
- package/mcp/dist/core-finding.js +1 -1
- package/mcp/dist/data-access.js +10 -31
- package/mcp/dist/data-tasks.js +5 -26
- package/mcp/dist/embedding.js +7 -8
- package/mcp/dist/entrypoint.js +133 -102
- package/mcp/dist/finding-impact.js +1 -32
- package/mcp/dist/finding-journal.js +1 -1
- package/mcp/dist/finding-lifecycle.js +2 -7
- package/mcp/dist/governance-locks.js +12 -5
- package/mcp/dist/governance-policy.js +156 -9
- package/mcp/dist/governance-scores.js +4 -10
- package/mcp/dist/hooks.js +62 -18
- package/mcp/dist/index.js +4 -4
- package/mcp/dist/init-config.js +4 -25
- package/mcp/dist/init-preferences.js +1 -1
- package/mcp/dist/init-setup.js +6 -55
- package/mcp/dist/init-shared.js +53 -1
- package/mcp/dist/init.js +191 -29
- package/mcp/dist/link-checksums.js +3 -2
- package/mcp/dist/link-context.js +2 -2
- package/mcp/dist/link-doctor.js +14 -57
- package/mcp/dist/link-skills.js +98 -12
- package/mcp/dist/link.js +16 -75
- package/mcp/dist/machine-identity.js +1 -9
- package/mcp/dist/mcp-config.js +247 -42
- package/mcp/dist/mcp-data.js +9 -9
- package/mcp/dist/mcp-extract-facts.js +12 -7
- package/mcp/dist/mcp-extract.js +2 -2
- package/mcp/dist/mcp-finding.js +16 -20
- package/mcp/dist/mcp-graph.js +12 -12
- package/mcp/dist/mcp-hooks.js +1 -1
- package/mcp/dist/mcp-ops.js +18 -18
- package/mcp/dist/mcp-search.js +11 -16
- package/mcp/dist/mcp-session.js +12 -2
- package/mcp/dist/memory-ui-assets.js +1 -36
- package/mcp/dist/memory-ui-graph.js +152 -50
- package/mcp/dist/memory-ui-page.js +30 -5
- package/mcp/dist/memory-ui-scripts.js +252 -63
- package/mcp/dist/memory-ui-server.js +115 -3
- package/mcp/dist/phren-core.js +2 -0
- package/mcp/dist/phren-paths.js +8 -9
- package/mcp/dist/proactivity.js +5 -5
- package/mcp/dist/profile-store.js +2 -2
- package/mcp/dist/project-config.js +64 -17
- package/mcp/dist/provider-adapters.js +1 -1
- package/mcp/dist/query-correlation.js +22 -19
- package/mcp/dist/session-checkpoints.js +14 -14
- package/mcp/dist/session-utils.js +3 -2
- package/mcp/dist/shared-data-utils.js +28 -0
- package/mcp/dist/shared-fragment-graph.js +22 -21
- package/mcp/dist/shared-governance.js +1 -1
- package/mcp/dist/shared-index.js +144 -105
- package/mcp/dist/shared-retrieval.js +21 -23
- package/mcp/dist/shared-search-fallback.js +15 -25
- package/mcp/dist/shared-sqljs.js +3 -2
- package/mcp/dist/shared.js +5 -6
- package/mcp/dist/shell-entry.js +1 -1
- package/mcp/dist/shell-input.js +63 -53
- package/mcp/dist/shell-palette.js +6 -1
- package/mcp/dist/shell-render.js +9 -5
- package/mcp/dist/shell-state-store.js +2 -5
- package/mcp/dist/shell-view.js +7 -6
- package/mcp/dist/shell.js +5 -55
- package/mcp/dist/skill-files.js +4 -10
- package/mcp/dist/skill-registry.js +3 -0
- package/mcp/dist/status.js +43 -21
- package/mcp/dist/task-hygiene.js +1 -1
- package/mcp/dist/telemetry.js +5 -4
- package/mcp/dist/update.js +1 -1
- package/mcp/dist/utils.js +4 -4
- package/package.json +2 -3
- package/skills/docs.md +11 -11
- package/starter/README.md +1 -1
- package/starter/global/CLAUDE.md +2 -2
- package/starter/global/skills/audit.md +106 -0
- package/mcp/dist/cli-hooks-retrieval.js +0 -2
- package/mcp/dist/impact-scoring.js +0 -22
- 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
|
|
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
|
|
27
|
-
- **Fragments
|
|
28
|
-
- **Tasks
|
|
29
|
-
- **Sessions
|
|
30
|
-
- **Skills
|
|
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
|
|
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
|
|
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
|
|
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).
|
package/mcp/dist/cli-actions.js
CHANGED
|
@@ -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
|
-
|
|
18
|
-
const result = await
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
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
|
|
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
|
|
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
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
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
|
|
219
|
-
process.stderr.write(`[phren]
|
|
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
|
-
|
|
235
|
-
|
|
236
|
-
const
|
|
237
|
-
|
|
238
|
-
|
|
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
|
-
|
|
249
|
-
|
|
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
|
-
|
|
260
|
-
|
|
261
|
-
|
|
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) {
|