codebyplan 1.13.22 → 1.13.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -109
- package/dist/cli.js +476 -690
- package/package.json +1 -1
- package/templates/hooks/README.md +3 -53
- package/templates/hooks/cbp-statusline.mjs +106 -11
- package/templates/hooks/cbp-statusline.py +79 -13
- package/templates/hooks/cbp-statusline.sh +97 -17
- package/templates/hooks/cbp-test-hooks.sh +0 -71
- package/templates/hooks/hooks.json +0 -20
- package/templates/settings.project.base.json +0 -7
- package/templates/skills/cbp-round-execute/SKILL.md +0 -18
- package/templates/skills/cbp-session-start/SKILL.md +2 -0
- package/templates/skills/cbp-task-complete/SKILL.md +0 -14
- package/templates/skills/cbp-task-start/SKILL.md +0 -8
- package/templates/hooks/cbp-cmux-branch-watch.sh +0 -39
- package/templates/hooks/cbp-cmux-workspace-sync.sh +0 -19
- package/templates/skills/cbp-setup-cmux/SKILL.md +0 -170
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.24";
|
|
18
18
|
PACKAGE_NAME = "codebyplan";
|
|
19
19
|
}
|
|
20
20
|
});
|
|
@@ -149,6 +149,7 @@ var init_gitignore_block = __esm({
|
|
|
149
149
|
".codebyplan/device.local.json",
|
|
150
150
|
".codebyplan/statusline.local.json",
|
|
151
151
|
".codebyplan/worktree.local.json",
|
|
152
|
+
".codebyplan/claude-status.local.json",
|
|
152
153
|
".codebyplan.local.json"
|
|
153
154
|
];
|
|
154
155
|
GITIGNORE_BLOCK_START = "# >>> codebyplan (managed) >>>";
|
|
@@ -225,8 +226,8 @@ async function readLocalConfig(projectPath, onMigrationNotice) {
|
|
|
225
226
|
}
|
|
226
227
|
async function writeLocalConfig(projectPath, config) {
|
|
227
228
|
const content = { device_id: config.device_id };
|
|
228
|
-
const
|
|
229
|
-
const dirPath = dirname(
|
|
229
|
+
const path10 = localConfigPath(projectPath);
|
|
230
|
+
const dirPath = dirname(path10);
|
|
230
231
|
let phase = "stat config directory";
|
|
231
232
|
try {
|
|
232
233
|
try {
|
|
@@ -246,7 +247,7 @@ async function writeLocalConfig(projectPath, config) {
|
|
|
246
247
|
phase = "create config directory";
|
|
247
248
|
await mkdir(dirPath, { recursive: true });
|
|
248
249
|
phase = "write local config";
|
|
249
|
-
await writeFile2(
|
|
250
|
+
await writeFile2(path10, JSON.stringify(content, null, 2) + "\n", "utf-8");
|
|
250
251
|
} catch (err) {
|
|
251
252
|
const code = err.code;
|
|
252
253
|
if (code === "LEGACY_FILE_BLOCKS_DIR") {
|
|
@@ -396,7 +397,8 @@ var init_statusline_config = __esm({
|
|
|
396
397
|
rate_limits: true,
|
|
397
398
|
repo_pr: true,
|
|
398
399
|
worktree: true,
|
|
399
|
-
infra_drift: true
|
|
400
|
+
infra_drift: true,
|
|
401
|
+
package_freshness: true
|
|
400
402
|
},
|
|
401
403
|
no_color: false
|
|
402
404
|
};
|
|
@@ -467,12 +469,12 @@ async function readFallback(filename) {
|
|
|
467
469
|
}
|
|
468
470
|
}
|
|
469
471
|
async function writeFallback(filename, data) {
|
|
470
|
-
const
|
|
471
|
-
await mkdir3(dirname2(
|
|
472
|
-
await writeFile4(
|
|
472
|
+
const path10 = fallbackFile(filename);
|
|
473
|
+
await mkdir3(dirname2(path10), { recursive: true });
|
|
474
|
+
await writeFile4(path10, JSON.stringify(data, null, 2) + "\n", "utf-8");
|
|
473
475
|
if (platform() !== "win32") {
|
|
474
476
|
try {
|
|
475
|
-
await chmod(
|
|
477
|
+
await chmod(path10, 384);
|
|
476
478
|
} catch {
|
|
477
479
|
}
|
|
478
480
|
}
|
|
@@ -677,8 +679,8 @@ async function getAuthHeaders() {
|
|
|
677
679
|
return { headers: { "x-api-key": key }, via: "api_key" };
|
|
678
680
|
}
|
|
679
681
|
}
|
|
680
|
-
function buildUrl(
|
|
681
|
-
const url = new URL(`${baseUrl()}/api${
|
|
682
|
+
function buildUrl(path10, params) {
|
|
683
|
+
const url = new URL(`${baseUrl()}/api${path10}`);
|
|
682
684
|
if (params) {
|
|
683
685
|
for (const [key, value] of Object.entries(params)) {
|
|
684
686
|
if (value !== void 0) {
|
|
@@ -695,10 +697,10 @@ function isRetryable(err) {
|
|
|
695
697
|
return false;
|
|
696
698
|
}
|
|
697
699
|
function delay(ms) {
|
|
698
|
-
return new Promise((
|
|
700
|
+
return new Promise((resolve9) => setTimeout(resolve9, ms));
|
|
699
701
|
}
|
|
700
|
-
async function request(method,
|
|
701
|
-
const url = buildUrl(
|
|
702
|
+
async function request(method, path10, options) {
|
|
703
|
+
const url = buildUrl(path10, options?.params);
|
|
702
704
|
const auth = await getAuthHeaders();
|
|
703
705
|
let lastError;
|
|
704
706
|
for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
|
|
@@ -718,7 +720,7 @@ async function request(method, path8, options) {
|
|
|
718
720
|
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS)
|
|
719
721
|
});
|
|
720
722
|
if (!res.ok) {
|
|
721
|
-
let message = `API ${method} ${
|
|
723
|
+
let message = `API ${method} ${path10} failed with status ${res.status}`;
|
|
722
724
|
let code;
|
|
723
725
|
try {
|
|
724
726
|
const body = await res.json();
|
|
@@ -752,14 +754,14 @@ async function request(method, path8, options) {
|
|
|
752
754
|
}
|
|
753
755
|
throw lastError;
|
|
754
756
|
}
|
|
755
|
-
async function apiGet(
|
|
756
|
-
return request("GET",
|
|
757
|
+
async function apiGet(path10, params) {
|
|
758
|
+
return request("GET", path10, { params });
|
|
757
759
|
}
|
|
758
|
-
async function apiPost(
|
|
759
|
-
return request("POST",
|
|
760
|
+
async function apiPost(path10, body) {
|
|
761
|
+
return request("POST", path10, { body });
|
|
760
762
|
}
|
|
761
|
-
async function apiPut(
|
|
762
|
-
return request("PUT",
|
|
763
|
+
async function apiPut(path10, body) {
|
|
764
|
+
return request("PUT", path10, { body });
|
|
763
765
|
}
|
|
764
766
|
async function callMcpTool(toolName, params) {
|
|
765
767
|
const url = mcpEndpoint();
|
|
@@ -1053,7 +1055,7 @@ var init_device_flow = __esm({
|
|
|
1053
1055
|
this.name = "OAuthInvalidClientError";
|
|
1054
1056
|
}
|
|
1055
1057
|
};
|
|
1056
|
-
defaultSleep = (ms) => new Promise((
|
|
1058
|
+
defaultSleep = (ms) => new Promise((resolve9) => setTimeout(resolve9, ms));
|
|
1057
1059
|
}
|
|
1058
1060
|
});
|
|
1059
1061
|
|
|
@@ -1861,9 +1863,9 @@ import { createInterface } from "node:readline/promises";
|
|
|
1861
1863
|
function getConfigPath(scope) {
|
|
1862
1864
|
return scope === "user" ? join9(homedir4(), ".claude.json") : join9(process.cwd(), ".mcp.json");
|
|
1863
1865
|
}
|
|
1864
|
-
async function readConfig(
|
|
1866
|
+
async function readConfig(path10) {
|
|
1865
1867
|
try {
|
|
1866
|
-
const raw = await readFile6(
|
|
1868
|
+
const raw = await readFile6(path10, "utf-8");
|
|
1867
1869
|
const parsed = JSON.parse(raw);
|
|
1868
1870
|
if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) {
|
|
1869
1871
|
return parsed;
|
|
@@ -1994,11 +1996,6 @@ async function writeCodebyplanDirectory(projectPath, selectedRepo, deviceId) {
|
|
|
1994
1996
|
JSON.stringify({}, null, 2) + "\n",
|
|
1995
1997
|
"utf-8"
|
|
1996
1998
|
);
|
|
1997
|
-
await writeFile6(
|
|
1998
|
-
join9(codebyplanDir, "cmux.json"),
|
|
1999
|
-
JSON.stringify({}, null, 2) + "\n",
|
|
2000
|
-
"utf-8"
|
|
2001
|
-
);
|
|
2002
1999
|
const statuslinePath = join9(codebyplanDir, "statusline.json");
|
|
2003
2000
|
let statuslineExists = false;
|
|
2004
2001
|
try {
|
|
@@ -2016,7 +2013,7 @@ async function writeCodebyplanDirectory(projectPath, selectedRepo, deviceId) {
|
|
|
2016
2013
|
await writeLocalConfig(projectPath, { device_id: deviceId });
|
|
2017
2014
|
console.log(` Created ${codebyplanDir}/`);
|
|
2018
2015
|
console.log(
|
|
2019
|
-
` repo.json, server.json, git.json, shipment.json, vendor.json, e2e.json, eslint.json,
|
|
2016
|
+
` repo.json, server.json, git.json, shipment.json, vendor.json, e2e.json, eslint.json, statusline.json`
|
|
2020
2017
|
);
|
|
2021
2018
|
console.log(` device.local.json (gitignored)`);
|
|
2022
2019
|
const gitignoreAction = await ensureManagedGitignoreBlock(projectPath);
|
|
@@ -2093,8 +2090,8 @@ async function runSetup() {
|
|
|
2093
2090
|
const deviceId = await getOrCreateDeviceId(projectPath);
|
|
2094
2091
|
let branch = "main";
|
|
2095
2092
|
try {
|
|
2096
|
-
const { execSync:
|
|
2097
|
-
branch =
|
|
2093
|
+
const { execSync: execSync9 } = await import("node:child_process");
|
|
2094
|
+
branch = execSync9("git symbolic-ref --short HEAD", {
|
|
2098
2095
|
cwd: projectPath,
|
|
2099
2096
|
encoding: "utf-8"
|
|
2100
2097
|
}).trim();
|
|
@@ -2455,9 +2452,9 @@ import { join as join11 } from "node:path";
|
|
|
2455
2452
|
function configPaths() {
|
|
2456
2453
|
return [join11(homedir5(), ".claude.json"), join11(process.cwd(), ".mcp.json")];
|
|
2457
2454
|
}
|
|
2458
|
-
async function readConfig2(
|
|
2455
|
+
async function readConfig2(path10) {
|
|
2459
2456
|
try {
|
|
2460
|
-
const raw = await readFile8(
|
|
2457
|
+
const raw = await readFile8(path10, "utf-8");
|
|
2461
2458
|
const parsed = JSON.parse(raw);
|
|
2462
2459
|
if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) {
|
|
2463
2460
|
return parsed;
|
|
@@ -2471,7 +2468,7 @@ function entryHasLegacyApiKey(entry) {
|
|
|
2471
2468
|
if (!entry || !entry.headers) return false;
|
|
2472
2469
|
return "x-api-key" in entry.headers;
|
|
2473
2470
|
}
|
|
2474
|
-
async function rewriteConfig(
|
|
2471
|
+
async function rewriteConfig(path10, config, newUrl) {
|
|
2475
2472
|
const servers = config.mcpServers;
|
|
2476
2473
|
if (!servers) return false;
|
|
2477
2474
|
const entry = servers.codebyplan;
|
|
@@ -2479,7 +2476,7 @@ async function rewriteConfig(path8, config, newUrl) {
|
|
|
2479
2476
|
if (!entryHasLegacyApiKey(entry) && entry.url === newUrl && entry.type === "http")
|
|
2480
2477
|
return false;
|
|
2481
2478
|
servers.codebyplan = { type: "http", url: newUrl };
|
|
2482
|
-
await writeFile7(
|
|
2479
|
+
await writeFile7(path10, JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
2483
2480
|
return true;
|
|
2484
2481
|
}
|
|
2485
2482
|
async function runUpgradeAuth() {
|
|
@@ -2487,12 +2484,12 @@ async function runUpgradeAuth() {
|
|
|
2487
2484
|
await runLogin();
|
|
2488
2485
|
const newUrl = mcpEndpoint();
|
|
2489
2486
|
let migrated = 0;
|
|
2490
|
-
for (const
|
|
2491
|
-
const config = await readConfig2(
|
|
2487
|
+
for (const path10 of configPaths()) {
|
|
2488
|
+
const config = await readConfig2(path10);
|
|
2492
2489
|
if (!config) continue;
|
|
2493
|
-
const changed = await rewriteConfig(
|
|
2490
|
+
const changed = await rewriteConfig(path10, config, newUrl);
|
|
2494
2491
|
if (changed) {
|
|
2495
|
-
console.log(` Updated ${
|
|
2492
|
+
console.log(` Updated ${path10}`);
|
|
2496
2493
|
migrated++;
|
|
2497
2494
|
}
|
|
2498
2495
|
}
|
|
@@ -3764,9 +3761,9 @@ async function eslintInit(repoId, projectPath) {
|
|
|
3764
3761
|
Install ${missingPkgs.length} missing packages? [Y/n] `
|
|
3765
3762
|
);
|
|
3766
3763
|
if (confirmed) {
|
|
3767
|
-
const { execSync:
|
|
3764
|
+
const { execSync: execSync9 } = await import("node:child_process");
|
|
3768
3765
|
try {
|
|
3769
|
-
|
|
3766
|
+
execSync9(installCmd, { cwd: projectPath, stdio: "inherit" });
|
|
3770
3767
|
console.log(" Packages installed.\n");
|
|
3771
3768
|
} catch (err) {
|
|
3772
3769
|
console.error(
|
|
@@ -4201,7 +4198,7 @@ function setRetryDelayMs(ms) {
|
|
|
4201
4198
|
RETRY_DELAY_MS = ms;
|
|
4202
4199
|
}
|
|
4203
4200
|
function sleep(ms) {
|
|
4204
|
-
return new Promise((
|
|
4201
|
+
return new Promise((resolve9) => setTimeout(resolve9, ms));
|
|
4205
4202
|
}
|
|
4206
4203
|
function isTransientMcpError(err) {
|
|
4207
4204
|
if (!(err instanceof McpError)) return false;
|
|
@@ -6252,6 +6249,8 @@ var init_create_repo = __esm({
|
|
|
6252
6249
|
// src/cli/version-status.ts
|
|
6253
6250
|
var version_status_exports = {};
|
|
6254
6251
|
__export(version_status_exports, {
|
|
6252
|
+
fetchLatestVersion: () => fetchLatestVersion,
|
|
6253
|
+
resolveGuard: () => resolveGuard,
|
|
6255
6254
|
runVersionStatus: () => runVersionStatus
|
|
6256
6255
|
});
|
|
6257
6256
|
import { execFileSync, execSync as execSync6 } from "node:child_process";
|
|
@@ -6667,451 +6666,6 @@ var init_upload_e2e_images = __esm({
|
|
|
6667
6666
|
}
|
|
6668
6667
|
});
|
|
6669
6668
|
|
|
6670
|
-
// src/lib/cmux.ts
|
|
6671
|
-
import { readFileSync as readFileSync6 } from "node:fs";
|
|
6672
|
-
import { join as join22 } from "node:path";
|
|
6673
|
-
function insideCmux() {
|
|
6674
|
-
return !!process.env.CMUX_WORKSPACE_ID;
|
|
6675
|
-
}
|
|
6676
|
-
function resolveCmuxBin() {
|
|
6677
|
-
return process.env.CMUX_BUNDLED_CLI_PATH || process.env.CMUX_CLAUDE_HOOK_CMUX_BIN || "cmux";
|
|
6678
|
-
}
|
|
6679
|
-
function readCmuxConfig(projectRoot) {
|
|
6680
|
-
let raw = {};
|
|
6681
|
-
try {
|
|
6682
|
-
const text = readFileSync6(
|
|
6683
|
-
join22(projectRoot, ".codebyplan", "cmux.json"),
|
|
6684
|
-
"utf-8"
|
|
6685
|
-
);
|
|
6686
|
-
raw = JSON.parse(text);
|
|
6687
|
-
} catch {
|
|
6688
|
-
raw = {};
|
|
6689
|
-
}
|
|
6690
|
-
if (typeof raw !== "object" || raw === null || Array.isArray(raw)) {
|
|
6691
|
-
raw = {};
|
|
6692
|
-
}
|
|
6693
|
-
const config = raw;
|
|
6694
|
-
return {
|
|
6695
|
-
...config,
|
|
6696
|
-
auto_status: config.auto_status ?? true,
|
|
6697
|
-
auto_dev_server: config.auto_dev_server ?? true
|
|
6698
|
-
};
|
|
6699
|
-
}
|
|
6700
|
-
var init_cmux = __esm({
|
|
6701
|
-
"src/lib/cmux.ts"() {
|
|
6702
|
-
"use strict";
|
|
6703
|
-
}
|
|
6704
|
-
});
|
|
6705
|
-
|
|
6706
|
-
// src/cli/cmux-sync.ts
|
|
6707
|
-
var cmux_sync_exports = {};
|
|
6708
|
-
__export(cmux_sync_exports, {
|
|
6709
|
-
runCmuxSync: () => runCmuxSync
|
|
6710
|
-
});
|
|
6711
|
-
import { execSync as execSync8, execFileSync as execFileSync2 } from "node:child_process";
|
|
6712
|
-
import { basename as basename2 } from "node:path";
|
|
6713
|
-
async function runCmuxSync() {
|
|
6714
|
-
try {
|
|
6715
|
-
if (!insideCmux()) {
|
|
6716
|
-
process.exit(0);
|
|
6717
|
-
}
|
|
6718
|
-
const bin = resolveCmuxBin();
|
|
6719
|
-
let branch = "";
|
|
6720
|
-
try {
|
|
6721
|
-
branch = execSync8("git rev-parse --abbrev-ref HEAD", {
|
|
6722
|
-
encoding: "utf8"
|
|
6723
|
-
}).trim();
|
|
6724
|
-
} catch {
|
|
6725
|
-
}
|
|
6726
|
-
let folder = "";
|
|
6727
|
-
let toplevel = "";
|
|
6728
|
-
try {
|
|
6729
|
-
toplevel = execSync8("git rev-parse --show-toplevel", {
|
|
6730
|
-
encoding: "utf8"
|
|
6731
|
-
}).trim();
|
|
6732
|
-
folder = basename2(toplevel);
|
|
6733
|
-
} catch {
|
|
6734
|
-
}
|
|
6735
|
-
if (branch) {
|
|
6736
|
-
try {
|
|
6737
|
-
execFileSync2(bin, [
|
|
6738
|
-
"workspace-action",
|
|
6739
|
-
"--action",
|
|
6740
|
-
"rename",
|
|
6741
|
-
"--title",
|
|
6742
|
-
branch
|
|
6743
|
-
]);
|
|
6744
|
-
} catch {
|
|
6745
|
-
}
|
|
6746
|
-
}
|
|
6747
|
-
if (folder) {
|
|
6748
|
-
try {
|
|
6749
|
-
execFileSync2(bin, [
|
|
6750
|
-
"workspace-action",
|
|
6751
|
-
"--action",
|
|
6752
|
-
"set-description",
|
|
6753
|
-
"--description",
|
|
6754
|
-
folder
|
|
6755
|
-
]);
|
|
6756
|
-
} catch {
|
|
6757
|
-
}
|
|
6758
|
-
}
|
|
6759
|
-
try {
|
|
6760
|
-
const cmuxCfg = readCmuxConfig(toplevel || process.cwd());
|
|
6761
|
-
if (typeof cmuxCfg.workspace_color === "string" && cmuxCfg.workspace_color !== "") {
|
|
6762
|
-
try {
|
|
6763
|
-
execFileSync2(bin, [
|
|
6764
|
-
"workspace-action",
|
|
6765
|
-
"--action",
|
|
6766
|
-
"set-color",
|
|
6767
|
-
"--color",
|
|
6768
|
-
cmuxCfg.workspace_color
|
|
6769
|
-
]);
|
|
6770
|
-
} catch {
|
|
6771
|
-
}
|
|
6772
|
-
} else {
|
|
6773
|
-
process.stdout.write(
|
|
6774
|
-
"cmux: no workspace color set \u2014 run /cbp-setup-cmux\n"
|
|
6775
|
-
);
|
|
6776
|
-
}
|
|
6777
|
-
} catch {
|
|
6778
|
-
}
|
|
6779
|
-
process.exit(0);
|
|
6780
|
-
} catch (err) {
|
|
6781
|
-
if (err instanceof ProcessExitSignal) throw err;
|
|
6782
|
-
process.exit(0);
|
|
6783
|
-
}
|
|
6784
|
-
}
|
|
6785
|
-
var init_cmux_sync = __esm({
|
|
6786
|
-
"src/cli/cmux-sync.ts"() {
|
|
6787
|
-
"use strict";
|
|
6788
|
-
init_process_exit_signal();
|
|
6789
|
-
init_cmux();
|
|
6790
|
-
}
|
|
6791
|
-
});
|
|
6792
|
-
|
|
6793
|
-
// src/cli/cmux-status.ts
|
|
6794
|
-
var cmux_status_exports = {};
|
|
6795
|
-
__export(cmux_status_exports, {
|
|
6796
|
-
normalizeProgress: () => normalizeProgress,
|
|
6797
|
-
runCmuxStatus: () => runCmuxStatus
|
|
6798
|
-
});
|
|
6799
|
-
import { execSync as execSync9, execFileSync as execFileSync3 } from "node:child_process";
|
|
6800
|
-
function normalizeProgress(raw) {
|
|
6801
|
-
if (raw.includes("/")) {
|
|
6802
|
-
const [numStr, denStr] = raw.split("/", 2);
|
|
6803
|
-
const num = parseInt(numStr ?? "", 10);
|
|
6804
|
-
const den = parseInt(denStr ?? "", 10);
|
|
6805
|
-
if (!Number.isFinite(num) || !Number.isFinite(den) || den === 0) return "0";
|
|
6806
|
-
const ratio = num / den;
|
|
6807
|
-
const clamped2 = Math.max(0, Math.min(1, ratio));
|
|
6808
|
-
return String(clamped2);
|
|
6809
|
-
}
|
|
6810
|
-
const f = parseFloat(raw);
|
|
6811
|
-
if (!Number.isFinite(f)) return null;
|
|
6812
|
-
const clamped = Math.max(0, Math.min(1, f));
|
|
6813
|
-
return String(clamped);
|
|
6814
|
-
}
|
|
6815
|
-
async function runCmuxStatus(args) {
|
|
6816
|
-
try {
|
|
6817
|
-
if (!insideCmux()) {
|
|
6818
|
-
process.exit(0);
|
|
6819
|
-
}
|
|
6820
|
-
let toplevel = "";
|
|
6821
|
-
try {
|
|
6822
|
-
toplevel = execSync9("git rev-parse --show-toplevel", {
|
|
6823
|
-
encoding: "utf8"
|
|
6824
|
-
}).trim();
|
|
6825
|
-
} catch {
|
|
6826
|
-
toplevel = process.cwd();
|
|
6827
|
-
}
|
|
6828
|
-
const cfg = readCmuxConfig(toplevel);
|
|
6829
|
-
if (cfg.auto_status === false) {
|
|
6830
|
-
process.exit(0);
|
|
6831
|
-
}
|
|
6832
|
-
let checkpoint;
|
|
6833
|
-
let task;
|
|
6834
|
-
let qa;
|
|
6835
|
-
let progress;
|
|
6836
|
-
let clear = false;
|
|
6837
|
-
for (let i = 0; i < args.length; i++) {
|
|
6838
|
-
const flag = args[i];
|
|
6839
|
-
if (flag === "--checkpoint" && i + 1 < args.length) {
|
|
6840
|
-
checkpoint = args[++i];
|
|
6841
|
-
} else if (flag === "--task" && i + 1 < args.length) {
|
|
6842
|
-
task = args[++i];
|
|
6843
|
-
} else if (flag === "--qa" && i + 1 < args.length) {
|
|
6844
|
-
qa = args[++i];
|
|
6845
|
-
} else if (flag === "--progress" && i + 1 < args.length) {
|
|
6846
|
-
progress = args[++i];
|
|
6847
|
-
} else if (flag === "--clear") {
|
|
6848
|
-
clear = true;
|
|
6849
|
-
}
|
|
6850
|
-
}
|
|
6851
|
-
const bin = resolveCmuxBin();
|
|
6852
|
-
if (clear) {
|
|
6853
|
-
try {
|
|
6854
|
-
execFileSync3(bin, ["clear-status", "cbp-checkpoint"]);
|
|
6855
|
-
} catch {
|
|
6856
|
-
}
|
|
6857
|
-
try {
|
|
6858
|
-
execFileSync3(bin, ["clear-status", "cbp-task"]);
|
|
6859
|
-
} catch {
|
|
6860
|
-
}
|
|
6861
|
-
try {
|
|
6862
|
-
execFileSync3(bin, ["clear-status", "cbp-qa"]);
|
|
6863
|
-
} catch {
|
|
6864
|
-
}
|
|
6865
|
-
try {
|
|
6866
|
-
execFileSync3(bin, ["clear-progress"]);
|
|
6867
|
-
} catch {
|
|
6868
|
-
}
|
|
6869
|
-
} else {
|
|
6870
|
-
if (checkpoint !== void 0) {
|
|
6871
|
-
try {
|
|
6872
|
-
execFileSync3(bin, ["set-status", "cbp-checkpoint", checkpoint]);
|
|
6873
|
-
} catch {
|
|
6874
|
-
}
|
|
6875
|
-
}
|
|
6876
|
-
if (task !== void 0) {
|
|
6877
|
-
try {
|
|
6878
|
-
execFileSync3(bin, ["set-status", "cbp-task", task]);
|
|
6879
|
-
} catch {
|
|
6880
|
-
}
|
|
6881
|
-
}
|
|
6882
|
-
if (qa !== void 0) {
|
|
6883
|
-
try {
|
|
6884
|
-
execFileSync3(bin, ["set-status", "cbp-qa", qa]);
|
|
6885
|
-
} catch {
|
|
6886
|
-
}
|
|
6887
|
-
}
|
|
6888
|
-
if (progress !== void 0) {
|
|
6889
|
-
const decimalStr = normalizeProgress(progress);
|
|
6890
|
-
if (decimalStr !== null) {
|
|
6891
|
-
try {
|
|
6892
|
-
execFileSync3(bin, ["set-progress", decimalStr]);
|
|
6893
|
-
} catch {
|
|
6894
|
-
}
|
|
6895
|
-
}
|
|
6896
|
-
}
|
|
6897
|
-
}
|
|
6898
|
-
process.exit(0);
|
|
6899
|
-
} catch (err) {
|
|
6900
|
-
if (err instanceof ProcessExitSignal) throw err;
|
|
6901
|
-
process.exit(0);
|
|
6902
|
-
}
|
|
6903
|
-
}
|
|
6904
|
-
var init_cmux_status = __esm({
|
|
6905
|
-
"src/cli/cmux-status.ts"() {
|
|
6906
|
-
"use strict";
|
|
6907
|
-
init_process_exit_signal();
|
|
6908
|
-
init_cmux();
|
|
6909
|
-
}
|
|
6910
|
-
});
|
|
6911
|
-
|
|
6912
|
-
// src/cli/cmux-serve.ts
|
|
6913
|
-
var cmux_serve_exports = {};
|
|
6914
|
-
__export(cmux_serve_exports, {
|
|
6915
|
-
probePort: () => probePort,
|
|
6916
|
-
runCmuxServe: () => runCmuxServe
|
|
6917
|
-
});
|
|
6918
|
-
import { execSync as execSync10, execFileSync as execFileSync4 } from "node:child_process";
|
|
6919
|
-
import { readFileSync as readFileSync7 } from "node:fs";
|
|
6920
|
-
import * as net from "node:net";
|
|
6921
|
-
import { join as join23 } from "node:path";
|
|
6922
|
-
function resolveAppDir(allocation, toplevel) {
|
|
6923
|
-
if (allocation.command !== null && allocation.working_dir !== null) {
|
|
6924
|
-
const wd = allocation.working_dir;
|
|
6925
|
-
const dir = wd.startsWith(toplevel + "/") ? wd.slice(toplevel.length + 1) : wd;
|
|
6926
|
-
return { appDir: dir, devCommand: allocation.command };
|
|
6927
|
-
}
|
|
6928
|
-
const label = allocation.label ?? "";
|
|
6929
|
-
if (label === "E2E Tests") return { skip: "skip-e2e" };
|
|
6930
|
-
if (label.includes("Web Dev") && !label.toLowerCase().includes("desktop")) {
|
|
6931
|
-
return { appDir: "apps/web", devCommand: null };
|
|
6932
|
-
}
|
|
6933
|
-
if (label.toLowerCase().includes("desktop")) {
|
|
6934
|
-
return { appDir: "apps/desktop", devCommand: null };
|
|
6935
|
-
}
|
|
6936
|
-
const appDir = LABEL_APP_MAP[label];
|
|
6937
|
-
if (appDir !== void 0) {
|
|
6938
|
-
return { appDir, devCommand: null };
|
|
6939
|
-
}
|
|
6940
|
-
return { skip: "no-match" };
|
|
6941
|
-
}
|
|
6942
|
-
function probePort(port) {
|
|
6943
|
-
return new Promise((resolve8) => {
|
|
6944
|
-
const socket = new net.Socket();
|
|
6945
|
-
let settled = false;
|
|
6946
|
-
const settle = (result) => {
|
|
6947
|
-
if (!settled) {
|
|
6948
|
-
settled = true;
|
|
6949
|
-
socket.destroy();
|
|
6950
|
-
resolve8(result);
|
|
6951
|
-
}
|
|
6952
|
-
};
|
|
6953
|
-
socket.setTimeout(500);
|
|
6954
|
-
socket.on("connect", () => settle(true));
|
|
6955
|
-
socket.on("error", () => settle(false));
|
|
6956
|
-
socket.on("timeout", () => settle(false));
|
|
6957
|
-
socket.connect({ port, host: "127.0.0.1" });
|
|
6958
|
-
});
|
|
6959
|
-
}
|
|
6960
|
-
async function runCmuxServe(args) {
|
|
6961
|
-
try {
|
|
6962
|
-
if (!insideCmux()) {
|
|
6963
|
-
process.exit(0);
|
|
6964
|
-
}
|
|
6965
|
-
let toplevel = "";
|
|
6966
|
-
try {
|
|
6967
|
-
toplevel = execSync10("git rev-parse --show-toplevel", {
|
|
6968
|
-
encoding: "utf8"
|
|
6969
|
-
}).trim();
|
|
6970
|
-
} catch {
|
|
6971
|
-
toplevel = process.cwd();
|
|
6972
|
-
}
|
|
6973
|
-
const cfg = readCmuxConfig(toplevel);
|
|
6974
|
-
if (cfg.auto_dev_server === false) {
|
|
6975
|
-
process.exit(0);
|
|
6976
|
-
}
|
|
6977
|
-
let filesArg;
|
|
6978
|
-
let appArg;
|
|
6979
|
-
for (let i = 0; i < args.length; i++) {
|
|
6980
|
-
const flag = args[i];
|
|
6981
|
-
if (flag === "--files" && i + 1 < args.length) {
|
|
6982
|
-
filesArg = args[++i];
|
|
6983
|
-
} else if (flag === "--app" && i + 1 < args.length) {
|
|
6984
|
-
appArg = args[++i];
|
|
6985
|
-
}
|
|
6986
|
-
}
|
|
6987
|
-
const changedFiles = filesArg !== void 0 ? filesArg.split(",").map((f) => f.trim()).filter(Boolean) : [];
|
|
6988
|
-
let serverConfig = null;
|
|
6989
|
-
try {
|
|
6990
|
-
const raw = readFileSync7(
|
|
6991
|
-
join23(toplevel, ".codebyplan", "server.json"),
|
|
6992
|
-
"utf-8"
|
|
6993
|
-
);
|
|
6994
|
-
serverConfig = JSON.parse(raw);
|
|
6995
|
-
} catch {
|
|
6996
|
-
process.exit(0);
|
|
6997
|
-
}
|
|
6998
|
-
const allocations = serverConfig?.port_allocations ?? [];
|
|
6999
|
-
if (allocations.length === 0) {
|
|
7000
|
-
process.exit(0);
|
|
7001
|
-
}
|
|
7002
|
-
const bin = resolveCmuxBin();
|
|
7003
|
-
for (const allocation of allocations) {
|
|
7004
|
-
try {
|
|
7005
|
-
const resolved = resolveAppDir(allocation, toplevel);
|
|
7006
|
-
if ("skip" in resolved) {
|
|
7007
|
-
if (resolved.skip === "no-match") {
|
|
7008
|
-
process.stdout.write(
|
|
7009
|
-
`cmux-serve: no app mapping for allocation "${allocation.label ?? ""}" \u2014 skipped
|
|
7010
|
-
`
|
|
7011
|
-
);
|
|
7012
|
-
}
|
|
7013
|
-
continue;
|
|
7014
|
-
}
|
|
7015
|
-
const { appDir, devCommand } = resolved;
|
|
7016
|
-
const appDirWithSlash = appDir + "/";
|
|
7017
|
-
const intersects = appArg !== void 0 && (appArg === appDir || appArg.startsWith(appDirWithSlash)) || changedFiles.some(
|
|
7018
|
-
(f) => f === appDir || f.startsWith(appDirWithSlash)
|
|
7019
|
-
);
|
|
7020
|
-
if (!intersects) {
|
|
7021
|
-
continue;
|
|
7022
|
-
}
|
|
7023
|
-
const port = allocation.port;
|
|
7024
|
-
const listening = await probePort(port);
|
|
7025
|
-
if (!listening) {
|
|
7026
|
-
let shellCommand = null;
|
|
7027
|
-
if (devCommand !== null) {
|
|
7028
|
-
shellCommand = `cd "${join23(toplevel, appDir)}" && ${devCommand}`;
|
|
7029
|
-
} else {
|
|
7030
|
-
let hasDev = false;
|
|
7031
|
-
try {
|
|
7032
|
-
const pkgRaw = readFileSync7(
|
|
7033
|
-
join23(toplevel, appDir, "package.json"),
|
|
7034
|
-
"utf-8"
|
|
7035
|
-
);
|
|
7036
|
-
const pkg = JSON.parse(pkgRaw);
|
|
7037
|
-
hasDev = typeof pkg.scripts?.dev === "string";
|
|
7038
|
-
} catch {
|
|
7039
|
-
}
|
|
7040
|
-
if (!hasDev) {
|
|
7041
|
-
process.stdout.write(
|
|
7042
|
-
`cmux-serve: no "dev" script in ${appDir}/package.json \u2014 skipped
|
|
7043
|
-
`
|
|
7044
|
-
);
|
|
7045
|
-
continue;
|
|
7046
|
-
}
|
|
7047
|
-
shellCommand = `cd "${join23(toplevel, appDir)}" && pnpm run dev`;
|
|
7048
|
-
}
|
|
7049
|
-
let splitSurfaceRef = null;
|
|
7050
|
-
try {
|
|
7051
|
-
const splitOut = execFileSync4(
|
|
7052
|
-
bin,
|
|
7053
|
-
["new-split", "down", "--json"],
|
|
7054
|
-
{
|
|
7055
|
-
encoding: "utf8"
|
|
7056
|
-
}
|
|
7057
|
-
);
|
|
7058
|
-
const parsed = JSON.parse(splitOut);
|
|
7059
|
-
if (typeof parsed.surface_ref === "string" && parsed.surface_ref) {
|
|
7060
|
-
splitSurfaceRef = parsed.surface_ref;
|
|
7061
|
-
}
|
|
7062
|
-
} catch {
|
|
7063
|
-
}
|
|
7064
|
-
if (splitSurfaceRef !== null) {
|
|
7065
|
-
try {
|
|
7066
|
-
execFileSync4(bin, [
|
|
7067
|
-
"send",
|
|
7068
|
-
"--surface",
|
|
7069
|
-
splitSurfaceRef,
|
|
7070
|
-
`${shellCommand}
|
|
7071
|
-
`
|
|
7072
|
-
]);
|
|
7073
|
-
} catch {
|
|
7074
|
-
}
|
|
7075
|
-
} else {
|
|
7076
|
-
process.stdout.write(
|
|
7077
|
-
`cmux-serve: could not resolve new split surface for ${appDir} \u2014 dev server not auto-started (open it manually)
|
|
7078
|
-
`
|
|
7079
|
-
);
|
|
7080
|
-
}
|
|
7081
|
-
}
|
|
7082
|
-
try {
|
|
7083
|
-
execFileSync4(bin, [
|
|
7084
|
-
"new-pane",
|
|
7085
|
-
"--type",
|
|
7086
|
-
"browser",
|
|
7087
|
-
"--url",
|
|
7088
|
-
`http://localhost:${port}`
|
|
7089
|
-
]);
|
|
7090
|
-
} catch {
|
|
7091
|
-
}
|
|
7092
|
-
} catch {
|
|
7093
|
-
}
|
|
7094
|
-
}
|
|
7095
|
-
process.exit(0);
|
|
7096
|
-
} catch (err) {
|
|
7097
|
-
if (err instanceof ProcessExitSignal) throw err;
|
|
7098
|
-
process.exit(0);
|
|
7099
|
-
}
|
|
7100
|
-
}
|
|
7101
|
-
var LABEL_APP_MAP;
|
|
7102
|
-
var init_cmux_serve = __esm({
|
|
7103
|
-
"src/cli/cmux-serve.ts"() {
|
|
7104
|
-
"use strict";
|
|
7105
|
-
init_process_exit_signal();
|
|
7106
|
-
init_cmux();
|
|
7107
|
-
LABEL_APP_MAP = {
|
|
7108
|
-
"Backend Dev": "apps/backend",
|
|
7109
|
-
"MCP Dev": "apps/mcp",
|
|
7110
|
-
"Docs Ingest": "apps/docs-ingest"
|
|
7111
|
-
};
|
|
7112
|
-
}
|
|
7113
|
-
});
|
|
7114
|
-
|
|
7115
6669
|
// src/lib/worktree-port-resolver.ts
|
|
7116
6670
|
async function resolveWorktreePortAllocations(repoId, projectPath) {
|
|
7117
6671
|
let resolvedWorktreeId;
|
|
@@ -7119,8 +6673,8 @@ async function resolveWorktreePortAllocations(repoId, projectPath) {
|
|
|
7119
6673
|
const deviceId = await getOrCreateDeviceId(projectPath);
|
|
7120
6674
|
let branch = "main";
|
|
7121
6675
|
try {
|
|
7122
|
-
const { execSync:
|
|
7123
|
-
branch =
|
|
6676
|
+
const { execSync: execSync9 } = await import("node:child_process");
|
|
6677
|
+
branch = execSync9("git symbolic-ref --short HEAD", {
|
|
7124
6678
|
cwd: projectPath,
|
|
7125
6679
|
encoding: "utf-8"
|
|
7126
6680
|
}).trim();
|
|
@@ -7202,18 +6756,18 @@ var init_worktree_port_resolver = __esm({
|
|
|
7202
6756
|
|
|
7203
6757
|
// src/lib/migrate-local-config.ts
|
|
7204
6758
|
import { mkdir as mkdir6, readFile as readFile16, unlink as unlink2, writeFile as writeFile12 } from "node:fs/promises";
|
|
7205
|
-
import { join as
|
|
6759
|
+
import { join as join22 } from "node:path";
|
|
7206
6760
|
function legacySharedPath(projectPath) {
|
|
7207
|
-
return
|
|
6761
|
+
return join22(projectPath, ".codebyplan.json");
|
|
7208
6762
|
}
|
|
7209
6763
|
function legacyLocalPath(projectPath) {
|
|
7210
|
-
return
|
|
6764
|
+
return join22(projectPath, ".codebyplan.local.json");
|
|
7211
6765
|
}
|
|
7212
6766
|
function newDirPath(projectPath) {
|
|
7213
|
-
return
|
|
6767
|
+
return join22(projectPath, ".codebyplan");
|
|
7214
6768
|
}
|
|
7215
6769
|
function sentinelPath(projectPath) {
|
|
7216
|
-
return
|
|
6770
|
+
return join22(projectPath, ".codebyplan", "repo.json");
|
|
7217
6771
|
}
|
|
7218
6772
|
async function statSafe(p) {
|
|
7219
6773
|
const { stat: stat2 } = await import("node:fs/promises");
|
|
@@ -7307,7 +6861,7 @@ async function runLocalMigration(projectPath) {
|
|
|
7307
6861
|
if ("organization_id" in cfg) repoJson.organization_id = cfg.organization_id;
|
|
7308
6862
|
if ("project_id" in cfg) repoJson.project_id = cfg.project_id;
|
|
7309
6863
|
await writeFile12(
|
|
7310
|
-
|
|
6864
|
+
join22(projectPath, ".codebyplan", "repo.json"),
|
|
7311
6865
|
JSON.stringify(repoJson, null, 2) + "\n",
|
|
7312
6866
|
"utf-8"
|
|
7313
6867
|
);
|
|
@@ -7320,7 +6874,7 @@ async function runLocalMigration(projectPath) {
|
|
|
7320
6874
|
if ("port_allocations" in cfg)
|
|
7321
6875
|
serverJson.port_allocations = cfg.port_allocations;
|
|
7322
6876
|
await writeFile12(
|
|
7323
|
-
|
|
6877
|
+
join22(projectPath, ".codebyplan", "server.json"),
|
|
7324
6878
|
JSON.stringify(serverJson, null, 2) + "\n",
|
|
7325
6879
|
"utf-8"
|
|
7326
6880
|
);
|
|
@@ -7329,7 +6883,7 @@ async function runLocalMigration(projectPath) {
|
|
|
7329
6883
|
if ("git_branch" in cfg) gitJson.git_branch = cfg.git_branch;
|
|
7330
6884
|
if ("branch_config" in cfg) gitJson.branch_config = cfg.branch_config;
|
|
7331
6885
|
await writeFile12(
|
|
7332
|
-
|
|
6886
|
+
join22(projectPath, ".codebyplan", "git.json"),
|
|
7333
6887
|
JSON.stringify(gitJson, null, 2) + "\n",
|
|
7334
6888
|
"utf-8"
|
|
7335
6889
|
);
|
|
@@ -7337,35 +6891,35 @@ async function runLocalMigration(projectPath) {
|
|
|
7337
6891
|
const shipmentJson = {};
|
|
7338
6892
|
if ("shipment" in cfg) shipmentJson.shipment = cfg.shipment;
|
|
7339
6893
|
await writeFile12(
|
|
7340
|
-
|
|
6894
|
+
join22(projectPath, ".codebyplan", "shipment.json"),
|
|
7341
6895
|
JSON.stringify(shipmentJson, null, 2) + "\n",
|
|
7342
6896
|
"utf-8"
|
|
7343
6897
|
);
|
|
7344
6898
|
filesChanged.push(".codebyplan/shipment.json");
|
|
7345
6899
|
const vendorJson = {};
|
|
7346
6900
|
await writeFile12(
|
|
7347
|
-
|
|
6901
|
+
join22(projectPath, ".codebyplan", "vendor.json"),
|
|
7348
6902
|
JSON.stringify(vendorJson, null, 2) + "\n",
|
|
7349
6903
|
"utf-8"
|
|
7350
6904
|
);
|
|
7351
6905
|
filesChanged.push(".codebyplan/vendor.json");
|
|
7352
6906
|
const e2eJson = {};
|
|
7353
6907
|
await writeFile12(
|
|
7354
|
-
|
|
6908
|
+
join22(projectPath, ".codebyplan", "e2e.json"),
|
|
7355
6909
|
JSON.stringify(e2eJson, null, 2) + "\n",
|
|
7356
6910
|
"utf-8"
|
|
7357
6911
|
);
|
|
7358
6912
|
filesChanged.push(".codebyplan/e2e.json");
|
|
7359
6913
|
const eslintJson = {};
|
|
7360
6914
|
await writeFile12(
|
|
7361
|
-
|
|
6915
|
+
join22(projectPath, ".codebyplan", "eslint.json"),
|
|
7362
6916
|
JSON.stringify(eslintJson, null, 2) + "\n",
|
|
7363
6917
|
"utf-8"
|
|
7364
6918
|
);
|
|
7365
6919
|
filesChanged.push(".codebyplan/eslint.json");
|
|
7366
6920
|
if (!deviceWrittenByHelper) {
|
|
7367
6921
|
await writeFile12(
|
|
7368
|
-
|
|
6922
|
+
join22(projectPath, ".codebyplan", "device.local.json"),
|
|
7369
6923
|
JSON.stringify({ device_id: deviceId }, null, 2) + "\n",
|
|
7370
6924
|
"utf-8"
|
|
7371
6925
|
);
|
|
@@ -7377,7 +6931,7 @@ async function runLocalMigration(projectPath) {
|
|
|
7377
6931
|
"Migration write incomplete: .codebyplan/repo.json was not persisted. Re-run migration to retry from a clean state."
|
|
7378
6932
|
);
|
|
7379
6933
|
}
|
|
7380
|
-
const gitignorePath =
|
|
6934
|
+
const gitignorePath = join22(projectPath, ".gitignore");
|
|
7381
6935
|
try {
|
|
7382
6936
|
const gitignoreContent = await readFile16(gitignorePath, "utf-8");
|
|
7383
6937
|
const legacyLine = ".codebyplan.local.json";
|
|
@@ -7440,7 +6994,7 @@ __export(config_exports, {
|
|
|
7440
6994
|
runConfig: () => runConfig
|
|
7441
6995
|
});
|
|
7442
6996
|
import { mkdir as mkdir7, readFile as readFile17, writeFile as writeFile13 } from "node:fs/promises";
|
|
7443
|
-
import { join as
|
|
6997
|
+
import { join as join23 } from "node:path";
|
|
7444
6998
|
async function runConfig() {
|
|
7445
6999
|
const flags = parseFlags(3);
|
|
7446
7000
|
const dryRun = hasFlag("dry-run", 3);
|
|
@@ -7473,7 +7027,7 @@ async function runConfig() {
|
|
|
7473
7027
|
console.log("\n Config complete.\n");
|
|
7474
7028
|
}
|
|
7475
7029
|
async function syncConfigToFile(repoId, projectPath, dryRun) {
|
|
7476
|
-
const codebyplanDir =
|
|
7030
|
+
const codebyplanDir = join23(projectPath, ".codebyplan");
|
|
7477
7031
|
const {
|
|
7478
7032
|
resolvedWorktreeId,
|
|
7479
7033
|
portAllocations,
|
|
@@ -7541,7 +7095,6 @@ async function syncConfigToFile(repoId, projectPath, dryRun) {
|
|
|
7541
7095
|
const vendorPayload = {};
|
|
7542
7096
|
const e2ePayload = {};
|
|
7543
7097
|
const eslintPayload = {};
|
|
7544
|
-
const cmuxPayload = {};
|
|
7545
7098
|
if (dryRun) {
|
|
7546
7099
|
console.log(" Config would be updated (dry-run).");
|
|
7547
7100
|
return;
|
|
@@ -7554,12 +7107,11 @@ async function syncConfigToFile(repoId, projectPath, dryRun) {
|
|
|
7554
7107
|
{ name: "shipment.json", payload: shipmentPayload },
|
|
7555
7108
|
{ name: "vendor.json", payload: vendorPayload },
|
|
7556
7109
|
{ name: "e2e.json", payload: e2ePayload, createOnly: true },
|
|
7557
|
-
{ name: "eslint.json", payload: eslintPayload, createOnly: true }
|
|
7558
|
-
{ name: "cmux.json", payload: cmuxPayload, createOnly: true }
|
|
7110
|
+
{ name: "eslint.json", payload: eslintPayload, createOnly: true }
|
|
7559
7111
|
];
|
|
7560
7112
|
let anyUpdated = false;
|
|
7561
7113
|
for (const { name, payload, createOnly } of files) {
|
|
7562
|
-
const filePath =
|
|
7114
|
+
const filePath = join23(codebyplanDir, name);
|
|
7563
7115
|
const newJson = JSON.stringify(payload, null, 2) + "\n";
|
|
7564
7116
|
let currentJson = "";
|
|
7565
7117
|
try {
|
|
@@ -7579,7 +7131,7 @@ async function syncConfigToFile(repoId, projectPath, dryRun) {
|
|
|
7579
7131
|
async function readRepoConfig(projectPath) {
|
|
7580
7132
|
try {
|
|
7581
7133
|
const raw = await readFile17(
|
|
7582
|
-
|
|
7134
|
+
join23(projectPath, ".codebyplan", "repo.json"),
|
|
7583
7135
|
"utf-8"
|
|
7584
7136
|
);
|
|
7585
7137
|
return JSON.parse(raw);
|
|
@@ -7590,7 +7142,7 @@ async function readRepoConfig(projectPath) {
|
|
|
7590
7142
|
async function readServerConfig(projectPath) {
|
|
7591
7143
|
try {
|
|
7592
7144
|
const raw = await readFile17(
|
|
7593
|
-
|
|
7145
|
+
join23(projectPath, ".codebyplan", "server.json"),
|
|
7594
7146
|
"utf-8"
|
|
7595
7147
|
);
|
|
7596
7148
|
return JSON.parse(raw);
|
|
@@ -7601,7 +7153,7 @@ async function readServerConfig(projectPath) {
|
|
|
7601
7153
|
async function readGitConfig(projectPath) {
|
|
7602
7154
|
try {
|
|
7603
7155
|
const raw = await readFile17(
|
|
7604
|
-
|
|
7156
|
+
join23(projectPath, ".codebyplan", "git.json"),
|
|
7605
7157
|
"utf-8"
|
|
7606
7158
|
);
|
|
7607
7159
|
return JSON.parse(raw);
|
|
@@ -7612,7 +7164,7 @@ async function readGitConfig(projectPath) {
|
|
|
7612
7164
|
async function readShipmentConfig(projectPath) {
|
|
7613
7165
|
try {
|
|
7614
7166
|
const raw = await readFile17(
|
|
7615
|
-
|
|
7167
|
+
join23(projectPath, ".codebyplan", "shipment.json"),
|
|
7616
7168
|
"utf-8"
|
|
7617
7169
|
);
|
|
7618
7170
|
return JSON.parse(raw);
|
|
@@ -7623,7 +7175,7 @@ async function readShipmentConfig(projectPath) {
|
|
|
7623
7175
|
async function readVendorConfig(projectPath) {
|
|
7624
7176
|
try {
|
|
7625
7177
|
const raw = await readFile17(
|
|
7626
|
-
|
|
7178
|
+
join23(projectPath, ".codebyplan", "vendor.json"),
|
|
7627
7179
|
"utf-8"
|
|
7628
7180
|
);
|
|
7629
7181
|
return JSON.parse(raw);
|
|
@@ -7634,7 +7186,7 @@ async function readVendorConfig(projectPath) {
|
|
|
7634
7186
|
async function readE2eConfig2(projectPath) {
|
|
7635
7187
|
try {
|
|
7636
7188
|
const raw = await readFile17(
|
|
7637
|
-
|
|
7189
|
+
join23(projectPath, ".codebyplan", "e2e.json"),
|
|
7638
7190
|
"utf-8"
|
|
7639
7191
|
);
|
|
7640
7192
|
return JSON.parse(raw);
|
|
@@ -7645,7 +7197,7 @@ async function readE2eConfig2(projectPath) {
|
|
|
7645
7197
|
async function readServerLocalConfig(projectPath) {
|
|
7646
7198
|
try {
|
|
7647
7199
|
const raw = await readFile17(
|
|
7648
|
-
|
|
7200
|
+
join23(projectPath, ".codebyplan", "server.local.json"),
|
|
7649
7201
|
"utf-8"
|
|
7650
7202
|
);
|
|
7651
7203
|
return JSON.parse(raw);
|
|
@@ -7821,7 +7373,7 @@ __export(ports_exports, {
|
|
|
7821
7373
|
runPorts: () => runPorts
|
|
7822
7374
|
});
|
|
7823
7375
|
import { mkdir as mkdir8, readFile as readFile19, writeFile as writeFile14 } from "node:fs/promises";
|
|
7824
|
-
import { join as
|
|
7376
|
+
import { join as join24 } from "node:path";
|
|
7825
7377
|
async function runPorts() {
|
|
7826
7378
|
const flags = parseFlags(3);
|
|
7827
7379
|
const dryRun = hasFlag("dry-run", 3);
|
|
@@ -7942,8 +7494,8 @@ async function writeServerLocalConfig(repoId, projectPath, dryRun) {
|
|
|
7942
7494
|
// and ServerLocalConfig.port_allocations is typed the same — honest end-to-end.
|
|
7943
7495
|
port_allocations: portAllocations
|
|
7944
7496
|
};
|
|
7945
|
-
const codebyplanDir =
|
|
7946
|
-
const filePath =
|
|
7497
|
+
const codebyplanDir = join24(projectPath, ".codebyplan");
|
|
7498
|
+
const filePath = join24(codebyplanDir, "server.local.json");
|
|
7947
7499
|
const newJson = JSON.stringify(payload, null, 2) + "\n";
|
|
7948
7500
|
let currentJson = "";
|
|
7949
7501
|
try {
|
|
@@ -7965,8 +7517,8 @@ async function writeServerLocalConfig(repoId, projectPath, dryRun) {
|
|
|
7965
7517
|
);
|
|
7966
7518
|
}
|
|
7967
7519
|
async function provisionE2eEnv(projectPath, dryRun) {
|
|
7968
|
-
const relSource =
|
|
7969
|
-
const sourcePath =
|
|
7520
|
+
const relSource = join24("apps", "web", ".env.local");
|
|
7521
|
+
const sourcePath = join24(projectPath, relSource);
|
|
7970
7522
|
let sourceRaw;
|
|
7971
7523
|
try {
|
|
7972
7524
|
sourceRaw = await readFile19(sourcePath, "utf-8");
|
|
@@ -7998,8 +7550,8 @@ async function provisionE2eEnv(projectPath, dryRun) {
|
|
|
7998
7550
|
);
|
|
7999
7551
|
return;
|
|
8000
7552
|
}
|
|
8001
|
-
const codebyplanDir =
|
|
8002
|
-
const filePath =
|
|
7553
|
+
const codebyplanDir = join24(projectPath, ".codebyplan");
|
|
7554
|
+
const filePath = join24(codebyplanDir, "e2e.env");
|
|
8003
7555
|
const newContent = lines.join("\n") + "\n";
|
|
8004
7556
|
let currentContent = "";
|
|
8005
7557
|
try {
|
|
@@ -8127,10 +7679,10 @@ async function runTechStack() {
|
|
|
8127
7679
|
);
|
|
8128
7680
|
}
|
|
8129
7681
|
try {
|
|
8130
|
-
const { execSync:
|
|
7682
|
+
const { execSync: execSync9 } = await import("node:child_process");
|
|
8131
7683
|
let branch = "main";
|
|
8132
7684
|
try {
|
|
8133
|
-
branch =
|
|
7685
|
+
branch = execSync9("git symbolic-ref --short HEAD", {
|
|
8134
7686
|
cwd: projectPath,
|
|
8135
7687
|
encoding: "utf-8"
|
|
8136
7688
|
}).trim();
|
|
@@ -8275,6 +7827,301 @@ var init_tech_stack = __esm({
|
|
|
8275
7827
|
}
|
|
8276
7828
|
});
|
|
8277
7829
|
|
|
7830
|
+
// src/lib/claude-plan.ts
|
|
7831
|
+
import * as fs5 from "node:fs";
|
|
7832
|
+
import * as path6 from "node:path";
|
|
7833
|
+
function buildDriftPlan(projectDir, templatesDir, manifest) {
|
|
7834
|
+
const packaged = walkTemplates(templatesDir);
|
|
7835
|
+
const packagedBySrc = new Map(packaged.map((f) => [f.src, f]));
|
|
7836
|
+
const manifestBySrc = new Map(manifest.files.map((f) => [f.src, f]));
|
|
7837
|
+
const plan = {
|
|
7838
|
+
unchanged: [],
|
|
7839
|
+
overwriteSafe: [],
|
|
7840
|
+
overwriteHandEdited: [],
|
|
7841
|
+
newOptIn: [],
|
|
7842
|
+
removedFromPackage: []
|
|
7843
|
+
};
|
|
7844
|
+
for (const pkg of packaged) {
|
|
7845
|
+
const inManifest = manifestBySrc.get(pkg.src);
|
|
7846
|
+
const absDest = path6.join(projectDir, ".claude", pkg.dest);
|
|
7847
|
+
const absSrc = path6.join(templatesDir, pkg.src);
|
|
7848
|
+
if (!inManifest) {
|
|
7849
|
+
plan.newOptIn.push({
|
|
7850
|
+
packaged: { src: pkg.src, dest: pkg.dest, hash: pkg.hash },
|
|
7851
|
+
absSrc
|
|
7852
|
+
});
|
|
7853
|
+
continue;
|
|
7854
|
+
}
|
|
7855
|
+
const onDiskExists = fs5.existsSync(absDest);
|
|
7856
|
+
const onDiskContent = onDiskExists ? fs5.readFileSync(absDest) : Buffer.alloc(0);
|
|
7857
|
+
const onDiskHash = onDiskExists ? sha256(onDiskContent) : null;
|
|
7858
|
+
if (pkg.hash === inManifest.hash && onDiskHash === inManifest.hash) {
|
|
7859
|
+
plan.unchanged.push(inManifest);
|
|
7860
|
+
continue;
|
|
7861
|
+
}
|
|
7862
|
+
if (onDiskHash !== null && onDiskHash !== inManifest.hash) {
|
|
7863
|
+
plan.overwriteHandEdited.push({
|
|
7864
|
+
packaged: { src: pkg.src, dest: pkg.dest, hash: pkg.hash },
|
|
7865
|
+
absSrc,
|
|
7866
|
+
onDiskContent
|
|
7867
|
+
});
|
|
7868
|
+
} else {
|
|
7869
|
+
plan.overwriteSafe.push({
|
|
7870
|
+
packaged: { src: pkg.src, dest: pkg.dest, hash: pkg.hash },
|
|
7871
|
+
absSrc
|
|
7872
|
+
});
|
|
7873
|
+
}
|
|
7874
|
+
}
|
|
7875
|
+
for (const m of manifest.files) {
|
|
7876
|
+
if (!packagedBySrc.has(m.src)) {
|
|
7877
|
+
plan.removedFromPackage.push(m);
|
|
7878
|
+
}
|
|
7879
|
+
}
|
|
7880
|
+
return plan;
|
|
7881
|
+
}
|
|
7882
|
+
var init_claude_plan = __esm({
|
|
7883
|
+
"src/lib/claude-plan.ts"() {
|
|
7884
|
+
"use strict";
|
|
7885
|
+
init_template_walker();
|
|
7886
|
+
init_hash();
|
|
7887
|
+
}
|
|
7888
|
+
});
|
|
7889
|
+
|
|
7890
|
+
// src/cli/claude/status.ts
|
|
7891
|
+
var status_exports = {};
|
|
7892
|
+
__export(status_exports, {
|
|
7893
|
+
runStatus: () => runStatus
|
|
7894
|
+
});
|
|
7895
|
+
import * as fs6 from "node:fs";
|
|
7896
|
+
import * as path7 from "node:path";
|
|
7897
|
+
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
7898
|
+
import { execSync as execSync8 } from "node:child_process";
|
|
7899
|
+
function makeFailSafe(checked_at) {
|
|
7900
|
+
return {
|
|
7901
|
+
installed: VERSION,
|
|
7902
|
+
manifest_version: null,
|
|
7903
|
+
latest: null,
|
|
7904
|
+
newer: false,
|
|
7905
|
+
version_skip: false,
|
|
7906
|
+
drifted_files: [],
|
|
7907
|
+
new_in_package: [],
|
|
7908
|
+
removed_from_package: [],
|
|
7909
|
+
settings_drift: false,
|
|
7910
|
+
guarded: true,
|
|
7911
|
+
guard_reason: "unknown",
|
|
7912
|
+
in_sync: true,
|
|
7913
|
+
action: null,
|
|
7914
|
+
checked_at
|
|
7915
|
+
};
|
|
7916
|
+
}
|
|
7917
|
+
function resolveTemplatesDirFromInstall() {
|
|
7918
|
+
const here = path7.dirname(fileURLToPath2(import.meta.url));
|
|
7919
|
+
const candidates = [
|
|
7920
|
+
path7.resolve(here, "..", "templates"),
|
|
7921
|
+
path7.resolve(here, "..", "..", "templates"),
|
|
7922
|
+
path7.resolve(here, "..", "..", "..", "templates")
|
|
7923
|
+
];
|
|
7924
|
+
for (const c of candidates) {
|
|
7925
|
+
if (fs6.existsSync(c) && fs6.statSync(c).isDirectory()) {
|
|
7926
|
+
return c;
|
|
7927
|
+
}
|
|
7928
|
+
}
|
|
7929
|
+
throw new Error(
|
|
7930
|
+
`codebyplan claude: could not locate templates/ directory. Probed:
|
|
7931
|
+
${candidates.join(
|
|
7932
|
+
"\n "
|
|
7933
|
+
)}`
|
|
7934
|
+
);
|
|
7935
|
+
}
|
|
7936
|
+
function resolveGitRoot2() {
|
|
7937
|
+
try {
|
|
7938
|
+
return execSync8("git rev-parse --show-toplevel", {
|
|
7939
|
+
encoding: "utf-8"
|
|
7940
|
+
}).trim();
|
|
7941
|
+
} catch {
|
|
7942
|
+
return null;
|
|
7943
|
+
}
|
|
7944
|
+
}
|
|
7945
|
+
function resolveCurrentBranch2() {
|
|
7946
|
+
try {
|
|
7947
|
+
return execSync8("git symbolic-ref --short HEAD", {
|
|
7948
|
+
encoding: "utf-8"
|
|
7949
|
+
}).trim();
|
|
7950
|
+
} catch {
|
|
7951
|
+
try {
|
|
7952
|
+
return execSync8("git rev-parse --abbrev-ref HEAD", {
|
|
7953
|
+
encoding: "utf-8"
|
|
7954
|
+
}).trim();
|
|
7955
|
+
} catch {
|
|
7956
|
+
return "";
|
|
7957
|
+
}
|
|
7958
|
+
}
|
|
7959
|
+
}
|
|
7960
|
+
async function runStatus(argv) {
|
|
7961
|
+
const checked_at = (/* @__PURE__ */ new Date()).toISOString();
|
|
7962
|
+
const writeCache = argv.includes("--write-cache");
|
|
7963
|
+
const quiet = argv.includes("--quiet");
|
|
7964
|
+
try {
|
|
7965
|
+
const projectDir = resolveGitRoot2() ?? process.cwd();
|
|
7966
|
+
let templatesDir;
|
|
7967
|
+
try {
|
|
7968
|
+
templatesDir = resolveTemplatesDirFromInstall();
|
|
7969
|
+
} catch {
|
|
7970
|
+
const gitRoot2 = resolveGitRoot2();
|
|
7971
|
+
const currentBranch2 = resolveCurrentBranch2();
|
|
7972
|
+
const { guardReason: guardReason2 } = await resolveGuard(gitRoot2, currentBranch2);
|
|
7973
|
+
const result2 = {
|
|
7974
|
+
...makeFailSafe(checked_at),
|
|
7975
|
+
// Mirror the main path: only the canonical source repo hides the
|
|
7976
|
+
// segment. A protected_branch consumer whose templates can't be
|
|
7977
|
+
// resolved must still be guarded:false (segment visible).
|
|
7978
|
+
guarded: guardReason2 === "canonical_source",
|
|
7979
|
+
guard_reason: guardReason2 ?? "no_manifest",
|
|
7980
|
+
in_sync: true
|
|
7981
|
+
};
|
|
7982
|
+
emitResult(result2, writeCache, quiet, projectDir);
|
|
7983
|
+
process.exit(0);
|
|
7984
|
+
return;
|
|
7985
|
+
}
|
|
7986
|
+
const gitRoot = resolveGitRoot2();
|
|
7987
|
+
const currentBranch = resolveCurrentBranch2();
|
|
7988
|
+
const { guardReason } = await resolveGuard(gitRoot, currentBranch);
|
|
7989
|
+
const manifest = readManifest(projectDir);
|
|
7990
|
+
if (manifest === null || guardReason === "canonical_source") {
|
|
7991
|
+
const result2 = {
|
|
7992
|
+
installed: VERSION,
|
|
7993
|
+
manifest_version: manifest === null ? null : manifest.version,
|
|
7994
|
+
latest: null,
|
|
7995
|
+
newer: false,
|
|
7996
|
+
version_skip: false,
|
|
7997
|
+
drifted_files: [],
|
|
7998
|
+
new_in_package: [],
|
|
7999
|
+
removed_from_package: [],
|
|
8000
|
+
settings_drift: false,
|
|
8001
|
+
guarded: true,
|
|
8002
|
+
// guarded:true must always pair with a non-null reason. canonical_source
|
|
8003
|
+
// keeps its reason; the bare no-manifest case (never-installed consumer)
|
|
8004
|
+
// gets the "no_manifest" sentinel instead of null.
|
|
8005
|
+
guard_reason: guardReason ?? "no_manifest",
|
|
8006
|
+
in_sync: true,
|
|
8007
|
+
action: null,
|
|
8008
|
+
checked_at
|
|
8009
|
+
};
|
|
8010
|
+
emitResult(result2, writeCache, quiet, projectDir);
|
|
8011
|
+
process.exit(0);
|
|
8012
|
+
return;
|
|
8013
|
+
}
|
|
8014
|
+
const installed = VERSION;
|
|
8015
|
+
const manifest_version = manifest.version;
|
|
8016
|
+
const version_skip = manifest_version != null && compareSemver(installed, manifest_version) > 0;
|
|
8017
|
+
const driftPlan = buildDriftPlan(projectDir, templatesDir, manifest);
|
|
8018
|
+
const drifted_files = driftPlan.overwriteHandEdited.map(
|
|
8019
|
+
(e) => e.packaged.dest
|
|
8020
|
+
);
|
|
8021
|
+
const new_in_package = driftPlan.newOptIn.map((e) => e.packaged.dest);
|
|
8022
|
+
const removed_from_package = driftPlan.removedFromPackage.map(
|
|
8023
|
+
(e) => e.dest
|
|
8024
|
+
);
|
|
8025
|
+
const latest = fetchLatestVersion();
|
|
8026
|
+
const newer = latest !== null && compareSemver(latest, installed) > 0;
|
|
8027
|
+
let settings_drift = false;
|
|
8028
|
+
const settingsPath = path7.join(projectDir, ".claude", "settings.json");
|
|
8029
|
+
const baseSettingsPath = path7.join(
|
|
8030
|
+
templatesDir,
|
|
8031
|
+
"settings.project.base.json"
|
|
8032
|
+
);
|
|
8033
|
+
const hooksJsonPath = path7.join(templatesDir, "hooks", "hooks.json");
|
|
8034
|
+
if (fs6.existsSync(settingsPath)) {
|
|
8035
|
+
try {
|
|
8036
|
+
const settingsRaw = fs6.readFileSync(settingsPath, "utf8");
|
|
8037
|
+
const before = JSON.stringify(JSON.parse(settingsRaw));
|
|
8038
|
+
const cloned = JSON.parse(settingsRaw);
|
|
8039
|
+
if (fs6.existsSync(baseSettingsPath)) {
|
|
8040
|
+
const base = JSON.parse(
|
|
8041
|
+
fs6.readFileSync(baseSettingsPath, "utf8")
|
|
8042
|
+
);
|
|
8043
|
+
mergeBaseSettingsIntoSettings(cloned, base);
|
|
8044
|
+
}
|
|
8045
|
+
if (fs6.existsSync(hooksJsonPath)) {
|
|
8046
|
+
const hooksJson = JSON.parse(
|
|
8047
|
+
fs6.readFileSync(hooksJsonPath, "utf8")
|
|
8048
|
+
);
|
|
8049
|
+
mergeHooksIntoSettings(cloned, hooksJson);
|
|
8050
|
+
}
|
|
8051
|
+
const after = JSON.stringify(cloned);
|
|
8052
|
+
settings_drift = before !== after;
|
|
8053
|
+
} catch {
|
|
8054
|
+
settings_drift = false;
|
|
8055
|
+
}
|
|
8056
|
+
}
|
|
8057
|
+
const in_sync = !version_skip && drifted_files.length === 0 && new_in_package.length === 0 && removed_from_package.length === 0 && !settings_drift;
|
|
8058
|
+
let action = null;
|
|
8059
|
+
if (guardReason !== "protected_branch") {
|
|
8060
|
+
action = !in_sync ? newer ? "newer available + drift: run npx codebyplan claude update" : "run npx codebyplan claude update" : newer ? "newer available: run npx codebyplan claude update" : null;
|
|
8061
|
+
}
|
|
8062
|
+
const result = {
|
|
8063
|
+
installed,
|
|
8064
|
+
manifest_version,
|
|
8065
|
+
latest,
|
|
8066
|
+
newer,
|
|
8067
|
+
version_skip,
|
|
8068
|
+
drifted_files,
|
|
8069
|
+
new_in_package,
|
|
8070
|
+
removed_from_package,
|
|
8071
|
+
settings_drift,
|
|
8072
|
+
// Always false in the full-detection path: a protected_branch consumer
|
|
8073
|
+
// (the only guarded case that reaches here) must still SEE the segment;
|
|
8074
|
+
// only canonical_source / no-manifest (Branch A) report guarded:true.
|
|
8075
|
+
guarded: false,
|
|
8076
|
+
guard_reason: guardReason,
|
|
8077
|
+
in_sync,
|
|
8078
|
+
action,
|
|
8079
|
+
checked_at
|
|
8080
|
+
};
|
|
8081
|
+
emitResult(result, writeCache, quiet, projectDir);
|
|
8082
|
+
process.exit(0);
|
|
8083
|
+
} catch (err) {
|
|
8084
|
+
const safe = makeFailSafe(checked_at);
|
|
8085
|
+
if (!quiet) {
|
|
8086
|
+
try {
|
|
8087
|
+
process.stdout.write(JSON.stringify(safe) + "\n");
|
|
8088
|
+
} catch {
|
|
8089
|
+
}
|
|
8090
|
+
}
|
|
8091
|
+
void err;
|
|
8092
|
+
process.exit(0);
|
|
8093
|
+
}
|
|
8094
|
+
}
|
|
8095
|
+
function emitResult(result, writeCache, quiet, projectDir) {
|
|
8096
|
+
const json = JSON.stringify(result, null, 2);
|
|
8097
|
+
if (writeCache) {
|
|
8098
|
+
try {
|
|
8099
|
+
const cacheDir = path7.join(projectDir, ".codebyplan");
|
|
8100
|
+
fs6.mkdirSync(cacheDir, { recursive: true });
|
|
8101
|
+
fs6.writeFileSync(
|
|
8102
|
+
path7.join(cacheDir, "claude-status.local.json"),
|
|
8103
|
+
json + "\n",
|
|
8104
|
+
"utf8"
|
|
8105
|
+
);
|
|
8106
|
+
} catch {
|
|
8107
|
+
}
|
|
8108
|
+
}
|
|
8109
|
+
if (!quiet) {
|
|
8110
|
+
process.stdout.write(json + "\n");
|
|
8111
|
+
}
|
|
8112
|
+
}
|
|
8113
|
+
var init_status = __esm({
|
|
8114
|
+
"src/cli/claude/status.ts"() {
|
|
8115
|
+
"use strict";
|
|
8116
|
+
init_version();
|
|
8117
|
+
init_bump();
|
|
8118
|
+
init_manifest();
|
|
8119
|
+
init_claude_plan();
|
|
8120
|
+
init_settings_merge();
|
|
8121
|
+
init_version_status();
|
|
8122
|
+
}
|
|
8123
|
+
});
|
|
8124
|
+
|
|
8278
8125
|
// src/lib/prompt.ts
|
|
8279
8126
|
import * as readline from "node:readline";
|
|
8280
8127
|
async function ask(q, opts) {
|
|
@@ -8293,11 +8140,11 @@ async function ask(q, opts) {
|
|
|
8293
8140
|
try {
|
|
8294
8141
|
while (true) {
|
|
8295
8142
|
const choices = q.choices.map((c) => `[${c.key}] ${c.label}`).join(" ");
|
|
8296
|
-
const answer = await new Promise((
|
|
8143
|
+
const answer = await new Promise((resolve9) => {
|
|
8297
8144
|
rl.question(`${q.message}
|
|
8298
8145
|
${choices}
|
|
8299
8146
|
> `, (input) => {
|
|
8300
|
-
|
|
8147
|
+
resolve9(input.trim().toLowerCase());
|
|
8301
8148
|
});
|
|
8302
8149
|
});
|
|
8303
8150
|
const match = q.choices.find(
|
|
@@ -8391,10 +8238,10 @@ var update_exports = {};
|
|
|
8391
8238
|
__export(update_exports, {
|
|
8392
8239
|
runUpdate: () => runUpdate
|
|
8393
8240
|
});
|
|
8394
|
-
import * as
|
|
8241
|
+
import * as fs7 from "node:fs";
|
|
8395
8242
|
import * as os3 from "node:os";
|
|
8396
|
-
import * as
|
|
8397
|
-
import { fileURLToPath as
|
|
8243
|
+
import * as path8 from "node:path";
|
|
8244
|
+
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
8398
8245
|
async function runUpdate(opts, deps = {}) {
|
|
8399
8246
|
await Promise.resolve();
|
|
8400
8247
|
const scope = opts.scope ?? "project";
|
|
@@ -8410,7 +8257,7 @@ async function runUpdate(opts, deps = {}) {
|
|
|
8410
8257
|
const projectDir = deps.projectDir ?? process.cwd();
|
|
8411
8258
|
let templatesDir;
|
|
8412
8259
|
try {
|
|
8413
|
-
templatesDir = deps.templatesDir ??
|
|
8260
|
+
templatesDir = deps.templatesDir ?? resolveTemplatesDirFromInstall2();
|
|
8414
8261
|
} catch (err) {
|
|
8415
8262
|
console.error(
|
|
8416
8263
|
err instanceof Error ? err.message : `codebyplan claude update: ${String(err)}`
|
|
@@ -8424,16 +8271,16 @@ async function runUpdate(opts, deps = {}) {
|
|
|
8424
8271
|
await runInstall(opts, { ...deps, templatesDir });
|
|
8425
8272
|
return;
|
|
8426
8273
|
}
|
|
8427
|
-
const plan =
|
|
8274
|
+
const plan = buildDriftPlan(projectDir, templatesDir, manifestBefore);
|
|
8428
8275
|
const finalManifestEntries = [];
|
|
8429
8276
|
for (const e of plan.unchanged) {
|
|
8430
8277
|
finalManifestEntries.push(e);
|
|
8431
8278
|
}
|
|
8432
8279
|
for (const { packaged, absSrc } of plan.overwriteSafe) {
|
|
8433
|
-
const absDest =
|
|
8280
|
+
const absDest = path8.join(projectDir, ".claude", packaged.dest);
|
|
8434
8281
|
if (!opts.dryRun) {
|
|
8435
|
-
|
|
8436
|
-
|
|
8282
|
+
fs7.mkdirSync(path8.dirname(absDest), { recursive: true });
|
|
8283
|
+
fs7.copyFileSync(absSrc, absDest);
|
|
8437
8284
|
if (opts.verbose) console.log(`updated ${packaged.dest}`);
|
|
8438
8285
|
} else if (opts.verbose) {
|
|
8439
8286
|
console.log(`[dry-run] would update ${packaged.dest}`);
|
|
@@ -8445,8 +8292,8 @@ async function runUpdate(opts, deps = {}) {
|
|
|
8445
8292
|
absSrc,
|
|
8446
8293
|
onDiskContent
|
|
8447
8294
|
} of plan.overwriteHandEdited) {
|
|
8448
|
-
const absDest =
|
|
8449
|
-
const newContent =
|
|
8295
|
+
const absDest = path8.join(projectDir, ".claude", packaged.dest);
|
|
8296
|
+
const newContent = fs7.readFileSync(absSrc);
|
|
8450
8297
|
const showDiff = () => {
|
|
8451
8298
|
console.log(
|
|
8452
8299
|
renderDiff(
|
|
@@ -8458,8 +8305,8 @@ async function runUpdate(opts, deps = {}) {
|
|
|
8458
8305
|
const answer = await promptOverwrite(packaged.dest, opts, showDiff);
|
|
8459
8306
|
if (answer === "overwrite") {
|
|
8460
8307
|
if (!opts.dryRun) {
|
|
8461
|
-
|
|
8462
|
-
|
|
8308
|
+
fs7.mkdirSync(path8.dirname(absDest), { recursive: true });
|
|
8309
|
+
fs7.copyFileSync(absSrc, absDest);
|
|
8463
8310
|
}
|
|
8464
8311
|
finalManifestEntries.push(packaged);
|
|
8465
8312
|
} else {
|
|
@@ -8474,10 +8321,10 @@ async function runUpdate(opts, deps = {}) {
|
|
|
8474
8321
|
for (const { packaged, absSrc } of plan.newOptIn) {
|
|
8475
8322
|
const answer = await promptOptIn(packaged.dest, opts);
|
|
8476
8323
|
if (answer === "opt-in") {
|
|
8477
|
-
const absDest =
|
|
8324
|
+
const absDest = path8.join(projectDir, ".claude", packaged.dest);
|
|
8478
8325
|
if (!opts.dryRun) {
|
|
8479
|
-
|
|
8480
|
-
|
|
8326
|
+
fs7.mkdirSync(path8.dirname(absDest), { recursive: true });
|
|
8327
|
+
fs7.copyFileSync(absSrc, absDest);
|
|
8481
8328
|
}
|
|
8482
8329
|
finalManifestEntries.push(packaged);
|
|
8483
8330
|
if (opts.verbose) console.log(`installed new file ${packaged.dest}`);
|
|
@@ -8488,25 +8335,25 @@ async function runUpdate(opts, deps = {}) {
|
|
|
8488
8335
|
for (const e of plan.removedFromPackage) {
|
|
8489
8336
|
const answer = await promptRemove(e.dest, opts);
|
|
8490
8337
|
if (answer === "remove") {
|
|
8491
|
-
const absDest =
|
|
8492
|
-
if (!opts.dryRun &&
|
|
8493
|
-
|
|
8494
|
-
const claudeDir =
|
|
8495
|
-
let cur =
|
|
8496
|
-
while (cur !== claudeDir && cur !==
|
|
8497
|
-
if (
|
|
8338
|
+
const absDest = path8.join(projectDir, ".claude", e.dest);
|
|
8339
|
+
if (!opts.dryRun && fs7.existsSync(absDest)) {
|
|
8340
|
+
fs7.rmSync(absDest);
|
|
8341
|
+
const claudeDir = path8.join(projectDir, ".claude");
|
|
8342
|
+
let cur = path8.dirname(absDest);
|
|
8343
|
+
while (cur !== claudeDir && cur !== path8.dirname(cur)) {
|
|
8344
|
+
if (path8.dirname(cur) === claudeDir) break;
|
|
8498
8345
|
try {
|
|
8499
|
-
|
|
8346
|
+
fs7.rmdirSync(cur);
|
|
8500
8347
|
if (opts.verbose)
|
|
8501
8348
|
console.log(
|
|
8502
|
-
`pruned empty dir ${
|
|
8349
|
+
`pruned empty dir ${path8.relative(claudeDir, cur)}`
|
|
8503
8350
|
);
|
|
8504
|
-
cur =
|
|
8351
|
+
cur = path8.dirname(cur);
|
|
8505
8352
|
} catch (err) {
|
|
8506
8353
|
const code = err.code;
|
|
8507
8354
|
if (code !== "ENOTEMPTY" && code !== "ENOENT") {
|
|
8508
8355
|
console.warn(
|
|
8509
|
-
`codebyplan claude: could not prune empty dir ${
|
|
8356
|
+
`codebyplan claude: could not prune empty dir ${path8.relative(claudeDir, cur)}: ${err.message}`
|
|
8510
8357
|
);
|
|
8511
8358
|
}
|
|
8512
8359
|
break;
|
|
@@ -8518,28 +8365,28 @@ async function runUpdate(opts, deps = {}) {
|
|
|
8518
8365
|
if (opts.verbose) console.log(`kept (untracked) ${e.dest}`);
|
|
8519
8366
|
}
|
|
8520
8367
|
}
|
|
8521
|
-
const hooksJsonPath =
|
|
8522
|
-
const baseSettingsPath =
|
|
8368
|
+
const hooksJsonPath = path8.join(templatesDir, "hooks", "hooks.json");
|
|
8369
|
+
const baseSettingsPath = path8.join(
|
|
8523
8370
|
templatesDir,
|
|
8524
8371
|
"settings.project.base.json"
|
|
8525
8372
|
);
|
|
8526
|
-
const settingsPath =
|
|
8527
|
-
const existingSettings =
|
|
8528
|
-
if (
|
|
8373
|
+
const settingsPath = path8.join(projectDir, ".claude", "settings.json");
|
|
8374
|
+
const existingSettings = fs7.existsSync(settingsPath) ? JSON.parse(fs7.readFileSync(settingsPath, "utf8")) : {};
|
|
8375
|
+
if (fs7.existsSync(baseSettingsPath)) {
|
|
8529
8376
|
const base = JSON.parse(
|
|
8530
|
-
|
|
8377
|
+
fs7.readFileSync(baseSettingsPath, "utf8")
|
|
8531
8378
|
);
|
|
8532
8379
|
mergeBaseSettingsIntoSettings(existingSettings, base);
|
|
8533
8380
|
}
|
|
8534
|
-
if (
|
|
8381
|
+
if (fs7.existsSync(hooksJsonPath)) {
|
|
8535
8382
|
const hooksJson = JSON.parse(
|
|
8536
|
-
|
|
8383
|
+
fs7.readFileSync(hooksJsonPath, "utf8")
|
|
8537
8384
|
);
|
|
8538
8385
|
mergeHooksIntoSettings(existingSettings, hooksJson);
|
|
8539
8386
|
}
|
|
8540
8387
|
if (!opts.dryRun) {
|
|
8541
|
-
|
|
8542
|
-
|
|
8388
|
+
fs7.mkdirSync(path8.dirname(settingsPath), { recursive: true });
|
|
8389
|
+
fs7.writeFileSync(
|
|
8543
8390
|
settingsPath,
|
|
8544
8391
|
JSON.stringify(existingSettings, null, 2) + "\n",
|
|
8545
8392
|
"utf8"
|
|
@@ -8551,7 +8398,7 @@ async function runUpdate(opts, deps = {}) {
|
|
|
8551
8398
|
);
|
|
8552
8399
|
if (opts.verbose && gitignoreAction !== "unchanged") {
|
|
8553
8400
|
console.log(
|
|
8554
|
-
`${opts.dryRun ? "[dry-run] would " : ""}${gitignoreAction} managed .gitignore block in ${
|
|
8401
|
+
`${opts.dryRun ? "[dry-run] would " : ""}${gitignoreAction} managed .gitignore block in ${path8.relative(projectDir, path8.join(projectDir, ".gitignore"))}`
|
|
8555
8402
|
);
|
|
8556
8403
|
}
|
|
8557
8404
|
if (!opts.dryRun) {
|
|
@@ -8577,7 +8424,7 @@ async function runUpdate(opts, deps = {}) {
|
|
|
8577
8424
|
function runUpdateUser(opts, deps) {
|
|
8578
8425
|
let templatesDir;
|
|
8579
8426
|
try {
|
|
8580
|
-
templatesDir = deps.templatesDir ??
|
|
8427
|
+
templatesDir = deps.templatesDir ?? resolveTemplatesDirFromInstall2();
|
|
8581
8428
|
} catch (err) {
|
|
8582
8429
|
console.error(
|
|
8583
8430
|
err instanceof Error ? err.message : `codebyplan claude update: ${String(err)}`
|
|
@@ -8586,9 +8433,9 @@ function runUpdateUser(opts, deps) {
|
|
|
8586
8433
|
return;
|
|
8587
8434
|
}
|
|
8588
8435
|
try {
|
|
8589
|
-
const userDir = deps.userDir ??
|
|
8590
|
-
const settingsPath =
|
|
8591
|
-
const userBaseSettingsPath =
|
|
8436
|
+
const userDir = deps.userDir ?? path8.join(os3.homedir(), ".claude");
|
|
8437
|
+
const settingsPath = path8.join(userDir, "settings.json");
|
|
8438
|
+
const userBaseSettingsPath = path8.join(
|
|
8592
8439
|
templatesDir,
|
|
8593
8440
|
"settings.user.base.json"
|
|
8594
8441
|
);
|
|
@@ -8600,7 +8447,7 @@ function runUpdateUser(opts, deps) {
|
|
|
8600
8447
|
process.exitCode = 1;
|
|
8601
8448
|
return;
|
|
8602
8449
|
}
|
|
8603
|
-
if (!
|
|
8450
|
+
if (!fs7.existsSync(userBaseSettingsPath)) {
|
|
8604
8451
|
console.error(
|
|
8605
8452
|
"codebyplan claude update: settings.user.base.json not found in templates."
|
|
8606
8453
|
);
|
|
@@ -8608,13 +8455,13 @@ function runUpdateUser(opts, deps) {
|
|
|
8608
8455
|
return;
|
|
8609
8456
|
}
|
|
8610
8457
|
const userBase = JSON.parse(
|
|
8611
|
-
|
|
8458
|
+
fs7.readFileSync(userBaseSettingsPath, "utf8")
|
|
8612
8459
|
);
|
|
8613
|
-
const existingSettings =
|
|
8460
|
+
const existingSettings = fs7.existsSync(settingsPath) ? JSON.parse(fs7.readFileSync(settingsPath, "utf8")) : {};
|
|
8614
8461
|
mergeBaseSettingsIntoSettings(existingSettings, userBase);
|
|
8615
8462
|
if (!opts.dryRun) {
|
|
8616
|
-
|
|
8617
|
-
|
|
8463
|
+
fs7.mkdirSync(userDir, { recursive: true });
|
|
8464
|
+
fs7.writeFileSync(
|
|
8618
8465
|
settingsPath,
|
|
8619
8466
|
JSON.stringify(existingSettings, null, 2) + "\n",
|
|
8620
8467
|
"utf8"
|
|
@@ -8637,64 +8484,15 @@ function runUpdateUser(opts, deps) {
|
|
|
8637
8484
|
process.exitCode = 1;
|
|
8638
8485
|
}
|
|
8639
8486
|
}
|
|
8640
|
-
function
|
|
8641
|
-
const
|
|
8642
|
-
const packagedBySrc = new Map(packaged.map((f) => [f.src, f]));
|
|
8643
|
-
const manifestBySrc = new Map(manifest.files.map((f) => [f.src, f]));
|
|
8644
|
-
const plan = {
|
|
8645
|
-
unchanged: [],
|
|
8646
|
-
overwriteSafe: [],
|
|
8647
|
-
overwriteHandEdited: [],
|
|
8648
|
-
newOptIn: [],
|
|
8649
|
-
removedFromPackage: []
|
|
8650
|
-
};
|
|
8651
|
-
for (const pkg of packaged) {
|
|
8652
|
-
const inManifest = manifestBySrc.get(pkg.src);
|
|
8653
|
-
const absDest = path6.join(projectDir, ".claude", pkg.dest);
|
|
8654
|
-
const absSrc = path6.join(templatesDir, pkg.src);
|
|
8655
|
-
if (!inManifest) {
|
|
8656
|
-
plan.newOptIn.push({
|
|
8657
|
-
packaged: { src: pkg.src, dest: pkg.dest, hash: pkg.hash },
|
|
8658
|
-
absSrc
|
|
8659
|
-
});
|
|
8660
|
-
continue;
|
|
8661
|
-
}
|
|
8662
|
-
const onDiskExists = fs5.existsSync(absDest);
|
|
8663
|
-
const onDiskContent = onDiskExists ? fs5.readFileSync(absDest) : Buffer.alloc(0);
|
|
8664
|
-
const onDiskHash = onDiskExists ? sha256(onDiskContent) : null;
|
|
8665
|
-
if (pkg.hash === inManifest.hash && onDiskHash === inManifest.hash) {
|
|
8666
|
-
plan.unchanged.push(inManifest);
|
|
8667
|
-
continue;
|
|
8668
|
-
}
|
|
8669
|
-
if (onDiskHash !== null && onDiskHash !== inManifest.hash) {
|
|
8670
|
-
plan.overwriteHandEdited.push({
|
|
8671
|
-
packaged: { src: pkg.src, dest: pkg.dest, hash: pkg.hash },
|
|
8672
|
-
absSrc,
|
|
8673
|
-
onDiskContent
|
|
8674
|
-
});
|
|
8675
|
-
} else {
|
|
8676
|
-
plan.overwriteSafe.push({
|
|
8677
|
-
packaged: { src: pkg.src, dest: pkg.dest, hash: pkg.hash },
|
|
8678
|
-
absSrc
|
|
8679
|
-
});
|
|
8680
|
-
}
|
|
8681
|
-
}
|
|
8682
|
-
for (const m of manifest.files) {
|
|
8683
|
-
if (!packagedBySrc.has(m.src)) {
|
|
8684
|
-
plan.removedFromPackage.push(m);
|
|
8685
|
-
}
|
|
8686
|
-
}
|
|
8687
|
-
return plan;
|
|
8688
|
-
}
|
|
8689
|
-
function resolveTemplatesDirFromInstall() {
|
|
8690
|
-
const here = path6.dirname(fileURLToPath2(import.meta.url));
|
|
8487
|
+
function resolveTemplatesDirFromInstall2() {
|
|
8488
|
+
const here = path8.dirname(fileURLToPath3(import.meta.url));
|
|
8691
8489
|
const candidates = [
|
|
8692
|
-
|
|
8693
|
-
|
|
8694
|
-
|
|
8490
|
+
path8.resolve(here, "..", "templates"),
|
|
8491
|
+
path8.resolve(here, "..", "..", "templates"),
|
|
8492
|
+
path8.resolve(here, "..", "..", "..", "templates")
|
|
8695
8493
|
];
|
|
8696
8494
|
for (const c of candidates) {
|
|
8697
|
-
if (
|
|
8495
|
+
if (fs7.existsSync(c) && fs7.statSync(c).isDirectory()) {
|
|
8698
8496
|
return c;
|
|
8699
8497
|
}
|
|
8700
8498
|
}
|
|
@@ -8708,14 +8506,14 @@ function resolveTemplatesDirFromInstall() {
|
|
|
8708
8506
|
var init_update = __esm({
|
|
8709
8507
|
"src/cli/claude/update.ts"() {
|
|
8710
8508
|
"use strict";
|
|
8711
|
-
init_template_walker();
|
|
8712
8509
|
init_gitignore_block();
|
|
8713
|
-
init_hash();
|
|
8714
8510
|
init_manifest();
|
|
8715
8511
|
init_settings_merge();
|
|
8716
8512
|
init_prompt();
|
|
8717
8513
|
init_install();
|
|
8718
8514
|
init_statusline_config();
|
|
8515
|
+
init_hash();
|
|
8516
|
+
init_claude_plan();
|
|
8719
8517
|
}
|
|
8720
8518
|
});
|
|
8721
8519
|
|
|
@@ -8724,9 +8522,9 @@ var uninstall_exports = {};
|
|
|
8724
8522
|
__export(uninstall_exports, {
|
|
8725
8523
|
runUninstall: () => runUninstall
|
|
8726
8524
|
});
|
|
8727
|
-
import * as
|
|
8525
|
+
import * as fs8 from "node:fs";
|
|
8728
8526
|
import * as os4 from "node:os";
|
|
8729
|
-
import * as
|
|
8527
|
+
import * as path9 from "node:path";
|
|
8730
8528
|
async function runUninstall(opts, deps = {}) {
|
|
8731
8529
|
await Promise.resolve();
|
|
8732
8530
|
const scope = opts.scope ?? "project";
|
|
@@ -8755,15 +8553,15 @@ async function runUninstall(opts, deps = {}) {
|
|
|
8755
8553
|
let removed = 0;
|
|
8756
8554
|
let warnings = 0;
|
|
8757
8555
|
for (const entry of manifest.files) {
|
|
8758
|
-
const abs =
|
|
8759
|
-
if (!
|
|
8556
|
+
const abs = path9.join(projectDir, ".claude", entry.dest);
|
|
8557
|
+
if (!fs8.existsSync(abs)) {
|
|
8760
8558
|
console.warn(
|
|
8761
8559
|
`codebyplan claude uninstall: ${entry.dest} already absent (skipping).`
|
|
8762
8560
|
);
|
|
8763
8561
|
warnings += 1;
|
|
8764
8562
|
continue;
|
|
8765
8563
|
}
|
|
8766
|
-
const onDiskHash = sha256(
|
|
8564
|
+
const onDiskHash = sha256(fs8.readFileSync(abs));
|
|
8767
8565
|
if (onDiskHash !== entry.hash) {
|
|
8768
8566
|
console.warn(
|
|
8769
8567
|
`codebyplan claude uninstall: ${entry.dest} has been modified locally; removing anyway.`
|
|
@@ -8771,7 +8569,7 @@ async function runUninstall(opts, deps = {}) {
|
|
|
8771
8569
|
warnings += 1;
|
|
8772
8570
|
}
|
|
8773
8571
|
if (!opts.dryRun) {
|
|
8774
|
-
|
|
8572
|
+
fs8.rmSync(abs);
|
|
8775
8573
|
}
|
|
8776
8574
|
removed += 1;
|
|
8777
8575
|
if (opts.verbose) console.log(`removed ${entry.dest}`);
|
|
@@ -8779,15 +8577,15 @@ async function runUninstall(opts, deps = {}) {
|
|
|
8779
8577
|
if (!opts.dryRun) {
|
|
8780
8578
|
pruneEmptyManagedDirs(projectDir);
|
|
8781
8579
|
}
|
|
8782
|
-
const settingsPath =
|
|
8783
|
-
if (
|
|
8580
|
+
const settingsPath = path9.join(projectDir, ".claude", "settings.json");
|
|
8581
|
+
if (fs8.existsSync(settingsPath)) {
|
|
8784
8582
|
const settings = JSON.parse(
|
|
8785
|
-
|
|
8583
|
+
fs8.readFileSync(settingsPath, "utf8")
|
|
8786
8584
|
);
|
|
8787
|
-
const baseSettingsPath = templatesDir ?
|
|
8788
|
-
if (baseSettingsPath &&
|
|
8585
|
+
const baseSettingsPath = templatesDir ? path9.join(templatesDir, "settings.project.base.json") : null;
|
|
8586
|
+
if (baseSettingsPath && fs8.existsSync(baseSettingsPath)) {
|
|
8789
8587
|
const base = JSON.parse(
|
|
8790
|
-
|
|
8588
|
+
fs8.readFileSync(baseSettingsPath, "utf8")
|
|
8791
8589
|
);
|
|
8792
8590
|
stripBaseSettingsFromSettings(settings, base);
|
|
8793
8591
|
}
|
|
@@ -8795,9 +8593,9 @@ async function runUninstall(opts, deps = {}) {
|
|
|
8795
8593
|
if (!opts.dryRun) {
|
|
8796
8594
|
const isEmpty = Object.keys(settings).length === 0;
|
|
8797
8595
|
if (isEmpty) {
|
|
8798
|
-
|
|
8596
|
+
fs8.rmSync(settingsPath);
|
|
8799
8597
|
} else {
|
|
8800
|
-
|
|
8598
|
+
fs8.writeFileSync(
|
|
8801
8599
|
settingsPath,
|
|
8802
8600
|
JSON.stringify(settings, null, 2) + "\n",
|
|
8803
8601
|
"utf8"
|
|
@@ -8816,11 +8614,11 @@ async function runUninstall(opts, deps = {}) {
|
|
|
8816
8614
|
}
|
|
8817
8615
|
if (!opts.dryRun) {
|
|
8818
8616
|
const m = manifestPath(projectDir);
|
|
8819
|
-
if (
|
|
8617
|
+
if (fs8.existsSync(m)) fs8.rmSync(m);
|
|
8820
8618
|
const mid = midManifestPath(projectDir);
|
|
8821
|
-
if (
|
|
8619
|
+
if (fs8.existsSync(mid)) fs8.rmSync(mid);
|
|
8822
8620
|
const legacy = oldManifestPath(projectDir);
|
|
8823
|
-
if (
|
|
8621
|
+
if (fs8.existsSync(legacy)) fs8.rmSync(legacy);
|
|
8824
8622
|
}
|
|
8825
8623
|
console.log(
|
|
8826
8624
|
`codebyplan claude uninstall${opts.dryRun ? " (dry-run)" : ""}: removed ${removed} files${warnings > 0 ? ` (${warnings} warnings)` : ""}.`
|
|
@@ -8842,7 +8640,7 @@ function runUninstallUser(opts, deps) {
|
|
|
8842
8640
|
}
|
|
8843
8641
|
}
|
|
8844
8642
|
try {
|
|
8845
|
-
const userDir = deps.userDir ??
|
|
8643
|
+
const userDir = deps.userDir ?? path9.join(os4.homedir(), ".claude");
|
|
8846
8644
|
const existingManifest = readManifestForScope("user", userDir);
|
|
8847
8645
|
if (!existingManifest) {
|
|
8848
8646
|
console.error(
|
|
@@ -8851,24 +8649,24 @@ function runUninstallUser(opts, deps) {
|
|
|
8851
8649
|
process.exitCode = 1;
|
|
8852
8650
|
return;
|
|
8853
8651
|
}
|
|
8854
|
-
const settingsPath =
|
|
8855
|
-
if (
|
|
8652
|
+
const settingsPath = path9.join(userDir, "settings.json");
|
|
8653
|
+
if (fs8.existsSync(settingsPath)) {
|
|
8856
8654
|
const settings = JSON.parse(
|
|
8857
|
-
|
|
8655
|
+
fs8.readFileSync(settingsPath, "utf8")
|
|
8858
8656
|
);
|
|
8859
|
-
const userBaseSettingsPath = templatesDir != null ?
|
|
8860
|
-
if (userBaseSettingsPath &&
|
|
8657
|
+
const userBaseSettingsPath = templatesDir != null ? path9.join(templatesDir, "settings.user.base.json") : null;
|
|
8658
|
+
if (userBaseSettingsPath && fs8.existsSync(userBaseSettingsPath)) {
|
|
8861
8659
|
const userBase = JSON.parse(
|
|
8862
|
-
|
|
8660
|
+
fs8.readFileSync(userBaseSettingsPath, "utf8")
|
|
8863
8661
|
);
|
|
8864
8662
|
stripBaseSettingsFromSettings(settings, userBase);
|
|
8865
8663
|
}
|
|
8866
8664
|
if (!opts.dryRun) {
|
|
8867
8665
|
const isEmpty = Object.keys(settings).length === 0;
|
|
8868
8666
|
if (isEmpty) {
|
|
8869
|
-
|
|
8667
|
+
fs8.rmSync(settingsPath);
|
|
8870
8668
|
} else {
|
|
8871
|
-
|
|
8669
|
+
fs8.writeFileSync(
|
|
8872
8670
|
settingsPath,
|
|
8873
8671
|
JSON.stringify(settings, null, 2) + "\n",
|
|
8874
8672
|
"utf8"
|
|
@@ -8878,11 +8676,11 @@ function runUninstallUser(opts, deps) {
|
|
|
8878
8676
|
}
|
|
8879
8677
|
if (!opts.dryRun) {
|
|
8880
8678
|
const m = userManifestPath(userDir);
|
|
8881
|
-
if (
|
|
8679
|
+
if (fs8.existsSync(m)) fs8.rmSync(m);
|
|
8882
8680
|
const midUser = userMidManifestPath(userDir);
|
|
8883
|
-
if (
|
|
8681
|
+
if (fs8.existsSync(midUser)) fs8.rmSync(midUser);
|
|
8884
8682
|
const oldUser = userOldManifestPath(userDir);
|
|
8885
|
-
if (
|
|
8683
|
+
if (fs8.existsSync(oldUser)) fs8.rmSync(oldUser);
|
|
8886
8684
|
}
|
|
8887
8685
|
console.log(
|
|
8888
8686
|
`codebyplan claude uninstall --scope user${opts.dryRun ? " (dry-run)" : ""}: user base settings stripped.`
|
|
@@ -8897,23 +8695,23 @@ function runUninstallUser(opts, deps) {
|
|
|
8897
8695
|
function pruneEmptyManagedDirs(projectDir) {
|
|
8898
8696
|
const managedRoots = ["skills", "agents", "hooks", "rules"];
|
|
8899
8697
|
for (const root of managedRoots) {
|
|
8900
|
-
const abs =
|
|
8901
|
-
if (!
|
|
8698
|
+
const abs = path9.join(projectDir, ".claude", root);
|
|
8699
|
+
if (!fs8.existsSync(abs)) continue;
|
|
8902
8700
|
pruneLeafFirst(abs);
|
|
8903
8701
|
}
|
|
8904
8702
|
}
|
|
8905
8703
|
function pruneLeafFirst(dir) {
|
|
8906
|
-
if (!
|
|
8907
|
-
const stat2 =
|
|
8704
|
+
if (!fs8.existsSync(dir)) return;
|
|
8705
|
+
const stat2 = fs8.statSync(dir);
|
|
8908
8706
|
if (!stat2.isDirectory()) return;
|
|
8909
|
-
for (const entry of
|
|
8707
|
+
for (const entry of fs8.readdirSync(dir, { withFileTypes: true })) {
|
|
8910
8708
|
if (entry.isDirectory()) {
|
|
8911
|
-
pruneLeafFirst(
|
|
8709
|
+
pruneLeafFirst(path9.join(dir, entry.name));
|
|
8912
8710
|
}
|
|
8913
8711
|
}
|
|
8914
|
-
const remaining =
|
|
8712
|
+
const remaining = fs8.readdirSync(dir);
|
|
8915
8713
|
if (remaining.length === 0) {
|
|
8916
|
-
|
|
8714
|
+
fs8.rmdirSync(dir);
|
|
8917
8715
|
}
|
|
8918
8716
|
}
|
|
8919
8717
|
var init_uninstall = __esm({
|
|
@@ -8930,11 +8728,11 @@ var init_uninstall = __esm({
|
|
|
8930
8728
|
// src/index.ts
|
|
8931
8729
|
init_version();
|
|
8932
8730
|
import { readFileSync as readFileSync10 } from "node:fs";
|
|
8933
|
-
import { resolve as
|
|
8731
|
+
import { resolve as resolve8 } from "node:path";
|
|
8934
8732
|
void (async () => {
|
|
8935
8733
|
if (!process.env.CODEBYPLAN_API_KEY) {
|
|
8936
8734
|
try {
|
|
8937
|
-
const envPath =
|
|
8735
|
+
const envPath = resolve8(process.cwd(), ".env.local");
|
|
8938
8736
|
const content = readFileSync10(envPath, "utf-8");
|
|
8939
8737
|
for (const line of content.split("\n")) {
|
|
8940
8738
|
const trimmed = line.trim();
|
|
@@ -9073,23 +8871,6 @@ void (async () => {
|
|
|
9073
8871
|
await runUploadE2eImagesCommand2(rest);
|
|
9074
8872
|
process.exit(0);
|
|
9075
8873
|
}
|
|
9076
|
-
if (arg === "cmux-sync") {
|
|
9077
|
-
const { runCmuxSync: runCmuxSync2 } = await Promise.resolve().then(() => (init_cmux_sync(), cmux_sync_exports));
|
|
9078
|
-
await runCmuxSync2();
|
|
9079
|
-
process.exit(0);
|
|
9080
|
-
}
|
|
9081
|
-
if (arg === "cmux-status") {
|
|
9082
|
-
const { runCmuxStatus: runCmuxStatus2 } = await Promise.resolve().then(() => (init_cmux_status(), cmux_status_exports));
|
|
9083
|
-
const rest = process.argv.slice(3);
|
|
9084
|
-
await runCmuxStatus2(rest);
|
|
9085
|
-
process.exit(0);
|
|
9086
|
-
}
|
|
9087
|
-
if (arg === "cmux-serve") {
|
|
9088
|
-
const { runCmuxServe: runCmuxServe2 } = await Promise.resolve().then(() => (init_cmux_serve(), cmux_serve_exports));
|
|
9089
|
-
const rest = process.argv.slice(3);
|
|
9090
|
-
await runCmuxServe2(rest);
|
|
9091
|
-
process.exit(0);
|
|
9092
|
-
}
|
|
9093
8874
|
if (arg === "config") {
|
|
9094
8875
|
const { runConfig: runConfig2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
9095
8876
|
await runConfig2();
|
|
@@ -9109,6 +8890,11 @@ void (async () => {
|
|
|
9109
8890
|
const subcommand = process.argv[3];
|
|
9110
8891
|
const flagArgs = process.argv.slice(3);
|
|
9111
8892
|
const parsed = parseClaudeFlags(flagArgs);
|
|
8893
|
+
if (subcommand === "status") {
|
|
8894
|
+
const { runStatus: runStatus2 } = await Promise.resolve().then(() => (init_status(), status_exports));
|
|
8895
|
+
await runStatus2(process.argv.slice(4));
|
|
8896
|
+
return;
|
|
8897
|
+
}
|
|
9112
8898
|
if (subcommand === "install") {
|
|
9113
8899
|
if (parsed === null) {
|
|
9114
8900
|
process.exit(1);
|
|
@@ -9149,6 +8935,9 @@ void (async () => {
|
|
|
9149
8935
|
codebyplan claude install [flags] Install skills/agents/hooks into ./.claude/
|
|
9150
8936
|
codebyplan claude update [flags] Update installed assets to latest versions
|
|
9151
8937
|
codebyplan claude uninstall [flags] Remove installed assets from ./.claude/
|
|
8938
|
+
codebyplan claude status Check package-sync state (drift, version skip, settings drift)
|
|
8939
|
+
--write-cache Write result to .codebyplan/claude-status.local.json
|
|
8940
|
+
--quiet Suppress stdout output
|
|
9152
8941
|
|
|
9153
8942
|
Flags (apply to install/update/uninstall):
|
|
9154
8943
|
--yes, -y Auto-accept every prompt with its recommended default
|
|
@@ -9193,9 +8982,6 @@ void (async () => {
|
|
|
9193
8982
|
codebyplan statusline Show or set the statusline renderer (bash/node/python)
|
|
9194
8983
|
codebyplan resolve-worktree Resolve active worktree UUID from device+path+branch tuple
|
|
9195
8984
|
codebyplan version-status Report installed vs latest version + update guard (JSON)
|
|
9196
|
-
codebyplan cmux-sync Sync cmux workspace title/description to current git branch and repo folder
|
|
9197
|
-
codebyplan cmux-status Push checkpoint/task/QA + progress to the cmux workspace sidebar
|
|
9198
|
-
codebyplan cmux-serve Auto-start dev server + browser pane for the round's app files (cmux)
|
|
9199
8985
|
codebyplan help Show this help message
|
|
9200
8986
|
codebyplan --version Print version
|
|
9201
8987
|
|