@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/index.js
CHANGED
|
@@ -4,22 +4,22 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
|
|
|
4
4
|
import * as fs from "fs";
|
|
5
5
|
import * as path from "path";
|
|
6
6
|
import { findPhrenPathWithArg, debugLog, runtimeDir, } from "./shared.js";
|
|
7
|
-
import { log as structuredLog } from "./logger.js";
|
|
8
|
-
import { buildIndex, updateFileInIndex as updateFileInIndexFn, } from "./shared
|
|
7
|
+
import { log as structuredLog, logger } from "./logger.js";
|
|
8
|
+
import { buildIndex, updateFileInIndex as updateFileInIndexFn, } from "./shared/index.js";
|
|
9
9
|
import { runCustomHooks } from "./hooks.js";
|
|
10
|
-
import { register as registerSearch } from "./
|
|
11
|
-
import { register as registerTask } from "./
|
|
12
|
-
import { register as registerFinding } from "./
|
|
13
|
-
import { register as registerMemory } from "./
|
|
14
|
-
import { register as registerData } from "./
|
|
15
|
-
import { register as registerGraph } from "./
|
|
16
|
-
import { register as registerSession } from "./
|
|
17
|
-
import { register as registerOps } from "./
|
|
18
|
-
import { register as registerSkills } from "./
|
|
19
|
-
import { register as registerHooks } from "./
|
|
20
|
-
import { register as registerExtract } from "./
|
|
21
|
-
import { register as registerConfig } from "./
|
|
22
|
-
import { mcpResponse } from "./
|
|
10
|
+
import { register as registerSearch } from "./tools/search.js";
|
|
11
|
+
import { register as registerTask } from "./tools/tasks.js";
|
|
12
|
+
import { register as registerFinding } from "./tools/finding.js";
|
|
13
|
+
import { register as registerMemory } from "./tools/memory.js";
|
|
14
|
+
import { register as registerData } from "./tools/data.js";
|
|
15
|
+
import { register as registerGraph } from "./tools/graph.js";
|
|
16
|
+
import { register as registerSession } from "./tools/session.js";
|
|
17
|
+
import { register as registerOps } from "./tools/ops.js";
|
|
18
|
+
import { register as registerSkills } from "./tools/skills.js";
|
|
19
|
+
import { register as registerHooks } from "./tools/hooks.js";
|
|
20
|
+
import { register as registerExtract } from "./tools/extract.js";
|
|
21
|
+
import { register as registerConfig } from "./tools/config.js";
|
|
22
|
+
import { mcpResponse } from "./tools/types.js";
|
|
23
23
|
import { errorMessage } from "./utils.js";
|
|
24
24
|
import { runTopLevelCommand } from "./entrypoint.js";
|
|
25
25
|
import { startEmbeddingWarmup } from "./startup-embedding.js";
|
|
@@ -48,14 +48,12 @@ function cleanStaleLocks(phrenPath) {
|
|
|
48
48
|
}
|
|
49
49
|
}
|
|
50
50
|
catch (err) {
|
|
51
|
-
|
|
52
|
-
process.stderr.write(`[phren] cleanStaleLocks statFile: ${errorMessage(err)}\n`);
|
|
51
|
+
logger.warn("cleanStaleLocks", `statFile: ${errorMessage(err)}`);
|
|
53
52
|
}
|
|
54
53
|
}
|
|
55
54
|
}
|
|
56
55
|
catch (err) {
|
|
57
|
-
|
|
58
|
-
process.stderr.write(`[phren] cleanStaleLocks readdir: ${errorMessage(err)}\n`);
|
|
56
|
+
logger.warn("cleanStaleLocks", `readdir: ${errorMessage(err)}`);
|
|
59
57
|
}
|
|
60
58
|
}
|
|
61
59
|
async function main() {
|
|
@@ -67,14 +65,14 @@ async function main() {
|
|
|
67
65
|
db = await buildIndex(phrenPath, profile);
|
|
68
66
|
indexReady = true;
|
|
69
67
|
// Load embedding cache and kick off background embedding (fire-and-forget)
|
|
70
|
-
const { getEmbeddingCache } = await import("./shared
|
|
68
|
+
const { getEmbeddingCache } = await import("./shared/embedding-cache.js");
|
|
71
69
|
const embCache = getEmbeddingCache(phrenPath);
|
|
72
70
|
void startEmbeddingWarmup(db, embCache);
|
|
73
71
|
}
|
|
74
72
|
catch (error) {
|
|
75
73
|
const msg = error instanceof Error ? error.message : String(error);
|
|
76
74
|
structuredLog("error", "startup", `Failed to build phren index: ${msg}`);
|
|
77
|
-
console.error("Failed to build phren index at startup:",
|
|
75
|
+
console.error("Failed to build phren index at startup:", msg);
|
|
78
76
|
process.exit(1);
|
|
79
77
|
}
|
|
80
78
|
let writeQueue = Promise.resolve();
|
|
@@ -83,21 +81,29 @@ async function main() {
|
|
|
83
81
|
const WRITE_TIMEOUT_MS = 30_000;
|
|
84
82
|
async function rebuildIndex() {
|
|
85
83
|
runCustomHooks(phrenPath, "pre-index");
|
|
86
|
-
|
|
84
|
+
const oldDb = db;
|
|
87
85
|
try {
|
|
88
|
-
|
|
86
|
+
indexReady = false;
|
|
87
|
+
db = await buildIndex(phrenPath, profile);
|
|
88
|
+
indexReady = true;
|
|
89
|
+
try {
|
|
90
|
+
oldDb?.close();
|
|
91
|
+
}
|
|
92
|
+
catch (err) {
|
|
93
|
+
logger.warn("rebuildIndex", `dbClose: ${errorMessage(err)}`);
|
|
94
|
+
}
|
|
89
95
|
}
|
|
90
96
|
catch (err) {
|
|
91
|
-
|
|
92
|
-
|
|
97
|
+
// Restore old state on failure
|
|
98
|
+
db = oldDb;
|
|
99
|
+
indexReady = !!oldDb;
|
|
100
|
+
throw err;
|
|
93
101
|
}
|
|
94
|
-
db = await buildIndex(phrenPath, profile);
|
|
95
|
-
indexReady = true;
|
|
96
102
|
runCustomHooks(phrenPath, "post-index");
|
|
97
103
|
}
|
|
98
104
|
async function withWriteQueue(fn) {
|
|
99
105
|
if (writeQueueDepth >= MAX_QUEUE_DEPTH) {
|
|
100
|
-
|
|
106
|
+
return mcpResponse({ ok: false, error: `Write queue full (${MAX_QUEUE_DEPTH} items). Try again shortly.`, errorCode: "TIMEOUT" });
|
|
101
107
|
}
|
|
102
108
|
writeQueueDepth++;
|
|
103
109
|
const run = writeQueue.then(async () => {
|
|
@@ -158,8 +164,7 @@ async function main() {
|
|
|
158
164
|
trackToolCall(phrenPath, registeredName);
|
|
159
165
|
}
|
|
160
166
|
catch (err) {
|
|
161
|
-
|
|
162
|
-
process.stderr.write(`[phren] trackToolCall: ${errorMessage(err)}\n`);
|
|
167
|
+
logger.warn("trackToolCall", errorMessage(err));
|
|
163
168
|
}
|
|
164
169
|
return handler(...args);
|
|
165
170
|
};
|
|
@@ -197,6 +202,25 @@ async function main() {
|
|
|
197
202
|
const transport = new StdioServerTransport();
|
|
198
203
|
await server.connect(transport);
|
|
199
204
|
console.error(`phren-mcp running (${phrenPath})`);
|
|
205
|
+
// Graceful shutdown: drain write queue and close DB before exit
|
|
206
|
+
async function shutdown(signal) {
|
|
207
|
+
structuredLog("info", "shutdown", `Received ${signal}, draining write queue...`);
|
|
208
|
+
try {
|
|
209
|
+
await writeQueue;
|
|
210
|
+
}
|
|
211
|
+
catch {
|
|
212
|
+
// Write queue errors already logged
|
|
213
|
+
}
|
|
214
|
+
try {
|
|
215
|
+
db?.close();
|
|
216
|
+
}
|
|
217
|
+
catch (err) {
|
|
218
|
+
logger.warn("shutdown", `dbClose: ${errorMessage(err)}`);
|
|
219
|
+
}
|
|
220
|
+
process.exit(0);
|
|
221
|
+
}
|
|
222
|
+
process.on("SIGTERM", () => void shutdown("SIGTERM"));
|
|
223
|
+
process.on("SIGINT", () => void shutdown("SIGINT"));
|
|
200
224
|
}
|
|
201
225
|
if (!handledTopLevelCommand) {
|
|
202
226
|
main().catch((err) => {
|
|
@@ -4,12 +4,12 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import * as fs from "fs";
|
|
6
6
|
import * as path from "path";
|
|
7
|
-
import { buildLifecycleCommands, commandExists } from "
|
|
8
|
-
import { isRecord, hookConfigPath, homePath, readRootManifest, atomicWriteText, } from "
|
|
9
|
-
import { isFeatureEnabled, errorMessage } from "
|
|
10
|
-
import { probeVsCodeConfig, resolveCodexMcpConfig, resolveCopilotMcpConfig, resolveCursorMcpConfig, } from "
|
|
11
|
-
import { getMcpEnabledPreference, getHooksEnabledPreference } from "./
|
|
12
|
-
import { resolveEntryScript, log, VERSION } from "./
|
|
7
|
+
import { buildLifecycleCommands, commandExists } from "../hooks.js";
|
|
8
|
+
import { isRecord, hookConfigPath, homePath, readRootManifest, atomicWriteText, } from "../shared.js";
|
|
9
|
+
import { isFeatureEnabled, errorMessage } from "../utils.js";
|
|
10
|
+
import { probeVsCodeConfig, resolveCodexMcpConfig, resolveCopilotMcpConfig, resolveCursorMcpConfig, } from "../provider-adapters.js";
|
|
11
|
+
import { getMcpEnabledPreference, getHooksEnabledPreference } from "./preferences.js";
|
|
12
|
+
import { resolveEntryScript, log, VERSION } from "./shared.js";
|
|
13
13
|
function getObjectProp(value, key) {
|
|
14
14
|
const candidate = value[key];
|
|
15
15
|
return isRecord(candidate) ? candidate : undefined;
|
|
@@ -6,24 +6,25 @@ import * as fs from "fs";
|
|
|
6
6
|
import * as path from "path";
|
|
7
7
|
import * as crypto from "crypto";
|
|
8
8
|
import { execFileSync, spawnSync } from "child_process";
|
|
9
|
-
import { configureAllHooks } from "
|
|
10
|
-
import { getMachineName, machineFilePath, persistMachineName } from "
|
|
11
|
-
import { atomicWriteText, debugLog, isRecord, hookConfigPath, homeDir, homePath, expandHomePath, findPhrenPath, getProjectDirs, readRootManifest, writeRootManifest, } from "
|
|
12
|
-
import { isValidProjectName, errorMessage } from "
|
|
13
|
-
import { codexJsonCandidates, copilotMcpCandidates, cursorMcpCandidates, vscodeMcpCandidates, } from "
|
|
14
|
-
|
|
15
|
-
export {
|
|
16
|
-
export {
|
|
17
|
-
export {
|
|
18
|
-
export {
|
|
9
|
+
import { configureAllHooks } from "../hooks.js";
|
|
10
|
+
import { getMachineName, machineFilePath, persistMachineName } from "../machine-identity.js";
|
|
11
|
+
import { atomicWriteText, debugLog, isRecord, hookConfigPath, homeDir, homePath, expandHomePath, findPhrenPath, getProjectDirs, readRootManifest, writeRootManifest, } from "../shared.js";
|
|
12
|
+
import { isValidProjectName, errorMessage } from "../utils.js";
|
|
13
|
+
import { codexJsonCandidates, copilotMcpCandidates, cursorMcpCandidates, vscodeMcpCandidates, } from "../provider-adapters.js";
|
|
14
|
+
import { logger } from "../logger.js";
|
|
15
|
+
export { configureClaude, configureVSCode, configureCursorMcp, configureCopilotMcp, configureCodexMcp, logMcpTargetStatus, resetVSCodeProbeCache, patchJsonFile, } from "./config.js";
|
|
16
|
+
export { getMcpEnabledPreference, setMcpEnabledPreference, getHooksEnabledPreference, setHooksEnabledPreference, } from "./preferences.js";
|
|
17
|
+
export { PROJECT_OWNERSHIP_MODES, parseProjectOwnershipMode, getProjectOwnershipDefault, } from "../project-config.js";
|
|
18
|
+
export { PROACTIVITY_LEVELS, getProactivityLevel, getProactivityLevelForFindings, getProactivityLevelForTask, } from "../proactivity.js";
|
|
19
|
+
export { ensureGovernanceFiles, repairPreexistingInstall, runPostInitVerify, getVerifyOutcomeNote, listTemplates, detectProjectDir, isProjectTracked, ensureLocalGitRepo, resolvePreferredHomeDir, inferInitScaffoldFromRepo, } from "./setup.js";
|
|
19
20
|
// Imports from helpers (used internally in this file)
|
|
20
|
-
import { configureClaude, configureVSCode, configureCursorMcp, configureCopilotMcp, configureCodexMcp, logMcpTargetStatus, removeMcpServerAtPath, removeTomlMcpServer, isPhrenCommand, patchJsonFile, } from "./
|
|
21
|
-
import { getMcpEnabledPreference, getHooksEnabledPreference, setMcpEnabledPreference, setHooksEnabledPreference, writeInstallPreferences, writeGovernanceInstallPreferences, readInstallPreferences, } from "./
|
|
22
|
-
import { ensureGovernanceFiles, repairPreexistingInstall, runPostInitVerify, applyStarterTemplateUpdates, listTemplates, applyTemplate, ensureProjectScaffold, ensureLocalGitRepo, bootstrapFromExisting, ensureGitignoreEntry, upsertProjectEnvVar, updateMachinesYaml, detectProjectDir, isProjectTracked, inferInitScaffoldFromRepo, } from "./
|
|
23
|
-
import { DEFAULT_PHREN_PATH, STARTER_DIR, VERSION, log, confirmPrompt } from "./
|
|
24
|
-
import { PROJECT_OWNERSHIP_MODES, getProjectOwnershipDefault, } from "
|
|
25
|
-
import { getWorkflowPolicy, updateWorkflowPolicy } from "
|
|
26
|
-
import { addProjectToProfile } from "
|
|
21
|
+
import { configureClaude, configureVSCode, configureCursorMcp, configureCopilotMcp, configureCodexMcp, logMcpTargetStatus, removeMcpServerAtPath, removeTomlMcpServer, isPhrenCommand, patchJsonFile, } from "./config.js";
|
|
22
|
+
import { getMcpEnabledPreference, getHooksEnabledPreference, setMcpEnabledPreference, setHooksEnabledPreference, writeInstallPreferences, writeGovernanceInstallPreferences, readInstallPreferences, } from "./preferences.js";
|
|
23
|
+
import { ensureGovernanceFiles, repairPreexistingInstall, runPostInitVerify, applyStarterTemplateUpdates, listTemplates, applyTemplate, ensureProjectScaffold, ensureLocalGitRepo, bootstrapFromExisting, ensureGitignoreEntry, upsertProjectEnvVar, updateMachinesYaml, detectProjectDir, isProjectTracked, inferInitScaffoldFromRepo, } from "./setup.js";
|
|
24
|
+
import { DEFAULT_PHREN_PATH, STARTER_DIR, VERSION, log, confirmPrompt } from "./shared.js";
|
|
25
|
+
import { PROJECT_OWNERSHIP_MODES, getProjectOwnershipDefault, } from "../project-config.js";
|
|
26
|
+
import { getWorkflowPolicy, updateWorkflowPolicy } from "../shared/governance.js";
|
|
27
|
+
import { addProjectToProfile } from "../profile-store.js";
|
|
27
28
|
const PHREN_NPM_PACKAGE_NAME = "@phren/cli";
|
|
28
29
|
function parseVersion(version) {
|
|
29
30
|
const match = version.trim().match(/^(\d+)\.(\d+)\.(\d+)(?:-(.+))?/);
|
|
@@ -289,7 +290,7 @@ async function runWalkthrough(phrenPath) {
|
|
|
289
290
|
log(style.success(`✓ ${item}`));
|
|
290
291
|
}
|
|
291
292
|
};
|
|
292
|
-
const { renderPhrenArt } = await import("
|
|
293
|
+
const { renderPhrenArt } = await import("../phren-art.js");
|
|
293
294
|
log("");
|
|
294
295
|
log(renderPhrenArt(" "));
|
|
295
296
|
log("");
|
|
@@ -434,37 +435,31 @@ async function runWalkthrough(phrenPath) {
|
|
|
434
435
|
log(" Change later: set PHREN_OLLAMA_URL=off to disable");
|
|
435
436
|
let ollamaEnabled = false;
|
|
436
437
|
try {
|
|
437
|
-
const {
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
ollamaEnabled = await prompts.confirm("Enable semantic search for fuzzy/paraphrase recovery? (will pull nomic-embed-text)", false);
|
|
449
|
-
if (ollamaEnabled) {
|
|
450
|
-
log(" Run after init: ollama pull nomic-embed-text");
|
|
451
|
-
}
|
|
452
|
-
}
|
|
438
|
+
const { checkOllamaStatus } = await import("../shared/ollama.js");
|
|
439
|
+
const status = await checkOllamaStatus();
|
|
440
|
+
if (status === "ready") {
|
|
441
|
+
log(" Ollama detected with nomic-embed-text ready.");
|
|
442
|
+
ollamaEnabled = await prompts.confirm("Enable semantic search for fuzzy/paraphrase recovery?", false);
|
|
443
|
+
}
|
|
444
|
+
else if (status === "no_model") {
|
|
445
|
+
log(" Ollama detected, but nomic-embed-text is not pulled yet.");
|
|
446
|
+
ollamaEnabled = await prompts.confirm("Enable semantic search for fuzzy/paraphrase recovery? (will pull nomic-embed-text)", false);
|
|
447
|
+
if (ollamaEnabled) {
|
|
448
|
+
log(" Run after init: ollama pull nomic-embed-text");
|
|
453
449
|
}
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
450
|
+
}
|
|
451
|
+
else if (status === "not_running") {
|
|
452
|
+
log(" Ollama not detected. Install it to enable semantic search:");
|
|
453
|
+
log(" https://ollama.com → then: ollama pull nomic-embed-text");
|
|
454
|
+
ollamaEnabled = await prompts.confirm("Enable semantic search (Ollama not installed yet)?", false);
|
|
455
|
+
if (ollamaEnabled) {
|
|
456
|
+
log(style.success(" Semantic search enabled — will activate once Ollama is running."));
|
|
457
|
+
log(" To disable: set PHREN_OLLAMA_URL=off in your shell profile");
|
|
462
458
|
}
|
|
463
459
|
}
|
|
464
460
|
}
|
|
465
461
|
catch (err) {
|
|
466
|
-
|
|
467
|
-
process.stderr.write(`[phren] init ollamaCheck: ${errorMessage(err)}\n`);
|
|
462
|
+
logger.debug("init", `init ollamaCheck: ${errorMessage(err)}`);
|
|
468
463
|
}
|
|
469
464
|
printSection("Auto-Capture (Optional)");
|
|
470
465
|
log("After each session, phren scans the conversation for insight-signal phrases");
|
|
@@ -663,7 +658,7 @@ async function runWalkthrough(phrenPath) {
|
|
|
663
658
|
};
|
|
664
659
|
}
|
|
665
660
|
export async function warmSemanticSearch(phrenPath, profile) {
|
|
666
|
-
const { checkOllamaAvailable, checkModelAvailable, getOllamaUrl, getEmbeddingModel } = await import("
|
|
661
|
+
const { checkOllamaAvailable, checkModelAvailable, getOllamaUrl, getEmbeddingModel } = await import("../shared/ollama.js");
|
|
667
662
|
const ollamaUrl = getOllamaUrl();
|
|
668
663
|
if (!ollamaUrl)
|
|
669
664
|
return "Semantic search: disabled.";
|
|
@@ -674,10 +669,10 @@ export async function warmSemanticSearch(phrenPath, profile) {
|
|
|
674
669
|
if (!await checkModelAvailable()) {
|
|
675
670
|
return `Semantic search not warmed: model ${model} is not pulled yet.`;
|
|
676
671
|
}
|
|
677
|
-
const { buildIndex, listIndexedDocumentPaths } = await import("
|
|
678
|
-
const { getEmbeddingCache, formatEmbeddingCoverage } = await import("
|
|
679
|
-
const { backgroundEmbedMissingDocs } = await import("
|
|
680
|
-
const { getPersistentVectorIndex } = await import("
|
|
672
|
+
const { buildIndex, listIndexedDocumentPaths } = await import("../shared/index.js");
|
|
673
|
+
const { getEmbeddingCache, formatEmbeddingCoverage } = await import("../shared/embedding-cache.js");
|
|
674
|
+
const { backgroundEmbedMissingDocs } = await import("../startup-embedding.js");
|
|
675
|
+
const { getPersistentVectorIndex } = await import("../shared/vector-index.js");
|
|
681
676
|
const db = await buildIndex(phrenPath, profile);
|
|
682
677
|
try {
|
|
683
678
|
const cache = getEmbeddingCache(phrenPath);
|
|
@@ -1450,29 +1445,23 @@ export async function runInit(opts = {}) {
|
|
|
1450
1445
|
const walkthroughCoveredOllama = Boolean(process.env._PHREN_WALKTHROUGH_OLLAMA_SKIP) || (!hasExistingInstall && !opts.yes);
|
|
1451
1446
|
if (!walkthroughCoveredOllama) {
|
|
1452
1447
|
try {
|
|
1453
|
-
const {
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
else {
|
|
1467
|
-
log("\n Tip: Install Ollama for semantic search (optional).");
|
|
1468
|
-
log(" https://ollama.com → then: ollama pull nomic-embed-text");
|
|
1469
|
-
log(" (Set PHREN_OLLAMA_URL=off to hide this message)");
|
|
1470
|
-
}
|
|
1448
|
+
const { checkOllamaStatus } = await import("../shared/ollama.js");
|
|
1449
|
+
const status = await checkOllamaStatus();
|
|
1450
|
+
if (status === "ready") {
|
|
1451
|
+
log("\n Semantic search: Ollama + nomic-embed-text ready.");
|
|
1452
|
+
}
|
|
1453
|
+
else if (status === "no_model") {
|
|
1454
|
+
log("\n Semantic search: Ollama running, but nomic-embed-text not pulled.");
|
|
1455
|
+
log(" Run: ollama pull nomic-embed-text");
|
|
1456
|
+
}
|
|
1457
|
+
else if (status === "not_running") {
|
|
1458
|
+
log("\n Tip: Install Ollama for semantic search (optional).");
|
|
1459
|
+
log(" https://ollama.com → then: ollama pull nomic-embed-text");
|
|
1460
|
+
log(" (Set PHREN_OLLAMA_URL=off to hide this message)");
|
|
1471
1461
|
}
|
|
1472
1462
|
}
|
|
1473
1463
|
catch (err) {
|
|
1474
|
-
|
|
1475
|
-
process.stderr.write(`[phren] init ollamaInstallHint: ${errorMessage(err)}\n`);
|
|
1464
|
+
logger.debug("init", `init ollamaInstallHint: ${errorMessage(err)}`);
|
|
1476
1465
|
}
|
|
1477
1466
|
}
|
|
1478
1467
|
for (const envLabel of writeWalkthroughEnvDefaults(phrenPath, opts)) {
|
|
@@ -2004,6 +1993,28 @@ export async function runUninstall(opts = {}) {
|
|
|
2004
1993
|
catch (err) {
|
|
2005
1994
|
debugLog(`uninstall: cleanup failed for ${contextFile}: ${errorMessage(err)}`);
|
|
2006
1995
|
}
|
|
1996
|
+
// Remove global CLAUDE.md symlink (created by linkGlobal -> ~/.claude/CLAUDE.md)
|
|
1997
|
+
const globalClaudeLink = homePath(".claude", "CLAUDE.md");
|
|
1998
|
+
try {
|
|
1999
|
+
if (fs.lstatSync(globalClaudeLink).isSymbolicLink()) {
|
|
2000
|
+
fs.unlinkSync(globalClaudeLink);
|
|
2001
|
+
log(` Removed global CLAUDE.md symlink (${globalClaudeLink})`);
|
|
2002
|
+
}
|
|
2003
|
+
}
|
|
2004
|
+
catch {
|
|
2005
|
+
// Does not exist or not a symlink — nothing to do
|
|
2006
|
+
}
|
|
2007
|
+
// Remove copilot-instructions.md symlink (created by linkGlobal -> ~/.github/copilot-instructions.md)
|
|
2008
|
+
const copilotInstrLink = homePath(".github", "copilot-instructions.md");
|
|
2009
|
+
try {
|
|
2010
|
+
if (fs.lstatSync(copilotInstrLink).isSymbolicLink()) {
|
|
2011
|
+
fs.unlinkSync(copilotInstrLink);
|
|
2012
|
+
log(` Removed copilot-instructions.md symlink (${copilotInstrLink})`);
|
|
2013
|
+
}
|
|
2014
|
+
}
|
|
2015
|
+
catch {
|
|
2016
|
+
// Does not exist or not a symlink — nothing to do
|
|
2017
|
+
}
|
|
2007
2018
|
// Sweep agent skill directories for symlinks pointing into the phren store
|
|
2008
2019
|
if (phrenPath) {
|
|
2009
2020
|
try {
|
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
import * as fs from "fs";
|
|
5
5
|
import * as path from "path";
|
|
6
6
|
import * as crypto from "crypto";
|
|
7
|
-
import { debugLog, installPreferencesFile } from "
|
|
8
|
-
import { errorMessage } from "
|
|
9
|
-
import { withFileLock } from "
|
|
7
|
+
import { debugLog, installPreferencesFile } from "../phren-paths.js";
|
|
8
|
+
import { errorMessage } from "../utils.js";
|
|
9
|
+
import { withFileLock } from "../shared/governance.js";
|
|
10
10
|
function preferencesFile(phrenPath) {
|
|
11
11
|
return installPreferencesFile(phrenPath);
|
|
12
12
|
}
|
|
@@ -5,19 +5,20 @@ import * as fs from "fs";
|
|
|
5
5
|
import * as path from "path";
|
|
6
6
|
import * as os from "os";
|
|
7
7
|
import * as yaml from "js-yaml";
|
|
8
|
-
import { atomicWriteText, debugLog, findProjectNameCaseInsensitive, hookConfigPath, EXEC_TIMEOUT_QUICK_MS, readRootManifest, sessionsDir, runtimeHealthFile, isRecord, } from "
|
|
9
|
-
import { addProjectToProfile, listProfiles, resolveActiveProfile, setMachineProfile } from "
|
|
10
|
-
import { getMachineName } from "
|
|
8
|
+
import { atomicWriteText, debugLog, findProjectNameCaseInsensitive, hookConfigPath, EXEC_TIMEOUT_QUICK_MS, readRootManifest, sessionsDir, runtimeHealthFile, isRecord, } from "../shared.js";
|
|
9
|
+
import { addProjectToProfile, listProfiles, resolveActiveProfile, setMachineProfile } from "../profile-store.js";
|
|
10
|
+
import { getMachineName } from "../machine-identity.js";
|
|
11
11
|
import { execFileSync } from "child_process";
|
|
12
|
-
import { GOVERNANCE_SCHEMA_VERSION, } from "
|
|
13
|
-
import { STOP_WORDS, errorMessage } from "
|
|
14
|
-
import { ROOT, STARTER_DIR, VERSION, resolveEntryScript, commandVersion, versionAtLeast, nearestWritableTarget } from "./
|
|
15
|
-
import { readInstallPreferences } from "./
|
|
16
|
-
import { TASKS_FILENAME } from "
|
|
17
|
-
import { getProjectOwnershipDefault, parseProjectOwnershipMode, readProjectConfig, writeProjectConfig, } from "
|
|
18
|
-
import { getBuiltinTopicConfig, normalizeBuiltinTopicDomain } from "
|
|
19
|
-
import { writeSkillMd } from "
|
|
20
|
-
import { syncScopeSkillsToDir } from "
|
|
12
|
+
import { GOVERNANCE_SCHEMA_VERSION, } from "../shared/governance.js";
|
|
13
|
+
import { STOP_WORDS, errorMessage } from "../utils.js";
|
|
14
|
+
import { ROOT, STARTER_DIR, VERSION, resolveEntryScript, commandVersion, versionAtLeast, nearestWritableTarget } from "./shared.js";
|
|
15
|
+
import { readInstallPreferences } from "./preferences.js";
|
|
16
|
+
import { TASKS_FILENAME } from "../data/tasks.js";
|
|
17
|
+
import { getProjectOwnershipDefault, parseProjectOwnershipMode, readProjectConfig, writeProjectConfig, } from "../project-config.js";
|
|
18
|
+
import { getBuiltinTopicConfig, normalizeBuiltinTopicDomain } from "../project-topics.js";
|
|
19
|
+
import { writeSkillMd } from "../link/skills.js";
|
|
20
|
+
import { syncScopeSkillsToDir } from "../skill/files.js";
|
|
21
|
+
import { logger } from "../logger.js";
|
|
21
22
|
const LEGACY_SAMPLE_PROJECTS = new Set(["my-api", "my-frontend"]);
|
|
22
23
|
function normalizeProjects(raw) {
|
|
23
24
|
if (!Array.isArray(raw))
|
|
@@ -1052,16 +1053,14 @@ export function updateMachinesYaml(phrenPath, machine, profile) {
|
|
|
1052
1053
|
}
|
|
1053
1054
|
}
|
|
1054
1055
|
catch (err) {
|
|
1055
|
-
|
|
1056
|
-
process.stderr.write(`[phren] updateMachinesYaml parse: ${errorMessage(err)}\n`);
|
|
1056
|
+
logger.debug("setup", `updateMachinesYaml parse: ${errorMessage(err)}`);
|
|
1057
1057
|
}
|
|
1058
1058
|
// Passive init/link refreshes should keep an existing mapping; explicit overrides can remap.
|
|
1059
1059
|
if (hasExistingMapping && !machine && !profile)
|
|
1060
1060
|
return;
|
|
1061
1061
|
const mapping = setMachineProfile(phrenPath, machineName, profileName);
|
|
1062
|
-
if (!mapping.ok
|
|
1063
|
-
|
|
1064
|
-
}
|
|
1062
|
+
if (!mapping.ok)
|
|
1063
|
+
logger.debug("setup", `updateMachinesYaml setMachineProfile: ${mapping.error}`);
|
|
1065
1064
|
}
|
|
1066
1065
|
/**
|
|
1067
1066
|
* Detect if a directory looks like a project that should be bootstrapped.
|
|
@@ -1262,8 +1261,7 @@ export function runPostInitVerify(phrenPath) {
|
|
|
1262
1261
|
ftsOk = entries.some(d => d.isDirectory() && !d.name.startsWith("."));
|
|
1263
1262
|
}
|
|
1264
1263
|
catch (err) {
|
|
1265
|
-
|
|
1266
|
-
process.stderr.write(`[phren] runPostInitVerify projectScan: ${errorMessage(err)}\n`);
|
|
1264
|
+
logger.debug("setup", `runPostInitVerify projectScan: ${errorMessage(err)}`);
|
|
1267
1265
|
ftsOk = false;
|
|
1268
1266
|
}
|
|
1269
1267
|
checks.push({
|
|
@@ -5,9 +5,9 @@
|
|
|
5
5
|
import * as fs from "fs";
|
|
6
6
|
import * as path from "path";
|
|
7
7
|
import { execFileSync } from "child_process";
|
|
8
|
-
import { homePath, EXEC_TIMEOUT_QUICK_MS, debugLog } from "
|
|
9
|
-
import { errorMessage } from "
|
|
10
|
-
import { ROOT as PACKAGE_ROOT, VERSION } from "
|
|
8
|
+
import { homePath, EXEC_TIMEOUT_QUICK_MS, debugLog } from "../shared.js";
|
|
9
|
+
import { errorMessage } from "../utils.js";
|
|
10
|
+
import { ROOT as PACKAGE_ROOT, VERSION } from "../package-metadata.js";
|
|
11
11
|
export const ROOT = PACKAGE_ROOT;
|
|
12
12
|
export { VERSION };
|
|
13
13
|
export const STARTER_DIR = path.join(ROOT, "starter");
|
|
@@ -33,7 +33,7 @@ export function commandVersion(cmd, args = ["--version"]) {
|
|
|
33
33
|
return null;
|
|
34
34
|
}
|
|
35
35
|
}
|
|
36
|
-
|
|
36
|
+
function parseSemverTriple(raw) {
|
|
37
37
|
const match = raw.match(/(\d+)\.(\d+)\.(\d+)/);
|
|
38
38
|
if (!match)
|
|
39
39
|
return null;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bootstrap-current-project prompting and execution for init.
|
|
3
|
+
*/
|
|
4
|
+
import { debugLog } from "./shared.js";
|
|
5
|
+
import { bootstrapFromExisting, } from "./init/setup.js";
|
|
6
|
+
import { log } from "./init/shared.js";
|
|
7
|
+
/**
|
|
8
|
+
* Bootstrap a project from an existing directory into phren.
|
|
9
|
+
*/
|
|
10
|
+
export function bootstrapProject(phrenPath, projectPath, profile, ownership, label) {
|
|
11
|
+
try {
|
|
12
|
+
const created = bootstrapFromExisting(phrenPath, projectPath, {
|
|
13
|
+
profile,
|
|
14
|
+
ownership,
|
|
15
|
+
});
|
|
16
|
+
log(`\n${label} "${created.project}" (${created.ownership})`);
|
|
17
|
+
}
|
|
18
|
+
catch (e) {
|
|
19
|
+
debugLog(`Bootstrap from CWD failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Detection helpers for init: bootstrap target, install markers, path resolution.
|
|
3
|
+
*/
|
|
4
|
+
import * as fs from "fs";
|
|
5
|
+
import * as path from "path";
|
|
6
|
+
import { expandHomePath } from "./shared.js";
|
|
7
|
+
import { detectProjectDir, isProjectTracked } from "./init/setup.js";
|
|
8
|
+
import { DEFAULT_PHREN_PATH } from "./init/shared.js";
|
|
9
|
+
export function normalizedBootstrapProjectName(projectPath) {
|
|
10
|
+
return path.basename(projectPath).toLowerCase().replace(/[^a-z0-9_-]/g, "-");
|
|
11
|
+
}
|
|
12
|
+
export function getPendingBootstrapTarget(phrenPath, _opts) {
|
|
13
|
+
const cwdProject = detectProjectDir(process.cwd(), phrenPath);
|
|
14
|
+
if (!cwdProject)
|
|
15
|
+
return null;
|
|
16
|
+
const projectName = normalizedBootstrapProjectName(cwdProject);
|
|
17
|
+
if (isProjectTracked(phrenPath, projectName))
|
|
18
|
+
return null;
|
|
19
|
+
return { path: cwdProject, mode: "detected" };
|
|
20
|
+
}
|
|
21
|
+
export function hasInstallMarkers(phrenPath) {
|
|
22
|
+
// Require at least two markers to consider this a real install.
|
|
23
|
+
// A partial clone or failed init may create one directory but not finish.
|
|
24
|
+
if (!fs.existsSync(phrenPath))
|
|
25
|
+
return false;
|
|
26
|
+
let found = 0;
|
|
27
|
+
if (fs.existsSync(path.join(phrenPath, "machines.yaml")))
|
|
28
|
+
found++;
|
|
29
|
+
if (fs.existsSync(path.join(phrenPath, ".config")))
|
|
30
|
+
found++;
|
|
31
|
+
if (fs.existsSync(path.join(phrenPath, "global")))
|
|
32
|
+
found++;
|
|
33
|
+
return found >= 2;
|
|
34
|
+
}
|
|
35
|
+
export function resolveInitPhrenPath(opts) {
|
|
36
|
+
const raw = opts._walkthroughStoragePath || process.env.PHREN_PATH || DEFAULT_PHREN_PATH;
|
|
37
|
+
return path.resolve(expandHomePath(raw));
|
|
38
|
+
}
|