@phren/cli 0.0.28 → 0.0.33
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/mcp/dist/capabilities/cli.js +2 -5
- package/mcp/dist/capabilities/mcp.js +5 -8
- package/mcp/dist/capabilities/types.js +2 -5
- package/mcp/dist/capabilities/vscode.js +2 -5
- package/mcp/dist/capabilities/web-ui.js +2 -5
- package/mcp/dist/{cli-actions.js → cli/actions.js} +25 -21
- package/mcp/dist/{cli.js → cli/cli.js} +13 -13
- package/mcp/dist/{cli-config.js → cli/config.js} +12 -12
- package/mcp/dist/{cli-extract.js → cli/extract.js} +8 -8
- package/mcp/dist/{cli-govern.js → cli/govern.js} +28 -17
- package/mcp/dist/{cli-graph.js → cli/graph.js} +10 -9
- package/mcp/dist/{cli-hooks-citations.js → cli/hooks-citations.js} +2 -2
- package/mcp/dist/{cli-hooks-context.js → cli/hooks-context.js} +23 -23
- package/mcp/dist/{cli-hooks-globs.js → cli/hooks-globs.js} +4 -4
- package/mcp/dist/{cli-hooks-output.js → cli/hooks-output.js} +9 -10
- package/mcp/dist/{cli-hooks-session.js → cli/hooks-session.js} +58 -117
- package/mcp/dist/{cli-hooks.js → cli/hooks.js} +27 -26
- package/mcp/dist/{cli-namespaces.js → cli/namespaces.js} +25 -24
- package/mcp/dist/{cli-ops.js → cli/ops.js} +9 -9
- package/mcp/dist/{cli-search.js → cli/search.js} +12 -11
- package/mcp/dist/cli-hooks-git.js +243 -0
- package/mcp/dist/cli-hooks-prompt.js +323 -0
- package/mcp/dist/cli-hooks-session-handlers.js +337 -0
- package/mcp/dist/cli-hooks-stop.js +519 -0
- package/mcp/dist/{content-archive.js → content/archive.js} +16 -29
- package/mcp/dist/{content-citation.js → content/citation.js} +5 -5
- package/mcp/dist/{content-dedup.js → content/dedup.js} +9 -12
- package/mcp/dist/{content-learning.js → content/learning.js} +41 -20
- package/mcp/dist/{content-validate.js → content/validate.js} +5 -5
- package/mcp/dist/{core-finding.js → core/finding.js} +4 -4
- package/mcp/dist/{core-project.js → core/project.js} +4 -4
- package/mcp/dist/{core-search.js → core/search.js} +2 -2
- package/mcp/dist/{data-access.js → data/access.js} +142 -15
- package/mcp/dist/{data-tasks.js → data/tasks.js} +7 -5
- package/mcp/dist/embedding.js +9 -14
- package/mcp/dist/entrypoint.js +11 -11
- package/mcp/dist/{finding-context.js → finding/context.js} +2 -2
- package/mcp/dist/{finding-impact.js → finding/impact.js} +3 -3
- package/mcp/dist/{finding-journal.js → finding/journal.js} +4 -4
- package/mcp/dist/{finding-lifecycle.js → finding/lifecycle.js} +13 -7
- package/mcp/dist/governance/audit.js +30 -0
- package/mcp/dist/{governance-locks.js → governance/locks.js} +14 -9
- package/mcp/dist/{governance-policy.js → governance/policy.js} +23 -12
- package/mcp/dist/{governance-rbac.js → governance/rbac.js} +4 -4
- package/mcp/dist/{governance-scores.js → governance/scores.js} +10 -11
- package/mcp/dist/hooks.js +53 -37
- package/mcp/dist/index-query.js +4 -1
- package/mcp/dist/index.js +54 -30
- package/mcp/dist/{init-config.js → init/config.js} +6 -6
- package/mcp/dist/{init.js → init/init.js} +80 -69
- package/mcp/dist/{init-preferences.js → init/preferences.js} +3 -3
- package/mcp/dist/{init-setup.js → init/setup.js} +17 -19
- package/mcp/dist/{init-shared.js → init/shared.js} +4 -4
- package/mcp/dist/init-bootstrap.js +21 -0
- package/mcp/dist/init-detect.js +38 -0
- package/mcp/dist/init-env.js +114 -0
- package/mcp/dist/init-fresh.js +234 -0
- package/mcp/dist/init-hooks.js +26 -0
- package/mcp/dist/init-mcp.js +65 -0
- package/mcp/dist/init-modes.js +135 -0
- package/mcp/dist/init-npm.js +37 -0
- package/mcp/dist/init-project-local.js +99 -0
- package/mcp/dist/init-semantic.js +48 -0
- package/mcp/dist/init-types.js +1 -0
- package/mcp/dist/init-uninstall.js +504 -0
- package/mcp/dist/init-update.js +96 -0
- package/mcp/dist/init-walkthrough.js +524 -0
- package/mcp/dist/{link-checksums.js → link/checksums.js} +5 -5
- package/mcp/dist/{link-context.js → link/context.js} +4 -4
- package/mcp/dist/{link-doctor.js → link/doctor.js} +20 -22
- package/mcp/dist/{link.js → link/link.js} +26 -31
- package/mcp/dist/{link-skills.js → link/skills.js} +10 -10
- package/mcp/dist/logger.js +11 -3
- package/mcp/dist/package-metadata.js +1 -1
- package/mcp/dist/phren-art.js +4 -126
- package/mcp/dist/phren-paths.js +30 -12
- package/mcp/dist/proactivity.js +3 -3
- package/mcp/dist/profile-store.js +5 -6
- package/mcp/dist/project-config.js +2 -2
- package/mcp/dist/project-topics.js +17 -47
- package/mcp/dist/provider-adapters.js +1 -1
- package/mcp/dist/query-correlation.js +1 -1
- package/mcp/dist/runtime-profile.js +1 -1
- package/mcp/dist/{session-checkpoints.js → session/checkpoints.js} +3 -3
- package/mcp/dist/{session-utils.js → session/utils.js} +1 -1
- package/mcp/dist/{shared-content.js → shared/content.js} +7 -7
- package/mcp/dist/{shared-data-utils.js → shared/data-utils.js} +28 -3
- package/mcp/dist/{shared-embedding-cache.js → shared/embedding-cache.js} +3 -3
- package/mcp/dist/{shared-fragment-graph.js → shared/fragment-graph.js} +19 -42
- package/mcp/dist/shared/governance.js +4 -0
- package/mcp/dist/{shared-index.js → shared/index.js} +105 -132
- package/mcp/dist/{shared-ollama.js → shared/ollama.js} +25 -7
- package/mcp/dist/shared/process.js +24 -0
- package/mcp/dist/{shared-retrieval.js → shared/retrieval.js} +22 -24
- package/mcp/dist/{shared-search-fallback.js → shared/search-fallback.js} +18 -20
- package/mcp/dist/{shared-sqljs.js → shared/sqljs.js} +3 -3
- package/mcp/dist/{shared-vector-index.js → shared/vector-index.js} +3 -3
- package/mcp/dist/shared.js +6 -60
- package/mcp/dist/{shell-entry.js → shell/entry.js} +6 -6
- package/mcp/dist/{shell-input.js → shell/input.js} +13 -13
- package/mcp/dist/{shell-palette.js → shell/palette.js} +3 -3
- package/mcp/dist/{shell-render.js → shell/render.js} +2 -2
- package/mcp/dist/{shell.js → shell/shell.js} +11 -11
- package/mcp/dist/{shell-state-store.js → shell/state-store.js} +5 -5
- package/mcp/dist/{shell-view-list.js → shell/view-list.js} +1 -1
- package/mcp/dist/{shell-view.js → shell/view.js} +13 -13
- package/mcp/dist/{skill-files.js → skill/files.js} +9 -9
- package/mcp/dist/{skill-registry.js → skill/registry.js} +5 -5
- package/mcp/dist/{skill-state.js → skill/state.js} +1 -4
- package/mcp/dist/startup-embedding.js +2 -2
- package/mcp/dist/status.js +15 -14
- package/mcp/dist/{tasks-github.js → task/github.js} +3 -2
- package/mcp/dist/{task-hygiene.js → task/hygiene.js} +4 -4
- package/mcp/dist/{task-lifecycle.js → task/lifecycle.js} +8 -13
- package/mcp/dist/telemetry.js +3 -4
- package/mcp/dist/tool-registry.js +29 -17
- package/mcp/dist/tools/config.js +530 -0
- package/mcp/dist/{mcp-data.js → tools/data.js} +8 -10
- package/mcp/dist/{mcp-extract-facts.js → tools/extract-facts.js} +6 -6
- package/mcp/dist/{mcp-extract.js → tools/extract.js} +6 -6
- package/mcp/dist/tools/finding.js +584 -0
- package/mcp/dist/{mcp-graph.js → tools/graph.js} +11 -14
- package/mcp/dist/{mcp-hooks.js → tools/hooks.js} +6 -6
- package/mcp/dist/{mcp-memory.js → tools/memory.js} +5 -5
- package/mcp/dist/tools/ops.js +468 -0
- package/mcp/dist/tools/search.js +672 -0
- package/mcp/dist/{mcp-session.js → tools/session.js} +51 -25
- package/mcp/dist/{mcp-skills.js → tools/skills.js} +42 -35
- package/mcp/dist/{mcp-tasks.js → tools/tasks.js} +155 -282
- package/mcp/dist/{memory-ui-data.js → ui/data.js} +31 -17
- package/mcp/dist/{memory-ui.js → ui/memory-ui.js} +3 -3
- package/mcp/dist/{memory-ui-page.js → ui/page.js} +5 -7
- package/mcp/dist/ui/server.js +1024 -0
- package/mcp/dist/update.js +2 -2
- package/mcp/dist/utils.js +63 -19
- package/package.json +2 -2
- package/scripts/preuninstall.mjs +31 -0
- package/starter/global/CLAUDE.md +3 -2
- package/mcp/dist/governance-audit.js +0 -22
- package/mcp/dist/mcp-config.js +0 -551
- package/mcp/dist/mcp-finding.js +0 -594
- package/mcp/dist/mcp-ops.js +0 -363
- package/mcp/dist/mcp-search.js +0 -668
- package/mcp/dist/memory-ui-server.js +0 -1411
- package/mcp/dist/shared-governance.js +0 -4
- /package/mcp/dist/{content-metadata.js → content/metadata.js} +0 -0
- /package/mcp/dist/{shared-stemmer.js → shared/stemmer.js} +0 -0
- /package/mcp/dist/{shell-types.js → shell/types.js} +0 -0
- /package/mcp/dist/{mcp-types.js → tools/types.js} +0 -0
- /package/mcp/dist/{memory-ui-assets.js → ui/assets.js} +0 -0
- /package/mcp/dist/{memory-ui-graph.js → ui/graph.js} +0 -0
- /package/mcp/dist/{memory-ui-scripts.js → ui/scripts.js} +0 -0
- /package/mcp/dist/{memory-ui-styles.js → ui/styles.js} +0 -0
package/mcp/dist/update.js
CHANGED
|
@@ -4,6 +4,7 @@ import { execFileSync } from "child_process";
|
|
|
4
4
|
import { fileURLToPath } from "url";
|
|
5
5
|
import { errorMessage } from "./utils.js";
|
|
6
6
|
import { PACKAGE_NAME, PACKAGE_SPEC } from "./package-metadata.js";
|
|
7
|
+
import { logger } from "./logger.js";
|
|
7
8
|
function shellCommand(bin) {
|
|
8
9
|
return process.platform === "win32" ? `${bin}.cmd` : bin;
|
|
9
10
|
}
|
|
@@ -63,8 +64,7 @@ export async function runPhrenUpdate(opts = {}) {
|
|
|
63
64
|
}
|
|
64
65
|
}
|
|
65
66
|
catch (err) {
|
|
66
|
-
|
|
67
|
-
process.stderr.write(`[phren] runPhrenUpdate gitStatus: ${errorMessage(err)}\n`);
|
|
67
|
+
logger.debug("runPhrenUpdate gitStatus", errorMessage(err));
|
|
68
68
|
}
|
|
69
69
|
const pull = run("git", ["pull", "--rebase", "--autostash"], root);
|
|
70
70
|
run(shellCommand("npm"), ["install"], root);
|
package/mcp/dist/utils.js
CHANGED
|
@@ -5,6 +5,28 @@ import * as yaml from "js-yaml";
|
|
|
5
5
|
import { fileURLToPath } from "url";
|
|
6
6
|
import { findPhrenPath } from "./phren-paths.js";
|
|
7
7
|
import { bootstrapPhrenDotEnv } from "./phren-dotenv.js";
|
|
8
|
+
// Lazy import of logDebug to break circular dependency:
|
|
9
|
+
// utils.ts -> phren-paths.ts -> logger.ts -> phren-paths.ts -> utils.ts
|
|
10
|
+
let _logDebug;
|
|
11
|
+
async function ensureLogDebug() {
|
|
12
|
+
if (!_logDebug) {
|
|
13
|
+
try {
|
|
14
|
+
const mod = await import("./logger.js");
|
|
15
|
+
_logDebug = mod.logger.debug;
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
_logDebug = () => { };
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
function getLogDebug() {
|
|
23
|
+
if (!_logDebug) {
|
|
24
|
+
// Kick off the async import for future calls; fall back to no-op for this call
|
|
25
|
+
void ensureLogDebug();
|
|
26
|
+
return () => { };
|
|
27
|
+
}
|
|
28
|
+
return _logDebug;
|
|
29
|
+
}
|
|
8
30
|
const _moduleDir = path.dirname(fileURLToPath(import.meta.url));
|
|
9
31
|
function loadSynonymsJson(fileName) {
|
|
10
32
|
const filePath = path.join(_moduleDir, fileName);
|
|
@@ -12,8 +34,7 @@ function loadSynonymsJson(fileName) {
|
|
|
12
34
|
return JSON.parse(fs.readFileSync(filePath, "utf8"));
|
|
13
35
|
}
|
|
14
36
|
catch (err) {
|
|
15
|
-
|
|
16
|
-
process.stderr.write(`[phren] ${fileName} load failed: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
37
|
+
getLogDebug()("loadSynonymsJson", `${fileName} load failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
17
38
|
return {};
|
|
18
39
|
}
|
|
19
40
|
}
|
|
@@ -148,7 +169,7 @@ export const STOP_WORDS = new Set([
|
|
|
148
169
|
export function extractKeywordEntries(text) {
|
|
149
170
|
const words = text
|
|
150
171
|
.toLowerCase()
|
|
151
|
-
.replace(/[^\
|
|
172
|
+
.replace(/[^\p{L}\p{N}\s_-]/gu, " ")
|
|
152
173
|
.split(/\s+/)
|
|
153
174
|
.filter(w => w.length > 1 && !STOP_WORDS.has(w));
|
|
154
175
|
// Build bigrams from adjacent non-stop-words
|
|
@@ -233,26 +254,27 @@ export function queueFilePath(phrenPath, project) {
|
|
|
233
254
|
}
|
|
234
255
|
return result;
|
|
235
256
|
}
|
|
257
|
+
const MAX_FTS_QUERY_LENGTH = 500;
|
|
236
258
|
// Sanitize user input before passing it to an FTS5 MATCH expression.
|
|
237
259
|
// Strips FTS5-specific syntax that could cause injection or parse errors.
|
|
238
260
|
export function sanitizeFts5Query(raw) {
|
|
239
261
|
if (!raw)
|
|
240
262
|
return "";
|
|
241
|
-
if (raw.length >
|
|
242
|
-
raw = raw.slice(0,
|
|
243
|
-
// Whitelist approach: only allow alphanumeric, spaces, hyphens, apostrophes,
|
|
244
|
-
let q = raw.replace(/[
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
//
|
|
249
|
-
// FTS5 syntax. Strip any asterisk that is not immediately preceded by a
|
|
250
|
-
// word character so the query remains valid.
|
|
263
|
+
if (raw.length > MAX_FTS_QUERY_LENGTH)
|
|
264
|
+
raw = raw.slice(0, MAX_FTS_QUERY_LENGTH);
|
|
265
|
+
// Whitelist approach: only allow alphanumeric, spaces, hyphens, apostrophes, asterisks
|
|
266
|
+
let q = raw.replace(/[^\p{L}\p{N} \-"*]/gu, " ");
|
|
267
|
+
// Strip all double quotes — buildFtsClauses wraps terms in quotes itself,
|
|
268
|
+
// so user-supplied quotes only risk producing unbalanced FTS5 syntax.
|
|
269
|
+
q = q.replace(/"/g, "");
|
|
270
|
+
// Q83: see docs/decisions/Q83-fts5-asterisk-validation.md
|
|
251
271
|
q = q.replace(/(?<!\w)\*/g, "");
|
|
252
272
|
// Also strip a trailing asterisk that is preceded only by whitespace at word
|
|
253
273
|
// end of the whole query (handles "foo *" → "foo").
|
|
254
274
|
q = q.replace(/\s+\*$/g, "");
|
|
255
|
-
|
|
275
|
+
// Normalize spaces after all stripping to avoid double spaces from removed characters
|
|
276
|
+
q = q.replace(/\s+/g, " ").trim();
|
|
277
|
+
return q;
|
|
256
278
|
}
|
|
257
279
|
function parseSynonymsYaml(filePath) {
|
|
258
280
|
if (!fs.existsSync(filePath))
|
|
@@ -276,8 +298,7 @@ function parseSynonymsYaml(filePath) {
|
|
|
276
298
|
return loaded;
|
|
277
299
|
}
|
|
278
300
|
catch (err) {
|
|
279
|
-
|
|
280
|
-
process.stderr.write(`[phren] synonyms.yaml parse failed (${filePath}): ${err instanceof Error ? err.message : String(err)}\n`);
|
|
301
|
+
getLogDebug()("parseSynonymsYaml", `synonyms.yaml parse failed (${filePath}): ${err instanceof Error ? err.message : String(err)}`);
|
|
281
302
|
return {};
|
|
282
303
|
}
|
|
283
304
|
}
|
|
@@ -315,8 +336,7 @@ function parseLearnedSynonymsJson(filePath) {
|
|
|
315
336
|
return loaded;
|
|
316
337
|
}
|
|
317
338
|
catch (err) {
|
|
318
|
-
|
|
319
|
-
process.stderr.write(`[phren] learned-synonyms parse failed (${filePath}): ${err instanceof Error ? err.message : String(err)}\n`);
|
|
339
|
+
getLogDebug()("parseLearnedSynonymsJson", `learned-synonyms parse failed (${filePath}): ${err instanceof Error ? err.message : String(err)}`);
|
|
320
340
|
return {};
|
|
321
341
|
}
|
|
322
342
|
}
|
|
@@ -512,8 +532,21 @@ export function buildRobustFtsQuery(raw, project, phrenPath) {
|
|
|
512
532
|
// nothing; it trades precision for recall while staying in the FTS index.
|
|
513
533
|
export function buildRelaxedFtsQuery(raw, project, phrenPath) {
|
|
514
534
|
const clauses = buildFtsClauses(raw, project, phrenPath);
|
|
515
|
-
if (clauses.length
|
|
535
|
+
if (clauses.length === 0)
|
|
516
536
|
return "";
|
|
537
|
+
// Short queries (1-2 terms): OR the clauses together with prefix expansion
|
|
538
|
+
if (clauses.length === 1) {
|
|
539
|
+
const term = clauses[0];
|
|
540
|
+
// Add prefix wildcard for unquoted-style terms to broaden recall
|
|
541
|
+
const inner = term.replace(/^"(.*)"$/, "$1");
|
|
542
|
+
if (inner.length >= 3) {
|
|
543
|
+
return `(${term} OR "${inner}"*)`;
|
|
544
|
+
}
|
|
545
|
+
return term;
|
|
546
|
+
}
|
|
547
|
+
if (clauses.length === 2) {
|
|
548
|
+
return `(${clauses[0]} OR ${clauses[1]})`;
|
|
549
|
+
}
|
|
517
550
|
const salientClauses = clauses
|
|
518
551
|
.map((clause, index) => ({ clause, index, score: clauseSignalScore(clause) }))
|
|
519
552
|
.sort((a, b) => {
|
|
@@ -539,5 +572,16 @@ export function buildFtsQueryVariants(raw, project, phrenPath) {
|
|
|
539
572
|
buildRobustFtsQuery(raw, project, phrenPath),
|
|
540
573
|
buildRelaxedFtsQuery(raw, project, phrenPath),
|
|
541
574
|
].filter(Boolean);
|
|
575
|
+
// For short queries, add a prefix-expanded variant to catch partial matches
|
|
576
|
+
const clauses = buildFtsClauses(raw, project, phrenPath);
|
|
577
|
+
if (clauses.length <= 2) {
|
|
578
|
+
const prefixParts = clauses
|
|
579
|
+
.map(c => c.replace(/^"(.*)"$/, "$1"))
|
|
580
|
+
.filter(t => t.length >= 3)
|
|
581
|
+
.map(t => `"${t}"*`);
|
|
582
|
+
if (prefixParts.length > 0) {
|
|
583
|
+
variants.push(prefixParts.join(" OR "));
|
|
584
|
+
}
|
|
585
|
+
}
|
|
542
586
|
return [...new Set(variants)];
|
|
543
587
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@phren/cli",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.33",
|
|
4
4
|
"description": "Knowledge layer for AI agents. Phren learns and recalls.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -16,7 +16,6 @@
|
|
|
16
16
|
"dependencies": {
|
|
17
17
|
"@modelcontextprotocol/sdk": "^1.27.1",
|
|
18
18
|
"chalk": "^5.6.2",
|
|
19
|
-
"esbuild": "^0.27.4",
|
|
20
19
|
"glob": "^13.0.6",
|
|
21
20
|
"graphology": "^0.26.0",
|
|
22
21
|
"graphology-layout-forceatlas2": "^0.10.1",
|
|
@@ -27,6 +26,7 @@
|
|
|
27
26
|
"zod": "^4.3.6"
|
|
28
27
|
},
|
|
29
28
|
"devDependencies": {
|
|
29
|
+
"esbuild": "^0.27.4",
|
|
30
30
|
"@playwright/test": "^1.58.2",
|
|
31
31
|
"@types/js-yaml": "^4.0.9",
|
|
32
32
|
"@types/node": "^25.5.0",
|
package/scripts/preuninstall.mjs
CHANGED
|
@@ -105,4 +105,35 @@ if (fs.existsSync(copilotHooks)) {
|
|
|
105
105
|
try { fs.unlinkSync(copilotHooks); } catch { /* best-effort */ }
|
|
106
106
|
}
|
|
107
107
|
|
|
108
|
+
// ── Codex MCP config (TOML + JSON) ──
|
|
109
|
+
const codexToml = homePath(".codex", "config.toml");
|
|
110
|
+
if (fs.existsSync(codexToml)) {
|
|
111
|
+
try {
|
|
112
|
+
const content = fs.readFileSync(codexToml, "utf8");
|
|
113
|
+
// Remove [mcp_servers.phren] section
|
|
114
|
+
const cleaned = content.replace(/\[mcp_servers\.phren\][^\[]*/, "").trim();
|
|
115
|
+
if (cleaned !== content.trim()) fs.writeFileSync(codexToml, cleaned + "\n");
|
|
116
|
+
} catch { /* best-effort */ }
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// ── Session wrapper scripts ──
|
|
120
|
+
const localBinDir = homePath(".local", "bin");
|
|
121
|
+
for (const tool of ["copilot", "cursor", "codex"]) {
|
|
122
|
+
const wrapperPath = path.join(localBinDir, tool);
|
|
123
|
+
try {
|
|
124
|
+
if (fs.existsSync(wrapperPath)) {
|
|
125
|
+
const content = fs.readFileSync(wrapperPath, "utf8");
|
|
126
|
+
if (content.includes("PHREN_PATH") && content.includes("phren")) {
|
|
127
|
+
fs.unlinkSync(wrapperPath);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
} catch { /* best-effort */ }
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// ── Machine context file ──
|
|
134
|
+
const contextFile = homePath(".phren-context.md");
|
|
135
|
+
if (fs.existsSync(contextFile)) {
|
|
136
|
+
try { fs.unlinkSync(contextFile); } catch { /* best-effort */ }
|
|
137
|
+
}
|
|
138
|
+
|
|
108
139
|
console.log("phren: cleaned up hooks and MCP config from agent settings.");
|
package/starter/global/CLAUDE.md
CHANGED
|
@@ -19,9 +19,10 @@ These skills are available as a full set via phren, or individually from the Cla
|
|
|
19
19
|
| Skill | What it does |
|
|
20
20
|
|-------|-------------|
|
|
21
21
|
| `/phren-sync` | Pull phren to a new machine or push config changes back to the repo |
|
|
22
|
-
| `/phren-init` | Scaffold a new project with summary, CLAUDE.md,
|
|
22
|
+
| `/phren-init` | Scaffold a new project with summary, CLAUDE.md, tasks |
|
|
23
23
|
| `/phren-discover` | Research what's missing in a project and surface gaps and opportunities |
|
|
24
24
|
| `/phren-consolidate` | Find patterns across all project FINDINGS.md files |
|
|
25
|
+
| `/phren-profiles` | Manages machine-to-profile mapping |
|
|
25
26
|
|
|
26
27
|
### Your own skills
|
|
27
28
|
|
|
@@ -48,7 +49,7 @@ In shared mode, skills and project config live in `~/.phren` (or wherever `PHREN
|
|
|
48
49
|
If you're using `phren init --mode project-local`, the root is `<repo>/.phren` instead. Project-local mode does not use profiles, machine mappings, or global hooks.
|
|
49
50
|
|
|
50
51
|
- `~/.phren/global/`: skills and config that apply everywhere
|
|
51
|
-
- `~/.phren/<project>/`: per-project CLAUDE.md, skills,
|
|
52
|
+
- `~/.phren/<project>/`: per-project CLAUDE.md, skills, tasks, findings
|
|
52
53
|
- `~/.phren/profiles/`: YAML files mapping project sets to machine roles
|
|
53
54
|
- `~/.phren/machines.yaml`: maps machine hostnames to profiles
|
|
54
55
|
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import * as fs from "fs";
|
|
2
|
-
import * as path from "path";
|
|
3
|
-
import { debugLog } from "./shared.js";
|
|
4
|
-
import { errorMessage } from "./utils.js";
|
|
5
|
-
export function recordRetrieval(phrenPath, file, section) {
|
|
6
|
-
const dir = path.join(phrenPath, ".runtime");
|
|
7
|
-
fs.mkdirSync(dir, { recursive: true });
|
|
8
|
-
const logPath = path.join(dir, "retrieval-log.jsonl");
|
|
9
|
-
const entry = { file, section, retrievedAt: new Date().toISOString() };
|
|
10
|
-
fs.appendFileSync(logPath, JSON.stringify(entry) + "\n");
|
|
11
|
-
try {
|
|
12
|
-
const stat = fs.statSync(logPath);
|
|
13
|
-
if (stat.size > 500_000) {
|
|
14
|
-
const content = fs.readFileSync(logPath, "utf8");
|
|
15
|
-
const lines = content.split("\n").filter(Boolean);
|
|
16
|
-
fs.writeFileSync(logPath, lines.slice(-1000).join("\n") + "\n");
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
catch (err) {
|
|
20
|
-
debugLog(`recordRetrieval rotation failed: ${errorMessage(err)}`);
|
|
21
|
-
}
|
|
22
|
-
}
|