@codebyplan/cli 3.0.1 → 3.0.3
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/dist/cli.js +196 -170
- package/package.json +3 -3
package/dist/cli.js
CHANGED
|
@@ -37,7 +37,7 @@ var VERSION, PACKAGE_NAME;
|
|
|
37
37
|
var init_version = __esm({
|
|
38
38
|
"src/lib/version.ts"() {
|
|
39
39
|
"use strict";
|
|
40
|
-
VERSION = "3.0.
|
|
40
|
+
VERSION = "3.0.3";
|
|
41
41
|
PACKAGE_NAME = "@codebyplan/cli";
|
|
42
42
|
}
|
|
43
43
|
});
|
|
@@ -1042,79 +1042,11 @@ var init_fileMapper = __esm({
|
|
|
1042
1042
|
}
|
|
1043
1043
|
});
|
|
1044
1044
|
|
|
1045
|
-
// src/cli/
|
|
1045
|
+
// src/cli/confirm.ts
|
|
1046
1046
|
import { createInterface as createInterface2 } from "node:readline/promises";
|
|
1047
1047
|
import { stdin as stdin2, stdout as stdout2 } from "node:process";
|
|
1048
|
-
async function resolveConflicts(conflicts) {
|
|
1049
|
-
const resolutions = /* @__PURE__ */ new Map();
|
|
1050
|
-
if (conflicts.length === 0) return resolutions;
|
|
1051
|
-
const rl = createInterface2({ input: stdin2, output: stdout2 });
|
|
1052
|
-
try {
|
|
1053
|
-
console.log(`
|
|
1054
|
-
${conflicts.length} conflict(s) found:
|
|
1055
|
-
`);
|
|
1056
|
-
let applyToAll = null;
|
|
1057
|
-
for (let i = 0; i < conflicts.length; i++) {
|
|
1058
|
-
const conflict = conflicts[i];
|
|
1059
|
-
if (applyToAll) {
|
|
1060
|
-
resolutions.set(conflict.key, applyToAll);
|
|
1061
|
-
continue;
|
|
1062
|
-
}
|
|
1063
|
-
console.log(` Conflict ${i + 1}/${conflicts.length}: ${conflict.displayPath}`);
|
|
1064
|
-
if (conflict.localModified) {
|
|
1065
|
-
console.log(` Local: modified ${conflict.localModified}`);
|
|
1066
|
-
}
|
|
1067
|
-
if (conflict.remoteModified) {
|
|
1068
|
-
console.log(` Remote: modified ${conflict.remoteModified}`);
|
|
1069
|
-
}
|
|
1070
|
-
const remaining = conflicts.length - i;
|
|
1071
|
-
const prompt = remaining > 1 ? " [L] Push local [R] Keep remote [S] Skip [LA/RA/SA] Apply to all: " : " [L] Push local [R] Keep remote [S] Skip: ";
|
|
1072
|
-
const answer = (await rl.question(prompt)).trim().toUpperCase();
|
|
1073
|
-
switch (answer) {
|
|
1074
|
-
case "L":
|
|
1075
|
-
resolutions.set(conflict.key, "local");
|
|
1076
|
-
break;
|
|
1077
|
-
case "R":
|
|
1078
|
-
resolutions.set(conflict.key, "remote");
|
|
1079
|
-
break;
|
|
1080
|
-
case "LA":
|
|
1081
|
-
resolutions.set(conflict.key, "local");
|
|
1082
|
-
applyToAll = "local";
|
|
1083
|
-
break;
|
|
1084
|
-
case "RA":
|
|
1085
|
-
resolutions.set(conflict.key, "remote");
|
|
1086
|
-
applyToAll = "remote";
|
|
1087
|
-
break;
|
|
1088
|
-
case "SA":
|
|
1089
|
-
resolutions.set(conflict.key, "skip");
|
|
1090
|
-
applyToAll = "skip";
|
|
1091
|
-
break;
|
|
1092
|
-
default:
|
|
1093
|
-
resolutions.set(conflict.key, "skip");
|
|
1094
|
-
break;
|
|
1095
|
-
}
|
|
1096
|
-
}
|
|
1097
|
-
if (applyToAll) {
|
|
1098
|
-
const appliedCount = conflicts.length - [...resolutions.values()].filter((_, idx) => idx === 0).length;
|
|
1099
|
-
console.log(`
|
|
1100
|
-
Applied "${applyToAll}" to remaining conflicts.`);
|
|
1101
|
-
}
|
|
1102
|
-
} finally {
|
|
1103
|
-
rl.close();
|
|
1104
|
-
}
|
|
1105
|
-
return resolutions;
|
|
1106
|
-
}
|
|
1107
|
-
var init_conflict = __esm({
|
|
1108
|
-
"src/cli/conflict.ts"() {
|
|
1109
|
-
"use strict";
|
|
1110
|
-
}
|
|
1111
|
-
});
|
|
1112
|
-
|
|
1113
|
-
// src/cli/confirm.ts
|
|
1114
|
-
import { createInterface as createInterface3 } from "node:readline/promises";
|
|
1115
|
-
import { stdin as stdin3, stdout as stdout3 } from "node:process";
|
|
1116
1048
|
async function confirmProceed(message) {
|
|
1117
|
-
const rl =
|
|
1049
|
+
const rl = createInterface2({ input: stdin2, output: stdout2 });
|
|
1118
1050
|
try {
|
|
1119
1051
|
const answer = await rl.question(message ?? " Proceed? [Y/n] ");
|
|
1120
1052
|
const a = answer.trim().toLowerCase();
|
|
@@ -1273,8 +1205,8 @@ var sync_exports = {};
|
|
|
1273
1205
|
__export(sync_exports, {
|
|
1274
1206
|
runSync: () => runSync
|
|
1275
1207
|
});
|
|
1276
|
-
import { readFile as readFile7, writeFile as writeFile3 } from "node:fs/promises";
|
|
1277
|
-
import { join as join7 } from "node:path";
|
|
1208
|
+
import { readFile as readFile7, writeFile as writeFile3, mkdir as mkdir2, chmod as chmod2 } from "node:fs/promises";
|
|
1209
|
+
import { join as join7, dirname as dirname2 } from "node:path";
|
|
1278
1210
|
async function runSync() {
|
|
1279
1211
|
const flags = parseFlags(3);
|
|
1280
1212
|
const dryRun = hasFlag("dry-run", 3);
|
|
@@ -1289,118 +1221,191 @@ async function runSync() {
|
|
|
1289
1221
|
if (dryRun) console.log(` Mode: dry-run`);
|
|
1290
1222
|
if (force) console.log(` Mode: force`);
|
|
1291
1223
|
console.log();
|
|
1292
|
-
console.log("
|
|
1293
|
-
const pullResult = await executeSyncToLocal({ repoId, projectPath, dryRun });
|
|
1294
|
-
const pullChanges = pullResult.totals.created + pullResult.totals.updated + pullResult.totals.deleted;
|
|
1295
|
-
if (pullChanges > 0) {
|
|
1296
|
-
for (const [typeKey, result] of Object.entries(pullResult.byType)) {
|
|
1297
|
-
for (const name of result.created) console.log(` + ${typeKey}/${name}`);
|
|
1298
|
-
for (const name of result.updated) console.log(` ~ ${typeKey}/${name}`);
|
|
1299
|
-
for (const name of result.deleted) console.log(` - ${typeKey}/${name}`);
|
|
1300
|
-
}
|
|
1301
|
-
console.log(` ${pullResult.totals.created} created, ${pullResult.totals.updated} updated, ${pullResult.totals.deleted} deleted`);
|
|
1302
|
-
} else {
|
|
1303
|
-
console.log(" All files up to date.");
|
|
1304
|
-
}
|
|
1305
|
-
console.log("\n Phase 2: Push (local \u2192 DB)...");
|
|
1306
|
-
await executePush(repoId, projectPath, dryRun, force);
|
|
1307
|
-
console.log("\n Phase 3: Config sync...");
|
|
1308
|
-
await syncConfig(repoId, projectPath, dryRun);
|
|
1309
|
-
console.log("\n Phase 4: Tech stack...");
|
|
1310
|
-
await syncTechStack(repoId, projectPath, dryRun);
|
|
1311
|
-
console.log("\n Sync complete.\n");
|
|
1312
|
-
}
|
|
1313
|
-
async function executePush(repoId, projectPath, dryRun, force) {
|
|
1224
|
+
console.log(" Reading local and remote state...");
|
|
1314
1225
|
const claudeDir = join7(projectPath, ".claude");
|
|
1315
|
-
let localFiles;
|
|
1226
|
+
let localFiles = /* @__PURE__ */ new Map();
|
|
1316
1227
|
try {
|
|
1317
1228
|
localFiles = await scanLocalFiles(claudeDir, projectPath);
|
|
1318
1229
|
} catch {
|
|
1319
|
-
console.log(" No .claude/ directory found. Skipping push.");
|
|
1320
|
-
return;
|
|
1321
1230
|
}
|
|
1322
|
-
const [
|
|
1231
|
+
const [defaultsRes, repoSyncRes, repoRes] = await Promise.all([
|
|
1232
|
+
apiGet("/sync/defaults"),
|
|
1323
1233
|
apiGet("/sync/files", { repo_id: repoId }),
|
|
1324
1234
|
apiGet(`/repos/${repoId}`)
|
|
1325
1235
|
]);
|
|
1326
1236
|
const repoData = repoRes.data;
|
|
1327
|
-
const
|
|
1328
|
-
const
|
|
1329
|
-
const
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1237
|
+
const remoteDefaults = flattenSyncData(defaultsRes.data);
|
|
1238
|
+
const remoteRepoFiles = flattenSyncData(repoSyncRes.data);
|
|
1239
|
+
const remoteFiles = new Map([...remoteDefaults, ...remoteRepoFiles]);
|
|
1240
|
+
console.log(` Local: ${localFiles.size} files, Remote: ${remoteFiles.size} files
|
|
1241
|
+
`);
|
|
1242
|
+
const plan = [];
|
|
1243
|
+
const allKeys = /* @__PURE__ */ new Set([...localFiles.keys(), ...remoteFiles.keys()]);
|
|
1244
|
+
for (const key of allKeys) {
|
|
1245
|
+
const local = localFiles.get(key);
|
|
1333
1246
|
const remote = remoteFiles.get(key);
|
|
1334
|
-
if (!remote) {
|
|
1335
|
-
|
|
1336
|
-
|
|
1247
|
+
if (local && !remote) {
|
|
1248
|
+
plan.push({
|
|
1249
|
+
key,
|
|
1250
|
+
displayPath: `${local.type}/${local.category ? local.category + "/" : ""}${local.name}`,
|
|
1251
|
+
action: "push",
|
|
1252
|
+
localContent: local.content,
|
|
1253
|
+
remoteContent: null,
|
|
1254
|
+
pushContent: reverseSubstituteVariables(local.content, repoData),
|
|
1255
|
+
filePath: null,
|
|
1256
|
+
type: local.type,
|
|
1257
|
+
name: local.name,
|
|
1258
|
+
category: local.category,
|
|
1259
|
+
isHook: local.type === "hook"
|
|
1260
|
+
});
|
|
1261
|
+
} else if (!local && remote) {
|
|
1262
|
+
const resolvedContent = substituteVariables(remote.content, repoData);
|
|
1263
|
+
plan.push({
|
|
1264
|
+
key,
|
|
1265
|
+
displayPath: `${remote.type}/${remote.category ? remote.category + "/" : ""}${remote.name}`,
|
|
1266
|
+
action: "pull",
|
|
1267
|
+
localContent: null,
|
|
1268
|
+
remoteContent: resolvedContent,
|
|
1269
|
+
pushContent: null,
|
|
1270
|
+
filePath: getLocalFilePath(claudeDir, projectPath, remote),
|
|
1271
|
+
type: remote.type,
|
|
1272
|
+
name: remote.name,
|
|
1273
|
+
category: remote.category ?? null,
|
|
1274
|
+
isHook: remote.type === "hook"
|
|
1275
|
+
});
|
|
1276
|
+
} else if (local && remote) {
|
|
1337
1277
|
const resolvedRemote = substituteVariables(remote.content, repoData);
|
|
1338
|
-
if (local.content
|
|
1339
|
-
|
|
1340
|
-
if (force) {
|
|
1341
|
-
toUpsert.push(reversed);
|
|
1342
|
-
} else {
|
|
1343
|
-
conflicts.push({
|
|
1344
|
-
key,
|
|
1345
|
-
displayPath: `${local.type}/${local.category ? local.category + "/" : ""}${local.name}`,
|
|
1346
|
-
remoteModified: remote.updated_at
|
|
1347
|
-
});
|
|
1348
|
-
conflictLocalRecords.set(key, reversed);
|
|
1349
|
-
}
|
|
1278
|
+
if (local.content === resolvedRemote) {
|
|
1279
|
+
continue;
|
|
1350
1280
|
}
|
|
1281
|
+
const repoSyncAt = repoRes.data.claude_sync_at;
|
|
1282
|
+
const remoteUpdatedAt = remote.updated_at;
|
|
1283
|
+
const remoteChanged = remoteUpdatedAt && repoSyncAt ? new Date(remoteUpdatedAt) > new Date(repoSyncAt) : true;
|
|
1284
|
+
let action;
|
|
1285
|
+
if (remoteChanged && force) {
|
|
1286
|
+
action = "pull";
|
|
1287
|
+
} else if (!remoteChanged) {
|
|
1288
|
+
action = "push";
|
|
1289
|
+
} else {
|
|
1290
|
+
action = "pull";
|
|
1291
|
+
}
|
|
1292
|
+
plan.push({
|
|
1293
|
+
key,
|
|
1294
|
+
displayPath: `${local.type}/${local.category ? local.category + "/" : ""}${local.name}`,
|
|
1295
|
+
action,
|
|
1296
|
+
localContent: local.content,
|
|
1297
|
+
remoteContent: resolvedRemote,
|
|
1298
|
+
pushContent: action === "push" ? reverseSubstituteVariables(local.content, repoData) : null,
|
|
1299
|
+
filePath: getLocalFilePath(claudeDir, projectPath, remote),
|
|
1300
|
+
type: local.type,
|
|
1301
|
+
name: local.name,
|
|
1302
|
+
category: local.category,
|
|
1303
|
+
isHook: local.type === "hook"
|
|
1304
|
+
});
|
|
1351
1305
|
}
|
|
1352
1306
|
}
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
}
|
|
1307
|
+
const pulls = plan.filter((p) => p.action === "pull");
|
|
1308
|
+
const pushes = plan.filter((p) => p.action === "push");
|
|
1309
|
+
if (pulls.length > 0) {
|
|
1310
|
+
console.log(` Pull (DB \u2192 local): ${pulls.length}`);
|
|
1311
|
+
for (const p of pulls) console.log(` \u2193 ${p.displayPath}`);
|
|
1312
|
+
}
|
|
1313
|
+
if (pushes.length > 0) {
|
|
1314
|
+
console.log(` Push (local \u2192 DB): ${pushes.length}`);
|
|
1315
|
+
for (const p of pushes) console.log(` \u2191 ${p.displayPath}`);
|
|
1357
1316
|
}
|
|
1358
|
-
if (
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1317
|
+
if (pulls.length === 0 && pushes.length === 0) {
|
|
1318
|
+
console.log(" All .claude/ files in sync.");
|
|
1319
|
+
}
|
|
1320
|
+
if (plan.length > 0 && !dryRun) {
|
|
1321
|
+
if (!force && pulls.length + pushes.length > 0) {
|
|
1322
|
+
console.log();
|
|
1323
|
+
const confirmed = await confirmProceed();
|
|
1324
|
+
if (!confirmed) {
|
|
1325
|
+
console.log(" Cancelled.\n");
|
|
1326
|
+
return;
|
|
1364
1327
|
}
|
|
1365
1328
|
}
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1329
|
+
for (const p of pulls) {
|
|
1330
|
+
if (p.filePath && p.remoteContent !== null) {
|
|
1331
|
+
await mkdir2(dirname2(p.filePath), { recursive: true });
|
|
1332
|
+
await writeFile3(p.filePath, p.remoteContent, "utf-8");
|
|
1333
|
+
if (p.isHook) await chmod2(p.filePath, 493);
|
|
1334
|
+
}
|
|
1370
1335
|
}
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1336
|
+
const toUpsert = pushes.filter((p) => p.pushContent !== null).map((p) => ({
|
|
1337
|
+
type: p.type,
|
|
1338
|
+
name: p.name,
|
|
1339
|
+
category: p.category,
|
|
1340
|
+
content: p.pushContent
|
|
1341
|
+
}));
|
|
1342
|
+
if (toUpsert.length > 0) {
|
|
1343
|
+
await apiPost("/sync/files", {
|
|
1344
|
+
repo_id: repoId,
|
|
1345
|
+
files: toUpsert
|
|
1346
|
+
});
|
|
1375
1347
|
}
|
|
1348
|
+
await apiPut(`/repos/${repoId}`, { claude_sync_at: (/* @__PURE__ */ new Date()).toISOString() });
|
|
1349
|
+
console.log(`
|
|
1350
|
+
Applied: ${pulls.length} pulled, ${pushes.length} pushed`);
|
|
1351
|
+
} else if (dryRun) {
|
|
1352
|
+
console.log("\n (dry-run \u2014 no changes)");
|
|
1353
|
+
}
|
|
1354
|
+
console.log("\n Settings sync...");
|
|
1355
|
+
await syncSettings(claudeDir, projectPath, defaultsRes.data, repoData, dryRun);
|
|
1356
|
+
console.log(" Config sync...");
|
|
1357
|
+
await syncConfig(repoId, projectPath, dryRun);
|
|
1358
|
+
console.log(" Tech stack...");
|
|
1359
|
+
await syncTechStack(repoId, projectPath, dryRun);
|
|
1360
|
+
console.log("\n Sync complete.\n");
|
|
1361
|
+
}
|
|
1362
|
+
async function syncSettings(claudeDir, projectPath, syncData, repoData, dryRun) {
|
|
1363
|
+
const settingsPath = join7(claudeDir, "settings.json");
|
|
1364
|
+
const globalSettingsFiles = syncData.global_settings ?? [];
|
|
1365
|
+
let globalSettings = {};
|
|
1366
|
+
for (const gf of globalSettingsFiles) {
|
|
1367
|
+
const parsed = JSON.parse(substituteVariables(gf.content, repoData));
|
|
1368
|
+
globalSettings = { ...globalSettings, ...parsed };
|
|
1369
|
+
}
|
|
1370
|
+
const repoSettingsFiles = syncData.settings ?? [];
|
|
1371
|
+
let repoSettings = {};
|
|
1372
|
+
for (const rf of repoSettingsFiles) {
|
|
1373
|
+
repoSettings = JSON.parse(substituteVariables(rf.content, repoData));
|
|
1374
|
+
}
|
|
1375
|
+
const combinedTemplate = mergeGlobalAndRepoSettings(globalSettings, repoSettings);
|
|
1376
|
+
const hooksDir = join7(projectPath, ".claude", "hooks");
|
|
1377
|
+
const discovered = await discoverHooks(hooksDir);
|
|
1378
|
+
let localSettings = {};
|
|
1379
|
+
try {
|
|
1380
|
+
const raw = await readFile7(settingsPath, "utf-8");
|
|
1381
|
+
localSettings = JSON.parse(raw);
|
|
1382
|
+
} catch {
|
|
1383
|
+
}
|
|
1384
|
+
let merged = Object.keys(localSettings).length > 0 ? mergeSettings(combinedTemplate, localSettings) : combinedTemplate;
|
|
1385
|
+
merged = stripPermissionsAllow(merged);
|
|
1386
|
+
if (discovered.size > 0) {
|
|
1387
|
+
merged.hooks = mergeDiscoveredHooks(
|
|
1388
|
+
merged.hooks ?? {},
|
|
1389
|
+
discovered
|
|
1390
|
+
);
|
|
1391
|
+
}
|
|
1392
|
+
const mergedContent = JSON.stringify(merged, null, 2) + "\n";
|
|
1393
|
+
let currentContent = "";
|
|
1394
|
+
try {
|
|
1395
|
+
currentContent = await readFile7(settingsPath, "utf-8");
|
|
1396
|
+
} catch {
|
|
1376
1397
|
}
|
|
1377
|
-
if (
|
|
1378
|
-
console.log("
|
|
1398
|
+
if (currentContent === mergedContent) {
|
|
1399
|
+
console.log(" Settings up to date.");
|
|
1379
1400
|
return;
|
|
1380
1401
|
}
|
|
1381
1402
|
if (dryRun) {
|
|
1382
|
-
console.log(" (dry-run
|
|
1403
|
+
console.log(" Settings would be updated (dry-run).");
|
|
1383
1404
|
return;
|
|
1384
1405
|
}
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
console.log(" Cancelled.");
|
|
1389
|
-
return;
|
|
1390
|
-
}
|
|
1391
|
-
}
|
|
1392
|
-
const result = await apiPost("/sync/files", {
|
|
1393
|
-
repo_id: repoId,
|
|
1394
|
-
files: toUpsert.map((f) => ({
|
|
1395
|
-
type: f.type,
|
|
1396
|
-
name: f.name,
|
|
1397
|
-
category: f.category,
|
|
1398
|
-
content: f.content
|
|
1399
|
-
})),
|
|
1400
|
-
delete_keys: toDelete
|
|
1401
|
-
});
|
|
1402
|
-
await apiPut(`/repos/${repoId}`, { claude_sync_at: (/* @__PURE__ */ new Date()).toISOString() });
|
|
1403
|
-
console.log(` ${result.data.upserted} upserted, ${result.data.deleted} deleted`);
|
|
1406
|
+
await mkdir2(dirname2(settingsPath), { recursive: true });
|
|
1407
|
+
await writeFile3(settingsPath, mergedContent, "utf-8");
|
|
1408
|
+
console.log(" Updated settings.json");
|
|
1404
1409
|
}
|
|
1405
1410
|
async function syncConfig(repoId, projectPath, dryRun) {
|
|
1406
1411
|
const configPath = join7(projectPath, ".codebyplan.json");
|
|
@@ -1462,6 +1467,27 @@ async function syncTechStack(repoId, projectPath, dryRun) {
|
|
|
1462
1467
|
console.log(" Tech stack detection skipped.");
|
|
1463
1468
|
}
|
|
1464
1469
|
}
|
|
1470
|
+
function getLocalFilePath(claudeDir, projectPath, remote) {
|
|
1471
|
+
const typeConfig2 = {
|
|
1472
|
+
command: { dir: "commands", ext: ".md" },
|
|
1473
|
+
agent: { dir: "agents", ext: ".md", subfolder: "AGENT" },
|
|
1474
|
+
skill: { dir: "skills", ext: ".md", subfolder: "SKILL" },
|
|
1475
|
+
rule: { dir: "rules", ext: ".md" },
|
|
1476
|
+
hook: { dir: "hooks", ext: ".sh" },
|
|
1477
|
+
template: { dir: "templates", ext: "" },
|
|
1478
|
+
claude_md: { dir: "", ext: "" },
|
|
1479
|
+
settings: { dir: "", ext: "" }
|
|
1480
|
+
};
|
|
1481
|
+
if (remote.type === "claude_md") return join7(projectPath, "CLAUDE.md");
|
|
1482
|
+
if (remote.type === "settings") return join7(claudeDir, "settings.json");
|
|
1483
|
+
const cfg = typeConfig2[remote.type];
|
|
1484
|
+
if (!cfg) return join7(claudeDir, remote.name);
|
|
1485
|
+
const typeDir = remote.type === "command" ? join7(claudeDir, cfg.dir, "cbp") : join7(claudeDir, cfg.dir);
|
|
1486
|
+
if (cfg.subfolder) return join7(typeDir, remote.name, `${cfg.subfolder}${cfg.ext}`);
|
|
1487
|
+
if (remote.type === "command" && remote.category) return join7(typeDir, remote.category, `${remote.name}${cfg.ext}`);
|
|
1488
|
+
if (remote.type === "template") return join7(typeDir, remote.name);
|
|
1489
|
+
return join7(typeDir, `${remote.name}${cfg.ext}`);
|
|
1490
|
+
}
|
|
1465
1491
|
function flattenSyncData(data) {
|
|
1466
1492
|
const result = /* @__PURE__ */ new Map();
|
|
1467
1493
|
const typeMap = {
|
|
@@ -1493,12 +1519,12 @@ var init_sync = __esm({
|
|
|
1493
1519
|
"use strict";
|
|
1494
1520
|
init_config();
|
|
1495
1521
|
init_fileMapper();
|
|
1496
|
-
init_conflict();
|
|
1497
1522
|
init_confirm();
|
|
1498
1523
|
init_api();
|
|
1499
|
-
init_sync_engine();
|
|
1500
1524
|
init_variables();
|
|
1501
1525
|
init_tech_detect();
|
|
1526
|
+
init_settings_merge();
|
|
1527
|
+
init_hook_registry();
|
|
1502
1528
|
}
|
|
1503
1529
|
});
|
|
1504
1530
|
|
|
@@ -23316,11 +23342,11 @@ async function createPR(options) {
|
|
|
23316
23342
|
}
|
|
23317
23343
|
} catch {
|
|
23318
23344
|
}
|
|
23319
|
-
const { stdout:
|
|
23345
|
+
const { stdout: stdout3 } = await exec(
|
|
23320
23346
|
`gh pr create --head "${head}" --base "${base}" --title "${title.replace(/"/g, '\\"')}" --body "${body.replace(/"/g, '\\"')}"`,
|
|
23321
23347
|
{ cwd: repoPath }
|
|
23322
23348
|
);
|
|
23323
|
-
const prUrl =
|
|
23349
|
+
const prUrl = stdout3.trim();
|
|
23324
23350
|
const prNumber = parseInt(prUrl.split("/").pop() ?? "0", 10);
|
|
23325
23351
|
return { pr_url: prUrl, pr_number: prNumber || null };
|
|
23326
23352
|
} catch (err) {
|
|
@@ -23331,11 +23357,11 @@ async function createPR(options) {
|
|
|
23331
23357
|
async function mergePR(options) {
|
|
23332
23358
|
const { repoPath, prNumber, mergeMethod } = options;
|
|
23333
23359
|
try {
|
|
23334
|
-
const { stdout:
|
|
23360
|
+
const { stdout: stdout3 } = await exec(
|
|
23335
23361
|
`gh pr merge ${prNumber} --${mergeMethod} --delete-branch`,
|
|
23336
23362
|
{ cwd: repoPath }
|
|
23337
23363
|
);
|
|
23338
|
-
return { merged: true, message:
|
|
23364
|
+
return { merged: true, message: stdout3.trim() || `PR #${prNumber} merged via ${mergeMethod}` };
|
|
23339
23365
|
} catch (err) {
|
|
23340
23366
|
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
23341
23367
|
return { merged: false, message: "Merge failed", error: errorMessage };
|
|
@@ -23343,11 +23369,11 @@ async function mergePR(options) {
|
|
|
23343
23369
|
}
|
|
23344
23370
|
async function getPRStatus(repoPath, prNumber) {
|
|
23345
23371
|
try {
|
|
23346
|
-
const { stdout:
|
|
23372
|
+
const { stdout: stdout3 } = await exec(
|
|
23347
23373
|
`gh pr view ${prNumber} --json state,mergeable,title,url,number`,
|
|
23348
23374
|
{ cwd: repoPath }
|
|
23349
23375
|
);
|
|
23350
|
-
const pr = JSON.parse(
|
|
23376
|
+
const pr = JSON.parse(stdout3.trim());
|
|
23351
23377
|
return {
|
|
23352
23378
|
state: pr.state,
|
|
23353
23379
|
mergeable: pr.mergeable,
|
|
@@ -24192,7 +24218,7 @@ function registerFileGenTools(server) {
|
|
|
24192
24218
|
}
|
|
24193
24219
|
const addCmd = files && files.length > 0 ? `git add ${files.map((f) => `"${f}"`).join(" ")}` : "git add .";
|
|
24194
24220
|
await exec2(addCmd, { cwd: repo.path });
|
|
24195
|
-
const { stdout:
|
|
24221
|
+
const { stdout: stdout3, stderr } = await exec2(
|
|
24196
24222
|
`git commit -m "${message.replace(/"/g, '\\"')}"`,
|
|
24197
24223
|
{ cwd: repo.path }
|
|
24198
24224
|
);
|
|
@@ -24203,7 +24229,7 @@ function registerFileGenTools(server) {
|
|
|
24203
24229
|
text: JSON.stringify({
|
|
24204
24230
|
status: "committed",
|
|
24205
24231
|
branch: branch.trim(),
|
|
24206
|
-
output:
|
|
24232
|
+
output: stdout3.trim(),
|
|
24207
24233
|
warnings: stderr.trim() || void 0
|
|
24208
24234
|
}, null, 2)
|
|
24209
24235
|
}]
|
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@codebyplan/cli",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.3",
|
|
4
4
|
"description": "MCP server for CodeByPlan — AI-powered development planning and tracking",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
|
-
"@codebyplan/cli": "dist/
|
|
8
|
-
"codebyplan": "dist/
|
|
7
|
+
"@codebyplan/cli": "dist/cli.js",
|
|
8
|
+
"codebyplan": "dist/cli.js"
|
|
9
9
|
},
|
|
10
10
|
"files": [
|
|
11
11
|
"dist/cli.js",
|