codebyplan 1.13.8 → 1.13.10
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 +436 -110
- package/package.json +1 -1
- package/templates/hooks/cbp-mcp-round-sync.sh +17 -1
- package/templates/settings.project.base.json +2 -0
- package/templates/skills/cbp-git-worktree-create/SKILL.md +1 -1
- package/templates/skills/cbp-round-update/SKILL.md +14 -1
- package/templates/skills/cbp-session-end/SKILL.md +28 -75
- package/templates/skills/cbp-session-start/SKILL.md +46 -30
package/dist/cli.js
CHANGED
|
@@ -14,7 +14,7 @@ var VERSION, PACKAGE_NAME;
|
|
|
14
14
|
var init_version = __esm({
|
|
15
15
|
"src/lib/version.ts"() {
|
|
16
16
|
"use strict";
|
|
17
|
-
VERSION = "1.13.
|
|
17
|
+
VERSION = "1.13.10";
|
|
18
18
|
PACKAGE_NAME = "codebyplan";
|
|
19
19
|
}
|
|
20
20
|
});
|
|
@@ -148,6 +148,7 @@ var init_gitignore_block = __esm({
|
|
|
148
148
|
".claude/scheduled_tasks.lock",
|
|
149
149
|
".codebyplan/device.local.json",
|
|
150
150
|
".codebyplan/statusline.local.json",
|
|
151
|
+
".codebyplan/worktree.local.json",
|
|
151
152
|
".codebyplan.local.json"
|
|
152
153
|
];
|
|
153
154
|
GITIGNORE_BLOCK_START = "# >>> codebyplan (managed) >>>";
|
|
@@ -1443,8 +1444,8 @@ async function runSetup() {
|
|
|
1443
1444
|
const deviceId = await getOrCreateDeviceId(projectPath);
|
|
1444
1445
|
let branch = "main";
|
|
1445
1446
|
try {
|
|
1446
|
-
const { execSync:
|
|
1447
|
-
branch =
|
|
1447
|
+
const { execSync: execSync8 } = await import("node:child_process");
|
|
1448
|
+
branch = execSync8("git symbolic-ref --short HEAD", {
|
|
1448
1449
|
cwd: projectPath,
|
|
1449
1450
|
encoding: "utf-8"
|
|
1450
1451
|
}).trim();
|
|
@@ -3064,9 +3065,9 @@ async function eslintInit(repoId, projectPath) {
|
|
|
3064
3065
|
Install ${missingPkgs.length} missing packages? [Y/n] `
|
|
3065
3066
|
);
|
|
3066
3067
|
if (confirmed) {
|
|
3067
|
-
const { execSync:
|
|
3068
|
+
const { execSync: execSync8 } = await import("node:child_process");
|
|
3068
3069
|
try {
|
|
3069
|
-
|
|
3070
|
+
execSync8(installCmd, { cwd: projectPath, stdio: "inherit" });
|
|
3070
3071
|
console.log(" Packages installed.\n");
|
|
3071
3072
|
} catch (err) {
|
|
3072
3073
|
console.error(
|
|
@@ -3409,6 +3410,81 @@ var init_sync_approvals = __esm({
|
|
|
3409
3410
|
}
|
|
3410
3411
|
});
|
|
3411
3412
|
|
|
3413
|
+
// src/lib/worktree-cache.ts
|
|
3414
|
+
import { mkdir as mkdir5, readFile as readFile11, writeFile as writeFile9 } from "node:fs/promises";
|
|
3415
|
+
import { dirname as dirname4, join as join11 } from "node:path";
|
|
3416
|
+
function worktreeCachePath(repoRoot) {
|
|
3417
|
+
return join11(repoRoot, ".codebyplan", "worktree.local.json");
|
|
3418
|
+
}
|
|
3419
|
+
async function readCachedWorktreeId(repoRoot, currentBranch) {
|
|
3420
|
+
const cachePath = worktreeCachePath(repoRoot);
|
|
3421
|
+
let raw;
|
|
3422
|
+
try {
|
|
3423
|
+
raw = await readFile11(cachePath, "utf-8");
|
|
3424
|
+
} catch (err) {
|
|
3425
|
+
const code = err.code;
|
|
3426
|
+
if (code === "ENOENT") {
|
|
3427
|
+
return null;
|
|
3428
|
+
}
|
|
3429
|
+
console.warn(
|
|
3430
|
+
`worktree-cache: read failed (non-fatal): ${err instanceof Error ? err.message : String(err)}`
|
|
3431
|
+
);
|
|
3432
|
+
return null;
|
|
3433
|
+
}
|
|
3434
|
+
let parsed;
|
|
3435
|
+
try {
|
|
3436
|
+
parsed = JSON.parse(raw);
|
|
3437
|
+
} catch {
|
|
3438
|
+
console.warn(
|
|
3439
|
+
"worktree-cache: JSON parse failed (non-fatal): cache entry will be ignored"
|
|
3440
|
+
);
|
|
3441
|
+
return null;
|
|
3442
|
+
}
|
|
3443
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed) || typeof parsed.worktree_id !== "string" || typeof parsed.branch !== "string" || typeof parsed.device_id !== "string" || typeof parsed.resolved_at !== "string") {
|
|
3444
|
+
return null;
|
|
3445
|
+
}
|
|
3446
|
+
const data = parsed;
|
|
3447
|
+
if (!data.branch || data.branch !== currentBranch) {
|
|
3448
|
+
return null;
|
|
3449
|
+
}
|
|
3450
|
+
return data.worktree_id;
|
|
3451
|
+
}
|
|
3452
|
+
async function writeWorktreeCache(repoRoot, data) {
|
|
3453
|
+
if (!data.branch) {
|
|
3454
|
+
console.warn(
|
|
3455
|
+
"worktree-cache: skipping write for empty branch (detached HEAD or non-repo)"
|
|
3456
|
+
);
|
|
3457
|
+
return false;
|
|
3458
|
+
}
|
|
3459
|
+
const cachePath = worktreeCachePath(repoRoot);
|
|
3460
|
+
const dirPath = dirname4(cachePath);
|
|
3461
|
+
const payload = {
|
|
3462
|
+
worktree_id: data.worktree_id,
|
|
3463
|
+
branch: data.branch,
|
|
3464
|
+
device_id: data.device_id,
|
|
3465
|
+
resolved_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
3466
|
+
};
|
|
3467
|
+
try {
|
|
3468
|
+
await mkdir5(dirPath, { recursive: true });
|
|
3469
|
+
await writeFile9(
|
|
3470
|
+
cachePath,
|
|
3471
|
+
JSON.stringify(payload, null, 2) + "\n",
|
|
3472
|
+
"utf-8"
|
|
3473
|
+
);
|
|
3474
|
+
return true;
|
|
3475
|
+
} catch (err) {
|
|
3476
|
+
console.warn(
|
|
3477
|
+
`worktree-cache: write failed (non-fatal): ${err instanceof Error ? err.message : String(err)}`
|
|
3478
|
+
);
|
|
3479
|
+
return false;
|
|
3480
|
+
}
|
|
3481
|
+
}
|
|
3482
|
+
var init_worktree_cache = __esm({
|
|
3483
|
+
"src/lib/worktree-cache.ts"() {
|
|
3484
|
+
"use strict";
|
|
3485
|
+
}
|
|
3486
|
+
});
|
|
3487
|
+
|
|
3412
3488
|
// src/cli/round.ts
|
|
3413
3489
|
var round_exports = {};
|
|
3414
3490
|
__export(round_exports, {
|
|
@@ -3420,7 +3496,7 @@ __export(round_exports, {
|
|
|
3420
3496
|
setRetryDelayMs: () => setRetryDelayMs
|
|
3421
3497
|
});
|
|
3422
3498
|
import { access as access3 } from "node:fs/promises";
|
|
3423
|
-
import { join as
|
|
3499
|
+
import { join as join12 } from "node:path";
|
|
3424
3500
|
import { execSync as execSync2 } from "node:child_process";
|
|
3425
3501
|
function setRetryDelayMs(ms) {
|
|
3426
3502
|
RETRY_DELAY_MS = ms;
|
|
@@ -3480,6 +3556,34 @@ function printRoundHelp() {
|
|
|
3480
3556
|
"\n codebyplan round <subcommand>\n\n Subcommands:\n sync-approvals Sync git diff and approvals with round/task state\n\n sync-approvals flags:\n --round-id <uuid> Round UUID (required)\n --task-id <uuid> Task UUID (required)\n --dry-run Print merged payload to stdout without writing\n\n"
|
|
3481
3557
|
);
|
|
3482
3558
|
}
|
|
3559
|
+
async function resolveCallerWorktreeId(repoRoot, currentBranch, repoId, overrideId) {
|
|
3560
|
+
if (overrideId) {
|
|
3561
|
+
return overrideId;
|
|
3562
|
+
}
|
|
3563
|
+
const cached = await readCachedWorktreeId(repoRoot, currentBranch);
|
|
3564
|
+
if (cached) {
|
|
3565
|
+
return cached;
|
|
3566
|
+
}
|
|
3567
|
+
if (!repoId || !currentBranch) {
|
|
3568
|
+
return null;
|
|
3569
|
+
}
|
|
3570
|
+
const deviceId = await getOrCreateDeviceId(repoRoot);
|
|
3571
|
+
const wid = await resolveWorktreeId({
|
|
3572
|
+
repoId,
|
|
3573
|
+
repoPath: repoRoot,
|
|
3574
|
+
branch: currentBranch,
|
|
3575
|
+
deviceId
|
|
3576
|
+
});
|
|
3577
|
+
if (wid) {
|
|
3578
|
+
await writeWorktreeCache(repoRoot, {
|
|
3579
|
+
worktree_id: wid,
|
|
3580
|
+
branch: currentBranch,
|
|
3581
|
+
device_id: deviceId
|
|
3582
|
+
});
|
|
3583
|
+
return wid;
|
|
3584
|
+
}
|
|
3585
|
+
return null;
|
|
3586
|
+
}
|
|
3483
3587
|
function parseFlagsFromArgs(args) {
|
|
3484
3588
|
const flags = {};
|
|
3485
3589
|
const booleans = /* @__PURE__ */ new Set();
|
|
@@ -3503,6 +3607,7 @@ async function runRoundSyncApprovals(args) {
|
|
|
3503
3607
|
const roundId = flags["round-id"];
|
|
3504
3608
|
const taskId = flags["task-id"];
|
|
3505
3609
|
const dryRun = booleans.has("dry-run");
|
|
3610
|
+
const overrideWorktreeId = flags["caller-worktree-id"];
|
|
3506
3611
|
if (!roundId) {
|
|
3507
3612
|
process.stderr.write(
|
|
3508
3613
|
"sync-approvals: --round-id is required\nUsage: codebyplan round sync-approvals --round-id <uuid> --task-id <uuid>\n"
|
|
@@ -3523,6 +3628,14 @@ async function runRoundSyncApprovals(args) {
|
|
|
3523
3628
|
// Walk up to the directory containing .codebyplan/ or .codebyplan.json
|
|
3524
3629
|
found.path.replace(/\/.codebyplan(\.json|\/repo\.json)$/, "")
|
|
3525
3630
|
) : process.cwd();
|
|
3631
|
+
let currentBranch = "";
|
|
3632
|
+
try {
|
|
3633
|
+
currentBranch = execSync2("git symbolic-ref --short HEAD", {
|
|
3634
|
+
cwd: repoRoot,
|
|
3635
|
+
encoding: "utf-8"
|
|
3636
|
+
}).trim();
|
|
3637
|
+
} catch {
|
|
3638
|
+
}
|
|
3526
3639
|
let rounds;
|
|
3527
3640
|
try {
|
|
3528
3641
|
rounds = await fetchRoundsWithRetry(taskId);
|
|
@@ -3542,6 +3655,17 @@ async function runRoundSyncApprovals(args) {
|
|
|
3542
3655
|
}
|
|
3543
3656
|
const taskResponse = await apiGet(`/tasks/${taskId}`);
|
|
3544
3657
|
const currentTask = taskResponse.data;
|
|
3658
|
+
const callerWorktreeId = await resolveCallerWorktreeId(
|
|
3659
|
+
repoRoot,
|
|
3660
|
+
currentBranch,
|
|
3661
|
+
found?.contents.repo_id,
|
|
3662
|
+
overrideWorktreeId
|
|
3663
|
+
);
|
|
3664
|
+
if (!dryRun && !callerWorktreeId) {
|
|
3665
|
+
throw new Error(
|
|
3666
|
+
"could not resolve caller_worktree_id for this worktree.\n Run: codebyplan resolve-worktree --cache\n If this worktree is not registered, run: npx codebyplan setup\n Then re-run /cbp-round-update (sync-approvals)."
|
|
3667
|
+
);
|
|
3668
|
+
}
|
|
3545
3669
|
let gitStatusOutput = "";
|
|
3546
3670
|
try {
|
|
3547
3671
|
gitStatusOutput = execSync2("git status --short --porcelain -z", {
|
|
@@ -3553,7 +3677,7 @@ async function runRoundSyncApprovals(args) {
|
|
|
3553
3677
|
"sync-approvals: git status failed; proceeding with empty diff\n"
|
|
3554
3678
|
);
|
|
3555
3679
|
}
|
|
3556
|
-
const hookPath =
|
|
3680
|
+
const hookPath = join12(
|
|
3557
3681
|
repoRoot,
|
|
3558
3682
|
".claude",
|
|
3559
3683
|
"hooks",
|
|
@@ -3586,12 +3710,14 @@ async function runRoundSyncApprovals(args) {
|
|
|
3586
3710
|
} else {
|
|
3587
3711
|
await mcpCall("update_round", {
|
|
3588
3712
|
round_id: roundId,
|
|
3589
|
-
files_changed: result.merged_files_changed
|
|
3713
|
+
files_changed: result.merged_files_changed,
|
|
3714
|
+
caller_worktree_id: callerWorktreeId
|
|
3590
3715
|
});
|
|
3591
3716
|
await mcpCall("update_task", {
|
|
3592
3717
|
task_id: taskId,
|
|
3593
3718
|
files_changed: result.merged_files_changed,
|
|
3594
|
-
app_file_approval_by_user: false
|
|
3719
|
+
app_file_approval_by_user: false,
|
|
3720
|
+
caller_worktree_id: callerWorktreeId
|
|
3595
3721
|
});
|
|
3596
3722
|
stdoutPayload = JSON.stringify(
|
|
3597
3723
|
{
|
|
@@ -3634,13 +3760,16 @@ var init_round = __esm({
|
|
|
3634
3760
|
init_mcp_client();
|
|
3635
3761
|
init_flags();
|
|
3636
3762
|
init_sync_approvals();
|
|
3763
|
+
init_worktree_cache();
|
|
3764
|
+
init_resolve_worktree();
|
|
3765
|
+
init_local_config();
|
|
3637
3766
|
RETRY_DELAY_MS = 1e3;
|
|
3638
3767
|
}
|
|
3639
3768
|
});
|
|
3640
3769
|
|
|
3641
3770
|
// src/lib/migrate-branch-model.ts
|
|
3642
|
-
import { readFile as
|
|
3643
|
-
import { join as
|
|
3771
|
+
import { readFile as readFile12, writeFile as writeFile10 } from "node:fs/promises";
|
|
3772
|
+
import { join as join13 } from "node:path";
|
|
3644
3773
|
import { execSync as execSync3 } from "node:child_process";
|
|
3645
3774
|
function assertValidBranchName(branch) {
|
|
3646
3775
|
if (!/^[a-zA-Z0-9/_.-]+$/.test(branch)) {
|
|
@@ -3650,7 +3779,7 @@ function assertValidBranchName(branch) {
|
|
|
3650
3779
|
}
|
|
3651
3780
|
}
|
|
3652
3781
|
async function readJsonFile(filePath) {
|
|
3653
|
-
const raw = await
|
|
3782
|
+
const raw = await readFile12(filePath, "utf-8");
|
|
3654
3783
|
const parsed = JSON.parse(raw);
|
|
3655
3784
|
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
3656
3785
|
throw new Error(`${filePath} does not contain a JSON object`);
|
|
@@ -3719,12 +3848,12 @@ async function runBranchMigration(opts) {
|
|
|
3719
3848
|
if (found) {
|
|
3720
3849
|
if (found.path.endsWith("/repo.json")) {
|
|
3721
3850
|
const dir = found.path.slice(0, found.path.lastIndexOf("/"));
|
|
3722
|
-
configPath =
|
|
3851
|
+
configPath = join13(dir, "git.json");
|
|
3723
3852
|
} else {
|
|
3724
3853
|
configPath = found.path;
|
|
3725
3854
|
}
|
|
3726
3855
|
} else {
|
|
3727
|
-
configPath =
|
|
3856
|
+
configPath = join13(cwd, ".codebyplan", "git.json");
|
|
3728
3857
|
}
|
|
3729
3858
|
let fileRaw;
|
|
3730
3859
|
let fileParsed;
|
|
@@ -3798,7 +3927,7 @@ async function runBranchMigration(opts) {
|
|
|
3798
3927
|
const updatedParsed = { ...fileParsed, branch_config: after };
|
|
3799
3928
|
const newJson = JSON.stringify(updatedParsed, null, 2) + "\n";
|
|
3800
3929
|
if (newJson !== fileRaw) {
|
|
3801
|
-
await
|
|
3930
|
+
await writeFile10(configPath, newJson, "utf-8");
|
|
3802
3931
|
}
|
|
3803
3932
|
}
|
|
3804
3933
|
return {
|
|
@@ -3904,8 +4033,8 @@ var init_branch = __esm({
|
|
|
3904
4033
|
});
|
|
3905
4034
|
|
|
3906
4035
|
// src/lib/git-utils.ts
|
|
3907
|
-
import { readFile as
|
|
3908
|
-
import { join as
|
|
4036
|
+
import { readFile as readFile13 } from "node:fs/promises";
|
|
4037
|
+
import { join as join14 } from "node:path";
|
|
3909
4038
|
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
3910
4039
|
async function readBaseBranch(cwd) {
|
|
3911
4040
|
const found = await findCodebyplanConfig(cwd);
|
|
@@ -3913,15 +4042,15 @@ async function readBaseBranch(cwd) {
|
|
|
3913
4042
|
if (found) {
|
|
3914
4043
|
if (found.path.endsWith("/repo.json")) {
|
|
3915
4044
|
const dir = found.path.slice(0, found.path.lastIndexOf("/"));
|
|
3916
|
-
gitJsonPath =
|
|
4045
|
+
gitJsonPath = join14(dir, "git.json");
|
|
3917
4046
|
} else {
|
|
3918
4047
|
gitJsonPath = found.path;
|
|
3919
4048
|
}
|
|
3920
4049
|
} else {
|
|
3921
|
-
gitJsonPath =
|
|
4050
|
+
gitJsonPath = join14(cwd, ".codebyplan", "git.json");
|
|
3922
4051
|
}
|
|
3923
4052
|
try {
|
|
3924
|
-
const raw = await
|
|
4053
|
+
const raw = await readFile13(gitJsonPath, "utf-8");
|
|
3925
4054
|
const parsed = JSON.parse(raw);
|
|
3926
4055
|
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
3927
4056
|
return "main";
|
|
@@ -3959,8 +4088,8 @@ var init_git_utils = __esm({
|
|
|
3959
4088
|
});
|
|
3960
4089
|
|
|
3961
4090
|
// src/lib/bump.ts
|
|
3962
|
-
import { readFile as
|
|
3963
|
-
import { join as
|
|
4091
|
+
import { readFile as readFile14, writeFile as writeFile11, access as access4, readdir as readdir3 } from "node:fs/promises";
|
|
4092
|
+
import { join as join15, relative as relative3, resolve as resolve2 } from "node:path";
|
|
3964
4093
|
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
3965
4094
|
function parsePnpmWorkspaceGlobs(raw) {
|
|
3966
4095
|
const lines = raw.split("\n");
|
|
@@ -3990,18 +4119,18 @@ async function expandGlob(cwd, glob) {
|
|
|
3990
4119
|
if (parts.length !== 2 || parts[1] !== "*") {
|
|
3991
4120
|
return [];
|
|
3992
4121
|
}
|
|
3993
|
-
const parentDir =
|
|
4122
|
+
const parentDir = join15(cwd, parts[0]);
|
|
3994
4123
|
let dirs;
|
|
3995
4124
|
try {
|
|
3996
4125
|
const entries = await readdir3(parentDir, { withFileTypes: true });
|
|
3997
|
-
dirs = entries.filter((e) => e.isDirectory()).map((e) =>
|
|
4126
|
+
dirs = entries.filter((e) => e.isDirectory()).map((e) => join15(parentDir, e.name));
|
|
3998
4127
|
} catch {
|
|
3999
4128
|
return [];
|
|
4000
4129
|
}
|
|
4001
4130
|
const results = [];
|
|
4002
4131
|
for (const dir of dirs) {
|
|
4003
4132
|
try {
|
|
4004
|
-
await access4(
|
|
4133
|
+
await access4(join15(dir, "package.json"));
|
|
4005
4134
|
results.push(dir);
|
|
4006
4135
|
} catch {
|
|
4007
4136
|
}
|
|
@@ -4012,7 +4141,7 @@ async function buildPackageMap(cwd) {
|
|
|
4012
4141
|
const map = /* @__PURE__ */ new Map();
|
|
4013
4142
|
let globs = [];
|
|
4014
4143
|
try {
|
|
4015
|
-
const raw = await
|
|
4144
|
+
const raw = await readFile14(join15(cwd, "pnpm-workspace.yaml"), "utf-8");
|
|
4016
4145
|
globs = parsePnpmWorkspaceGlobs(raw);
|
|
4017
4146
|
} catch {
|
|
4018
4147
|
}
|
|
@@ -4020,7 +4149,7 @@ async function buildPackageMap(cwd) {
|
|
|
4020
4149
|
const dirs = await expandGlob(cwd, glob);
|
|
4021
4150
|
for (const dir of dirs) {
|
|
4022
4151
|
try {
|
|
4023
|
-
const pkgRaw = await
|
|
4152
|
+
const pkgRaw = await readFile14(join15(dir, "package.json"), "utf-8");
|
|
4024
4153
|
const pkg = JSON.parse(pkgRaw);
|
|
4025
4154
|
const name = pkg.name ?? relative3(cwd, dir);
|
|
4026
4155
|
map.set(dir, { name, dir });
|
|
@@ -4110,7 +4239,7 @@ function injectVersion(raw, nextVersion, filePath) {
|
|
|
4110
4239
|
async function prependChangelog(changelogPath, packageName, nextVersion, now, dryRun) {
|
|
4111
4240
|
let existing;
|
|
4112
4241
|
try {
|
|
4113
|
-
existing = await
|
|
4242
|
+
existing = await readFile14(changelogPath, "utf-8");
|
|
4114
4243
|
} catch {
|
|
4115
4244
|
return false;
|
|
4116
4245
|
}
|
|
@@ -4123,7 +4252,7 @@ async function prependChangelog(changelogPath, packageName, nextVersion, now, dr
|
|
|
4123
4252
|
`;
|
|
4124
4253
|
const updated = entry + existing;
|
|
4125
4254
|
if (!dryRun) {
|
|
4126
|
-
await
|
|
4255
|
+
await writeFile11(changelogPath, updated, "utf-8");
|
|
4127
4256
|
}
|
|
4128
4257
|
return true;
|
|
4129
4258
|
}
|
|
@@ -4149,7 +4278,7 @@ async function runBump(opts) {
|
|
|
4149
4278
|
const changedFiles = (diffResult.stdout ?? "").trim().split("\n").filter(Boolean).map((f) => resolve2(cwd, f));
|
|
4150
4279
|
const packageMap = await buildPackageMap(cwd);
|
|
4151
4280
|
const packageDirs = Array.from(packageMap.keys());
|
|
4152
|
-
const rootPkgPath =
|
|
4281
|
+
const rootPkgPath = join15(cwd, "package.json");
|
|
4153
4282
|
const changedPackageDirs = /* @__PURE__ */ new Set();
|
|
4154
4283
|
for (const absFile of changedFiles) {
|
|
4155
4284
|
const owner = findOwningPackage(absFile, packageDirs);
|
|
@@ -4160,19 +4289,19 @@ async function runBump(opts) {
|
|
|
4160
4289
|
const entries = [];
|
|
4161
4290
|
for (const pkgDir of changedPackageDirs) {
|
|
4162
4291
|
const pkgInfo = packageMap.get(pkgDir);
|
|
4163
|
-
const pkgJsonPath =
|
|
4292
|
+
const pkgJsonPath = join15(pkgDir, "package.json");
|
|
4164
4293
|
if (pkgJsonPath === rootPkgPath) continue;
|
|
4165
4294
|
const versionFileCandidates = [
|
|
4166
4295
|
{ abs: pkgJsonPath, rel: relative3(cwd, pkgJsonPath).replace(/\\/g, "/") }
|
|
4167
4296
|
];
|
|
4168
|
-
const tauriConfPath =
|
|
4297
|
+
const tauriConfPath = join15(pkgDir, "src-tauri", "tauri.conf.json");
|
|
4169
4298
|
const tauriRelPath = relative3(cwd, tauriConfPath).replace(/\\/g, "/");
|
|
4170
4299
|
try {
|
|
4171
4300
|
await access4(tauriConfPath);
|
|
4172
4301
|
versionFileCandidates.push({ abs: tauriConfPath, rel: tauriRelPath });
|
|
4173
4302
|
} catch {
|
|
4174
4303
|
}
|
|
4175
|
-
const appJsonPath =
|
|
4304
|
+
const appJsonPath = join15(pkgDir, "app.json");
|
|
4176
4305
|
const appJsonRelPath = relative3(cwd, appJsonPath).replace(/\\/g, "/");
|
|
4177
4306
|
try {
|
|
4178
4307
|
await access4(appJsonPath);
|
|
@@ -4181,7 +4310,7 @@ async function runBump(opts) {
|
|
|
4181
4310
|
}
|
|
4182
4311
|
let currentPkgJsonRaw;
|
|
4183
4312
|
try {
|
|
4184
|
-
currentPkgJsonRaw = await
|
|
4313
|
+
currentPkgJsonRaw = await readFile14(pkgJsonPath, "utf-8");
|
|
4185
4314
|
} catch (err) {
|
|
4186
4315
|
console.warn(
|
|
4187
4316
|
`runBump: could not read ${pkgJsonPath}: ${err instanceof Error ? err.message : String(err)}`
|
|
@@ -4226,7 +4355,7 @@ async function runBump(opts) {
|
|
|
4226
4355
|
for (const { abs, rel } of versionFileCandidates) {
|
|
4227
4356
|
let raw;
|
|
4228
4357
|
try {
|
|
4229
|
-
raw = await
|
|
4358
|
+
raw = await readFile14(abs, "utf-8");
|
|
4230
4359
|
} catch {
|
|
4231
4360
|
continue;
|
|
4232
4361
|
}
|
|
@@ -4240,11 +4369,11 @@ async function runBump(opts) {
|
|
|
4240
4369
|
}
|
|
4241
4370
|
const updated = injectVersion(raw, nextVersion, abs);
|
|
4242
4371
|
if (!dryRun) {
|
|
4243
|
-
await
|
|
4372
|
+
await writeFile11(abs, updated, "utf-8");
|
|
4244
4373
|
}
|
|
4245
4374
|
updatedVersionFiles.push(rel);
|
|
4246
4375
|
}
|
|
4247
|
-
const changelogPath =
|
|
4376
|
+
const changelogPath = join15(pkgDir, "CHANGELOG.md");
|
|
4248
4377
|
const changelogUpdated = await prependChangelog(
|
|
4249
4378
|
changelogPath,
|
|
4250
4379
|
pkgInfo.name,
|
|
@@ -5612,6 +5741,7 @@ function distress(kind, message, jsonMode) {
|
|
|
5612
5741
|
}
|
|
5613
5742
|
async function runResolveWorktree() {
|
|
5614
5743
|
const jsonMode = hasFlag("json", 3);
|
|
5744
|
+
const cacheMode = hasFlag("cache", 3);
|
|
5615
5745
|
let errorContext = null;
|
|
5616
5746
|
const migrationNoticeCallback = (legacyPath, primaryPath) => {
|
|
5617
5747
|
if (!jsonMode) {
|
|
@@ -5625,7 +5755,7 @@ async function runResolveWorktree() {
|
|
|
5625
5755
|
const projectPath = process.cwd();
|
|
5626
5756
|
const found = await findCodebyplanConfig(projectPath);
|
|
5627
5757
|
if (!found?.contents.repo_id) {
|
|
5628
|
-
emitAndExit(null, null, jsonMode);
|
|
5758
|
+
emitAndExit(null, null, jsonMode, cacheMode ? false : void 0);
|
|
5629
5759
|
}
|
|
5630
5760
|
const repoId = found.contents.repo_id;
|
|
5631
5761
|
try {
|
|
@@ -5656,7 +5786,7 @@ async function runResolveWorktree() {
|
|
|
5656
5786
|
message: deviceErr instanceof Error ? deviceErr.message : String(deviceErr)
|
|
5657
5787
|
};
|
|
5658
5788
|
}
|
|
5659
|
-
emitAndExit(null, errorContext, jsonMode);
|
|
5789
|
+
emitAndExit(null, errorContext, jsonMode, cacheMode ? false : void 0);
|
|
5660
5790
|
}
|
|
5661
5791
|
let branch = "";
|
|
5662
5792
|
try {
|
|
@@ -5685,7 +5815,12 @@ async function runResolveWorktree() {
|
|
|
5685
5815
|
onError: onResolverError
|
|
5686
5816
|
});
|
|
5687
5817
|
if (worktreeId) {
|
|
5688
|
-
|
|
5818
|
+
const cacheWritten = cacheMode ? await writeWorktreeCache(projectPath, {
|
|
5819
|
+
worktree_id: worktreeId,
|
|
5820
|
+
branch,
|
|
5821
|
+
device_id: deviceId
|
|
5822
|
+
}) : void 0;
|
|
5823
|
+
emitAndExit(worktreeId, errorContext, jsonMode, cacheWritten);
|
|
5689
5824
|
}
|
|
5690
5825
|
const useFallback = hasFlag("fallback-from-branch", 3);
|
|
5691
5826
|
if (useFallback) {
|
|
@@ -5696,23 +5831,33 @@ async function runResolveWorktree() {
|
|
|
5696
5831
|
onError: onResolverError
|
|
5697
5832
|
});
|
|
5698
5833
|
if (fallbackId) {
|
|
5699
|
-
|
|
5834
|
+
const cacheWritten = cacheMode ? await writeWorktreeCache(projectPath, {
|
|
5835
|
+
worktree_id: fallbackId,
|
|
5836
|
+
branch,
|
|
5837
|
+
device_id: deviceId
|
|
5838
|
+
}) : void 0;
|
|
5839
|
+
emitAndExit(fallbackId, errorContext, jsonMode, cacheWritten);
|
|
5700
5840
|
}
|
|
5701
5841
|
}
|
|
5702
|
-
emitAndExit(null, errorContext, jsonMode);
|
|
5842
|
+
emitAndExit(null, errorContext, jsonMode, cacheMode ? false : void 0);
|
|
5703
5843
|
} catch (err) {
|
|
5704
5844
|
if (err instanceof ProcessExitSignal) throw err;
|
|
5705
5845
|
const msg = err instanceof Error ? err.message : String(err);
|
|
5706
5846
|
errorContext = { kind: "unhandled", message: msg };
|
|
5707
|
-
emitAndExit(null, errorContext, jsonMode);
|
|
5847
|
+
emitAndExit(null, errorContext, jsonMode, cacheMode ? false : void 0);
|
|
5708
5848
|
}
|
|
5709
5849
|
}
|
|
5710
|
-
function emitAndExit(worktreeId, errorContext, jsonMode) {
|
|
5850
|
+
function emitAndExit(worktreeId, errorContext, jsonMode, cacheWritten) {
|
|
5711
5851
|
if (jsonMode) {
|
|
5712
5852
|
const errorKind = errorContext?.kind ?? (worktreeId === null ? "tuple_miss" : null);
|
|
5713
|
-
|
|
5714
|
-
|
|
5715
|
-
|
|
5853
|
+
const payload = {
|
|
5854
|
+
worktree_id: worktreeId,
|
|
5855
|
+
error_kind: errorKind
|
|
5856
|
+
};
|
|
5857
|
+
if (cacheWritten !== void 0) {
|
|
5858
|
+
payload.cache_written = cacheWritten;
|
|
5859
|
+
}
|
|
5860
|
+
process.stdout.write(JSON.stringify(payload) + "\n");
|
|
5716
5861
|
} else {
|
|
5717
5862
|
if (worktreeId !== null) {
|
|
5718
5863
|
process.stdout.write(worktreeId);
|
|
@@ -5731,7 +5876,177 @@ var init_resolve_worktree2 = __esm({
|
|
|
5731
5876
|
init_flags();
|
|
5732
5877
|
init_local_config();
|
|
5733
5878
|
init_resolve_worktree();
|
|
5879
|
+
init_worktree_cache();
|
|
5880
|
+
init_process_exit_signal();
|
|
5881
|
+
}
|
|
5882
|
+
});
|
|
5883
|
+
|
|
5884
|
+
// src/cli/version-status.ts
|
|
5885
|
+
var version_status_exports = {};
|
|
5886
|
+
__export(version_status_exports, {
|
|
5887
|
+
runVersionStatus: () => runVersionStatus
|
|
5888
|
+
});
|
|
5889
|
+
import { execFileSync, execSync as execSync6 } from "node:child_process";
|
|
5890
|
+
import { existsSync as existsSync4, readFileSync as readFileSync5 } from "node:fs";
|
|
5891
|
+
import { dirname as dirname8, join as join20 } from "node:path";
|
|
5892
|
+
function fetchLatestVersion() {
|
|
5893
|
+
try {
|
|
5894
|
+
return execFileSync("npm", ["view", "codebyplan", "version"], {
|
|
5895
|
+
encoding: "utf-8",
|
|
5896
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
5897
|
+
}).trim() || null;
|
|
5898
|
+
} catch {
|
|
5899
|
+
return null;
|
|
5900
|
+
}
|
|
5901
|
+
}
|
|
5902
|
+
function resolveGitRoot() {
|
|
5903
|
+
try {
|
|
5904
|
+
return execSync6("git rev-parse --show-toplevel", {
|
|
5905
|
+
encoding: "utf-8"
|
|
5906
|
+
}).trim();
|
|
5907
|
+
} catch {
|
|
5908
|
+
return null;
|
|
5909
|
+
}
|
|
5910
|
+
}
|
|
5911
|
+
function resolveCurrentBranch() {
|
|
5912
|
+
try {
|
|
5913
|
+
return execSync6("git symbolic-ref --short HEAD", {
|
|
5914
|
+
encoding: "utf-8"
|
|
5915
|
+
}).trim();
|
|
5916
|
+
} catch {
|
|
5917
|
+
try {
|
|
5918
|
+
return execSync6("git rev-parse --abbrev-ref HEAD", {
|
|
5919
|
+
encoding: "utf-8"
|
|
5920
|
+
}).trim();
|
|
5921
|
+
} catch {
|
|
5922
|
+
return "";
|
|
5923
|
+
}
|
|
5924
|
+
}
|
|
5925
|
+
}
|
|
5926
|
+
function detectPackageManager2(gitRoot) {
|
|
5927
|
+
let dir = process.cwd();
|
|
5928
|
+
const stopAt = gitRoot ?? null;
|
|
5929
|
+
while (true) {
|
|
5930
|
+
if (existsSync4(join20(dir, "pnpm-lock.yaml"))) return "pnpm";
|
|
5931
|
+
if (existsSync4(join20(dir, "yarn.lock"))) return "yarn";
|
|
5932
|
+
if (existsSync4(join20(dir, "package-lock.json"))) return "npm";
|
|
5933
|
+
if (stopAt !== null && dir === stopAt) break;
|
|
5934
|
+
const parent = dirname8(dir);
|
|
5935
|
+
if (parent === dir) break;
|
|
5936
|
+
dir = parent;
|
|
5937
|
+
}
|
|
5938
|
+
return "npm";
|
|
5939
|
+
}
|
|
5940
|
+
function buildInstallCommand2(pm) {
|
|
5941
|
+
switch (pm) {
|
|
5942
|
+
case "pnpm":
|
|
5943
|
+
return "pnpm add codebyplan@latest";
|
|
5944
|
+
case "yarn":
|
|
5945
|
+
return "yarn add codebyplan@latest";
|
|
5946
|
+
case "npm":
|
|
5947
|
+
return "npm install codebyplan@latest";
|
|
5948
|
+
}
|
|
5949
|
+
}
|
|
5950
|
+
async function resolveGuard(gitRoot, currentBranch) {
|
|
5951
|
+
if (gitRoot !== null) {
|
|
5952
|
+
const canonicalPkgPath = join20(
|
|
5953
|
+
gitRoot,
|
|
5954
|
+
"packages",
|
|
5955
|
+
"codebyplan-package",
|
|
5956
|
+
"package.json"
|
|
5957
|
+
);
|
|
5958
|
+
try {
|
|
5959
|
+
if (existsSync4(canonicalPkgPath)) {
|
|
5960
|
+
const raw = readFileSync5(canonicalPkgPath, "utf-8");
|
|
5961
|
+
const parsed = JSON.parse(raw);
|
|
5962
|
+
if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed) && parsed["name"] === "codebyplan") {
|
|
5963
|
+
return { guarded: true, guardReason: "canonical_source" };
|
|
5964
|
+
}
|
|
5965
|
+
}
|
|
5966
|
+
} catch {
|
|
5967
|
+
}
|
|
5968
|
+
}
|
|
5969
|
+
let protectedBranches = [];
|
|
5970
|
+
try {
|
|
5971
|
+
const found = await findCodebyplanConfig(process.cwd());
|
|
5972
|
+
if (found) {
|
|
5973
|
+
let gitJsonPath;
|
|
5974
|
+
if (found.path.endsWith("/repo.json")) {
|
|
5975
|
+
const dir = found.path.slice(0, found.path.lastIndexOf("/"));
|
|
5976
|
+
gitJsonPath = join20(dir, "git.json");
|
|
5977
|
+
} else {
|
|
5978
|
+
const legacyDir = found.path.slice(0, found.path.lastIndexOf("/"));
|
|
5979
|
+
gitJsonPath = join20(legacyDir, ".codebyplan", "git.json");
|
|
5980
|
+
}
|
|
5981
|
+
const raw = readFileSync5(gitJsonPath, "utf-8");
|
|
5982
|
+
const parsed = JSON.parse(raw);
|
|
5983
|
+
if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) {
|
|
5984
|
+
const bc = parsed["branch_config"];
|
|
5985
|
+
if (typeof bc === "object" && bc !== null && !Array.isArray(bc)) {
|
|
5986
|
+
const protectedField = bc["protected"];
|
|
5987
|
+
if (Array.isArray(protectedField)) {
|
|
5988
|
+
protectedBranches = protectedField.filter(
|
|
5989
|
+
(v) => typeof v === "string"
|
|
5990
|
+
);
|
|
5991
|
+
}
|
|
5992
|
+
}
|
|
5993
|
+
}
|
|
5994
|
+
}
|
|
5995
|
+
} catch {
|
|
5996
|
+
protectedBranches = [];
|
|
5997
|
+
}
|
|
5998
|
+
const isProtected = currentBranch === "main" || currentBranch !== "" && protectedBranches.includes(currentBranch);
|
|
5999
|
+
if (isProtected) {
|
|
6000
|
+
return { guarded: true, guardReason: "protected_branch" };
|
|
6001
|
+
}
|
|
6002
|
+
return { guarded: false, guardReason: null };
|
|
6003
|
+
}
|
|
6004
|
+
async function runVersionStatus() {
|
|
6005
|
+
try {
|
|
6006
|
+
const installed = VERSION;
|
|
6007
|
+
const latest = fetchLatestVersion();
|
|
6008
|
+
const newer = latest !== null && compareSemver(latest, installed) > 0;
|
|
6009
|
+
const gitRoot = resolveGitRoot();
|
|
6010
|
+
const pm = detectPackageManager2(gitRoot);
|
|
6011
|
+
const installCommand = buildInstallCommand2(pm);
|
|
6012
|
+
const currentBranch = resolveCurrentBranch();
|
|
6013
|
+
const { guarded, guardReason } = await resolveGuard(gitRoot, currentBranch);
|
|
6014
|
+
const result = {
|
|
6015
|
+
installed,
|
|
6016
|
+
latest,
|
|
6017
|
+
newer,
|
|
6018
|
+
packageManager: pm,
|
|
6019
|
+
installCommand,
|
|
6020
|
+
guarded,
|
|
6021
|
+
guardReason
|
|
6022
|
+
};
|
|
6023
|
+
process.stdout.write(JSON.stringify(result) + "\n");
|
|
6024
|
+
process.exit(0);
|
|
6025
|
+
} catch (err) {
|
|
6026
|
+
if (err instanceof ProcessExitSignal) throw err;
|
|
6027
|
+
process.stdout.write(JSON.stringify(FAIL_SAFE) + "\n");
|
|
6028
|
+
process.exit(0);
|
|
6029
|
+
}
|
|
6030
|
+
}
|
|
6031
|
+
var FAIL_SAFE;
|
|
6032
|
+
var init_version_status = __esm({
|
|
6033
|
+
"src/cli/version-status.ts"() {
|
|
6034
|
+
"use strict";
|
|
6035
|
+
init_version();
|
|
6036
|
+
init_bump();
|
|
6037
|
+
init_flags();
|
|
5734
6038
|
init_process_exit_signal();
|
|
6039
|
+
FAIL_SAFE = {
|
|
6040
|
+
installed: VERSION,
|
|
6041
|
+
latest: null,
|
|
6042
|
+
newer: false,
|
|
6043
|
+
packageManager: "npm",
|
|
6044
|
+
installCommand: "npm install codebyplan@latest",
|
|
6045
|
+
guarded: true,
|
|
6046
|
+
// Detection failed entirely — guard conservatively with an explicit reason
|
|
6047
|
+
// so consumers never see guarded:true paired with a null reason.
|
|
6048
|
+
guardReason: "unknown"
|
|
6049
|
+
};
|
|
5735
6050
|
}
|
|
5736
6051
|
});
|
|
5737
6052
|
|
|
@@ -5740,7 +6055,7 @@ var cmux_sync_exports = {};
|
|
|
5740
6055
|
__export(cmux_sync_exports, {
|
|
5741
6056
|
runCmuxSync: () => runCmuxSync
|
|
5742
6057
|
});
|
|
5743
|
-
import { execSync as
|
|
6058
|
+
import { execSync as execSync7, execFileSync as execFileSync2 } from "node:child_process";
|
|
5744
6059
|
import { basename } from "node:path";
|
|
5745
6060
|
async function runCmuxSync() {
|
|
5746
6061
|
try {
|
|
@@ -5750,14 +6065,14 @@ async function runCmuxSync() {
|
|
|
5750
6065
|
const bin = process.env.CMUX_BUNDLED_CLI_PATH || process.env.CMUX_CLAUDE_HOOK_CMUX_BIN || "cmux";
|
|
5751
6066
|
let branch = "";
|
|
5752
6067
|
try {
|
|
5753
|
-
branch =
|
|
6068
|
+
branch = execSync7("git rev-parse --abbrev-ref HEAD", {
|
|
5754
6069
|
encoding: "utf8"
|
|
5755
6070
|
}).trim();
|
|
5756
6071
|
} catch {
|
|
5757
6072
|
}
|
|
5758
6073
|
let folder = "";
|
|
5759
6074
|
try {
|
|
5760
|
-
const toplevel =
|
|
6075
|
+
const toplevel = execSync7("git rev-parse --show-toplevel", {
|
|
5761
6076
|
encoding: "utf8"
|
|
5762
6077
|
}).trim();
|
|
5763
6078
|
folder = basename(toplevel);
|
|
@@ -5765,7 +6080,7 @@ async function runCmuxSync() {
|
|
|
5765
6080
|
}
|
|
5766
6081
|
if (branch) {
|
|
5767
6082
|
try {
|
|
5768
|
-
|
|
6083
|
+
execFileSync2(bin, [
|
|
5769
6084
|
"workspace-action",
|
|
5770
6085
|
"--action",
|
|
5771
6086
|
"rename",
|
|
@@ -5777,7 +6092,7 @@ async function runCmuxSync() {
|
|
|
5777
6092
|
}
|
|
5778
6093
|
if (folder) {
|
|
5779
6094
|
try {
|
|
5780
|
-
|
|
6095
|
+
execFileSync2(bin, [
|
|
5781
6096
|
"workspace-action",
|
|
5782
6097
|
"--action",
|
|
5783
6098
|
"set-description",
|
|
@@ -5801,19 +6116,19 @@ var init_cmux_sync = __esm({
|
|
|
5801
6116
|
});
|
|
5802
6117
|
|
|
5803
6118
|
// src/lib/migrate-local-config.ts
|
|
5804
|
-
import { mkdir as
|
|
5805
|
-
import { join as
|
|
6119
|
+
import { mkdir as mkdir6, readFile as readFile15, unlink as unlink2, writeFile as writeFile12 } from "node:fs/promises";
|
|
6120
|
+
import { join as join21 } from "node:path";
|
|
5806
6121
|
function legacySharedPath(projectPath) {
|
|
5807
|
-
return
|
|
6122
|
+
return join21(projectPath, ".codebyplan.json");
|
|
5808
6123
|
}
|
|
5809
6124
|
function legacyLocalPath(projectPath) {
|
|
5810
|
-
return
|
|
6125
|
+
return join21(projectPath, ".codebyplan.local.json");
|
|
5811
6126
|
}
|
|
5812
6127
|
function newDirPath(projectPath) {
|
|
5813
|
-
return
|
|
6128
|
+
return join21(projectPath, ".codebyplan");
|
|
5814
6129
|
}
|
|
5815
6130
|
function sentinelPath(projectPath) {
|
|
5816
|
-
return
|
|
6131
|
+
return join21(projectPath, ".codebyplan", "repo.json");
|
|
5817
6132
|
}
|
|
5818
6133
|
async function statSafe(p) {
|
|
5819
6134
|
const { stat: stat2 } = await import("node:fs/promises");
|
|
@@ -5852,7 +6167,7 @@ async function runLocalMigration(projectPath) {
|
|
|
5852
6167
|
}
|
|
5853
6168
|
let legacyRaw;
|
|
5854
6169
|
try {
|
|
5855
|
-
legacyRaw = await
|
|
6170
|
+
legacyRaw = await readFile15(legacySharedPath(projectPath), "utf-8");
|
|
5856
6171
|
} catch {
|
|
5857
6172
|
return {
|
|
5858
6173
|
migrated: true,
|
|
@@ -5879,7 +6194,7 @@ async function runLocalMigration(projectPath) {
|
|
|
5879
6194
|
let deviceId;
|
|
5880
6195
|
let deviceWrittenByHelper = false;
|
|
5881
6196
|
try {
|
|
5882
|
-
const localRaw = await
|
|
6197
|
+
const localRaw = await readFile15(legacyLocalPath(projectPath), "utf-8");
|
|
5883
6198
|
const localParsed = JSON.parse(localRaw);
|
|
5884
6199
|
if (typeof localParsed.device_id === "string") {
|
|
5885
6200
|
deviceId = localParsed.device_id;
|
|
@@ -5887,7 +6202,7 @@ async function runLocalMigration(projectPath) {
|
|
|
5887
6202
|
} catch {
|
|
5888
6203
|
}
|
|
5889
6204
|
try {
|
|
5890
|
-
await
|
|
6205
|
+
await mkdir6(newDirPath(projectPath), { recursive: true });
|
|
5891
6206
|
} catch (err) {
|
|
5892
6207
|
const code = err.code;
|
|
5893
6208
|
if (code === "ENOTDIR" || code === "EEXIST") {
|
|
@@ -5906,8 +6221,8 @@ async function runLocalMigration(projectPath) {
|
|
|
5906
6221
|
if ("repo_id" in cfg) repoJson.repo_id = cfg.repo_id;
|
|
5907
6222
|
if ("organization_id" in cfg) repoJson.organization_id = cfg.organization_id;
|
|
5908
6223
|
if ("project_id" in cfg) repoJson.project_id = cfg.project_id;
|
|
5909
|
-
await
|
|
5910
|
-
|
|
6224
|
+
await writeFile12(
|
|
6225
|
+
join21(projectPath, ".codebyplan", "repo.json"),
|
|
5911
6226
|
JSON.stringify(repoJson, null, 2) + "\n",
|
|
5912
6227
|
"utf-8"
|
|
5913
6228
|
);
|
|
@@ -5919,8 +6234,8 @@ async function runLocalMigration(projectPath) {
|
|
|
5919
6234
|
serverJson.auto_push_enabled = cfg.auto_push_enabled;
|
|
5920
6235
|
if ("port_allocations" in cfg)
|
|
5921
6236
|
serverJson.port_allocations = cfg.port_allocations;
|
|
5922
|
-
await
|
|
5923
|
-
|
|
6237
|
+
await writeFile12(
|
|
6238
|
+
join21(projectPath, ".codebyplan", "server.json"),
|
|
5924
6239
|
JSON.stringify(serverJson, null, 2) + "\n",
|
|
5925
6240
|
"utf-8"
|
|
5926
6241
|
);
|
|
@@ -5928,44 +6243,44 @@ async function runLocalMigration(projectPath) {
|
|
|
5928
6243
|
const gitJson = {};
|
|
5929
6244
|
if ("git_branch" in cfg) gitJson.git_branch = cfg.git_branch;
|
|
5930
6245
|
if ("branch_config" in cfg) gitJson.branch_config = cfg.branch_config;
|
|
5931
|
-
await
|
|
5932
|
-
|
|
6246
|
+
await writeFile12(
|
|
6247
|
+
join21(projectPath, ".codebyplan", "git.json"),
|
|
5933
6248
|
JSON.stringify(gitJson, null, 2) + "\n",
|
|
5934
6249
|
"utf-8"
|
|
5935
6250
|
);
|
|
5936
6251
|
filesChanged.push(".codebyplan/git.json");
|
|
5937
6252
|
const shipmentJson = {};
|
|
5938
6253
|
if ("shipment" in cfg) shipmentJson.shipment = cfg.shipment;
|
|
5939
|
-
await
|
|
5940
|
-
|
|
6254
|
+
await writeFile12(
|
|
6255
|
+
join21(projectPath, ".codebyplan", "shipment.json"),
|
|
5941
6256
|
JSON.stringify(shipmentJson, null, 2) + "\n",
|
|
5942
6257
|
"utf-8"
|
|
5943
6258
|
);
|
|
5944
6259
|
filesChanged.push(".codebyplan/shipment.json");
|
|
5945
6260
|
const vendorJson = {};
|
|
5946
|
-
await
|
|
5947
|
-
|
|
6261
|
+
await writeFile12(
|
|
6262
|
+
join21(projectPath, ".codebyplan", "vendor.json"),
|
|
5948
6263
|
JSON.stringify(vendorJson, null, 2) + "\n",
|
|
5949
6264
|
"utf-8"
|
|
5950
6265
|
);
|
|
5951
6266
|
filesChanged.push(".codebyplan/vendor.json");
|
|
5952
6267
|
const e2eJson = {};
|
|
5953
|
-
await
|
|
5954
|
-
|
|
6268
|
+
await writeFile12(
|
|
6269
|
+
join21(projectPath, ".codebyplan", "e2e.json"),
|
|
5955
6270
|
JSON.stringify(e2eJson, null, 2) + "\n",
|
|
5956
6271
|
"utf-8"
|
|
5957
6272
|
);
|
|
5958
6273
|
filesChanged.push(".codebyplan/e2e.json");
|
|
5959
6274
|
const eslintJson = {};
|
|
5960
|
-
await
|
|
5961
|
-
|
|
6275
|
+
await writeFile12(
|
|
6276
|
+
join21(projectPath, ".codebyplan", "eslint.json"),
|
|
5962
6277
|
JSON.stringify(eslintJson, null, 2) + "\n",
|
|
5963
6278
|
"utf-8"
|
|
5964
6279
|
);
|
|
5965
6280
|
filesChanged.push(".codebyplan/eslint.json");
|
|
5966
6281
|
if (!deviceWrittenByHelper) {
|
|
5967
|
-
await
|
|
5968
|
-
|
|
6282
|
+
await writeFile12(
|
|
6283
|
+
join21(projectPath, ".codebyplan", "device.local.json"),
|
|
5969
6284
|
JSON.stringify({ device_id: deviceId }, null, 2) + "\n",
|
|
5970
6285
|
"utf-8"
|
|
5971
6286
|
);
|
|
@@ -5977,9 +6292,9 @@ async function runLocalMigration(projectPath) {
|
|
|
5977
6292
|
"Migration write incomplete: .codebyplan/repo.json was not persisted. Re-run migration to retry from a clean state."
|
|
5978
6293
|
);
|
|
5979
6294
|
}
|
|
5980
|
-
const gitignorePath =
|
|
6295
|
+
const gitignorePath = join21(projectPath, ".gitignore");
|
|
5981
6296
|
try {
|
|
5982
|
-
const gitignoreContent = await
|
|
6297
|
+
const gitignoreContent = await readFile15(gitignorePath, "utf-8");
|
|
5983
6298
|
const legacyLine = ".codebyplan.local.json";
|
|
5984
6299
|
const newLine = ".codebyplan/device.local.json";
|
|
5985
6300
|
const hasLegacy = gitignoreContent.split("\n").some((l) => l.trimEnd() === legacyLine);
|
|
@@ -5998,7 +6313,7 @@ async function runLocalMigration(projectPath) {
|
|
|
5998
6313
|
updated = gitignoreContent;
|
|
5999
6314
|
}
|
|
6000
6315
|
if (updated !== gitignoreContent) {
|
|
6001
|
-
await
|
|
6316
|
+
await writeFile12(gitignorePath, updated, "utf-8");
|
|
6002
6317
|
filesChanged.push(".gitignore");
|
|
6003
6318
|
}
|
|
6004
6319
|
} catch {
|
|
@@ -6038,8 +6353,8 @@ __export(config_exports, {
|
|
|
6038
6353
|
readVendorConfig: () => readVendorConfig,
|
|
6039
6354
|
runConfig: () => runConfig
|
|
6040
6355
|
});
|
|
6041
|
-
import { mkdir as
|
|
6042
|
-
import { join as
|
|
6356
|
+
import { mkdir as mkdir7, readFile as readFile16, writeFile as writeFile13 } from "node:fs/promises";
|
|
6357
|
+
import { join as join22 } from "node:path";
|
|
6043
6358
|
async function runConfig() {
|
|
6044
6359
|
const flags = parseFlags(3);
|
|
6045
6360
|
const dryRun = hasFlag("dry-run", 3);
|
|
@@ -6072,14 +6387,14 @@ async function runConfig() {
|
|
|
6072
6387
|
console.log("\n Config complete.\n");
|
|
6073
6388
|
}
|
|
6074
6389
|
async function syncConfigToFile(repoId, projectPath, dryRun) {
|
|
6075
|
-
const codebyplanDir =
|
|
6390
|
+
const codebyplanDir = join22(projectPath, ".codebyplan");
|
|
6076
6391
|
let resolvedWorktreeId;
|
|
6077
6392
|
try {
|
|
6078
6393
|
const deviceId = await getOrCreateDeviceId(projectPath);
|
|
6079
6394
|
let branch = "main";
|
|
6080
6395
|
try {
|
|
6081
|
-
const { execSync:
|
|
6082
|
-
branch =
|
|
6396
|
+
const { execSync: execSync8 } = await import("node:child_process");
|
|
6397
|
+
branch = execSync8("git symbolic-ref --short HEAD", {
|
|
6083
6398
|
cwd: projectPath,
|
|
6084
6399
|
encoding: "utf-8"
|
|
6085
6400
|
}).trim();
|
|
@@ -6203,7 +6518,7 @@ async function syncConfigToFile(repoId, projectPath, dryRun) {
|
|
|
6203
6518
|
console.log(" Config would be updated (dry-run).");
|
|
6204
6519
|
return;
|
|
6205
6520
|
}
|
|
6206
|
-
await
|
|
6521
|
+
await mkdir7(codebyplanDir, { recursive: true });
|
|
6207
6522
|
const files = [
|
|
6208
6523
|
{ name: "repo.json", payload: repoPayload },
|
|
6209
6524
|
{ name: "server.json", payload: serverPayload },
|
|
@@ -6215,16 +6530,16 @@ async function syncConfigToFile(repoId, projectPath, dryRun) {
|
|
|
6215
6530
|
];
|
|
6216
6531
|
let anyUpdated = false;
|
|
6217
6532
|
for (const { name, payload, createOnly } of files) {
|
|
6218
|
-
const filePath =
|
|
6533
|
+
const filePath = join22(codebyplanDir, name);
|
|
6219
6534
|
const newJson = JSON.stringify(payload, null, 2) + "\n";
|
|
6220
6535
|
let currentJson = "";
|
|
6221
6536
|
try {
|
|
6222
|
-
currentJson = await
|
|
6537
|
+
currentJson = await readFile16(filePath, "utf-8");
|
|
6223
6538
|
} catch {
|
|
6224
6539
|
}
|
|
6225
6540
|
if (createOnly && currentJson !== "") continue;
|
|
6226
6541
|
if (currentJson === newJson) continue;
|
|
6227
|
-
await
|
|
6542
|
+
await writeFile13(filePath, newJson, "utf-8");
|
|
6228
6543
|
console.log(` Updated .codebyplan/${name}`);
|
|
6229
6544
|
anyUpdated = true;
|
|
6230
6545
|
}
|
|
@@ -6234,8 +6549,8 @@ async function syncConfigToFile(repoId, projectPath, dryRun) {
|
|
|
6234
6549
|
}
|
|
6235
6550
|
async function readRepoConfig(projectPath) {
|
|
6236
6551
|
try {
|
|
6237
|
-
const raw = await
|
|
6238
|
-
|
|
6552
|
+
const raw = await readFile16(
|
|
6553
|
+
join22(projectPath, ".codebyplan", "repo.json"),
|
|
6239
6554
|
"utf-8"
|
|
6240
6555
|
);
|
|
6241
6556
|
return JSON.parse(raw);
|
|
@@ -6245,8 +6560,8 @@ async function readRepoConfig(projectPath) {
|
|
|
6245
6560
|
}
|
|
6246
6561
|
async function readServerConfig(projectPath) {
|
|
6247
6562
|
try {
|
|
6248
|
-
const raw = await
|
|
6249
|
-
|
|
6563
|
+
const raw = await readFile16(
|
|
6564
|
+
join22(projectPath, ".codebyplan", "server.json"),
|
|
6250
6565
|
"utf-8"
|
|
6251
6566
|
);
|
|
6252
6567
|
return JSON.parse(raw);
|
|
@@ -6256,8 +6571,8 @@ async function readServerConfig(projectPath) {
|
|
|
6256
6571
|
}
|
|
6257
6572
|
async function readGitConfig(projectPath) {
|
|
6258
6573
|
try {
|
|
6259
|
-
const raw = await
|
|
6260
|
-
|
|
6574
|
+
const raw = await readFile16(
|
|
6575
|
+
join22(projectPath, ".codebyplan", "git.json"),
|
|
6261
6576
|
"utf-8"
|
|
6262
6577
|
);
|
|
6263
6578
|
return JSON.parse(raw);
|
|
@@ -6267,8 +6582,8 @@ async function readGitConfig(projectPath) {
|
|
|
6267
6582
|
}
|
|
6268
6583
|
async function readShipmentConfig(projectPath) {
|
|
6269
6584
|
try {
|
|
6270
|
-
const raw = await
|
|
6271
|
-
|
|
6585
|
+
const raw = await readFile16(
|
|
6586
|
+
join22(projectPath, ".codebyplan", "shipment.json"),
|
|
6272
6587
|
"utf-8"
|
|
6273
6588
|
);
|
|
6274
6589
|
return JSON.parse(raw);
|
|
@@ -6278,8 +6593,8 @@ async function readShipmentConfig(projectPath) {
|
|
|
6278
6593
|
}
|
|
6279
6594
|
async function readVendorConfig(projectPath) {
|
|
6280
6595
|
try {
|
|
6281
|
-
const raw = await
|
|
6282
|
-
|
|
6596
|
+
const raw = await readFile16(
|
|
6597
|
+
join22(projectPath, ".codebyplan", "vendor.json"),
|
|
6283
6598
|
"utf-8"
|
|
6284
6599
|
);
|
|
6285
6600
|
return JSON.parse(raw);
|
|
@@ -6289,8 +6604,8 @@ async function readVendorConfig(projectPath) {
|
|
|
6289
6604
|
}
|
|
6290
6605
|
async function readE2eConfig(projectPath) {
|
|
6291
6606
|
try {
|
|
6292
|
-
const raw = await
|
|
6293
|
-
|
|
6607
|
+
const raw = await readFile16(
|
|
6608
|
+
join22(projectPath, ".codebyplan", "e2e.json"),
|
|
6294
6609
|
"utf-8"
|
|
6295
6610
|
);
|
|
6296
6611
|
return JSON.parse(raw);
|
|
@@ -6346,14 +6661,14 @@ var init_server_detect = __esm({
|
|
|
6346
6661
|
});
|
|
6347
6662
|
|
|
6348
6663
|
// src/lib/port-verify.ts
|
|
6349
|
-
import { readFile as
|
|
6664
|
+
import { readFile as readFile17 } from "node:fs/promises";
|
|
6350
6665
|
async function verifyPorts(projectPath, portAllocations) {
|
|
6351
6666
|
const mismatches = [];
|
|
6352
6667
|
const allocatedPorts = new Set(portAllocations.map((a) => a.port));
|
|
6353
6668
|
const packageJsonPaths = await findPackageJsonFiles(projectPath, projectPath);
|
|
6354
6669
|
for (const pkgPath of packageJsonPaths) {
|
|
6355
6670
|
try {
|
|
6356
|
-
const raw = await
|
|
6671
|
+
const raw = await readFile17(pkgPath, "utf-8");
|
|
6357
6672
|
const pkg = JSON.parse(raw);
|
|
6358
6673
|
const scriptPort = detectPortFromScripts(pkg);
|
|
6359
6674
|
if (scriptPort !== null && !allocatedPorts.has(scriptPort)) {
|
|
@@ -6416,7 +6731,7 @@ async function findUnallocatedApps(projectPath, portAllocations) {
|
|
|
6416
6731
|
}
|
|
6417
6732
|
let pkg;
|
|
6418
6733
|
try {
|
|
6419
|
-
const raw = await
|
|
6734
|
+
const raw = await readFile17(`${app.absPath}/package.json`, "utf-8");
|
|
6420
6735
|
pkg = JSON.parse(raw);
|
|
6421
6736
|
} catch {
|
|
6422
6737
|
continue;
|
|
@@ -6562,7 +6877,7 @@ __export(tech_stack_exports, {
|
|
|
6562
6877
|
runFullTechStack: () => runFullTechStack,
|
|
6563
6878
|
runTechStack: () => runTechStack
|
|
6564
6879
|
});
|
|
6565
|
-
import { existsSync as
|
|
6880
|
+
import { existsSync as existsSync5 } from "node:fs";
|
|
6566
6881
|
async function runTechStack() {
|
|
6567
6882
|
const flags = parseFlags(3);
|
|
6568
6883
|
const dryRun = hasFlag("dry-run", 3);
|
|
@@ -6624,10 +6939,10 @@ async function runTechStack() {
|
|
|
6624
6939
|
);
|
|
6625
6940
|
}
|
|
6626
6941
|
try {
|
|
6627
|
-
const { execSync:
|
|
6942
|
+
const { execSync: execSync8 } = await import("node:child_process");
|
|
6628
6943
|
let branch = "main";
|
|
6629
6944
|
try {
|
|
6630
|
-
branch =
|
|
6945
|
+
branch = execSync8("git symbolic-ref --short HEAD", {
|
|
6631
6946
|
cwd: projectPath,
|
|
6632
6947
|
encoding: "utf-8"
|
|
6633
6948
|
}).trim();
|
|
@@ -6735,7 +7050,7 @@ async function runFullTechStack(dryRun) {
|
|
|
6735
7050
|
continue;
|
|
6736
7051
|
}
|
|
6737
7052
|
const localWorktrees = worktrees.filter(
|
|
6738
|
-
(wt) => wt.path ?
|
|
7053
|
+
(wt) => wt.path ? existsSync5(wt.path) : false
|
|
6739
7054
|
);
|
|
6740
7055
|
if (localWorktrees.length === 0) {
|
|
6741
7056
|
console.log(` skipping ${repo.name} \u2014 no local worktree on this device`);
|
|
@@ -7418,13 +7733,13 @@ var init_uninstall = __esm({
|
|
|
7418
7733
|
|
|
7419
7734
|
// src/index.ts
|
|
7420
7735
|
init_version();
|
|
7421
|
-
import { readFileSync as
|
|
7736
|
+
import { readFileSync as readFileSync8 } from "node:fs";
|
|
7422
7737
|
import { resolve as resolve6 } from "node:path";
|
|
7423
7738
|
void (async () => {
|
|
7424
7739
|
if (!process.env.CODEBYPLAN_API_KEY) {
|
|
7425
7740
|
try {
|
|
7426
7741
|
const envPath = resolve6(process.cwd(), ".env.local");
|
|
7427
|
-
const content =
|
|
7742
|
+
const content = readFileSync8(envPath, "utf-8");
|
|
7428
7743
|
for (const line of content.split("\n")) {
|
|
7429
7744
|
const trimmed = line.trim();
|
|
7430
7745
|
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
@@ -7536,6 +7851,11 @@ void (async () => {
|
|
|
7536
7851
|
await runResolveWorktree2();
|
|
7537
7852
|
process.exit(0);
|
|
7538
7853
|
}
|
|
7854
|
+
if (arg === "version-status") {
|
|
7855
|
+
const { runVersionStatus: runVersionStatus2 } = await Promise.resolve().then(() => (init_version_status(), version_status_exports));
|
|
7856
|
+
await runVersionStatus2();
|
|
7857
|
+
process.exit(0);
|
|
7858
|
+
}
|
|
7539
7859
|
if (arg === "cmux-sync") {
|
|
7540
7860
|
const { runCmuxSync: runCmuxSync2 } = await Promise.resolve().then(() => (init_cmux_sync(), cmux_sync_exports));
|
|
7541
7861
|
await runCmuxSync2();
|
|
@@ -7639,6 +7959,7 @@ void (async () => {
|
|
|
7639
7959
|
codebyplan claude Claude asset management (install/update/uninstall)
|
|
7640
7960
|
codebyplan statusline Show or set the statusline renderer (bash/node/python)
|
|
7641
7961
|
codebyplan resolve-worktree Resolve active worktree UUID from device+path+branch tuple
|
|
7962
|
+
codebyplan version-status Report installed vs latest version + update guard (JSON)
|
|
7642
7963
|
codebyplan cmux-sync Sync cmux workspace title/description to current git branch and repo folder
|
|
7643
7964
|
codebyplan help Show this help message
|
|
7644
7965
|
codebyplan --version Print version
|
|
@@ -7677,6 +7998,11 @@ void (async () => {
|
|
|
7677
7998
|
--node Set statusline renderer to node after install/update
|
|
7678
7999
|
--python Set statusline renderer to python after install/update
|
|
7679
8000
|
|
|
8001
|
+
Resolve-worktree options:
|
|
8002
|
+
--json Structured JSON output instead of bare UUID
|
|
8003
|
+
--fallback-from-branch Fallback resolver: filter by (device_id, branch) client-side
|
|
8004
|
+
--cache Resolve and write worktree id to .codebyplan/worktree.local.json
|
|
8005
|
+
|
|
7680
8006
|
MCP Server:
|
|
7681
8007
|
Claude Code connects to CodeByPlan via remote MCP:
|
|
7682
8008
|
URL: https://mcp.codebyplan.com/mcp
|