@phren/cli 0.0.27 → 0.0.32
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} +22 -21
- package/mcp/dist/{cli.js → cli/cli.js} +13 -13
- package/mcp/dist/{cli-config.js → cli/config.js} +9 -9
- package/mcp/dist/{cli-extract.js → cli/extract.js} +8 -8
- package/mcp/dist/{cli-govern.js → cli/govern.js} +10 -9
- 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} +42 -57
- 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} +8 -7
- package/mcp/dist/cli-hooks-git.js +243 -0
- package/mcp/dist/cli-hooks-prompt.js +319 -0
- package/mcp/dist/cli-hooks-session-handlers.js +349 -0
- package/mcp/dist/cli-hooks-stop.js +557 -0
- package/mcp/dist/{content-archive.js → content/archive.js} +8 -9
- 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} +12 -12
- 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} +131 -13
- package/mcp/dist/{data-tasks.js → data/tasks.js} +7 -5
- package/mcp/dist/embedding.js +9 -14
- package/mcp/dist/entrypoint.js +13 -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} +4 -4
- package/mcp/dist/{governance-audit.js → governance/audit.js} +2 -2
- package/mcp/dist/{governance-locks.js → governance/locks.js} +14 -9
- package/mcp/dist/{governance-policy.js → governance/policy.js} +10 -12
- package/mcp/dist/{governance-rbac.js → governance/rbac.js} +3 -3
- package/mcp/dist/{governance-scores.js → governance/scores.js} +8 -10
- package/mcp/dist/hooks.js +39 -31
- package/mcp/dist/index-query.js +4 -1
- package/mcp/dist/index.js +53 -29
- package/mcp/dist/{init-config.js → init/config.js} +6 -6
- package/mcp/dist/{init.js → init/init.js} +28 -29
- 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} +3 -3
- package/mcp/dist/init-bootstrap.js +68 -0
- package/mcp/dist/init-detect.js +38 -0
- package/mcp/dist/init-dryrun.js +55 -0
- package/mcp/dist/init-env.js +114 -0
- package/mcp/dist/init-fresh.js +239 -0
- package/mcp/dist/init-hooks.js +26 -0
- package/mcp/dist/init-mcp.js +65 -0
- package/mcp/dist/init-migrate.js +51 -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 +482 -0
- package/mcp/dist/init-update.js +96 -0
- package/mcp/dist/init-walkthrough-merge.js +90 -0
- package/mcp/dist/init-walkthrough.js +529 -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/phren-art.js +0 -6
- package/mcp/dist/phren-paths.js +30 -12
- package/mcp/dist/proactivity.js +2 -2
- package/mcp/dist/profile-store.js +5 -6
- package/mcp/dist/project-config.js +2 -2
- package/mcp/dist/project-topics.js +1 -1
- package/mcp/dist/query-correlation.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} +3 -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} +15 -24
- package/mcp/dist/shared/governance.js +4 -0
- package/mcp/dist/{shared-index.js → shared/index.js} +92 -123
- package/mcp/dist/{shared-ollama.js → shared/ollama.js} +2 -2
- package/mcp/dist/{shared-retrieval.js → shared/retrieval.js} +16 -21
- package/mcp/dist/{shared-search-fallback.js → shared/search-fallback.js} +17 -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 +4 -59
- 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} +1 -1
- 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} +4 -4
- package/mcp/dist/{skill-state.js → skill/state.js} +1 -1
- package/mcp/dist/startup-embedding.js +2 -2
- package/mcp/dist/status.js +15 -14
- package/mcp/dist/{tasks-github.js → task/github.js} +2 -2
- package/mcp/dist/{task-hygiene.js → task/hygiene.js} +4 -4
- package/mcp/dist/{task-lifecycle.js → task/lifecycle.js} +7 -7
- package/mcp/dist/telemetry.js +3 -4
- package/mcp/dist/tool-registry.js +29 -17
- package/mcp/dist/tools/config.js +515 -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/{mcp-finding.js → tools/finding.js} +97 -124
- 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/{mcp-ops.js → tools/ops.js} +169 -71
- package/mcp/dist/{mcp-search.js → tools/search.js} +19 -23
- package/mcp/dist/{mcp-session.js → tools/session.js} +48 -23
- package/mcp/dist/{mcp-skills.js → tools/skills.js} +33 -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} +4 -6
- package/mcp/dist/{memory-ui-server.js → ui/server.js} +30 -22
- package/mcp/dist/update.js +2 -2
- package/mcp/dist/utils.js +51 -11
- package/package.json +17 -11
- package/scripts/preuninstall.mjs +139 -0
- package/starter/global/CLAUDE.md +3 -2
- package/mcp/dist/mcp-config.js +0 -551
- package/mcp/dist/shared-governance.js +0 -4
- package/starter/global/skills/pipeline.md +0 -35
- package/starter/global/skills/release.md +0 -35
- /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
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP-mode and hooks-mode toggle commands.
|
|
3
|
+
*/
|
|
4
|
+
import { configureClaude, configureVSCode, configureCursorMcp, configureCopilotMcp, configureCodexMcp, } from "./init/config.js";
|
|
5
|
+
import { configureAllHooks } from "./hooks.js";
|
|
6
|
+
import { debugLog, findPhrenPath, readRootManifest, } from "./shared.js";
|
|
7
|
+
import { errorMessage } from "./utils.js";
|
|
8
|
+
import { getMcpEnabledPreference, getHooksEnabledPreference, setMcpEnabledPreference, setHooksEnabledPreference, } from "./init/preferences.js";
|
|
9
|
+
import { DEFAULT_PHREN_PATH, log } from "./init/shared.js";
|
|
10
|
+
export function parseMcpMode(raw) {
|
|
11
|
+
if (!raw)
|
|
12
|
+
return undefined;
|
|
13
|
+
const normalized = raw.trim().toLowerCase();
|
|
14
|
+
if (normalized === "on" || normalized === "off")
|
|
15
|
+
return normalized;
|
|
16
|
+
return undefined;
|
|
17
|
+
}
|
|
18
|
+
export async function runMcpMode(modeArg) {
|
|
19
|
+
const phrenPath = findPhrenPath() || (process.env.PHREN_PATH) || DEFAULT_PHREN_PATH;
|
|
20
|
+
const manifest = readRootManifest(phrenPath);
|
|
21
|
+
const normalizedArg = modeArg?.trim().toLowerCase();
|
|
22
|
+
if (!normalizedArg || normalizedArg === "status") {
|
|
23
|
+
const current = getMcpEnabledPreference(phrenPath);
|
|
24
|
+
const hooks = getHooksEnabledPreference(phrenPath);
|
|
25
|
+
log(`MCP mode: ${current ? "on (recommended)" : "off (hooks-only fallback)"}`);
|
|
26
|
+
log(`Hooks mode: ${hooks ? "on (active)" : "off (disabled)"}`);
|
|
27
|
+
log(`Change mode: npx phren mcp-mode on|off`);
|
|
28
|
+
log(`Hooks toggle: npx phren hooks-mode on|off`);
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
const mode = parseMcpMode(normalizedArg);
|
|
32
|
+
if (!mode) {
|
|
33
|
+
throw new Error(`Invalid mode "${modeArg}". Use: on | off | status`);
|
|
34
|
+
}
|
|
35
|
+
const enabled = mode === "on";
|
|
36
|
+
if (manifest?.installMode === "project-local") {
|
|
37
|
+
const vscodeStatus = configureVSCode(phrenPath, { mcpEnabled: enabled, scope: "workspace" });
|
|
38
|
+
setMcpEnabledPreference(phrenPath, enabled);
|
|
39
|
+
log(`MCP mode set to ${mode}.`);
|
|
40
|
+
log(`VS Code status: ${vscodeStatus}`);
|
|
41
|
+
log(`Project-local mode only configures workspace VS Code MCP.`);
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
let claudeStatus = "no_settings";
|
|
45
|
+
let vscodeStatus = "no_vscode";
|
|
46
|
+
let cursorStatus = "no_cursor";
|
|
47
|
+
let copilotStatus = "no_copilot";
|
|
48
|
+
let codexStatus = "no_codex";
|
|
49
|
+
try {
|
|
50
|
+
claudeStatus = configureClaude(phrenPath, { mcpEnabled: enabled }) ?? claudeStatus;
|
|
51
|
+
}
|
|
52
|
+
catch (err) {
|
|
53
|
+
debugLog(`mcp-mode: configureClaude failed: ${errorMessage(err)}`);
|
|
54
|
+
}
|
|
55
|
+
try {
|
|
56
|
+
vscodeStatus = configureVSCode(phrenPath, { mcpEnabled: enabled }) ?? vscodeStatus;
|
|
57
|
+
}
|
|
58
|
+
catch (err) {
|
|
59
|
+
debugLog(`mcp-mode: configureVSCode failed: ${errorMessage(err)}`);
|
|
60
|
+
}
|
|
61
|
+
try {
|
|
62
|
+
cursorStatus = configureCursorMcp(phrenPath, { mcpEnabled: enabled }) ?? cursorStatus;
|
|
63
|
+
}
|
|
64
|
+
catch (err) {
|
|
65
|
+
debugLog(`mcp-mode: configureCursorMcp failed: ${errorMessage(err)}`);
|
|
66
|
+
}
|
|
67
|
+
try {
|
|
68
|
+
copilotStatus = configureCopilotMcp(phrenPath, { mcpEnabled: enabled }) ?? copilotStatus;
|
|
69
|
+
}
|
|
70
|
+
catch (err) {
|
|
71
|
+
debugLog(`mcp-mode: configureCopilotMcp failed: ${errorMessage(err)}`);
|
|
72
|
+
}
|
|
73
|
+
try {
|
|
74
|
+
codexStatus = configureCodexMcp(phrenPath, { mcpEnabled: enabled }) ?? codexStatus;
|
|
75
|
+
}
|
|
76
|
+
catch (err) {
|
|
77
|
+
debugLog(`mcp-mode: configureCodexMcp failed: ${errorMessage(err)}`);
|
|
78
|
+
}
|
|
79
|
+
// Persist preference only after config writes have been attempted
|
|
80
|
+
setMcpEnabledPreference(phrenPath, enabled);
|
|
81
|
+
log(`MCP mode set to ${mode}.`);
|
|
82
|
+
log(`Claude status: ${claudeStatus}`);
|
|
83
|
+
log(`VS Code status: ${vscodeStatus}`);
|
|
84
|
+
log(`Cursor status: ${cursorStatus}`);
|
|
85
|
+
log(`Copilot CLI status: ${copilotStatus}`);
|
|
86
|
+
log(`Codex status: ${codexStatus}`);
|
|
87
|
+
log(`Restart your agent to apply changes.`);
|
|
88
|
+
}
|
|
89
|
+
export async function runHooksMode(modeArg) {
|
|
90
|
+
const phrenPath = findPhrenPath() || (process.env.PHREN_PATH) || DEFAULT_PHREN_PATH;
|
|
91
|
+
const manifest = readRootManifest(phrenPath);
|
|
92
|
+
const normalizedArg = modeArg?.trim().toLowerCase();
|
|
93
|
+
if (!normalizedArg || normalizedArg === "status") {
|
|
94
|
+
const current = getHooksEnabledPreference(phrenPath);
|
|
95
|
+
log(`Hooks mode: ${current ? "on (active)" : "off (disabled)"}`);
|
|
96
|
+
log(`Change mode: npx phren hooks-mode on|off`);
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
const mode = parseMcpMode(normalizedArg);
|
|
100
|
+
if (!mode) {
|
|
101
|
+
throw new Error(`Invalid mode "${modeArg}". Use: on | off | status`);
|
|
102
|
+
}
|
|
103
|
+
if (manifest?.installMode === "project-local") {
|
|
104
|
+
throw new Error("hooks-mode is unsupported in project-local mode");
|
|
105
|
+
}
|
|
106
|
+
const enabled = mode === "on";
|
|
107
|
+
let claudeStatus = "no_settings";
|
|
108
|
+
try {
|
|
109
|
+
claudeStatus = configureClaude(phrenPath, {
|
|
110
|
+
mcpEnabled: getMcpEnabledPreference(phrenPath),
|
|
111
|
+
hooksEnabled: enabled,
|
|
112
|
+
}) ?? claudeStatus;
|
|
113
|
+
}
|
|
114
|
+
catch (err) {
|
|
115
|
+
debugLog(`hooks-mode: configureClaude failed: ${errorMessage(err)}`);
|
|
116
|
+
}
|
|
117
|
+
if (enabled) {
|
|
118
|
+
try {
|
|
119
|
+
const hooked = configureAllHooks(phrenPath, { allTools: true });
|
|
120
|
+
if (hooked.length)
|
|
121
|
+
log(`Updated hooks: ${hooked.join(", ")}`);
|
|
122
|
+
}
|
|
123
|
+
catch (err) {
|
|
124
|
+
debugLog(`hooks-mode: configureAllHooks failed: ${errorMessage(err)}`);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
log("Hooks will no-op immediately via preference and Claude hooks are removed.");
|
|
129
|
+
}
|
|
130
|
+
// Persist preference only after config writes have been attempted
|
|
131
|
+
setHooksEnabledPreference(phrenPath, enabled);
|
|
132
|
+
log(`Hooks mode set to ${mode}.`);
|
|
133
|
+
log(`Claude status: ${claudeStatus}`);
|
|
134
|
+
log(`Restart your agent to apply changes.`);
|
|
135
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Version comparison utilities for phren init and update flows.
|
|
3
|
+
*/
|
|
4
|
+
function parseVersion(version) {
|
|
5
|
+
const match = version.trim().match(/^(\d+)\.(\d+)\.(\d+)(?:-(.+))?/);
|
|
6
|
+
if (!match)
|
|
7
|
+
return { major: 0, minor: 0, patch: 0, pre: "" };
|
|
8
|
+
return {
|
|
9
|
+
major: Number.parseInt(match[1], 10) || 0,
|
|
10
|
+
minor: Number.parseInt(match[2], 10) || 0,
|
|
11
|
+
patch: Number.parseInt(match[3], 10) || 0,
|
|
12
|
+
pre: match[4] || "",
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Compare two semver strings. Returns true when `current` is strictly newer
|
|
17
|
+
* than `previous`. Pre-release versions (e.g. 1.2.3-rc.1) sort before the
|
|
18
|
+
* corresponding release (1.2.3). Among pre-release tags, comparison is
|
|
19
|
+
* lexicographic.
|
|
20
|
+
*/
|
|
21
|
+
export function isVersionNewer(current, previous) {
|
|
22
|
+
if (!previous)
|
|
23
|
+
return false;
|
|
24
|
+
const c = parseVersion(current);
|
|
25
|
+
const p = parseVersion(previous);
|
|
26
|
+
if (c.major !== p.major)
|
|
27
|
+
return c.major > p.major;
|
|
28
|
+
if (c.minor !== p.minor)
|
|
29
|
+
return c.minor > p.minor;
|
|
30
|
+
if (c.patch !== p.patch)
|
|
31
|
+
return c.patch > p.patch;
|
|
32
|
+
if (c.pre && !p.pre)
|
|
33
|
+
return false;
|
|
34
|
+
if (!c.pre && p.pre)
|
|
35
|
+
return true;
|
|
36
|
+
return c.pre > p.pre;
|
|
37
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Project-local init mode: creates a .phren directory inside the workspace.
|
|
3
|
+
*/
|
|
4
|
+
import * as fs from "fs";
|
|
5
|
+
import * as path from "path";
|
|
6
|
+
import { atomicWriteText, debugLog, readRootManifest, writeRootManifest, } from "./shared.js";
|
|
7
|
+
import { errorMessage } from "./utils.js";
|
|
8
|
+
import { configureVSCode, logMcpTargetStatus, } from "./init/config.js";
|
|
9
|
+
import { writeInstallPreferences, } from "./init/preferences.js";
|
|
10
|
+
import { ensureGovernanceFiles, repairPreexistingInstall, runPostInitVerify, bootstrapFromExisting, detectProjectDir, } from "./init/setup.js";
|
|
11
|
+
import { getProjectOwnershipDefault, } from "./project-config.js";
|
|
12
|
+
import { VERSION, log } from "./init/shared.js";
|
|
13
|
+
import { applyOnboardingPreferences } from "./init-env.js";
|
|
14
|
+
export async function runProjectLocalInit(opts = {}) {
|
|
15
|
+
const detectedRoot = detectProjectDir(process.cwd(), path.join(process.cwd(), ".phren")) || process.cwd();
|
|
16
|
+
const hasWorkspaceMarker = fs.existsSync(path.join(detectedRoot, ".git")) ||
|
|
17
|
+
fs.existsSync(path.join(detectedRoot, "CLAUDE.md")) ||
|
|
18
|
+
fs.existsSync(path.join(detectedRoot, "AGENTS.md")) ||
|
|
19
|
+
fs.existsSync(path.join(detectedRoot, ".claude", "CLAUDE.md"));
|
|
20
|
+
if (!hasWorkspaceMarker) {
|
|
21
|
+
throw new Error("project-local mode must be run inside a repo or project root");
|
|
22
|
+
}
|
|
23
|
+
const workspaceRoot = path.resolve(detectedRoot);
|
|
24
|
+
const phrenPath = path.join(workspaceRoot, ".phren");
|
|
25
|
+
const existingManifest = readRootManifest(phrenPath);
|
|
26
|
+
if (existingManifest && existingManifest.installMode !== "project-local") {
|
|
27
|
+
throw new Error(`Refusing to reuse non-local phren root at ${phrenPath}`);
|
|
28
|
+
}
|
|
29
|
+
const ownershipDefault = opts.projectOwnershipDefault
|
|
30
|
+
?? (existingManifest ? getProjectOwnershipDefault(phrenPath) : "detached");
|
|
31
|
+
if (!existingManifest && !opts.projectOwnershipDefault) {
|
|
32
|
+
opts.projectOwnershipDefault = ownershipDefault;
|
|
33
|
+
}
|
|
34
|
+
const mcpEnabled = opts.mcp ? opts.mcp === "on" : true;
|
|
35
|
+
const projectName = path.basename(workspaceRoot).toLowerCase().replace(/[^a-z0-9_-]/g, "-");
|
|
36
|
+
if (opts.dryRun) {
|
|
37
|
+
log("\nInit dry run. No files will be written.\n");
|
|
38
|
+
log(`Mode: project-local`);
|
|
39
|
+
log(`Workspace root: ${workspaceRoot}`);
|
|
40
|
+
log(`Phren root: ${phrenPath}`);
|
|
41
|
+
log(`Project: ${projectName}`);
|
|
42
|
+
log(`VS Code workspace MCP: ${mcpEnabled ? "on" : "off"}`);
|
|
43
|
+
log(`Hooks: unsupported in project-local mode`);
|
|
44
|
+
log("");
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
fs.mkdirSync(phrenPath, { recursive: true });
|
|
48
|
+
writeRootManifest(phrenPath, {
|
|
49
|
+
version: 1,
|
|
50
|
+
installMode: "project-local",
|
|
51
|
+
syncMode: "workspace-git",
|
|
52
|
+
workspaceRoot,
|
|
53
|
+
primaryProject: projectName,
|
|
54
|
+
});
|
|
55
|
+
ensureGovernanceFiles(phrenPath);
|
|
56
|
+
repairPreexistingInstall(phrenPath);
|
|
57
|
+
fs.mkdirSync(path.join(phrenPath, "global", "skills"), { recursive: true });
|
|
58
|
+
fs.mkdirSync(path.join(phrenPath, ".runtime"), { recursive: true });
|
|
59
|
+
fs.mkdirSync(path.join(phrenPath, ".sessions"), { recursive: true });
|
|
60
|
+
if (!fs.existsSync(path.join(phrenPath, ".gitignore"))) {
|
|
61
|
+
atomicWriteText(path.join(phrenPath, ".gitignore"), [
|
|
62
|
+
".runtime/",
|
|
63
|
+
".sessions/",
|
|
64
|
+
"*.lock",
|
|
65
|
+
"*.tmp-*",
|
|
66
|
+
"",
|
|
67
|
+
].join("\n"));
|
|
68
|
+
}
|
|
69
|
+
if (!fs.existsSync(path.join(phrenPath, "global", "CLAUDE.md"))) {
|
|
70
|
+
atomicWriteText(path.join(phrenPath, "global", "CLAUDE.md"), "# Global Context\n\nRepo-local Phren instructions shared across this workspace.\n");
|
|
71
|
+
}
|
|
72
|
+
const created = bootstrapFromExisting(phrenPath, workspaceRoot, { ownership: ownershipDefault });
|
|
73
|
+
applyOnboardingPreferences(phrenPath, opts);
|
|
74
|
+
writeInstallPreferences(phrenPath, {
|
|
75
|
+
mcpEnabled,
|
|
76
|
+
hooksEnabled: false,
|
|
77
|
+
skillsScope: opts.skillsScope ?? "global",
|
|
78
|
+
installedVersion: VERSION,
|
|
79
|
+
});
|
|
80
|
+
try {
|
|
81
|
+
const vscodeResult = configureVSCode(phrenPath, { mcpEnabled, scope: "workspace" });
|
|
82
|
+
logMcpTargetStatus("VS Code", vscodeResult, existingManifest ? "Updated" : "Configured");
|
|
83
|
+
}
|
|
84
|
+
catch (err) {
|
|
85
|
+
debugLog(`configureVSCode(workspace) failed: ${errorMessage(err)}`);
|
|
86
|
+
}
|
|
87
|
+
log(`\n${existingManifest ? "Updated" : "Created"} project-local phren at ${phrenPath}`);
|
|
88
|
+
log(` Workspace root: ${workspaceRoot}`);
|
|
89
|
+
log(` Project: ${created.project}`);
|
|
90
|
+
log(` Ownership: ${created.ownership}`);
|
|
91
|
+
log(` Sync mode: workspace-git`);
|
|
92
|
+
log(` Hooks: off (unsupported in project-local mode)`);
|
|
93
|
+
log(` VS Code MCP: ${mcpEnabled ? "workspace on" : "workspace off"}`);
|
|
94
|
+
const verify = runPostInitVerify(phrenPath);
|
|
95
|
+
log(`\nVerifying setup...`);
|
|
96
|
+
for (const check of verify.checks) {
|
|
97
|
+
log(` ${check.ok ? "pass" : "FAIL"} ${check.name}: ${check.detail}`);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Semantic search warm-up for init.
|
|
3
|
+
*/
|
|
4
|
+
export async function warmSemanticSearch(phrenPath, profile) {
|
|
5
|
+
const { checkOllamaAvailable, checkModelAvailable, getOllamaUrl, getEmbeddingModel } = await import("./shared/ollama.js");
|
|
6
|
+
const ollamaUrl = getOllamaUrl();
|
|
7
|
+
if (!ollamaUrl)
|
|
8
|
+
return "Semantic search: disabled.";
|
|
9
|
+
const model = getEmbeddingModel();
|
|
10
|
+
if (!await checkOllamaAvailable()) {
|
|
11
|
+
return `Semantic search not warmed: Ollama offline at ${ollamaUrl}.`;
|
|
12
|
+
}
|
|
13
|
+
if (!await checkModelAvailable()) {
|
|
14
|
+
return `Semantic search not warmed: model ${model} is not pulled yet.`;
|
|
15
|
+
}
|
|
16
|
+
const { buildIndex, listIndexedDocumentPaths } = await import("./shared/index.js");
|
|
17
|
+
const { getEmbeddingCache, formatEmbeddingCoverage } = await import("./shared/embedding-cache.js");
|
|
18
|
+
const { backgroundEmbedMissingDocs } = await import("./startup-embedding.js");
|
|
19
|
+
const { getPersistentVectorIndex } = await import("./shared/vector-index.js");
|
|
20
|
+
const db = await buildIndex(phrenPath, profile);
|
|
21
|
+
try {
|
|
22
|
+
const cache = getEmbeddingCache(phrenPath);
|
|
23
|
+
await cache.load().catch(() => { });
|
|
24
|
+
const allPaths = listIndexedDocumentPaths(phrenPath, profile);
|
|
25
|
+
const before = cache.coverage(allPaths);
|
|
26
|
+
if (before.missing > 0) {
|
|
27
|
+
await backgroundEmbedMissingDocs(db, cache);
|
|
28
|
+
}
|
|
29
|
+
await cache.load().catch(() => { });
|
|
30
|
+
const after = cache.coverage(allPaths);
|
|
31
|
+
if (cache.size() > 0) {
|
|
32
|
+
getPersistentVectorIndex(phrenPath).ensure(cache.getAllEntries());
|
|
33
|
+
}
|
|
34
|
+
if (after.total === 0) {
|
|
35
|
+
return `Semantic search ready (${model}), but there are no indexed docs yet.`;
|
|
36
|
+
}
|
|
37
|
+
const embeddedNow = Math.max(0, after.embedded - before.embedded);
|
|
38
|
+
const prefix = after.state === "warm" ? "Semantic search warmed" : "Semantic search warming";
|
|
39
|
+
const delta = embeddedNow > 0 ? `; embedded ${embeddedNow} new docs during init` : "";
|
|
40
|
+
return `${prefix}: ${model}, ${formatEmbeddingCoverage(after)}${delta}.`;
|
|
41
|
+
}
|
|
42
|
+
finally {
|
|
43
|
+
try {
|
|
44
|
+
db.close();
|
|
45
|
+
}
|
|
46
|
+
catch { /* ignore close errors in init */ }
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|