@phren/cli 0.0.36 → 0.0.38
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/cli-hooks-stop.js +28 -0
- package/mcp/dist/content/learning.js +2 -2
- package/mcp/dist/governance/locks.js +5 -34
- package/mcp/dist/governance/policy.js +2 -2
- package/mcp/dist/init/init-configure.js +338 -0
- package/mcp/dist/init/init-hooks-mode.js +57 -0
- package/mcp/dist/init/init-mcp-mode.js +80 -0
- package/mcp/dist/init/init-uninstall.js +493 -0
- package/mcp/dist/init/init-walkthrough.js +524 -0
- package/mcp/dist/init/init.js +18 -1447
- package/mcp/dist/init/setup.js +15 -5
- package/mcp/dist/init-uninstall.js +11 -2
- package/mcp/dist/phren-paths.js +20 -3
- package/mcp/dist/shared/index.js +8 -0
- package/mcp/dist/task/lifecycle.js +1 -1
- package/package.json +2 -1
package/mcp/dist/init/setup.js
CHANGED
|
@@ -884,15 +884,25 @@ export function ensureProjectScaffold(projectDir, projectName, domain = "softwar
|
|
|
884
884
|
}
|
|
885
885
|
}
|
|
886
886
|
export function ensureLocalGitRepo(phrenPath) {
|
|
887
|
+
// Check if phrenPath already has its own git repo (not just being inside a parent)
|
|
887
888
|
try {
|
|
888
|
-
execFileSync("git", ["-C", phrenPath, "rev-parse", "--
|
|
889
|
-
|
|
889
|
+
const topLevel = execFileSync("git", ["-C", phrenPath, "rev-parse", "--show-toplevel"], {
|
|
890
|
+
encoding: "utf8",
|
|
891
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
890
892
|
timeout: EXEC_TIMEOUT_QUICK_MS,
|
|
891
|
-
});
|
|
892
|
-
|
|
893
|
+
}).trim();
|
|
894
|
+
const resolvedTopLevel = path.resolve(topLevel);
|
|
895
|
+
const resolvedPhrenPath = path.resolve(phrenPath);
|
|
896
|
+
if (resolvedTopLevel === resolvedPhrenPath) {
|
|
897
|
+
// phrenPath IS the repo root — it has its own git repo
|
|
898
|
+
return { ok: true, initialized: false, detail: "existing git repo" };
|
|
899
|
+
}
|
|
900
|
+
// phrenPath is inside a parent repo — skip nested init
|
|
901
|
+
logger.warn("init", `Skipping git init: ${resolvedPhrenPath} is inside existing repo ${resolvedTopLevel}`);
|
|
902
|
+
return { ok: true, initialized: false, detail: `skipped: inside existing repo ${resolvedTopLevel}` };
|
|
893
903
|
}
|
|
894
904
|
catch {
|
|
895
|
-
//
|
|
905
|
+
// Not inside any git repo — fall through to initialization below.
|
|
896
906
|
}
|
|
897
907
|
try {
|
|
898
908
|
try {
|
|
@@ -170,8 +170,17 @@ function filterAgentHooks(filePath, commandField) {
|
|
|
170
170
|
return true;
|
|
171
171
|
}
|
|
172
172
|
catch (err) {
|
|
173
|
-
|
|
174
|
-
|
|
173
|
+
// JSON parse or other failure — back up the corrupted file so uninstall can proceed
|
|
174
|
+
const bakPath = filePath + ".bak";
|
|
175
|
+
try {
|
|
176
|
+
fs.renameSync(filePath, bakPath);
|
|
177
|
+
log(` Warning: corrupted hook config backed up to ${bakPath} (${errorMessage(err)})`);
|
|
178
|
+
}
|
|
179
|
+
catch (bakErr) {
|
|
180
|
+
debugLog(`filterAgentHooks: backup failed for ${filePath}: ${errorMessage(bakErr)}`);
|
|
181
|
+
log(` Warning: could not process hook config ${filePath}: ${errorMessage(err)}`);
|
|
182
|
+
}
|
|
183
|
+
return true;
|
|
175
184
|
}
|
|
176
185
|
}
|
|
177
186
|
async function promptUninstallConfirm(phrenPath) {
|
package/mcp/dist/phren-paths.js
CHANGED
|
@@ -35,7 +35,16 @@ export function atomicWriteText(filePath, content) {
|
|
|
35
35
|
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
36
36
|
const tmpPath = `${filePath}.tmp-${crypto.randomUUID()}`;
|
|
37
37
|
fs.writeFileSync(tmpPath, content);
|
|
38
|
-
|
|
38
|
+
try {
|
|
39
|
+
fs.renameSync(tmpPath, filePath);
|
|
40
|
+
}
|
|
41
|
+
catch (err) {
|
|
42
|
+
try {
|
|
43
|
+
fs.unlinkSync(tmpPath);
|
|
44
|
+
}
|
|
45
|
+
catch { }
|
|
46
|
+
throw err;
|
|
47
|
+
}
|
|
39
48
|
}
|
|
40
49
|
function isInstallMode(value) {
|
|
41
50
|
return value === "shared" || value === "project-local";
|
|
@@ -51,8 +60,16 @@ function normalizeManifest(raw) {
|
|
|
51
60
|
const syncMode = raw.syncMode;
|
|
52
61
|
if (version !== 1 || !isInstallMode(installMode) || !isSyncMode(syncMode))
|
|
53
62
|
return null;
|
|
54
|
-
|
|
55
|
-
?
|
|
63
|
+
let workspaceRootRaw = typeof raw.workspaceRoot === "string" && raw.workspaceRoot.trim()
|
|
64
|
+
? raw.workspaceRoot.trim()
|
|
65
|
+
: undefined;
|
|
66
|
+
// Cross-platform path normalization: convert Windows backslashes to forward slashes
|
|
67
|
+
// when reading on a non-Windows platform (e.g. manifest created on Windows, read on Linux).
|
|
68
|
+
if (workspaceRootRaw && process.platform !== "win32") {
|
|
69
|
+
workspaceRootRaw = workspaceRootRaw.replace(/\\/g, "/");
|
|
70
|
+
}
|
|
71
|
+
const workspaceRoot = workspaceRootRaw
|
|
72
|
+
? path.resolve(expandHomePath(workspaceRootRaw))
|
|
56
73
|
: undefined;
|
|
57
74
|
const primaryProject = typeof raw.primaryProject === "string" && raw.primaryProject.trim()
|
|
58
75
|
? raw.primaryProject.trim()
|
package/mcp/dist/shared/index.js
CHANGED
|
@@ -22,7 +22,13 @@ export { buildSourceDocKey, decodeFiniteNumber, decodeStringRow, extractSnippet,
|
|
|
22
22
|
// ── Async embedding queue ───────────────────────────────────────────────────
|
|
23
23
|
const _embQueue = new Map();
|
|
24
24
|
let _embTimer = null;
|
|
25
|
+
const MAX_EMB_QUEUE = 500;
|
|
25
26
|
function scheduleEmbedding(phrenPath, docPath, content) {
|
|
27
|
+
if (_embQueue.size >= MAX_EMB_QUEUE) {
|
|
28
|
+
const oldest = _embQueue.keys().next().value;
|
|
29
|
+
if (oldest !== undefined)
|
|
30
|
+
_embQueue.delete(oldest);
|
|
31
|
+
}
|
|
26
32
|
_embQueue.set(docPath, { phrenPath, content });
|
|
27
33
|
if (_embTimer)
|
|
28
34
|
clearTimeout(_embTimer);
|
|
@@ -63,6 +69,7 @@ async function _drainEmbQueue() {
|
|
|
63
69
|
}
|
|
64
70
|
catch (err) {
|
|
65
71
|
logger.debug("embeddingQueue embedText", errorMessage(err));
|
|
72
|
+
_embQueue.clear();
|
|
66
73
|
}
|
|
67
74
|
}
|
|
68
75
|
try {
|
|
@@ -70,6 +77,7 @@ async function _drainEmbQueue() {
|
|
|
70
77
|
}
|
|
71
78
|
catch (err) {
|
|
72
79
|
logger.debug("embeddingQueue cacheFlush", errorMessage(err));
|
|
80
|
+
_embQueue.clear();
|
|
73
81
|
}
|
|
74
82
|
}
|
|
75
83
|
}
|
|
@@ -302,7 +302,7 @@ export function finalizeTaskSession(args) {
|
|
|
302
302
|
if (!state || state.mode !== "auto")
|
|
303
303
|
return;
|
|
304
304
|
const match = state.stableId ? `bid:${state.stableId}` : state.item;
|
|
305
|
-
if (args.status === "saved-local" || args.status === "saved-pushed") {
|
|
305
|
+
if (args.status === "saved-local" || args.status === "saved-pushed" || args.status === "no-upstream") {
|
|
306
306
|
const completed = completeTask(args.phrenPath, state.project, match);
|
|
307
307
|
if (!completed.ok) {
|
|
308
308
|
debugLog(`task lifecycle complete ${state.project}: ${completed.error}`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@phren/cli",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.38",
|
|
4
4
|
"description": "Knowledge layer for AI agents. Phren learns and recalls.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -51,6 +51,7 @@
|
|
|
51
51
|
"bench:retrieval": "tsx scripts/bench-retrieval-modes.ts",
|
|
52
52
|
"bench:retrieval:synthetic": "tsx scripts/bench-retrieval-synthetic.ts",
|
|
53
53
|
"preuninstall": "node scripts/preuninstall.mjs",
|
|
54
|
+
"install-hooks": "cp scripts/pre-commit .git/hooks/pre-commit && chmod +x .git/hooks/pre-commit",
|
|
54
55
|
"prepublishOnly": "npm run build && npm test"
|
|
55
56
|
},
|
|
56
57
|
"engines": {
|