@phren/cli 0.0.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/LICENSE +21 -0
- package/README.md +590 -0
- package/mcp/dist/capabilities/cli.js +61 -0
- package/mcp/dist/capabilities/index.js +15 -0
- package/mcp/dist/capabilities/mcp.js +61 -0
- package/mcp/dist/capabilities/types.js +57 -0
- package/mcp/dist/capabilities/vscode.js +61 -0
- package/mcp/dist/capabilities/web-ui.js +61 -0
- package/mcp/dist/cli-actions.js +302 -0
- package/mcp/dist/cli-config.js +580 -0
- package/mcp/dist/cli-extract.js +305 -0
- package/mcp/dist/cli-govern.js +371 -0
- package/mcp/dist/cli-graph.js +169 -0
- package/mcp/dist/cli-hooks-citations.js +44 -0
- package/mcp/dist/cli-hooks-context.js +56 -0
- package/mcp/dist/cli-hooks-globs.js +83 -0
- package/mcp/dist/cli-hooks-output.js +130 -0
- package/mcp/dist/cli-hooks-retrieval.js +2 -0
- package/mcp/dist/cli-hooks-session.js +1402 -0
- package/mcp/dist/cli-hooks.js +350 -0
- package/mcp/dist/cli-namespaces.js +989 -0
- package/mcp/dist/cli-ops.js +253 -0
- package/mcp/dist/cli-search.js +407 -0
- package/mcp/dist/cli.js +108 -0
- package/mcp/dist/content-archive.js +278 -0
- package/mcp/dist/content-citation.js +391 -0
- package/mcp/dist/content-dedup.js +622 -0
- package/mcp/dist/content-learning.js +472 -0
- package/mcp/dist/content-metadata.js +186 -0
- package/mcp/dist/content-validate.js +462 -0
- package/mcp/dist/core-finding.js +54 -0
- package/mcp/dist/core-project.js +36 -0
- package/mcp/dist/core-search.js +50 -0
- package/mcp/dist/data-access.js +400 -0
- package/mcp/dist/data-tasks.js +821 -0
- package/mcp/dist/embedding.js +344 -0
- package/mcp/dist/entrypoint.js +387 -0
- package/mcp/dist/finding-context.js +172 -0
- package/mcp/dist/finding-impact.js +181 -0
- package/mcp/dist/finding-journal.js +122 -0
- package/mcp/dist/finding-lifecycle.js +259 -0
- package/mcp/dist/governance-audit.js +22 -0
- package/mcp/dist/governance-locks.js +96 -0
- package/mcp/dist/governance-policy.js +648 -0
- package/mcp/dist/governance-scores.js +355 -0
- package/mcp/dist/hooks.js +449 -0
- package/mcp/dist/impact-scoring.js +22 -0
- package/mcp/dist/index-query.js +168 -0
- package/mcp/dist/index.js +205 -0
- package/mcp/dist/init-config.js +336 -0
- package/mcp/dist/init-preferences.js +62 -0
- package/mcp/dist/init-setup.js +1305 -0
- package/mcp/dist/init-shared.js +29 -0
- package/mcp/dist/init.js +1730 -0
- package/mcp/dist/link-checksums.js +62 -0
- package/mcp/dist/link-context.js +257 -0
- package/mcp/dist/link-doctor.js +591 -0
- package/mcp/dist/link-skills.js +212 -0
- package/mcp/dist/link.js +596 -0
- package/mcp/dist/logger.js +15 -0
- package/mcp/dist/machine-identity.js +38 -0
- package/mcp/dist/mcp-config.js +254 -0
- package/mcp/dist/mcp-data.js +315 -0
- package/mcp/dist/mcp-extract-facts.js +78 -0
- package/mcp/dist/mcp-extract.js +133 -0
- package/mcp/dist/mcp-finding.js +557 -0
- package/mcp/dist/mcp-graph.js +339 -0
- package/mcp/dist/mcp-hooks.js +256 -0
- package/mcp/dist/mcp-memory.js +58 -0
- package/mcp/dist/mcp-ops.js +328 -0
- package/mcp/dist/mcp-search.js +628 -0
- package/mcp/dist/mcp-session.js +651 -0
- package/mcp/dist/mcp-skills.js +189 -0
- package/mcp/dist/mcp-tasks.js +551 -0
- package/mcp/dist/mcp-types.js +7 -0
- package/mcp/dist/memory-ui-assets.js +6 -0
- package/mcp/dist/memory-ui-data.js +513 -0
- package/mcp/dist/memory-ui-graph.js +1910 -0
- package/mcp/dist/memory-ui-page.js +353 -0
- package/mcp/dist/memory-ui-scripts.js +1387 -0
- package/mcp/dist/memory-ui-server.js +1218 -0
- package/mcp/dist/memory-ui-styles.js +555 -0
- package/mcp/dist/memory-ui.js +9 -0
- package/mcp/dist/package-metadata.js +13 -0
- package/mcp/dist/phren-art.js +52 -0
- package/mcp/dist/phren-core.js +108 -0
- package/mcp/dist/phren-dotenv.js +67 -0
- package/mcp/dist/phren-paths.js +476 -0
- package/mcp/dist/proactivity.js +172 -0
- package/mcp/dist/profile-store.js +228 -0
- package/mcp/dist/project-config.js +85 -0
- package/mcp/dist/project-locator.js +25 -0
- package/mcp/dist/project-topics.js +1134 -0
- package/mcp/dist/provider-adapters.js +176 -0
- package/mcp/dist/runtime-profile.js +18 -0
- package/mcp/dist/session-checkpoints.js +131 -0
- package/mcp/dist/session-utils.js +68 -0
- package/mcp/dist/shared-content.js +8 -0
- package/mcp/dist/shared-embedding-cache.js +143 -0
- package/mcp/dist/shared-fragment-graph.js +456 -0
- package/mcp/dist/shared-governance.js +4 -0
- package/mcp/dist/shared-index.js +1334 -0
- package/mcp/dist/shared-ollama.js +192 -0
- package/mcp/dist/shared-paths.js +1 -0
- package/mcp/dist/shared-retrieval.js +796 -0
- package/mcp/dist/shared-search-fallback.js +375 -0
- package/mcp/dist/shared-sqljs.js +42 -0
- package/mcp/dist/shared-stemmer.js +171 -0
- package/mcp/dist/shared-vector-index.js +199 -0
- package/mcp/dist/shared.js +114 -0
- package/mcp/dist/shell-entry.js +209 -0
- package/mcp/dist/shell-input.js +943 -0
- package/mcp/dist/shell-palette.js +119 -0
- package/mcp/dist/shell-render.js +252 -0
- package/mcp/dist/shell-state-store.js +81 -0
- package/mcp/dist/shell-types.js +13 -0
- package/mcp/dist/shell-view-list.js +14 -0
- package/mcp/dist/shell-view.js +707 -0
- package/mcp/dist/shell.js +352 -0
- package/mcp/dist/skill-files.js +117 -0
- package/mcp/dist/skill-registry.js +279 -0
- package/mcp/dist/skill-state.js +28 -0
- package/mcp/dist/startup-embedding.js +57 -0
- package/mcp/dist/status.js +323 -0
- package/mcp/dist/synonyms.json +670 -0
- package/mcp/dist/task-hygiene.js +251 -0
- package/mcp/dist/task-lifecycle.js +347 -0
- package/mcp/dist/tasks-github.js +76 -0
- package/mcp/dist/telemetry.js +165 -0
- package/mcp/dist/test-global-setup.js +37 -0
- package/mcp/dist/tool-registry.js +104 -0
- package/mcp/dist/update.js +97 -0
- package/mcp/dist/utils.js +543 -0
- package/package.json +67 -0
- package/skills/README.md +7 -0
- package/skills/consolidate/SKILL.md +152 -0
- package/skills/discover/SKILL.md +175 -0
- package/skills/init/SKILL.md +216 -0
- package/skills/profiles/SKILL.md +121 -0
- package/skills/sync/SKILL.md +261 -0
- package/starter/README.md +74 -0
- package/starter/global/CLAUDE.md +89 -0
- package/starter/global/skills/humanize.md +30 -0
- package/starter/global/skills/pipeline.md +35 -0
- package/starter/global/skills/release.md +35 -0
- package/starter/machines.yaml +8 -0
- package/starter/my-api/.claude/skills/README.md +7 -0
- package/starter/my-api/CLAUDE.md +33 -0
- package/starter/my-api/FINDINGS.md +9 -0
- package/starter/my-api/summary.md +7 -0
- package/starter/my-api/tasks.md +7 -0
- package/starter/my-first-project/.claude/skills/README.md +7 -0
- package/starter/my-first-project/CLAUDE.md +49 -0
- package/starter/my-first-project/FINDINGS.md +24 -0
- package/starter/my-first-project/summary.md +11 -0
- package/starter/my-first-project/tasks.md +25 -0
- package/starter/my-frontend/.claude/skills/README.md +7 -0
- package/starter/my-frontend/CLAUDE.md +33 -0
- package/starter/my-frontend/FINDINGS.md +9 -0
- package/starter/my-frontend/summary.md +7 -0
- package/starter/my-frontend/tasks.md +7 -0
- package/starter/profiles/default.yaml +4 -0
- package/starter/profiles/personal.yaml +4 -0
- package/starter/profiles/work.yaml +4 -0
- package/starter/templates/README.md +7 -0
- package/starter/templates/frontend/CLAUDE.md +23 -0
- package/starter/templates/frontend/FINDINGS.md +7 -0
- package/starter/templates/frontend/reference/README.md +4 -0
- package/starter/templates/frontend/summary.md +7 -0
- package/starter/templates/frontend/tasks.md +11 -0
- package/starter/templates/library/CLAUDE.md +22 -0
- package/starter/templates/library/FINDINGS.md +7 -0
- package/starter/templates/library/reference/README.md +4 -0
- package/starter/templates/library/summary.md +7 -0
- package/starter/templates/library/tasks.md +11 -0
- package/starter/templates/monorepo/CLAUDE.md +21 -0
- package/starter/templates/monorepo/FINDINGS.md +7 -0
- package/starter/templates/monorepo/reference/README.md +4 -0
- package/starter/templates/monorepo/summary.md +7 -0
- package/starter/templates/monorepo/tasks.md +11 -0
- package/starter/templates/python-project/CLAUDE.md +21 -0
- package/starter/templates/python-project/FINDINGS.md +7 -0
- package/starter/templates/python-project/reference/README.md +4 -0
- package/starter/templates/python-project/summary.md +7 -0
- package/starter/templates/python-project/tasks.md +10 -0
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { mcpResponse } from "./mcp-types.js";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { isValidProjectName, safeProjectPath } from "./utils.js";
|
|
4
|
+
import { addFindingsToFile } from "./shared-content.js";
|
|
5
|
+
import { checkOllamaAvailable, checkModelAvailable, generateText, getOllamaUrl, getExtractModel } from "./shared-ollama.js";
|
|
6
|
+
import { debugLog } from "./shared.js";
|
|
7
|
+
import { getProactivityLevelForFindings, shouldAutoCaptureFindingsForLevel } from "./proactivity.js";
|
|
8
|
+
import * as path from "path";
|
|
9
|
+
const EXTRACT_PROMPT = `You are extracting non-obvious engineering insights from text.
|
|
10
|
+
Output ONLY a JSON array of strings. Each string is a specific, actionable finding.
|
|
11
|
+
|
|
12
|
+
Rules:
|
|
13
|
+
- Only extract non-obvious patterns, bugs, decisions, pitfalls, or workarounds
|
|
14
|
+
- Do NOT extract obvious facts or things any developer would know
|
|
15
|
+
- Do NOT extract credentials, API keys, or personal information
|
|
16
|
+
- Each finding must be self-contained (understandable without seeing the source text)
|
|
17
|
+
- Prefix each finding with its type in brackets: [decision], [pitfall], [pattern], [tradeoff], [bug], or [architecture]
|
|
18
|
+
- Maximum 10 findings
|
|
19
|
+
- If nothing is worth extracting, return []
|
|
20
|
+
- Return ONLY the JSON array, no explanation, no markdown
|
|
21
|
+
|
|
22
|
+
Text to analyze:
|
|
23
|
+
`;
|
|
24
|
+
function parseFindings(raw) {
|
|
25
|
+
// Strip markdown code fences if present
|
|
26
|
+
const cleaned = raw.replace(/^```(?:json)?\s*/m, "").replace(/\s*```\s*$/m, "").trim();
|
|
27
|
+
try {
|
|
28
|
+
const parsed = JSON.parse(cleaned);
|
|
29
|
+
if (Array.isArray(parsed)) {
|
|
30
|
+
return parsed
|
|
31
|
+
.filter((f) => typeof f === "string" && f.trim().length > 0)
|
|
32
|
+
.map(f => f.trim())
|
|
33
|
+
.slice(0, 10);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
catch (err) {
|
|
37
|
+
debugLog(`auto_extract: failed to parse LLM output as JSON: ${cleaned.slice(0, 200)} (${err instanceof Error ? err.message : String(err)})`);
|
|
38
|
+
}
|
|
39
|
+
return [];
|
|
40
|
+
}
|
|
41
|
+
export function register(server, ctx) {
|
|
42
|
+
const { phrenPath, withWriteQueue, updateFileInIndex } = ctx;
|
|
43
|
+
server.registerTool("auto_extract_findings", {
|
|
44
|
+
title: "◆ phren · auto-extract findings",
|
|
45
|
+
description: "Use a local Ollama LLM to automatically extract non-obvious findings from text. " +
|
|
46
|
+
"Pass conversation snippets, code review notes, error logs, or any engineering text. " +
|
|
47
|
+
"The model identifies patterns, pitfalls, decisions, and bugs worth remembering. " +
|
|
48
|
+
"Requires Ollama running locally. Set PHREN_EXTRACT_MODEL env var to choose model (default: llama3.2). " +
|
|
49
|
+
"Set PHREN_OLLAMA_URL=off to disable.",
|
|
50
|
+
inputSchema: z.object({
|
|
51
|
+
project: z.string().describe("Project name to save extracted findings to."),
|
|
52
|
+
text: z.string().describe("Text to extract findings from (conversation, code review, error log, etc.). Max 10000 chars."),
|
|
53
|
+
model: z.string().optional().describe("Ollama model to use (overrides PHREN_EXTRACT_MODEL env var)."),
|
|
54
|
+
dryRun: z.boolean().optional().describe("If true, return what would be extracted without saving."),
|
|
55
|
+
}),
|
|
56
|
+
}, async ({ project, text, model, dryRun }) => {
|
|
57
|
+
if (!isValidProjectName(project)) {
|
|
58
|
+
return mcpResponse({ ok: false, error: `Invalid project name: "${project}"` });
|
|
59
|
+
}
|
|
60
|
+
if (text.length > 10000) {
|
|
61
|
+
text = text.slice(0, 10000);
|
|
62
|
+
}
|
|
63
|
+
const findingsLevel = getProactivityLevelForFindings(ctx.phrenPath);
|
|
64
|
+
if (!dryRun && !shouldAutoCaptureFindingsForLevel(findingsLevel, text)) {
|
|
65
|
+
const error = findingsLevel === "low"
|
|
66
|
+
? 'Findings auto-extraction is disabled when PHREN_PROACTIVITY_FINDINGS is "low". Use add_finding for manual saves.'
|
|
67
|
+
: 'Findings auto-extraction at "medium" requires an explicit signal like "add finding" or "worth remembering".';
|
|
68
|
+
return mcpResponse({ ok: false, error });
|
|
69
|
+
}
|
|
70
|
+
const ollamaUrl = getOllamaUrl();
|
|
71
|
+
if (!ollamaUrl) {
|
|
72
|
+
return mcpResponse({
|
|
73
|
+
ok: false,
|
|
74
|
+
error: "Ollama is disabled (PHREN_OLLAMA_URL=off). Set PHREN_OLLAMA_URL=http://localhost:11434 to enable auto-extraction.",
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
const available = await checkOllamaAvailable(ollamaUrl);
|
|
78
|
+
if (!available) {
|
|
79
|
+
return mcpResponse({
|
|
80
|
+
ok: false,
|
|
81
|
+
error: `Ollama not running at ${ollamaUrl}. Start Ollama first: https://ollama.com`,
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
const extractModel = model ?? getExtractModel();
|
|
85
|
+
const modelAvailable = await checkModelAvailable(extractModel, ollamaUrl);
|
|
86
|
+
if (!modelAvailable) {
|
|
87
|
+
return mcpResponse({
|
|
88
|
+
ok: false,
|
|
89
|
+
error: `Model "${extractModel}" not found. Pull it with: ollama pull ${extractModel}`,
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
const prompt = EXTRACT_PROMPT + text;
|
|
93
|
+
const raw = await generateText(prompt, extractModel, ollamaUrl);
|
|
94
|
+
if (!raw) {
|
|
95
|
+
return mcpResponse({ ok: false, error: "Ollama returned no response. Try again or check model availability." });
|
|
96
|
+
}
|
|
97
|
+
const findings = parseFindings(raw);
|
|
98
|
+
if (findings.length === 0) {
|
|
99
|
+
return mcpResponse({
|
|
100
|
+
ok: true,
|
|
101
|
+
message: "No findings worth extracting from the provided text.",
|
|
102
|
+
data: { project, extracted: [], added: [], skipped: [], dryRun: dryRun ?? false },
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
if (dryRun) {
|
|
106
|
+
return mcpResponse({
|
|
107
|
+
ok: true,
|
|
108
|
+
message: `Would extract ${findings.length} finding(s) (dry run, nothing saved).`,
|
|
109
|
+
data: { project, extracted: findings, added: [], skipped: [], dryRun: true },
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
return withWriteQueue(async () => {
|
|
113
|
+
// Use addFindingsToFile so extracted findings go through the full pipeline:
|
|
114
|
+
// secret scan, dedup check, validation, and index update.
|
|
115
|
+
const result = addFindingsToFile(phrenPath, project, findings, { source: "extract" });
|
|
116
|
+
if (!result.ok) {
|
|
117
|
+
return mcpResponse({ ok: false, error: result.error });
|
|
118
|
+
}
|
|
119
|
+
const { added, skipped, rejected } = result.data;
|
|
120
|
+
const allSkipped = [...skipped, ...rejected.map(r => r.text)];
|
|
121
|
+
// Update index for the findings file
|
|
122
|
+
const resolvedDir = safeProjectPath(phrenPath, project);
|
|
123
|
+
if (resolvedDir) {
|
|
124
|
+
updateFileInIndex(path.join(resolvedDir, "FINDINGS.md"));
|
|
125
|
+
}
|
|
126
|
+
return mcpResponse({
|
|
127
|
+
ok: added.length > 0,
|
|
128
|
+
message: `Extracted ${findings.length} finding(s): ${added.length} added, ${allSkipped.length} skipped (duplicates or errors).`,
|
|
129
|
+
data: { project, extracted: findings, added, skipped: allSkipped, dryRun: false },
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
}
|