codebyplan 1.13.9 → 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
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) >>>";
|
|
@@ -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,6 +5876,7 @@ var init_resolve_worktree2 = __esm({
|
|
|
5731
5876
|
init_flags();
|
|
5732
5877
|
init_local_config();
|
|
5733
5878
|
init_resolve_worktree();
|
|
5879
|
+
init_worktree_cache();
|
|
5734
5880
|
init_process_exit_signal();
|
|
5735
5881
|
}
|
|
5736
5882
|
});
|
|
@@ -5742,7 +5888,7 @@ __export(version_status_exports, {
|
|
|
5742
5888
|
});
|
|
5743
5889
|
import { execFileSync, execSync as execSync6 } from "node:child_process";
|
|
5744
5890
|
import { existsSync as existsSync4, readFileSync as readFileSync5 } from "node:fs";
|
|
5745
|
-
import { dirname as
|
|
5891
|
+
import { dirname as dirname8, join as join20 } from "node:path";
|
|
5746
5892
|
function fetchLatestVersion() {
|
|
5747
5893
|
try {
|
|
5748
5894
|
return execFileSync("npm", ["view", "codebyplan", "version"], {
|
|
@@ -5781,11 +5927,11 @@ function detectPackageManager2(gitRoot) {
|
|
|
5781
5927
|
let dir = process.cwd();
|
|
5782
5928
|
const stopAt = gitRoot ?? null;
|
|
5783
5929
|
while (true) {
|
|
5784
|
-
if (existsSync4(
|
|
5785
|
-
if (existsSync4(
|
|
5786
|
-
if (existsSync4(
|
|
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";
|
|
5787
5933
|
if (stopAt !== null && dir === stopAt) break;
|
|
5788
|
-
const parent =
|
|
5934
|
+
const parent = dirname8(dir);
|
|
5789
5935
|
if (parent === dir) break;
|
|
5790
5936
|
dir = parent;
|
|
5791
5937
|
}
|
|
@@ -5803,7 +5949,7 @@ function buildInstallCommand2(pm) {
|
|
|
5803
5949
|
}
|
|
5804
5950
|
async function resolveGuard(gitRoot, currentBranch) {
|
|
5805
5951
|
if (gitRoot !== null) {
|
|
5806
|
-
const canonicalPkgPath =
|
|
5952
|
+
const canonicalPkgPath = join20(
|
|
5807
5953
|
gitRoot,
|
|
5808
5954
|
"packages",
|
|
5809
5955
|
"codebyplan-package",
|
|
@@ -5827,10 +5973,10 @@ async function resolveGuard(gitRoot, currentBranch) {
|
|
|
5827
5973
|
let gitJsonPath;
|
|
5828
5974
|
if (found.path.endsWith("/repo.json")) {
|
|
5829
5975
|
const dir = found.path.slice(0, found.path.lastIndexOf("/"));
|
|
5830
|
-
gitJsonPath =
|
|
5976
|
+
gitJsonPath = join20(dir, "git.json");
|
|
5831
5977
|
} else {
|
|
5832
5978
|
const legacyDir = found.path.slice(0, found.path.lastIndexOf("/"));
|
|
5833
|
-
gitJsonPath =
|
|
5979
|
+
gitJsonPath = join20(legacyDir, ".codebyplan", "git.json");
|
|
5834
5980
|
}
|
|
5835
5981
|
const raw = readFileSync5(gitJsonPath, "utf-8");
|
|
5836
5982
|
const parsed = JSON.parse(raw);
|
|
@@ -5970,19 +6116,19 @@ var init_cmux_sync = __esm({
|
|
|
5970
6116
|
});
|
|
5971
6117
|
|
|
5972
6118
|
// src/lib/migrate-local-config.ts
|
|
5973
|
-
import { mkdir as
|
|
5974
|
-
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";
|
|
5975
6121
|
function legacySharedPath(projectPath) {
|
|
5976
|
-
return
|
|
6122
|
+
return join21(projectPath, ".codebyplan.json");
|
|
5977
6123
|
}
|
|
5978
6124
|
function legacyLocalPath(projectPath) {
|
|
5979
|
-
return
|
|
6125
|
+
return join21(projectPath, ".codebyplan.local.json");
|
|
5980
6126
|
}
|
|
5981
6127
|
function newDirPath(projectPath) {
|
|
5982
|
-
return
|
|
6128
|
+
return join21(projectPath, ".codebyplan");
|
|
5983
6129
|
}
|
|
5984
6130
|
function sentinelPath(projectPath) {
|
|
5985
|
-
return
|
|
6131
|
+
return join21(projectPath, ".codebyplan", "repo.json");
|
|
5986
6132
|
}
|
|
5987
6133
|
async function statSafe(p) {
|
|
5988
6134
|
const { stat: stat2 } = await import("node:fs/promises");
|
|
@@ -6021,7 +6167,7 @@ async function runLocalMigration(projectPath) {
|
|
|
6021
6167
|
}
|
|
6022
6168
|
let legacyRaw;
|
|
6023
6169
|
try {
|
|
6024
|
-
legacyRaw = await
|
|
6170
|
+
legacyRaw = await readFile15(legacySharedPath(projectPath), "utf-8");
|
|
6025
6171
|
} catch {
|
|
6026
6172
|
return {
|
|
6027
6173
|
migrated: true,
|
|
@@ -6048,7 +6194,7 @@ async function runLocalMigration(projectPath) {
|
|
|
6048
6194
|
let deviceId;
|
|
6049
6195
|
let deviceWrittenByHelper = false;
|
|
6050
6196
|
try {
|
|
6051
|
-
const localRaw = await
|
|
6197
|
+
const localRaw = await readFile15(legacyLocalPath(projectPath), "utf-8");
|
|
6052
6198
|
const localParsed = JSON.parse(localRaw);
|
|
6053
6199
|
if (typeof localParsed.device_id === "string") {
|
|
6054
6200
|
deviceId = localParsed.device_id;
|
|
@@ -6056,7 +6202,7 @@ async function runLocalMigration(projectPath) {
|
|
|
6056
6202
|
} catch {
|
|
6057
6203
|
}
|
|
6058
6204
|
try {
|
|
6059
|
-
await
|
|
6205
|
+
await mkdir6(newDirPath(projectPath), { recursive: true });
|
|
6060
6206
|
} catch (err) {
|
|
6061
6207
|
const code = err.code;
|
|
6062
6208
|
if (code === "ENOTDIR" || code === "EEXIST") {
|
|
@@ -6075,8 +6221,8 @@ async function runLocalMigration(projectPath) {
|
|
|
6075
6221
|
if ("repo_id" in cfg) repoJson.repo_id = cfg.repo_id;
|
|
6076
6222
|
if ("organization_id" in cfg) repoJson.organization_id = cfg.organization_id;
|
|
6077
6223
|
if ("project_id" in cfg) repoJson.project_id = cfg.project_id;
|
|
6078
|
-
await
|
|
6079
|
-
|
|
6224
|
+
await writeFile12(
|
|
6225
|
+
join21(projectPath, ".codebyplan", "repo.json"),
|
|
6080
6226
|
JSON.stringify(repoJson, null, 2) + "\n",
|
|
6081
6227
|
"utf-8"
|
|
6082
6228
|
);
|
|
@@ -6088,8 +6234,8 @@ async function runLocalMigration(projectPath) {
|
|
|
6088
6234
|
serverJson.auto_push_enabled = cfg.auto_push_enabled;
|
|
6089
6235
|
if ("port_allocations" in cfg)
|
|
6090
6236
|
serverJson.port_allocations = cfg.port_allocations;
|
|
6091
|
-
await
|
|
6092
|
-
|
|
6237
|
+
await writeFile12(
|
|
6238
|
+
join21(projectPath, ".codebyplan", "server.json"),
|
|
6093
6239
|
JSON.stringify(serverJson, null, 2) + "\n",
|
|
6094
6240
|
"utf-8"
|
|
6095
6241
|
);
|
|
@@ -6097,44 +6243,44 @@ async function runLocalMigration(projectPath) {
|
|
|
6097
6243
|
const gitJson = {};
|
|
6098
6244
|
if ("git_branch" in cfg) gitJson.git_branch = cfg.git_branch;
|
|
6099
6245
|
if ("branch_config" in cfg) gitJson.branch_config = cfg.branch_config;
|
|
6100
|
-
await
|
|
6101
|
-
|
|
6246
|
+
await writeFile12(
|
|
6247
|
+
join21(projectPath, ".codebyplan", "git.json"),
|
|
6102
6248
|
JSON.stringify(gitJson, null, 2) + "\n",
|
|
6103
6249
|
"utf-8"
|
|
6104
6250
|
);
|
|
6105
6251
|
filesChanged.push(".codebyplan/git.json");
|
|
6106
6252
|
const shipmentJson = {};
|
|
6107
6253
|
if ("shipment" in cfg) shipmentJson.shipment = cfg.shipment;
|
|
6108
|
-
await
|
|
6109
|
-
|
|
6254
|
+
await writeFile12(
|
|
6255
|
+
join21(projectPath, ".codebyplan", "shipment.json"),
|
|
6110
6256
|
JSON.stringify(shipmentJson, null, 2) + "\n",
|
|
6111
6257
|
"utf-8"
|
|
6112
6258
|
);
|
|
6113
6259
|
filesChanged.push(".codebyplan/shipment.json");
|
|
6114
6260
|
const vendorJson = {};
|
|
6115
|
-
await
|
|
6116
|
-
|
|
6261
|
+
await writeFile12(
|
|
6262
|
+
join21(projectPath, ".codebyplan", "vendor.json"),
|
|
6117
6263
|
JSON.stringify(vendorJson, null, 2) + "\n",
|
|
6118
6264
|
"utf-8"
|
|
6119
6265
|
);
|
|
6120
6266
|
filesChanged.push(".codebyplan/vendor.json");
|
|
6121
6267
|
const e2eJson = {};
|
|
6122
|
-
await
|
|
6123
|
-
|
|
6268
|
+
await writeFile12(
|
|
6269
|
+
join21(projectPath, ".codebyplan", "e2e.json"),
|
|
6124
6270
|
JSON.stringify(e2eJson, null, 2) + "\n",
|
|
6125
6271
|
"utf-8"
|
|
6126
6272
|
);
|
|
6127
6273
|
filesChanged.push(".codebyplan/e2e.json");
|
|
6128
6274
|
const eslintJson = {};
|
|
6129
|
-
await
|
|
6130
|
-
|
|
6275
|
+
await writeFile12(
|
|
6276
|
+
join21(projectPath, ".codebyplan", "eslint.json"),
|
|
6131
6277
|
JSON.stringify(eslintJson, null, 2) + "\n",
|
|
6132
6278
|
"utf-8"
|
|
6133
6279
|
);
|
|
6134
6280
|
filesChanged.push(".codebyplan/eslint.json");
|
|
6135
6281
|
if (!deviceWrittenByHelper) {
|
|
6136
|
-
await
|
|
6137
|
-
|
|
6282
|
+
await writeFile12(
|
|
6283
|
+
join21(projectPath, ".codebyplan", "device.local.json"),
|
|
6138
6284
|
JSON.stringify({ device_id: deviceId }, null, 2) + "\n",
|
|
6139
6285
|
"utf-8"
|
|
6140
6286
|
);
|
|
@@ -6146,9 +6292,9 @@ async function runLocalMigration(projectPath) {
|
|
|
6146
6292
|
"Migration write incomplete: .codebyplan/repo.json was not persisted. Re-run migration to retry from a clean state."
|
|
6147
6293
|
);
|
|
6148
6294
|
}
|
|
6149
|
-
const gitignorePath =
|
|
6295
|
+
const gitignorePath = join21(projectPath, ".gitignore");
|
|
6150
6296
|
try {
|
|
6151
|
-
const gitignoreContent = await
|
|
6297
|
+
const gitignoreContent = await readFile15(gitignorePath, "utf-8");
|
|
6152
6298
|
const legacyLine = ".codebyplan.local.json";
|
|
6153
6299
|
const newLine = ".codebyplan/device.local.json";
|
|
6154
6300
|
const hasLegacy = gitignoreContent.split("\n").some((l) => l.trimEnd() === legacyLine);
|
|
@@ -6167,7 +6313,7 @@ async function runLocalMigration(projectPath) {
|
|
|
6167
6313
|
updated = gitignoreContent;
|
|
6168
6314
|
}
|
|
6169
6315
|
if (updated !== gitignoreContent) {
|
|
6170
|
-
await
|
|
6316
|
+
await writeFile12(gitignorePath, updated, "utf-8");
|
|
6171
6317
|
filesChanged.push(".gitignore");
|
|
6172
6318
|
}
|
|
6173
6319
|
} catch {
|
|
@@ -6207,8 +6353,8 @@ __export(config_exports, {
|
|
|
6207
6353
|
readVendorConfig: () => readVendorConfig,
|
|
6208
6354
|
runConfig: () => runConfig
|
|
6209
6355
|
});
|
|
6210
|
-
import { mkdir as
|
|
6211
|
-
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";
|
|
6212
6358
|
async function runConfig() {
|
|
6213
6359
|
const flags = parseFlags(3);
|
|
6214
6360
|
const dryRun = hasFlag("dry-run", 3);
|
|
@@ -6241,7 +6387,7 @@ async function runConfig() {
|
|
|
6241
6387
|
console.log("\n Config complete.\n");
|
|
6242
6388
|
}
|
|
6243
6389
|
async function syncConfigToFile(repoId, projectPath, dryRun) {
|
|
6244
|
-
const codebyplanDir =
|
|
6390
|
+
const codebyplanDir = join22(projectPath, ".codebyplan");
|
|
6245
6391
|
let resolvedWorktreeId;
|
|
6246
6392
|
try {
|
|
6247
6393
|
const deviceId = await getOrCreateDeviceId(projectPath);
|
|
@@ -6372,7 +6518,7 @@ async function syncConfigToFile(repoId, projectPath, dryRun) {
|
|
|
6372
6518
|
console.log(" Config would be updated (dry-run).");
|
|
6373
6519
|
return;
|
|
6374
6520
|
}
|
|
6375
|
-
await
|
|
6521
|
+
await mkdir7(codebyplanDir, { recursive: true });
|
|
6376
6522
|
const files = [
|
|
6377
6523
|
{ name: "repo.json", payload: repoPayload },
|
|
6378
6524
|
{ name: "server.json", payload: serverPayload },
|
|
@@ -6384,16 +6530,16 @@ async function syncConfigToFile(repoId, projectPath, dryRun) {
|
|
|
6384
6530
|
];
|
|
6385
6531
|
let anyUpdated = false;
|
|
6386
6532
|
for (const { name, payload, createOnly } of files) {
|
|
6387
|
-
const filePath =
|
|
6533
|
+
const filePath = join22(codebyplanDir, name);
|
|
6388
6534
|
const newJson = JSON.stringify(payload, null, 2) + "\n";
|
|
6389
6535
|
let currentJson = "";
|
|
6390
6536
|
try {
|
|
6391
|
-
currentJson = await
|
|
6537
|
+
currentJson = await readFile16(filePath, "utf-8");
|
|
6392
6538
|
} catch {
|
|
6393
6539
|
}
|
|
6394
6540
|
if (createOnly && currentJson !== "") continue;
|
|
6395
6541
|
if (currentJson === newJson) continue;
|
|
6396
|
-
await
|
|
6542
|
+
await writeFile13(filePath, newJson, "utf-8");
|
|
6397
6543
|
console.log(` Updated .codebyplan/${name}`);
|
|
6398
6544
|
anyUpdated = true;
|
|
6399
6545
|
}
|
|
@@ -6403,8 +6549,8 @@ async function syncConfigToFile(repoId, projectPath, dryRun) {
|
|
|
6403
6549
|
}
|
|
6404
6550
|
async function readRepoConfig(projectPath) {
|
|
6405
6551
|
try {
|
|
6406
|
-
const raw = await
|
|
6407
|
-
|
|
6552
|
+
const raw = await readFile16(
|
|
6553
|
+
join22(projectPath, ".codebyplan", "repo.json"),
|
|
6408
6554
|
"utf-8"
|
|
6409
6555
|
);
|
|
6410
6556
|
return JSON.parse(raw);
|
|
@@ -6414,8 +6560,8 @@ async function readRepoConfig(projectPath) {
|
|
|
6414
6560
|
}
|
|
6415
6561
|
async function readServerConfig(projectPath) {
|
|
6416
6562
|
try {
|
|
6417
|
-
const raw = await
|
|
6418
|
-
|
|
6563
|
+
const raw = await readFile16(
|
|
6564
|
+
join22(projectPath, ".codebyplan", "server.json"),
|
|
6419
6565
|
"utf-8"
|
|
6420
6566
|
);
|
|
6421
6567
|
return JSON.parse(raw);
|
|
@@ -6425,8 +6571,8 @@ async function readServerConfig(projectPath) {
|
|
|
6425
6571
|
}
|
|
6426
6572
|
async function readGitConfig(projectPath) {
|
|
6427
6573
|
try {
|
|
6428
|
-
const raw = await
|
|
6429
|
-
|
|
6574
|
+
const raw = await readFile16(
|
|
6575
|
+
join22(projectPath, ".codebyplan", "git.json"),
|
|
6430
6576
|
"utf-8"
|
|
6431
6577
|
);
|
|
6432
6578
|
return JSON.parse(raw);
|
|
@@ -6436,8 +6582,8 @@ async function readGitConfig(projectPath) {
|
|
|
6436
6582
|
}
|
|
6437
6583
|
async function readShipmentConfig(projectPath) {
|
|
6438
6584
|
try {
|
|
6439
|
-
const raw = await
|
|
6440
|
-
|
|
6585
|
+
const raw = await readFile16(
|
|
6586
|
+
join22(projectPath, ".codebyplan", "shipment.json"),
|
|
6441
6587
|
"utf-8"
|
|
6442
6588
|
);
|
|
6443
6589
|
return JSON.parse(raw);
|
|
@@ -6447,8 +6593,8 @@ async function readShipmentConfig(projectPath) {
|
|
|
6447
6593
|
}
|
|
6448
6594
|
async function readVendorConfig(projectPath) {
|
|
6449
6595
|
try {
|
|
6450
|
-
const raw = await
|
|
6451
|
-
|
|
6596
|
+
const raw = await readFile16(
|
|
6597
|
+
join22(projectPath, ".codebyplan", "vendor.json"),
|
|
6452
6598
|
"utf-8"
|
|
6453
6599
|
);
|
|
6454
6600
|
return JSON.parse(raw);
|
|
@@ -6458,8 +6604,8 @@ async function readVendorConfig(projectPath) {
|
|
|
6458
6604
|
}
|
|
6459
6605
|
async function readE2eConfig(projectPath) {
|
|
6460
6606
|
try {
|
|
6461
|
-
const raw = await
|
|
6462
|
-
|
|
6607
|
+
const raw = await readFile16(
|
|
6608
|
+
join22(projectPath, ".codebyplan", "e2e.json"),
|
|
6463
6609
|
"utf-8"
|
|
6464
6610
|
);
|
|
6465
6611
|
return JSON.parse(raw);
|
|
@@ -6515,14 +6661,14 @@ var init_server_detect = __esm({
|
|
|
6515
6661
|
});
|
|
6516
6662
|
|
|
6517
6663
|
// src/lib/port-verify.ts
|
|
6518
|
-
import { readFile as
|
|
6664
|
+
import { readFile as readFile17 } from "node:fs/promises";
|
|
6519
6665
|
async function verifyPorts(projectPath, portAllocations) {
|
|
6520
6666
|
const mismatches = [];
|
|
6521
6667
|
const allocatedPorts = new Set(portAllocations.map((a) => a.port));
|
|
6522
6668
|
const packageJsonPaths = await findPackageJsonFiles(projectPath, projectPath);
|
|
6523
6669
|
for (const pkgPath of packageJsonPaths) {
|
|
6524
6670
|
try {
|
|
6525
|
-
const raw = await
|
|
6671
|
+
const raw = await readFile17(pkgPath, "utf-8");
|
|
6526
6672
|
const pkg = JSON.parse(raw);
|
|
6527
6673
|
const scriptPort = detectPortFromScripts(pkg);
|
|
6528
6674
|
if (scriptPort !== null && !allocatedPorts.has(scriptPort)) {
|
|
@@ -6585,7 +6731,7 @@ async function findUnallocatedApps(projectPath, portAllocations) {
|
|
|
6585
6731
|
}
|
|
6586
6732
|
let pkg;
|
|
6587
6733
|
try {
|
|
6588
|
-
const raw = await
|
|
6734
|
+
const raw = await readFile17(`${app.absPath}/package.json`, "utf-8");
|
|
6589
6735
|
pkg = JSON.parse(raw);
|
|
6590
6736
|
} catch {
|
|
6591
6737
|
continue;
|
|
@@ -7852,6 +7998,11 @@ void (async () => {
|
|
|
7852
7998
|
--node Set statusline renderer to node after install/update
|
|
7853
7999
|
--python Set statusline renderer to python after install/update
|
|
7854
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
|
+
|
|
7855
8006
|
MCP Server:
|
|
7856
8007
|
Claude Code connects to CodeByPlan via remote MCP:
|
|
7857
8008
|
URL: https://mcp.codebyplan.com/mcp
|
package/package.json
CHANGED
|
@@ -12,6 +12,14 @@
|
|
|
12
12
|
# - Web-UI flag (app_file_approval_by_user) consumption + reset
|
|
13
13
|
# - Writes both PATCH /api/rounds/${ROUND_ID} and PATCH /api/tasks/${TASK_ID}
|
|
14
14
|
#
|
|
15
|
+
# Caller worktree identity:
|
|
16
|
+
# The CLI auto-resolves caller_worktree_id (override flag → cache →
|
|
17
|
+
# in-process tuple API) and hard-fails with exit 1 if it cannot resolve
|
|
18
|
+
# on the write path. This hook resolves the worktree id before invoking the
|
|
19
|
+
# CLI and passes it via --caller-worktree-id so the server can honor the
|
|
20
|
+
# feat-worktree lock. The hook itself stays non-fatal (exits 0) and surfaces
|
|
21
|
+
# the CLI's stderr output to the user.
|
|
22
|
+
#
|
|
15
23
|
# Flags:
|
|
16
24
|
# --dry-run Pass through to CLI (prints merged payload, no API writes).
|
|
17
25
|
# Used by fixture-based smoke tests.
|
|
@@ -67,11 +75,19 @@ if [ -z "$TASK_ID" ]; then
|
|
|
67
75
|
exit 0
|
|
68
76
|
fi
|
|
69
77
|
|
|
78
|
+
# Resolve worktree id before invoking the CLI so the server can honor the
|
|
79
|
+
# feat-worktree lock. On miss (unregistered worktree) the CLI falls back to
|
|
80
|
+
# its in-process resolve and hard-fails with guidance if still unresolved.
|
|
81
|
+
WORKTREE_ID=$(npx codebyplan resolve-worktree 2>/dev/null)
|
|
82
|
+
|
|
70
83
|
# Delegate to the codebyplan CLI (single source of truth for merge semantics)
|
|
71
84
|
CMD_ARGS=("round" "sync-approvals" "--round-id" "$ROUND_ID" "--task-id" "$TASK_ID")
|
|
85
|
+
if [ -n "$WORKTREE_ID" ]; then
|
|
86
|
+
CMD_ARGS+=("--caller-worktree-id" "$WORKTREE_ID")
|
|
87
|
+
fi
|
|
72
88
|
[ "$DRY_RUN" = "true" ] && CMD_ARGS+=("--dry-run")
|
|
73
89
|
|
|
74
|
-
if npx codebyplan "${CMD_ARGS[@]}"
|
|
90
|
+
if npx codebyplan "${CMD_ARGS[@]}"; then
|
|
75
91
|
echo "cbp-mcp-round-sync: synced via CLI for round ${ROUND_ID}" >&2
|
|
76
92
|
else
|
|
77
93
|
echo "cbp-mcp-round-sync: CLI sync failed for round ${ROUND_ID} (non-fatal)" >&2
|
|
@@ -196,7 +196,7 @@ echo '{}' > "$WORKTREE_PATH/.codebyplan/shipment.json"
|
|
|
196
196
|
echo '{}' > "$WORKTREE_PATH/.codebyplan/vendor.json"
|
|
197
197
|
```
|
|
198
198
|
|
|
199
|
-
The `.codebyplan/device.local.json` file is created by `npx codebyplan setup` on the device (gitignored). The `worktree_id` is never
|
|
199
|
+
The `.codebyplan/device.local.json` file is created by `npx codebyplan setup` on the device (gitignored). The `worktree_id` is never COMMITTED; it may be cached per-device in the gitignored `.codebyplan/worktree.local.json` (branch-keyed, re-derivable via `codebyplan resolve-worktree --cache`), otherwise resolved at runtime from the `(device_id, repo path, branch)` tuple via `npx codebyplan resolve-worktree`.
|
|
200
200
|
|
|
201
201
|
No need to mark as `skip-worktree` — the committed files are merge-safe per CHK-108 and CHK-120.
|
|
202
202
|
|
|
@@ -69,7 +69,20 @@ Run:
|
|
|
69
69
|
npx codebyplan round sync-approvals --round-id <round_id> --task-id <task_id>
|
|
70
70
|
```
|
|
71
71
|
|
|
72
|
-
The CLI auto-resolves the worktree id
|
|
72
|
+
The CLI auto-resolves the caller worktree id with the following precedence:
|
|
73
|
+
1. `--caller-worktree-id <uuid>` override (if passed — skips all resolution)
|
|
74
|
+
2. Per-device branch-keyed cache (`.codebyplan/worktree.local.json`)
|
|
75
|
+
3. In-process tuple API call: `POST /worktrees/resolve` using `(device_id, repo_path, branch)`
|
|
76
|
+
|
|
77
|
+
On the write path (non `--dry-run`), if the worktree id cannot be resolved the CLI **hard-fails with exit 1** and prints an actionable message. To pre-populate the cache:
|
|
78
|
+
|
|
79
|
+
```
|
|
80
|
+
npx codebyplan resolve-worktree --cache
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
If this worktree is not yet registered, run `npx codebyplan setup` first, then re-run `/cbp-round-update`.
|
|
84
|
+
|
|
85
|
+
The CLI parses `git status --short`, merges drift + staging + web-UI flag, and writes both round and task (forwarding `caller_worktree_id` on both writes so the server honors the feat-worktree lock).
|
|
73
86
|
|
|
74
87
|
Read the stdout JSON: `{ added, stale_marked, reactivated, total_files }`.
|
|
75
88
|
|