@phren/cli 0.0.23 → 0.0.24
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/init-setup.js
CHANGED
|
@@ -290,9 +290,10 @@ export function repairPreexistingInstall(phrenPath) {
|
|
|
290
290
|
function isExpectedVerifyFailure(phrenPath, check) {
|
|
291
291
|
if (check.ok)
|
|
292
292
|
return false;
|
|
293
|
-
if (check.name === "git-remote")
|
|
294
|
-
return true;
|
|
295
293
|
const prefs = readInstallPreferences(phrenPath);
|
|
294
|
+
// git-remote failure is only expected when the user chose local-only (no clone URL)
|
|
295
|
+
if (check.name === "git-remote")
|
|
296
|
+
return prefs.syncIntent !== "sync";
|
|
296
297
|
if (check.name === "mcp-config" && prefs.mcpEnabled === false)
|
|
297
298
|
return true;
|
|
298
299
|
if (check.name === "hooks-registered" && prefs.hooksEnabled === false)
|
|
@@ -339,17 +340,30 @@ function gitRemoteStatus(phrenPath) {
|
|
|
339
340
|
catch {
|
|
340
341
|
return { ok: false, detail: "phren path is not a git repository" };
|
|
341
342
|
}
|
|
343
|
+
let remote;
|
|
342
344
|
try {
|
|
343
|
-
|
|
345
|
+
remote = execFileSync("git", ["-C", phrenPath, "remote", "get-url", "origin"], {
|
|
344
346
|
encoding: "utf8",
|
|
345
347
|
stdio: ["ignore", "pipe", "ignore"],
|
|
346
348
|
timeout: EXEC_TIMEOUT_QUICK_MS,
|
|
347
349
|
}).trim();
|
|
348
|
-
|
|
350
|
+
if (!remote)
|
|
351
|
+
return { ok: false, detail: "git origin remote not configured" };
|
|
349
352
|
}
|
|
350
353
|
catch {
|
|
351
354
|
return { ok: false, detail: "git origin remote not configured" };
|
|
352
355
|
}
|
|
356
|
+
// Connectivity test: verify the remote is reachable (10s timeout)
|
|
357
|
+
try {
|
|
358
|
+
execFileSync("git", ["-C", phrenPath, "ls-remote", "--exit-code", "origin"], {
|
|
359
|
+
stdio: ["ignore", "ignore", "ignore"],
|
|
360
|
+
timeout: 10_000,
|
|
361
|
+
});
|
|
362
|
+
return { ok: true, detail: `origin=${remote}` };
|
|
363
|
+
}
|
|
364
|
+
catch {
|
|
365
|
+
return { ok: false, detail: `origin=${remote} (configured but unreachable)` };
|
|
366
|
+
}
|
|
353
367
|
}
|
|
354
368
|
function copyStarterFile(phrenPath, src, dest) {
|
|
355
369
|
fs.mkdirSync(path.dirname(dest), { recursive: true });
|
|
@@ -1147,14 +1161,22 @@ export function runPostInitVerify(phrenPath) {
|
|
|
1147
1161
|
}
|
|
1148
1162
|
else {
|
|
1149
1163
|
const gitRemote = gitRemoteStatus(phrenPath);
|
|
1164
|
+
const wantSync = prefs.syncIntent === "sync";
|
|
1150
1165
|
const gitRemoteDetail = gitRemote.ok
|
|
1151
1166
|
? gitRemote.detail
|
|
1152
|
-
:
|
|
1167
|
+
: wantSync
|
|
1168
|
+
? `${gitRemote.detail} — sync was configured but remote is missing or unreachable`
|
|
1169
|
+
: `${gitRemote.detail} (optional unless you want cross-machine sync)`;
|
|
1170
|
+
const gitRemoteFix = gitRemote.ok
|
|
1171
|
+
? undefined
|
|
1172
|
+
: wantSync
|
|
1173
|
+
? `Your clone URL didn't work. Fix: cd ${phrenPath} && git remote add origin <URL> && git push -u origin main`
|
|
1174
|
+
: "Optional: initialize a repo and add an origin remote for cross-machine sync.";
|
|
1153
1175
|
checks.push({
|
|
1154
1176
|
name: "git-remote",
|
|
1155
1177
|
ok: gitRemote.ok,
|
|
1156
1178
|
detail: gitRemoteDetail,
|
|
1157
|
-
fix:
|
|
1179
|
+
fix: gitRemoteFix,
|
|
1158
1180
|
});
|
|
1159
1181
|
const settingsPath = hookConfigPath("claude");
|
|
1160
1182
|
const configWritable = nearestWritableTarget(settingsPath);
|
package/mcp/dist/init.js
CHANGED
|
@@ -1037,9 +1037,23 @@ export async function runInit(opts = {}) {
|
|
|
1037
1037
|
}
|
|
1038
1038
|
catch (e) {
|
|
1039
1039
|
log(` Clone failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
1040
|
-
log(
|
|
1040
|
+
log("");
|
|
1041
|
+
log(" ┌──────────────────────────────────────────────────────────────────┐");
|
|
1042
|
+
log(" │ WARNING: Sync is NOT configured. Your phren data is local-only. │");
|
|
1043
|
+
log(" │ │");
|
|
1044
|
+
log(" │ To fix later: │");
|
|
1045
|
+
log(` │ cd ${phrenPath}`);
|
|
1046
|
+
log(" │ git remote add origin <YOUR_REPO_URL> │");
|
|
1047
|
+
log(" │ git push -u origin main │");
|
|
1048
|
+
log(" └──────────────────────────────────────────────────────────────────┘");
|
|
1049
|
+
log("");
|
|
1050
|
+
log(` Continuing with fresh local-only install.`);
|
|
1041
1051
|
}
|
|
1042
1052
|
}
|
|
1053
|
+
// Record sync intent: "sync" if a clone URL was provided (regardless of success), "local" otherwise.
|
|
1054
|
+
// On re-runs of existing installs, preserve the existing syncIntent unless the user provided a new clone URL.
|
|
1055
|
+
const existingSyncIntent = hasExistingInstall ? readInstallPreferences(phrenPath).syncIntent : undefined;
|
|
1056
|
+
const syncIntent = opts._walkthroughCloneUrl ? "sync" : (existingSyncIntent ?? "local");
|
|
1043
1057
|
const mcpEnabled = opts.mcp ? opts.mcp === "on" : getMcpEnabledPreference(phrenPath);
|
|
1044
1058
|
const hooksEnabled = opts.hooks ? opts.hooks === "on" : getHooksEnabledPreference(phrenPath);
|
|
1045
1059
|
const skillsScope = opts.skillsScope ?? "global";
|
|
@@ -1194,7 +1208,7 @@ export async function runInit(opts = {}) {
|
|
|
1194
1208
|
log(` No starter template updates were applied (starter files not found).`);
|
|
1195
1209
|
}
|
|
1196
1210
|
}
|
|
1197
|
-
writeInstallPreferences(phrenPath, { mcpEnabled, hooksEnabled, skillsScope, installedVersion: VERSION });
|
|
1211
|
+
writeInstallPreferences(phrenPath, { mcpEnabled, hooksEnabled, skillsScope, installedVersion: VERSION, syncIntent });
|
|
1198
1212
|
if (repaired.removedLegacyProjects > 0) {
|
|
1199
1213
|
log(` Removed ${repaired.removedLegacyProjects} legacy starter project entr${repaired.removedLegacyProjects === 1 ? "y" : "ies"} from profiles.`);
|
|
1200
1214
|
}
|
|
@@ -1372,7 +1386,7 @@ export async function runInit(opts = {}) {
|
|
|
1372
1386
|
// Configure MCP for all detected AI coding tools and hooks
|
|
1373
1387
|
configureMcpTargets(phrenPath, { mcpEnabled, hooksEnabled }, "Configured");
|
|
1374
1388
|
configureHooksIfEnabled(phrenPath, hooksEnabled, "Configured");
|
|
1375
|
-
writeInstallPreferences(phrenPath, { mcpEnabled, hooksEnabled, skillsScope, installedVersion: VERSION });
|
|
1389
|
+
writeInstallPreferences(phrenPath, { mcpEnabled, hooksEnabled, skillsScope, installedVersion: VERSION, syncIntent });
|
|
1376
1390
|
// Post-init verification
|
|
1377
1391
|
log(`\nVerifying setup...`);
|
|
1378
1392
|
const verify = runPostInitVerify(phrenPath);
|
package/mcp/dist/mcp-ops.js
CHANGED
|
@@ -163,15 +163,52 @@ export function register(server, ctx) {
|
|
|
163
163
|
if ((process.env.PHREN_DEBUG))
|
|
164
164
|
process.stderr.write(`[phren] healthCheck taskMode: ${errorMessage(err)}\n`);
|
|
165
165
|
}
|
|
166
|
+
let syncIntent;
|
|
166
167
|
try {
|
|
167
168
|
const { readInstallPreferences } = await import("./init-preferences.js");
|
|
168
169
|
const prefs = readInstallPreferences(phrenPath);
|
|
169
170
|
proactivity = prefs.proactivity || "high";
|
|
171
|
+
syncIntent = prefs.syncIntent;
|
|
170
172
|
}
|
|
171
173
|
catch (err) {
|
|
172
174
|
if ((process.env.PHREN_DEBUG))
|
|
173
175
|
process.stderr.write(`[phren] healthCheck proactivity: ${errorMessage(err)}\n`);
|
|
174
176
|
}
|
|
177
|
+
// Determine sync status from intent + git remote state
|
|
178
|
+
let syncStatus = "local-only";
|
|
179
|
+
let syncDetail = "no git remote configured";
|
|
180
|
+
try {
|
|
181
|
+
const { execFileSync } = await import("child_process");
|
|
182
|
+
const remote = execFileSync("git", ["-C", phrenPath, "remote", "get-url", "origin"], {
|
|
183
|
+
encoding: "utf8",
|
|
184
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
185
|
+
timeout: 5_000,
|
|
186
|
+
}).trim();
|
|
187
|
+
if (remote) {
|
|
188
|
+
try {
|
|
189
|
+
execFileSync("git", ["-C", phrenPath, "ls-remote", "--exit-code", "origin"], {
|
|
190
|
+
stdio: ["ignore", "ignore", "ignore"],
|
|
191
|
+
timeout: 10_000,
|
|
192
|
+
});
|
|
193
|
+
syncStatus = "synced";
|
|
194
|
+
syncDetail = `origin=${remote}`;
|
|
195
|
+
}
|
|
196
|
+
catch {
|
|
197
|
+
syncStatus = syncIntent === "sync" ? "broken" : "local-only";
|
|
198
|
+
syncDetail = `origin=${remote} (unreachable)`;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
else if (syncIntent === "sync") {
|
|
202
|
+
syncStatus = "broken";
|
|
203
|
+
syncDetail = "sync was configured but no remote found";
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
catch {
|
|
207
|
+
if (syncIntent === "sync") {
|
|
208
|
+
syncStatus = "broken";
|
|
209
|
+
syncDetail = "sync was configured but no remote found";
|
|
210
|
+
}
|
|
211
|
+
}
|
|
175
212
|
const lines = [
|
|
176
213
|
`Phren v${version}`,
|
|
177
214
|
`Profile: ${activeProfile || "(default)"}`,
|
|
@@ -182,6 +219,7 @@ export function register(server, ctx) {
|
|
|
182
219
|
`Hooks: ${hooksEnabled ? "enabled" : "disabled"}`,
|
|
183
220
|
`Proactivity: ${proactivity}`,
|
|
184
221
|
`Task mode: ${taskMode}`,
|
|
222
|
+
`Sync: ${syncStatus}${syncStatus !== "synced" ? ` (${syncDetail})` : ""}`,
|
|
185
223
|
`Path: ${phrenPath}`,
|
|
186
224
|
].filter(Boolean);
|
|
187
225
|
return mcpResponse({
|
|
@@ -197,6 +235,8 @@ export function register(server, ctx) {
|
|
|
197
235
|
hooksEnabled,
|
|
198
236
|
proactivity,
|
|
199
237
|
taskMode,
|
|
238
|
+
syncStatus,
|
|
239
|
+
syncDetail,
|
|
200
240
|
phrenPath,
|
|
201
241
|
},
|
|
202
242
|
});
|