codebyplan 1.13.56 → 1.13.57

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
@@ -39,7 +39,7 @@ var VERSION, PACKAGE_NAME;
39
39
  var init_version = __esm({
40
40
  "src/lib/version.ts"() {
41
41
  "use strict";
42
- VERSION = "1.13.56";
42
+ VERSION = "1.13.57";
43
43
  PACKAGE_NAME = "codebyplan";
44
44
  }
45
45
  });
@@ -113,8 +113,8 @@ async function readLocalConfig(projectPath, onMigrationNotice) {
113
113
  }
114
114
  async function writeLocalConfig(projectPath, config) {
115
115
  const content = { device_id: config.device_id };
116
- const path21 = localConfigPath(projectPath);
117
- const dirPath = dirname(path21);
116
+ const path22 = localConfigPath(projectPath);
117
+ const dirPath = dirname(path22);
118
118
  let phase = "stat config directory";
119
119
  try {
120
120
  try {
@@ -134,7 +134,7 @@ async function writeLocalConfig(projectPath, config) {
134
134
  phase = "create config directory";
135
135
  await mkdir(dirPath, { recursive: true });
136
136
  phase = "write local config";
137
- await writeFile(path21, JSON.stringify(content, null, 2) + "\n", "utf-8");
137
+ await writeFile(path22, JSON.stringify(content, null, 2) + "\n", "utf-8");
138
138
  } catch (err) {
139
139
  const code = err.code;
140
140
  if (code === "LEGACY_FILE_BLOCKS_DIR") {
@@ -652,8 +652,8 @@ var init_gitignore_block = __esm({
652
652
  // src/lib/worktree.ts
653
653
  import { mkdir as mkdir3, writeFile as writeFile4, readFile as readFile6 } from "node:fs/promises";
654
654
  import { join as join6 } from "node:path";
655
- function defaultExists(path21) {
656
- return readFile6(path21, "utf-8").then(() => true).catch(() => false);
655
+ function defaultExists(path22) {
656
+ return readFile6(path22, "utf-8").then(() => true).catch(() => false);
657
657
  }
658
658
  async function writeRepoJson(codebyplanDir, selectedRepo, deps) {
659
659
  const repoJson = {
@@ -774,9 +774,9 @@ var init_worktree = __esm({
774
774
  init_local_config();
775
775
  init_gitignore_block();
776
776
  defaultFsDeps = {
777
- mkdir: (path21, opts) => mkdir3(path21, opts).then(() => void 0),
778
- writeFile: (path21, data, encoding) => writeFile4(path21, data, encoding),
779
- readFile: (path21, encoding) => readFile6(path21, encoding),
777
+ mkdir: (path22, opts) => mkdir3(path22, opts).then(() => void 0),
778
+ writeFile: (path22, data, encoding) => writeFile4(path22, data, encoding),
779
+ readFile: (path22, encoding) => readFile6(path22, encoding),
780
780
  exists: defaultExists
781
781
  };
782
782
  }
@@ -844,12 +844,12 @@ async function readFallback(filename) {
844
844
  }
845
845
  }
846
846
  async function writeFallback(filename, data) {
847
- const path21 = fallbackFile(filename);
848
- await mkdir4(dirname2(path21), { recursive: true });
849
- await writeFile5(path21, JSON.stringify(data, null, 2) + "\n", "utf-8");
847
+ const path22 = fallbackFile(filename);
848
+ await mkdir4(dirname2(path22), { recursive: true });
849
+ await writeFile5(path22, JSON.stringify(data, null, 2) + "\n", "utf-8");
850
850
  if (platform() !== "win32") {
851
851
  try {
852
- await chmod(path21, 384);
852
+ await chmod(path22, 384);
853
853
  } catch {
854
854
  }
855
855
  }
@@ -1143,8 +1143,8 @@ async function validateConnectivity() {
1143
1143
  );
1144
1144
  }
1145
1145
  }
1146
- function buildUrl(path21, params) {
1147
- const url = new URL(`${baseUrl()}/api${path21}`);
1146
+ function buildUrl(path22, params) {
1147
+ const url = new URL(`${baseUrl()}/api${path22}`);
1148
1148
  if (params) {
1149
1149
  for (const [key, value] of Object.entries(params)) {
1150
1150
  if (value !== void 0) {
@@ -1163,8 +1163,8 @@ function isRetryable(err) {
1163
1163
  function delay(ms) {
1164
1164
  return new Promise((resolve16) => setTimeout(resolve16, ms));
1165
1165
  }
1166
- async function request(method, path21, options) {
1167
- const url = buildUrl(path21, options?.params);
1166
+ async function request(method, path22, options) {
1167
+ const url = buildUrl(path22, options?.params);
1168
1168
  const auth = await getAuthHeaders();
1169
1169
  let lastError;
1170
1170
  for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
@@ -1184,7 +1184,7 @@ async function request(method, path21, options) {
1184
1184
  signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS)
1185
1185
  });
1186
1186
  if (!res.ok) {
1187
- let message = `API ${method} ${path21} failed with status ${res.status}`;
1187
+ let message = `API ${method} ${path22} failed with status ${res.status}`;
1188
1188
  let code;
1189
1189
  try {
1190
1190
  const body = await res.json();
@@ -1218,20 +1218,20 @@ async function request(method, path21, options) {
1218
1218
  }
1219
1219
  throw lastError;
1220
1220
  }
1221
- async function apiGet(path21, params) {
1222
- return request("GET", path21, { params });
1221
+ async function apiGet(path22, params) {
1222
+ return request("GET", path22, { params });
1223
1223
  }
1224
- async function apiPost(path21, body) {
1225
- return request("POST", path21, { body });
1224
+ async function apiPost(path22, body) {
1225
+ return request("POST", path22, { body });
1226
1226
  }
1227
- async function apiPut(path21, body) {
1228
- return request("PUT", path21, { body });
1227
+ async function apiPut(path22, body) {
1228
+ return request("PUT", path22, { body });
1229
1229
  }
1230
- async function apiPatch(path21, body) {
1231
- return request("PATCH", path21, { body });
1230
+ async function apiPatch(path22, body) {
1231
+ return request("PATCH", path22, { body });
1232
1232
  }
1233
- async function apiDelete(path21, params) {
1234
- await request("DELETE", path21, { params });
1233
+ async function apiDelete(path22, params) {
1234
+ await request("DELETE", path22, { params });
1235
1235
  }
1236
1236
  async function callMcpTool(toolName, params) {
1237
1237
  const url = mcpEndpoint();
@@ -2229,9 +2229,229 @@ var init_templates_dir = __esm({
2229
2229
  }
2230
2230
  });
2231
2231
 
2232
+ // src/lib/gitignore-detect.ts
2233
+ import * as path5 from "node:path";
2234
+ import { readFile as readFile9, writeFile as writeFile7 } from "node:fs/promises";
2235
+ import { spawnSync as spawnSync3 } from "node:child_process";
2236
+ function defaultGitCheckIgnore(projectDir) {
2237
+ const result = spawnSync3(
2238
+ "git",
2239
+ ["check-ignore", "-v", "--", ".claude/settings.json"],
2240
+ {
2241
+ cwd: projectDir,
2242
+ encoding: "utf-8",
2243
+ stdio: ["pipe", "pipe", "pipe"]
2244
+ }
2245
+ );
2246
+ if (result.error) {
2247
+ return { exitCode: 128, stdout: "", stderr: "" };
2248
+ }
2249
+ return {
2250
+ exitCode: result.status,
2251
+ stdout: (result.stdout ?? "").toString(),
2252
+ stderr: (result.stderr ?? "").toString()
2253
+ };
2254
+ }
2255
+ function defaultGitLsFiles(projectDir) {
2256
+ const result = spawnSync3(
2257
+ "git",
2258
+ ["ls-files", "--error-unmatch", "--", ".claude/settings.json"],
2259
+ {
2260
+ cwd: projectDir,
2261
+ encoding: "utf-8",
2262
+ stdio: ["pipe", "pipe", "pipe"]
2263
+ }
2264
+ );
2265
+ if (result.error) {
2266
+ return 128;
2267
+ }
2268
+ return result.status ?? 1;
2269
+ }
2270
+ async function defaultPromptRemoveIgnore(displayLine, opts) {
2271
+ if (opts.yes) {
2272
+ return true;
2273
+ }
2274
+ const readline2 = await import("node:readline");
2275
+ if (!process.stdin.isTTY) {
2276
+ throw new Error(
2277
+ "@codebyplan/claude: interactive prompts require a TTY. Re-run with --yes to accept defaults."
2278
+ );
2279
+ }
2280
+ const rl = readline2.createInterface({
2281
+ input: process.stdin,
2282
+ output: process.stdout
2283
+ });
2284
+ try {
2285
+ while (true) {
2286
+ const answer = await new Promise((resolve16) => {
2287
+ rl.question(
2288
+ `The following gitignore rule matches .claude/settings.json:
2289
+ ${displayLine}
2290
+ Remove this line?
2291
+ [r] remove [k] keep
2292
+ > `,
2293
+ (input) => {
2294
+ resolve16(input.trim().toLowerCase());
2295
+ }
2296
+ );
2297
+ });
2298
+ if (answer === "r" || answer === "remove") return true;
2299
+ if (answer === "k" || answer === "keep") return false;
2300
+ console.error(`Unknown answer: ${answer || "(empty)"} \u2014 try again.`);
2301
+ }
2302
+ } finally {
2303
+ rl.close();
2304
+ }
2305
+ }
2306
+ function patternTargetsSettingsJson(pattern) {
2307
+ const trimmed = pattern.trim();
2308
+ if (trimmed === "" || trimmed.startsWith("!")) return false;
2309
+ const lastSegment = trimmed.split("/").filter(Boolean).pop() ?? "";
2310
+ return lastSegment === "settings.json" && !trimmed.endsWith("/");
2311
+ }
2312
+ function parseCheckIgnoreLine(line) {
2313
+ const tabIdx = line.indexOf(" ");
2314
+ if (tabIdx === -1) return null;
2315
+ const meta = line.slice(0, tabIdx);
2316
+ const matchedPath = line.slice(tabIdx + 1);
2317
+ const m = /^(.*):(\d+):(.*)$/.exec(meta);
2318
+ if (!m) return null;
2319
+ return {
2320
+ sourceFile: m[1] ?? "",
2321
+ lineNum: parseInt(m[2] ?? "0", 10),
2322
+ pattern: m[3] ?? "",
2323
+ matchedPath
2324
+ };
2325
+ }
2326
+ async function detectAndHealSettingsGitignore(projectDir, opts, deps = {}) {
2327
+ const gitCheckIgnore = deps.gitCheckIgnore ?? defaultGitCheckIgnore;
2328
+ const readFileFn = deps.readFileFn ?? ((p) => readFile9(p, "utf-8"));
2329
+ const writeFileFn = deps.writeFileFn ?? ((p, content) => writeFile7(p, content, "utf-8"));
2330
+ const promptFn = deps.promptRemoveIgnore ?? defaultPromptRemoveIgnore;
2331
+ const printWarning = deps.printWarning ?? ((msg) => console.warn(msg));
2332
+ const printInfo = deps.printInfo ?? ((msg) => console.log(msg));
2333
+ let ciResult;
2334
+ try {
2335
+ ciResult = gitCheckIgnore(projectDir);
2336
+ } catch {
2337
+ return { healed: false, skipped: "non-git" };
2338
+ }
2339
+ if (ciResult.exitCode === 128 || ciResult.exitCode === null) {
2340
+ return { healed: false, skipped: "non-git" };
2341
+ }
2342
+ if (ciResult.exitCode !== 0) {
2343
+ return { healed: false, skipped: "not-ignored" };
2344
+ }
2345
+ const rawLine = ciResult.stdout.trim().split(/\r?\n/)[0] ?? "";
2346
+ const parsed = parseCheckIgnoreLine(rawLine);
2347
+ if (!parsed) {
2348
+ return { healed: false, skipped: "not-ignored" };
2349
+ }
2350
+ const gitignorePath = path5.isAbsolute(parsed.sourceFile) ? parsed.sourceFile : path5.join(projectDir, parsed.sourceFile);
2351
+ let gitignoreContent;
2352
+ try {
2353
+ gitignoreContent = await readFileFn(gitignorePath);
2354
+ } catch {
2355
+ return { healed: false, skipped: "not-ignored" };
2356
+ }
2357
+ const nl = gitignoreContent.includes("\r\n") ? "\r\n" : "\n";
2358
+ const lines = gitignoreContent.split(/\r?\n/);
2359
+ const startIdx = lines.findIndex((l) => l === GITIGNORE_BLOCK_START);
2360
+ const endIdx = lines.findIndex((l) => l === GITIGNORE_BLOCK_END);
2361
+ const lineIdx = parsed.lineNum - 1;
2362
+ if (startIdx !== -1 && endIdx !== -1 && endIdx > startIdx && lineIdx > startIdx && lineIdx < endIdx) {
2363
+ return { healed: false, skipped: "managed-block" };
2364
+ }
2365
+ const offendingLine = lines[lineIdx] ?? parsed.pattern;
2366
+ const displayLine = `${parsed.sourceFile}:${parsed.lineNum}: ${offendingLine}`;
2367
+ if (patternTargetsSettingsJson(parsed.pattern)) {
2368
+ printInfo(
2369
+ `codebyplan: ${opts.dryRun ? "(dry-run) would remove" : "removing"} gitignore rule "${offendingLine}" (${parsed.sourceFile}:${parsed.lineNum}) \u2014 .claude/settings.json must be committed.`
2370
+ );
2371
+ } else {
2372
+ let accepted;
2373
+ try {
2374
+ accepted = await promptFn(displayLine, opts);
2375
+ } catch (err) {
2376
+ printWarning(
2377
+ `codebyplan: could not prompt to remove gitignore line (${err instanceof Error ? err.message : String(err)}). Manual fix: remove "${offendingLine}" from ${parsed.sourceFile}, then git add .claude/settings.json.`
2378
+ );
2379
+ return { healed: false, skipped: "user-declined" };
2380
+ }
2381
+ if (!accepted) {
2382
+ printWarning(
2383
+ `codebyplan: .claude/settings.json is gitignored by "${offendingLine}" in ${parsed.sourceFile}:${parsed.lineNum}. To fix manually: remove that line and run \`git add .claude/settings.json\`.`
2384
+ );
2385
+ return { healed: false, skipped: "user-declined" };
2386
+ }
2387
+ }
2388
+ if (!opts.dryRun) {
2389
+ const newLines = lines.filter((_l, idx) => idx !== lineIdx);
2390
+ const newContent = newLines.join(nl);
2391
+ try {
2392
+ await writeFileFn(gitignorePath, newContent);
2393
+ } catch (err) {
2394
+ printWarning(
2395
+ `codebyplan: failed to write ${parsed.sourceFile}: ${err instanceof Error ? err.message : String(err)}`
2396
+ );
2397
+ return { healed: false, skipped: "user-declined" };
2398
+ }
2399
+ }
2400
+ return { healed: true };
2401
+ }
2402
+ function detectSettingsIgnored(projectDir, deps) {
2403
+ const gitCheckIgnoreFn = deps?.gitCheckIgnore ?? defaultGitCheckIgnore;
2404
+ let ciResult;
2405
+ try {
2406
+ ciResult = gitCheckIgnoreFn(projectDir);
2407
+ } catch {
2408
+ return { status: "non-git" };
2409
+ }
2410
+ if (ciResult.exitCode === 128 || ciResult.exitCode === null) {
2411
+ return { status: "non-git" };
2412
+ }
2413
+ if (ciResult.exitCode !== 0) {
2414
+ return { status: "not-ignored" };
2415
+ }
2416
+ const rawLine = ciResult.stdout.trim().split(/\r?\n/)[0] ?? "";
2417
+ const parsed = parseCheckIgnoreLine(rawLine);
2418
+ if (!parsed) {
2419
+ return { status: "not-ignored" };
2420
+ }
2421
+ return {
2422
+ status: "ignored",
2423
+ info: {
2424
+ sourceFile: parsed.sourceFile,
2425
+ lineNum: parsed.lineNum,
2426
+ pattern: parsed.pattern
2427
+ }
2428
+ };
2429
+ }
2430
+ function checkSettingsUntracked(projectDir, deps = {}) {
2431
+ const lsFn = deps.gitLsFiles ?? defaultGitLsFiles;
2432
+ const code = lsFn(projectDir);
2433
+ if (code === 0) return "tracked";
2434
+ if (code === 128) return "non-git";
2435
+ return "untracked";
2436
+ }
2437
+ function warnIfSettingsUntracked(projectDir, deps = {}) {
2438
+ const status = checkSettingsUntracked(projectDir, deps);
2439
+ if (status === "untracked") {
2440
+ console.warn(
2441
+ "codebyplan: .claude/settings.json is untracked \u2014 run `git add .claude/settings.json` and commit it."
2442
+ );
2443
+ }
2444
+ }
2445
+ var init_gitignore_detect = __esm({
2446
+ "src/lib/gitignore-detect.ts"() {
2447
+ "use strict";
2448
+ init_gitignore_block();
2449
+ }
2450
+ });
2451
+
2232
2452
  // src/lib/tech-detect.ts
2233
- import { readFile as readFile9, access, readdir } from "node:fs/promises";
2234
- import { join as join11, relative as relative2 } from "node:path";
2453
+ import { readFile as readFile10, access, readdir } from "node:fs/promises";
2454
+ import { join as join12, relative as relative2 } from "node:path";
2235
2455
  async function fileExists(filePath) {
2236
2456
  try {
2237
2457
  await access(filePath);
@@ -2244,8 +2464,8 @@ async function discoverMonorepoApps(projectPath) {
2244
2464
  const apps = [];
2245
2465
  const patterns = [];
2246
2466
  try {
2247
- const raw = await readFile9(
2248
- join11(projectPath, "pnpm-workspace.yaml"),
2467
+ const raw = await readFile10(
2468
+ join12(projectPath, "pnpm-workspace.yaml"),
2249
2469
  "utf-8"
2250
2470
  );
2251
2471
  const matches = raw.match(/^\s*-\s*['"]?([^'"#\n]+)['"]?/gm);
@@ -2259,7 +2479,7 @@ async function discoverMonorepoApps(projectPath) {
2259
2479
  }
2260
2480
  if (patterns.length === 0) {
2261
2481
  try {
2262
- const raw = await readFile9(join11(projectPath, "package.json"), "utf-8");
2482
+ const raw = await readFile10(join12(projectPath, "package.json"), "utf-8");
2263
2483
  const pkg = JSON.parse(raw);
2264
2484
  const ws = Array.isArray(pkg.workspaces) ? pkg.workspaces : pkg.workspaces?.packages;
2265
2485
  if (ws) patterns.push(...ws);
@@ -2269,14 +2489,14 @@ async function discoverMonorepoApps(projectPath) {
2269
2489
  for (const pattern of patterns) {
2270
2490
  if (pattern.endsWith("/*")) {
2271
2491
  const dir = pattern.slice(0, -2);
2272
- const absDir = join11(projectPath, dir);
2492
+ const absDir = join12(projectPath, dir);
2273
2493
  try {
2274
2494
  const entries = await readdir(absDir, { withFileTypes: true });
2275
2495
  for (const entry of entries) {
2276
2496
  if (entry.isDirectory()) {
2277
- const relPath = join11(dir, entry.name);
2278
- const absPath = join11(absDir, entry.name);
2279
- if (await fileExists(join11(absPath, "package.json"))) {
2497
+ const relPath = join12(dir, entry.name);
2498
+ const absPath = join12(absDir, entry.name);
2499
+ if (await fileExists(join12(absPath, "package.json"))) {
2280
2500
  apps.push({ name: entry.name, path: relPath, absPath });
2281
2501
  }
2282
2502
  }
@@ -2295,7 +2515,7 @@ async function hasJsxFile(dir, depth = 0) {
2295
2515
  const name = entry.name;
2296
2516
  if (entry.isDirectory()) {
2297
2517
  if (SKIP_DIRS.has(name) || JSX_SKIP_DIRS.has(name)) continue;
2298
- if (await hasJsxFile(join11(dir, name), depth + 1)) return true;
2518
+ if (await hasJsxFile(join12(dir, name), depth + 1)) return true;
2299
2519
  } else if (entry.isFile()) {
2300
2520
  if (JSX_TEST_PATTERN.test(name)) continue;
2301
2521
  if (name.endsWith(".tsx") || name.endsWith(".jsx")) return true;
@@ -2314,7 +2534,7 @@ async function hasJsxFile(dir, depth = 0) {
2314
2534
  async function detectCapabilities(dirPath, pkgJson) {
2315
2535
  const caps = /* @__PURE__ */ new Set();
2316
2536
  for (const sub of JSX_SCAN_DIRS) {
2317
- if (await hasJsxFile(join11(dirPath, sub))) {
2537
+ if (await hasJsxFile(join12(dirPath, sub))) {
2318
2538
  caps.add("jsx");
2319
2539
  break;
2320
2540
  }
@@ -2336,7 +2556,7 @@ async function detectCapabilities(dirPath, pkgJson) {
2336
2556
  }
2337
2557
  }
2338
2558
  }
2339
- if (!caps.has("node-server") && await fileExists(join11(dirPath, "src", "main.ts"))) {
2559
+ if (!caps.has("node-server") && await fileExists(join12(dirPath, "src", "main.ts"))) {
2340
2560
  caps.add("node-server");
2341
2561
  }
2342
2562
  if (pkgJson && pkgJson.bin) {
@@ -2352,7 +2572,7 @@ async function detectFromDirectory(dirPath) {
2352
2572
  const seen = /* @__PURE__ */ new Map();
2353
2573
  let pkgJson = null;
2354
2574
  try {
2355
- const raw = await readFile9(join11(dirPath, "package.json"), "utf-8");
2575
+ const raw = await readFile10(join12(dirPath, "package.json"), "utf-8");
2356
2576
  pkgJson = JSON.parse(raw);
2357
2577
  const allDeps = {
2358
2578
  ...pkgJson.dependencies ?? {},
@@ -2384,7 +2604,7 @@ async function detectFromDirectory(dirPath) {
2384
2604
  }
2385
2605
  for (const { file, rule } of CONFIG_FILE_MAP) {
2386
2606
  const key = rule.name.toLowerCase();
2387
- if (!seen.has(key) && await fileExists(join11(dirPath, file))) {
2607
+ if (!seen.has(key) && await fileExists(join12(dirPath, file))) {
2388
2608
  seen.set(key, { name: rule.name, category: rule.category });
2389
2609
  }
2390
2610
  }
@@ -2562,7 +2782,7 @@ function categorizeDependency(depName) {
2562
2782
  async function findPackageJsonFiles(dir, projectPath, depth = 0) {
2563
2783
  if (depth > 4) return [];
2564
2784
  const results = [];
2565
- const pkgPath = join11(dir, "package.json");
2785
+ const pkgPath = join12(dir, "package.json");
2566
2786
  if (await fileExists(pkgPath)) {
2567
2787
  results.push(pkgPath);
2568
2788
  }
@@ -2571,7 +2791,7 @@ async function findPackageJsonFiles(dir, projectPath, depth = 0) {
2571
2791
  for (const entry of entries) {
2572
2792
  if (!entry.isDirectory() || SKIP_DIRS.has(entry.name)) continue;
2573
2793
  const subResults = await findPackageJsonFiles(
2574
- join11(dir, entry.name),
2794
+ join12(dir, entry.name),
2575
2795
  projectPath,
2576
2796
  depth + 1
2577
2797
  );
@@ -2586,7 +2806,7 @@ async function scanAllDependencies(projectPath) {
2586
2806
  const dependencies = [];
2587
2807
  for (const pkgPath of packageJsonPaths) {
2588
2808
  try {
2589
- const raw = await readFile9(pkgPath, "utf-8");
2809
+ const raw = await readFile10(pkgPath, "utf-8");
2590
2810
  const pkg = JSON.parse(raw);
2591
2811
  const sourcePath = relative2(projectPath, pkgPath);
2592
2812
  const depSections = [
@@ -2825,7 +3045,7 @@ var init_tech_detect = __esm({
2825
3045
  });
2826
3046
 
2827
3047
  // src/lib/lsp-detect.ts
2828
- import { spawnSync as spawnSync3 } from "node:child_process";
3048
+ import { spawnSync as spawnSync4 } from "node:child_process";
2829
3049
  function mapTechStackToLsp(detectedNames) {
2830
3050
  const pluginIndex = new Map(
2831
3051
  LSP_TABLE.map((s) => [s.plugin, s])
@@ -2847,7 +3067,7 @@ function binaryOnPath(binary) {
2847
3067
  }
2848
3068
  function probeWith(probe, binary) {
2849
3069
  try {
2850
- const result = spawnSync3(probe, [binary], {
3070
+ const result = spawnSync4(probe, [binary], {
2851
3071
  encoding: "utf-8",
2852
3072
  timeout: 5e3
2853
3073
  });
@@ -2988,9 +3208,9 @@ __export(lsp_exports, {
2988
3208
  runLsp: () => runLsp,
2989
3209
  runLspFull: () => runLspFull
2990
3210
  });
2991
- import { readFile as readFile10, writeFile as writeFile7, mkdir as mkdir5, unlink as unlink2, access as access2 } from "node:fs/promises";
2992
- import { join as join12 } from "node:path";
2993
- import { spawnSync as spawnSync4 } from "node:child_process";
3211
+ import { readFile as readFile11, writeFile as writeFile8, mkdir as mkdir5, unlink as unlink2, access as access2 } from "node:fs/promises";
3212
+ import { join as join13 } from "node:path";
3213
+ import { spawnSync as spawnSync5 } from "node:child_process";
2994
3214
  async function fileExists2(filePath) {
2995
3215
  try {
2996
3216
  await access2(filePath);
@@ -3001,7 +3221,7 @@ async function fileExists2(filePath) {
3001
3221
  }
3002
3222
  async function readJsonFile(filePath) {
3003
3223
  try {
3004
- const raw = await readFile10(filePath, "utf-8");
3224
+ const raw = await readFile11(filePath, "utf-8");
3005
3225
  return JSON.parse(raw);
3006
3226
  } catch {
3007
3227
  return null;
@@ -3009,7 +3229,7 @@ async function readJsonFile(filePath) {
3009
3229
  }
3010
3230
  function tryNpmInstallGlobal(pkg) {
3011
3231
  try {
3012
- const result = spawnSync4("npm", ["i", "-g", pkg], {
3232
+ const result = spawnSync5("npm", ["i", "-g", pkg], {
3013
3233
  encoding: "utf-8",
3014
3234
  timeout: 6e4,
3015
3235
  // "pipe" (not "inherit"): inheriting the parent's fds can surface EPIPE/EIO
@@ -3042,7 +3262,7 @@ async function runLspFull(projectPath, opts = {}) {
3042
3262
  ` Detected LSP servers: ${servers.map((s) => s.plugin).join(", ")}
3043
3263
  `
3044
3264
  );
3045
- const settingsLocalPath = join12(projectPath, ".claude", "settings.local.json");
3265
+ const settingsLocalPath = join13(projectPath, ".claude", "settings.local.json");
3046
3266
  let settings = {};
3047
3267
  const existingSettingsRaw = await readJsonFile(settingsLocalPath);
3048
3268
  if (existingSettingsRaw) {
@@ -3055,15 +3275,15 @@ async function runLspFull(projectPath, opts = {}) {
3055
3275
  if (dryRun) {
3056
3276
  console.log(` [dry-run] would update ${settingsLocalPath}`);
3057
3277
  } else {
3058
- await mkdir5(join12(projectPath, ".claude"), { recursive: true });
3059
- await writeFile7(
3278
+ await mkdir5(join13(projectPath, ".claude"), { recursive: true });
3279
+ await writeFile8(
3060
3280
  settingsLocalPath,
3061
3281
  JSON.stringify(settings, null, 2) + "\n",
3062
3282
  "utf-8"
3063
3283
  );
3064
3284
  console.log(` Updated ${settingsLocalPath}`);
3065
3285
  }
3066
- const lspJsonPath = join12(projectPath, ".codebyplan", "lsp.json");
3286
+ const lspJsonPath = join13(projectPath, ".codebyplan", "lsp.json");
3067
3287
  const lspJsonContent = {
3068
3288
  servers: servers.map((s) => ({
3069
3289
  plugin: s.plugin,
@@ -3074,15 +3294,15 @@ async function runLspFull(projectPath, opts = {}) {
3074
3294
  if (dryRun) {
3075
3295
  console.log(` [dry-run] would write ${lspJsonPath}`);
3076
3296
  } else {
3077
- await mkdir5(join12(projectPath, ".codebyplan"), { recursive: true });
3078
- await writeFile7(
3297
+ await mkdir5(join13(projectPath, ".codebyplan"), { recursive: true });
3298
+ await writeFile8(
3079
3299
  lspJsonPath,
3080
3300
  JSON.stringify(lspJsonContent, null, 2) + "\n",
3081
3301
  "utf-8"
3082
3302
  );
3083
3303
  console.log(` Wrote ${lspJsonPath}`);
3084
3304
  }
3085
- const todoDir = join12(projectPath, ".codebyplan", "todo", "session-start");
3305
+ const todoDir = join13(projectPath, ".codebyplan", "todo", "session-start");
3086
3306
  const autoInstalled = [];
3087
3307
  const nudged = [];
3088
3308
  for (const server of servers) {
@@ -3105,10 +3325,10 @@ async function runLspFull(projectPath, opts = {}) {
3105
3325
  ` npm install failed for ${server.npmPackage}. Writing nudge file.`
3106
3326
  );
3107
3327
  await mkdir5(todoDir, { recursive: true });
3108
- const nudgeFile = join12(todoDir, `install-${server.binary}.md`);
3328
+ const nudgeFile = join13(todoDir, `install-${server.binary}.md`);
3109
3329
  const nudgeContent = `Run \`${server.installHint}\` to enable ${server.language} LSP support in Claude Code.
3110
3330
  `;
3111
- await writeFile7(nudgeFile, nudgeContent, "utf-8");
3331
+ await writeFile8(nudgeFile, nudgeContent, "utf-8");
3112
3332
  nudged.push(server.binary);
3113
3333
  }
3114
3334
  } else {
@@ -3117,10 +3337,10 @@ async function runLspFull(projectPath, opts = {}) {
3117
3337
  nudged.push(server.binary);
3118
3338
  } else {
3119
3339
  await mkdir5(todoDir, { recursive: true });
3120
- const nudgeFile = join12(todoDir, `install-${server.binary}.md`);
3340
+ const nudgeFile = join13(todoDir, `install-${server.binary}.md`);
3121
3341
  const nudgeContent = `Run \`${server.installHint}\` to enable ${server.language} LSP support in Claude Code.
3122
3342
  `;
3123
- await writeFile7(nudgeFile, nudgeContent, "utf-8");
3343
+ await writeFile8(nudgeFile, nudgeContent, "utf-8");
3124
3344
  nudged.push(server.binary);
3125
3345
  }
3126
3346
  }
@@ -3154,19 +3374,19 @@ async function runLspFull(projectPath, opts = {}) {
3154
3374
  `);
3155
3375
  }
3156
3376
  async function runLspCheck(projectPath) {
3157
- const lspJsonPath = join12(projectPath, ".codebyplan", "lsp.json");
3377
+ const lspJsonPath = join13(projectPath, ".codebyplan", "lsp.json");
3158
3378
  const lspJson = await readJsonFile(lspJsonPath);
3159
3379
  if (!lspJson || !Array.isArray(lspJson.servers)) {
3160
3380
  return;
3161
3381
  }
3162
- const todoDir = join12(projectPath, ".codebyplan", "todo", "session-start");
3382
+ const todoDir = join13(projectPath, ".codebyplan", "todo", "session-start");
3163
3383
  const stillMissing = [];
3164
3384
  for (const entry of lspJson.servers) {
3165
3385
  const { binary, plugin } = entry;
3166
3386
  const found = binaryOnPath(binary);
3167
3387
  const fullServer = LSP_TABLE.find((s) => s.plugin === plugin);
3168
3388
  if (found) {
3169
- const nudgeFile = join12(todoDir, `install-${binary}.md`);
3389
+ const nudgeFile = join13(todoDir, `install-${binary}.md`);
3170
3390
  if (await fileExists2(nudgeFile)) {
3171
3391
  try {
3172
3392
  await unlink2(nudgeFile);
@@ -3212,7 +3432,7 @@ __export(install_exports, {
3212
3432
  });
3213
3433
  import * as fs4 from "node:fs";
3214
3434
  import * as os2 from "node:os";
3215
- import * as path5 from "node:path";
3435
+ import * as path6 from "node:path";
3216
3436
  async function runInstall(opts, deps = {}) {
3217
3437
  await Promise.resolve();
3218
3438
  const scope = opts.scope ?? "project";
@@ -3240,14 +3460,14 @@ async function runInstall(opts, deps = {}) {
3240
3460
  const files = walkTemplates(templatesDir);
3241
3461
  const manifestEntries = [];
3242
3462
  for (const f of files) {
3243
- const absDest = path5.join(projectDir, ".claude", f.dest);
3244
- const absSrc = path5.join(templatesDir, f.src);
3463
+ const absDest = path6.join(projectDir, ".claude", f.dest);
3464
+ const absSrc = path6.join(templatesDir, f.src);
3245
3465
  if (opts.dryRun) {
3246
3466
  if (opts.verbose) {
3247
3467
  console.log(`[dry-run] would copy ${f.src} \u2192 .claude/${f.dest}`);
3248
3468
  }
3249
3469
  } else {
3250
- fs4.mkdirSync(path5.dirname(absDest), { recursive: true });
3470
+ fs4.mkdirSync(path6.dirname(absDest), { recursive: true });
3251
3471
  fs4.copyFileSync(absSrc, absDest);
3252
3472
  if (opts.verbose) {
3253
3473
  console.log(`copied ${f.src} \u2192 .claude/${f.dest}`);
@@ -3255,14 +3475,14 @@ async function runInstall(opts, deps = {}) {
3255
3475
  }
3256
3476
  manifestEntries.push({ src: f.src, dest: f.dest, hash: f.hash });
3257
3477
  }
3258
- const hooksJsonPath = path5.join(templatesDir, "hooks", "hooks.json");
3259
- const baseSettingsPath = path5.join(
3478
+ const hooksJsonPath = path6.join(templatesDir, "hooks", "hooks.json");
3479
+ const baseSettingsPath = path6.join(
3260
3480
  templatesDir,
3261
3481
  "settings.project.base.json"
3262
3482
  );
3263
3483
  const hasHooks = fs4.existsSync(hooksJsonPath);
3264
3484
  const hasBase = fs4.existsSync(baseSettingsPath);
3265
- const settingsPath = path5.join(projectDir, ".claude", "settings.json");
3485
+ const settingsPath = path6.join(projectDir, ".claude", "settings.json");
3266
3486
  const existingSettings = fs4.existsSync(settingsPath) ? JSON.parse(fs4.readFileSync(settingsPath, "utf8")) : {};
3267
3487
  if (hasBase) {
3268
3488
  const base = JSON.parse(
@@ -3283,8 +3503,13 @@ async function runInstall(opts, deps = {}) {
3283
3503
  ) : void 0
3284
3504
  );
3285
3505
  }
3506
+ await detectAndHealSettingsGitignore(
3507
+ projectDir,
3508
+ { yes: opts.yes, dryRun: opts.dryRun },
3509
+ deps.detectHealDeps
3510
+ );
3286
3511
  if (!opts.dryRun) {
3287
- fs4.mkdirSync(path5.dirname(settingsPath), { recursive: true });
3512
+ fs4.mkdirSync(path6.dirname(settingsPath), { recursive: true });
3288
3513
  fs4.writeFileSync(
3289
3514
  settingsPath,
3290
3515
  JSON.stringify(existingSettings, null, 2) + "\n",
@@ -3292,16 +3517,19 @@ async function runInstall(opts, deps = {}) {
3292
3517
  );
3293
3518
  } else if (opts.verbose) {
3294
3519
  console.log(
3295
- `[dry-run] would merge settings into ${path5.relative(projectDir, settingsPath)}`
3520
+ `[dry-run] would merge settings into ${path6.relative(projectDir, settingsPath)}`
3296
3521
  );
3297
3522
  }
3523
+ if (!opts.dryRun) {
3524
+ warnIfSettingsUntracked(projectDir, deps.lsFilesDep);
3525
+ }
3298
3526
  const gitignoreAction = await ensureManagedGitignoreBlock(
3299
3527
  projectDir,
3300
3528
  opts.dryRun
3301
3529
  );
3302
3530
  if (opts.verbose && gitignoreAction !== "unchanged") {
3303
3531
  console.log(
3304
- `${opts.dryRun ? "[dry-run] would " : ""}${gitignoreAction} managed .gitignore block in ${path5.relative(projectDir, path5.join(projectDir, ".gitignore"))}`
3532
+ `${opts.dryRun ? "[dry-run] would " : ""}${gitignoreAction} managed .gitignore block in ${path6.relative(projectDir, path6.join(projectDir, ".gitignore"))}`
3305
3533
  );
3306
3534
  }
3307
3535
  if (!opts.dryRun) {
@@ -3339,9 +3567,9 @@ function runInstallUser(opts, deps) {
3339
3567
  return;
3340
3568
  }
3341
3569
  try {
3342
- const userDir = deps.userDir ?? path5.join(os2.homedir(), ".claude");
3343
- const settingsPath = path5.join(userDir, "settings.json");
3344
- const userBaseSettingsPath = path5.join(
3570
+ const userDir = deps.userDir ?? path6.join(os2.homedir(), ".claude");
3571
+ const settingsPath = path6.join(userDir, "settings.json");
3572
+ const userBaseSettingsPath = path6.join(
3345
3573
  templatesDir,
3346
3574
  "settings.user.base.json"
3347
3575
  );
@@ -3383,7 +3611,7 @@ function runInstallUser(opts, deps) {
3383
3611
  }
3384
3612
  }
3385
3613
  function countHookEntries(templatesDir) {
3386
- const p = path5.join(templatesDir, "hooks", "hooks.json");
3614
+ const p = path6.join(templatesDir, "hooks", "hooks.json");
3387
3615
  if (!fs4.existsSync(p)) return 0;
3388
3616
  try {
3389
3617
  const j = JSON.parse(fs4.readFileSync(p, "utf8"));
@@ -3408,6 +3636,7 @@ var init_install = __esm({
3408
3636
  init_settings_merge();
3409
3637
  init_statusline_config();
3410
3638
  init_templates_dir();
3639
+ init_gitignore_detect();
3411
3640
  }
3412
3641
  });
3413
3642
 
@@ -3416,17 +3645,17 @@ var setup_exports = {};
3416
3645
  __export(setup_exports, {
3417
3646
  runSetup: () => runSetup
3418
3647
  });
3419
- import { readFile as readFile11, writeFile as writeFile8 } from "node:fs/promises";
3648
+ import { readFile as readFile12, writeFile as writeFile9 } from "node:fs/promises";
3420
3649
  import { homedir as homedir4 } from "node:os";
3421
- import { join as join14 } from "node:path";
3650
+ import { join as join15 } from "node:path";
3422
3651
  import { stdin, stdout as stdout2 } from "node:process";
3423
3652
  import { createInterface } from "node:readline/promises";
3424
3653
  function getConfigPath(scope) {
3425
- return scope === "user" ? join14(homedir4(), ".claude.json") : join14(process.cwd(), ".mcp.json");
3654
+ return scope === "user" ? join15(homedir4(), ".claude.json") : join15(process.cwd(), ".mcp.json");
3426
3655
  }
3427
- async function readConfig(path21) {
3656
+ async function readConfig(path22) {
3428
3657
  try {
3429
- const raw = await readFile11(path21, "utf-8");
3658
+ const raw = await readFile12(path22, "utf-8");
3430
3659
  const parsed = JSON.parse(raw);
3431
3660
  if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) {
3432
3661
  return parsed;
@@ -3446,7 +3675,7 @@ async function writeMcpConfig(scope) {
3446
3675
  config.mcpServers = {};
3447
3676
  }
3448
3677
  config.mcpServers.codebyplan = buildMcpEntry();
3449
- await writeFile8(configPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
3678
+ await writeFile9(configPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
3450
3679
  return configPath;
3451
3680
  }
3452
3681
  async function fetchRepos(auth) {
@@ -3851,15 +4080,15 @@ var upgrade_auth_exports = {};
3851
4080
  __export(upgrade_auth_exports, {
3852
4081
  runUpgradeAuth: () => runUpgradeAuth
3853
4082
  });
3854
- import { readFile as readFile12, writeFile as writeFile9 } from "node:fs/promises";
4083
+ import { readFile as readFile13, writeFile as writeFile10 } from "node:fs/promises";
3855
4084
  import { homedir as homedir5 } from "node:os";
3856
- import { join as join15 } from "node:path";
4085
+ import { join as join16 } from "node:path";
3857
4086
  function configPaths() {
3858
- return [join15(homedir5(), ".claude.json"), join15(process.cwd(), ".mcp.json")];
4087
+ return [join16(homedir5(), ".claude.json"), join16(process.cwd(), ".mcp.json")];
3859
4088
  }
3860
- async function readConfig2(path21) {
4089
+ async function readConfig2(path22) {
3861
4090
  try {
3862
- const raw = await readFile12(path21, "utf-8");
4091
+ const raw = await readFile13(path22, "utf-8");
3863
4092
  const parsed = JSON.parse(raw);
3864
4093
  if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) {
3865
4094
  return parsed;
@@ -3873,7 +4102,7 @@ function entryHasLegacyApiKey(entry) {
3873
4102
  if (!entry || !entry.headers) return false;
3874
4103
  return "x-api-key" in entry.headers;
3875
4104
  }
3876
- async function rewriteConfig(path21, config, newUrl) {
4105
+ async function rewriteConfig(path22, config, newUrl) {
3877
4106
  const servers = config.mcpServers;
3878
4107
  if (!servers) return false;
3879
4108
  const entry = servers.codebyplan;
@@ -3881,7 +4110,7 @@ async function rewriteConfig(path21, config, newUrl) {
3881
4110
  if (!entryHasLegacyApiKey(entry) && entry.url === newUrl && entry.type === "http")
3882
4111
  return false;
3883
4112
  servers.codebyplan = { type: "http", url: newUrl };
3884
- await writeFile9(path21, JSON.stringify(config, null, 2) + "\n", "utf-8");
4113
+ await writeFile10(path22, JSON.stringify(config, null, 2) + "\n", "utf-8");
3885
4114
  return true;
3886
4115
  }
3887
4116
  async function runUpgradeAuth() {
@@ -3889,12 +4118,12 @@ async function runUpgradeAuth() {
3889
4118
  await runLogin();
3890
4119
  const newUrl = mcpEndpoint();
3891
4120
  let migrated = 0;
3892
- for (const path21 of configPaths()) {
3893
- const config = await readConfig2(path21);
4121
+ for (const path22 of configPaths()) {
4122
+ const config = await readConfig2(path22);
3894
4123
  if (!config) continue;
3895
- const changed = await rewriteConfig(path21, config, newUrl);
4124
+ const changed = await rewriteConfig(path22, config, newUrl);
3896
4125
  if (changed) {
3897
- console.log(` Updated ${path21}`);
4126
+ console.log(` Updated ${path22}`);
3898
4127
  migrated++;
3899
4128
  }
3900
4129
  }
@@ -4347,8 +4576,8 @@ __export(eslint_exports, {
4347
4576
  eslintInit: () => eslintInit,
4348
4577
  runEslint: () => runEslint
4349
4578
  });
4350
- import { readFile as readFile13, writeFile as writeFile10, access as access3, readdir as readdir2 } from "node:fs/promises";
4351
- import { join as join16, relative as relative4 } from "node:path";
4579
+ import { readFile as readFile14, writeFile as writeFile11, access as access3, readdir as readdir2 } from "node:fs/promises";
4580
+ import { join as join17, relative as relative4 } from "node:path";
4352
4581
  async function fileExists3(filePath) {
4353
4582
  try {
4354
4583
  await access3(filePath);
@@ -4359,7 +4588,7 @@ async function fileExists3(filePath) {
4359
4588
  }
4360
4589
  async function autoDetectIgnorePatterns(absPath) {
4361
4590
  const patterns = [];
4362
- if (await fileExists3(join16(absPath, "esbuild.js"))) {
4591
+ if (await fileExists3(join17(absPath, "esbuild.js"))) {
4363
4592
  patterns.push("esbuild.js");
4364
4593
  }
4365
4594
  let entries = [];
@@ -4379,19 +4608,19 @@ async function autoDetectIgnorePatterns(absPath) {
4379
4608
  }
4380
4609
  for (const ext of ["ts", "mts", "js", "mjs"]) {
4381
4610
  const candidate = `vitest.config.${ext}`;
4382
- if (await fileExists3(join16(absPath, candidate))) {
4611
+ if (await fileExists3(join17(absPath, candidate))) {
4383
4612
  patterns.push(candidate);
4384
4613
  break;
4385
4614
  }
4386
4615
  }
4387
4616
  for (const ext of ["ts", "mts", "js", "mjs"]) {
4388
4617
  const candidate = `vite.config.${ext}`;
4389
- if (await fileExists3(join16(absPath, candidate))) {
4618
+ if (await fileExists3(join17(absPath, candidate))) {
4390
4619
  patterns.push(candidate);
4391
4620
  break;
4392
4621
  }
4393
4622
  }
4394
- if (await fileExists3(join16(absPath, "tauri.conf.json"))) {
4623
+ if (await fileExists3(join17(absPath, "tauri.conf.json"))) {
4395
4624
  patterns.push("src-tauri/**");
4396
4625
  patterns.push("**/*.d.ts");
4397
4626
  }
@@ -4399,14 +4628,14 @@ async function autoDetectIgnorePatterns(absPath) {
4399
4628
  }
4400
4629
  function detectPackageManager(projectPath) {
4401
4630
  return (async () => {
4402
- if (await fileExists3(join16(projectPath, "pnpm-lock.yaml"))) return "pnpm";
4403
- if (await fileExists3(join16(projectPath, "yarn.lock"))) return "yarn";
4631
+ if (await fileExists3(join17(projectPath, "pnpm-lock.yaml"))) return "pnpm";
4632
+ if (await fileExists3(join17(projectPath, "yarn.lock"))) return "yarn";
4404
4633
  return "npm";
4405
4634
  })();
4406
4635
  }
4407
4636
  async function getInstalledDeps(pkgJsonPath) {
4408
4637
  try {
4409
- const raw = await readFile13(pkgJsonPath, "utf-8");
4638
+ const raw = await readFile14(pkgJsonPath, "utf-8");
4410
4639
  const pkg = JSON.parse(raw);
4411
4640
  const all = /* @__PURE__ */ new Set();
4412
4641
  for (const name of Object.keys(pkg.dependencies ?? {})) all.add(name);
@@ -4519,7 +4748,7 @@ async function eslintInit(repoId, projectPath) {
4519
4748
  ignorePatterns: detectedIgnores
4520
4749
  });
4521
4750
  const hash = hashConfig(content);
4522
- const configPath = join16(target.absPath, "eslint.config.mjs");
4751
+ const configPath = join17(target.absPath, "eslint.config.mjs");
4523
4752
  configsToWrite.push({
4524
4753
  target,
4525
4754
  presets,
@@ -4541,11 +4770,11 @@ async function eslintInit(repoId, projectPath) {
4541
4770
  return;
4542
4771
  }
4543
4772
  const pm = await detectPackageManager(projectPath);
4544
- const rootPkgJsonPath = join16(projectPath, "package.json");
4773
+ const rootPkgJsonPath = join17(projectPath, "package.json");
4545
4774
  const installed = await getInstalledDeps(rootPkgJsonPath);
4546
4775
  if (isMonorepo2) {
4547
4776
  for (const { target } of configsToWrite) {
4548
- const appPkgJson = join16(target.absPath, "package.json");
4777
+ const appPkgJson = join17(target.absPath, "package.json");
4549
4778
  const appDeps = await getInstalledDeps(appPkgJson);
4550
4779
  for (const dep of appDeps) {
4551
4780
  installed.add(dep);
@@ -4597,7 +4826,7 @@ async function eslintInit(repoId, projectPath) {
4597
4826
  } of configsToWrite) {
4598
4827
  if (await fileExists3(configPath)) {
4599
4828
  try {
4600
- const existing = await readFile13(configPath, "utf-8");
4829
+ const existing = await readFile14(configPath, "utf-8");
4601
4830
  const existingHash = hashConfig(existing);
4602
4831
  if (existingHash === hash) {
4603
4832
  console.log(
@@ -4617,7 +4846,7 @@ async function eslintInit(repoId, projectPath) {
4617
4846
  }
4618
4847
  }
4619
4848
  try {
4620
- await writeFile10(configPath, content, "utf-8");
4849
+ await writeFile11(configPath, content, "utf-8");
4621
4850
  } catch (err) {
4622
4851
  console.error(
4623
4852
  ` ${target.name}: Failed to write config: ${err instanceof Error ? err.message : String(err)}`
@@ -4670,16 +4899,16 @@ var init_eslint = __esm({
4670
4899
  });
4671
4900
 
4672
4901
  // src/lib/worktree-cache.ts
4673
- import { mkdir as mkdir6, readFile as readFile14, writeFile as writeFile11 } from "node:fs/promises";
4674
- import { dirname as dirname7, join as join17 } from "node:path";
4902
+ import { mkdir as mkdir6, readFile as readFile15, writeFile as writeFile12 } from "node:fs/promises";
4903
+ import { dirname as dirname7, join as join18 } from "node:path";
4675
4904
  function worktreeCachePath(repoRoot) {
4676
- return join17(repoRoot, ".codebyplan", "worktree.local.json");
4905
+ return join18(repoRoot, ".codebyplan", "worktree.local.json");
4677
4906
  }
4678
4907
  async function readCachedWorktreeId(repoRoot, currentBranch) {
4679
4908
  const cachePath = worktreeCachePath(repoRoot);
4680
4909
  let raw;
4681
4910
  try {
4682
- raw = await readFile14(cachePath, "utf-8");
4911
+ raw = await readFile15(cachePath, "utf-8");
4683
4912
  } catch (err) {
4684
4913
  const code = err.code;
4685
4914
  if (code === "ENOENT") {
@@ -4725,7 +4954,7 @@ async function writeWorktreeCache(repoRoot, data) {
4725
4954
  };
4726
4955
  try {
4727
4956
  await mkdir6(dirPath, { recursive: true });
4728
- await writeFile11(
4957
+ await writeFile12(
4729
4958
  cachePath,
4730
4959
  JSON.stringify(payload, null, 2) + "\n",
4731
4960
  "utf-8"
@@ -4767,25 +4996,25 @@ __export(state_store_exports, {
4767
4996
  import { createHash as createHash4 } from "node:crypto";
4768
4997
  import {
4769
4998
  mkdir as mkdir7,
4770
- readFile as readFile15,
4771
- writeFile as writeFile12,
4999
+ readFile as readFile16,
5000
+ writeFile as writeFile13,
4772
5001
  unlink as unlink3,
4773
5002
  readdir as readdir3,
4774
5003
  stat as stat2,
4775
5004
  rm
4776
5005
  } from "node:fs/promises";
4777
- import { join as join18, dirname as dirname8 } from "node:path";
5006
+ import { join as join19, dirname as dirname8 } from "node:path";
4778
5007
  function stateDir(repoRoot) {
4779
- return join18(repoRoot, ".codebyplan", "state");
5008
+ return join19(repoRoot, ".codebyplan", "state");
4780
5009
  }
4781
5010
  function cursorPath(repoRoot) {
4782
- return join18(stateDir(repoRoot), "_cursor.json");
5011
+ return join19(stateDir(repoRoot), "_cursor.json");
4783
5012
  }
4784
5013
  function checkpointPath(repoRoot, checkpointId) {
4785
- return join18(stateDir(repoRoot), "checkpoints", `${checkpointId}.json`);
5014
+ return join19(stateDir(repoRoot), "checkpoints", `${checkpointId}.json`);
4786
5015
  }
4787
5016
  function taskPath(repoRoot, checkpointId, taskId) {
4788
- return join18(
5017
+ return join19(
4789
5018
  stateDir(repoRoot),
4790
5019
  "checkpoints",
4791
5020
  checkpointId,
@@ -4794,7 +5023,7 @@ function taskPath(repoRoot, checkpointId, taskId) {
4794
5023
  );
4795
5024
  }
4796
5025
  function roundPath(repoRoot, checkpointId, taskId, roundId) {
4797
- return join18(
5026
+ return join19(
4798
5027
  stateDir(repoRoot),
4799
5028
  "checkpoints",
4800
5029
  checkpointId,
@@ -4805,19 +5034,19 @@ function roundPath(repoRoot, checkpointId, taskId, roundId) {
4805
5034
  );
4806
5035
  }
4807
5036
  function standaloneTaskPath(repoRoot, taskId) {
4808
- return join18(stateDir(repoRoot), "standalone_tasks", `${taskId}.json`);
5037
+ return join19(stateDir(repoRoot), "standalone_tasks", `${taskId}.json`);
4809
5038
  }
4810
5039
  function sessionLogPath(repoRoot) {
4811
- return join18(stateDir(repoRoot), "session", "current.json");
5040
+ return join19(stateDir(repoRoot), "session", "current.json");
4812
5041
  }
4813
5042
  function todosPath(repoRoot) {
4814
- return join18(stateDir(repoRoot), "todos.json");
5043
+ return join19(stateDir(repoRoot), "todos.json");
4815
5044
  }
4816
5045
  function worktreesPath(repoRoot) {
4817
- return join18(stateDir(repoRoot), "worktrees.json");
5046
+ return join19(stateDir(repoRoot), "worktrees.json");
4818
5047
  }
4819
5048
  function pendingMarkerPath(repoRoot, entityId) {
4820
- return join18(stateDir(repoRoot), "_pending", `${entityId}.json`);
5049
+ return join19(stateDir(repoRoot), "_pending", `${entityId}.json`);
4821
5050
  }
4822
5051
  function serializeEntity(row) {
4823
5052
  return JSON.stringify(row, null, 2) + "\n";
@@ -4828,7 +5057,7 @@ function hashEntity(row) {
4828
5057
  async function readCursor(repoRoot) {
4829
5058
  const p = cursorPath(repoRoot);
4830
5059
  try {
4831
- const raw = await readFile15(p, "utf-8");
5060
+ const raw = await readFile16(p, "utf-8");
4832
5061
  return JSON.parse(raw);
4833
5062
  } catch (err) {
4834
5063
  const code = err.code;
@@ -4845,7 +5074,7 @@ async function writeCursor(repoRoot, cursor) {
4845
5074
  const p = cursorPath(repoRoot);
4846
5075
  try {
4847
5076
  await mkdir7(dirname8(p), { recursive: true });
4848
- await writeFile12(p, JSON.stringify(cursor, null, 2) + "\n", "utf-8");
5077
+ await writeFile13(p, JSON.stringify(cursor, null, 2) + "\n", "utf-8");
4849
5078
  } catch (err) {
4850
5079
  process.stderr.write(
4851
5080
  `state-store: writeCursor failed (non-fatal): ${err instanceof Error ? err.message : String(err)}
@@ -4855,7 +5084,7 @@ async function writeCursor(repoRoot, cursor) {
4855
5084
  }
4856
5085
  async function readEntityFile(filePath) {
4857
5086
  try {
4858
- const raw = await readFile15(filePath, "utf-8");
5087
+ const raw = await readFile16(filePath, "utf-8");
4859
5088
  return JSON.parse(raw);
4860
5089
  } catch (err) {
4861
5090
  const code = err.code;
@@ -4873,7 +5102,7 @@ async function writeEntityFile(filePath, row) {
4873
5102
  const hash = createHash4("sha256").update(serialized).digest("hex");
4874
5103
  try {
4875
5104
  await mkdir7(dirname8(filePath), { recursive: true });
4876
- await writeFile12(filePath, serialized, "utf-8");
5105
+ await writeFile13(filePath, serialized, "utf-8");
4877
5106
  } catch (err) {
4878
5107
  process.stderr.write(
4879
5108
  `state-store: writeEntityFile failed for ${filePath} (non-fatal): ${err instanceof Error ? err.message : String(err)}
@@ -4920,7 +5149,7 @@ async function collectJsonFiles(dir, out) {
4920
5149
  throw err;
4921
5150
  }
4922
5151
  for (const entry of entries) {
4923
- const full = join18(dir, entry);
5152
+ const full = join19(dir, entry);
4924
5153
  try {
4925
5154
  const s = await stat2(full);
4926
5155
  if (s.isDirectory()) {
@@ -4938,7 +5167,7 @@ async function pruneEntityTree(repoRoot, knownIdsByTable) {
4938
5167
  const taskIds = knownIdsByTable.tasks ?? /* @__PURE__ */ new Set();
4939
5168
  const roundIds = knownIdsByTable.rounds ?? /* @__PURE__ */ new Set();
4940
5169
  const base = stateDir(repoRoot);
4941
- const checkpointsDir = join18(base, "checkpoints");
5170
+ const checkpointsDir = join19(base, "checkpoints");
4942
5171
  const prunedCheckpointIds = /* @__PURE__ */ new Set();
4943
5172
  const beforePrune = pruned.length;
4944
5173
  await pruneJsonDir(checkpointsDir, checkpointIds, pruned);
@@ -4948,7 +5177,7 @@ async function pruneEntityTree(repoRoot, knownIdsByTable) {
4948
5177
  }
4949
5178
  for (const id of prunedCheckpointIds) {
4950
5179
  try {
4951
- await rm(join18(checkpointsDir, id), { recursive: true, force: true });
5180
+ await rm(join19(checkpointsDir, id), { recursive: true, force: true });
4952
5181
  } catch (err) {
4953
5182
  process.stderr.write(
4954
5183
  `state-store: pruneEntityTree could not remove subtree for checkpoint ${id} (non-fatal): ${String(err)}
@@ -4956,7 +5185,7 @@ async function pruneEntityTree(repoRoot, knownIdsByTable) {
4956
5185
  );
4957
5186
  }
4958
5187
  }
4959
- const taskFiles = await listEntityFiles(join18(checkpointsDir));
5188
+ const taskFiles = await listEntityFiles(join19(checkpointsDir));
4960
5189
  for (const f of taskFiles) {
4961
5190
  const chkMatch = f.match(/[/\\]checkpoints[/\\]([^/\\]+)[/\\]/);
4962
5191
  if (chkMatch?.[1] && prunedCheckpointIds.has(chkMatch[1])) continue;
@@ -4996,7 +5225,7 @@ async function pruneJsonDir(dir, knownIds, pruned) {
4996
5225
  if (!entry.endsWith(".json")) continue;
4997
5226
  const id = entry.slice(0, -5);
4998
5227
  if (!knownIds.has(id)) {
4999
- const full = join18(dir, entry);
5228
+ const full = join19(dir, entry);
5000
5229
  await deleteEntityFile(full);
5001
5230
  pruned.push(full);
5002
5231
  }
@@ -5653,13 +5882,13 @@ function __disposeResources(env) {
5653
5882
  }
5654
5883
  return next();
5655
5884
  }
5656
- function __rewriteRelativeImportExtension(path21, preserveJsx) {
5657
- if (typeof path21 === "string" && /^\.\.?\//.test(path21)) {
5658
- return path21.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function(m, tsx, d, ext, cm) {
5885
+ function __rewriteRelativeImportExtension(path22, preserveJsx) {
5886
+ if (typeof path22 === "string" && /^\.\.?\//.test(path22)) {
5887
+ return path22.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function(m, tsx, d, ext, cm) {
5659
5888
  return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : d + ext + "." + cm.toLowerCase() + "js";
5660
5889
  });
5661
5890
  }
5662
- return path21;
5891
+ return path22;
5663
5892
  }
5664
5893
  var extendStatics, __assign, __createBinding, __setModuleDefault, ownKeys, _SuppressedError, tslib_es6_default;
5665
5894
  var init_tslib_es6 = __esm({
@@ -14297,8 +14526,8 @@ var require_RealtimeChannel = __commonJS({
14297
14526
  }
14298
14527
  /** @internal */
14299
14528
  _notThisChannelEvent(event, ref) {
14300
- const { close, error, leave, join: join54 } = constants_1.CHANNEL_EVENTS;
14301
- const events = [close, error, leave, join54];
14529
+ const { close, error, leave, join: join56 } = constants_1.CHANNEL_EVENTS;
14530
+ const events = [close, error, leave, join56];
14302
14531
  return ref && events.includes(event) && ref !== this.joinPush.ref;
14303
14532
  }
14304
14533
  /** @internal */
@@ -15181,8 +15410,8 @@ var require_main2 = __commonJS({
15181
15410
  });
15182
15411
 
15183
15412
  // ../../node_modules/.pnpm/iceberg-js@0.8.1/node_modules/iceberg-js/dist/index.mjs
15184
- function buildUrl2(baseUrl3, path21, query) {
15185
- const url = new URL(path21, baseUrl3);
15413
+ function buildUrl2(baseUrl3, path22, query) {
15414
+ const url = new URL(path22, baseUrl3);
15186
15415
  if (query) {
15187
15416
  for (const [key, value] of Object.entries(query)) {
15188
15417
  if (value !== void 0) {
@@ -15212,12 +15441,12 @@ function createFetchClient(options) {
15212
15441
  return {
15213
15442
  async request({
15214
15443
  method,
15215
- path: path21,
15444
+ path: path22,
15216
15445
  query,
15217
15446
  body,
15218
15447
  headers
15219
15448
  }) {
15220
- const url = buildUrl2(options.baseUrl, path21, query);
15449
+ const url = buildUrl2(options.baseUrl, path22, query);
15221
15450
  const authHeaders = await buildAuthHeaders(options.auth);
15222
15451
  const res = await fetchFn(url, {
15223
15452
  method,
@@ -16115,7 +16344,7 @@ var init_dist3 = __esm({
16115
16344
  * @param path The relative file path. Should be of the format `folder/subfolder/filename.png`. The bucket must already exist before attempting to upload.
16116
16345
  * @param fileBody The body of the file to be stored in the bucket.
16117
16346
  */
16118
- async uploadOrUpdate(method, path21, fileBody, fileOptions) {
16347
+ async uploadOrUpdate(method, path22, fileBody, fileOptions) {
16119
16348
  var _this = this;
16120
16349
  return _this.handleOperation(async () => {
16121
16350
  let body;
@@ -16139,7 +16368,7 @@ var init_dist3 = __esm({
16139
16368
  if ((typeof ReadableStream !== "undefined" && body instanceof ReadableStream || body && typeof body === "object" && "pipe" in body && typeof body.pipe === "function") && !options.duplex) options.duplex = "half";
16140
16369
  }
16141
16370
  if (fileOptions === null || fileOptions === void 0 ? void 0 : fileOptions.headers) for (const [key, value] of Object.entries(fileOptions.headers)) headers = setHeader(headers, key, value);
16142
- const cleanPath = _this._removeEmptyFolders(path21);
16371
+ const cleanPath = _this._removeEmptyFolders(path22);
16143
16372
  const _path = _this._getFinalPath(cleanPath);
16144
16373
  const data = await (method == "PUT" ? put : post)(_this.fetch, `${_this.url}/object/${_path}`, body, _objectSpread22({ headers }, (options === null || options === void 0 ? void 0 : options.duplex) ? { duplex: options.duplex } : {}));
16145
16374
  return {
@@ -16201,8 +16430,8 @@ var init_dist3 = __esm({
16201
16430
  * - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
16202
16431
  * - For React Native, using either `Blob`, `File` or `FormData` does not work as intended. Upload file using `ArrayBuffer` from base64 file data instead, see example below.
16203
16432
  */
16204
- async upload(path21, fileBody, fileOptions) {
16205
- return this.uploadOrUpdate("POST", path21, fileBody, fileOptions);
16433
+ async upload(path22, fileBody, fileOptions) {
16434
+ return this.uploadOrUpdate("POST", path22, fileBody, fileOptions);
16206
16435
  }
16207
16436
  /**
16208
16437
  * Upload a file with a token generated from `createSignedUploadUrl`.
@@ -16242,9 +16471,9 @@ var init_dist3 = __esm({
16242
16471
  * - `objects` table permissions: none
16243
16472
  * - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
16244
16473
  */
16245
- async uploadToSignedUrl(path21, token, fileBody, fileOptions) {
16474
+ async uploadToSignedUrl(path22, token, fileBody, fileOptions) {
16246
16475
  var _this3 = this;
16247
- const cleanPath = _this3._removeEmptyFolders(path21);
16476
+ const cleanPath = _this3._removeEmptyFolders(path22);
16248
16477
  const _path = _this3._getFinalPath(cleanPath);
16249
16478
  const url = new URL(_this3.url + `/object/upload/sign/${_path}`);
16250
16479
  url.searchParams.set("token", token);
@@ -16313,10 +16542,10 @@ var init_dist3 = __esm({
16313
16542
  * - `objects` table permissions: `insert`
16314
16543
  * - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
16315
16544
  */
16316
- async createSignedUploadUrl(path21, options) {
16545
+ async createSignedUploadUrl(path22, options) {
16317
16546
  var _this4 = this;
16318
16547
  return _this4.handleOperation(async () => {
16319
- let _path = _this4._getFinalPath(path21);
16548
+ let _path = _this4._getFinalPath(path22);
16320
16549
  const headers = _objectSpread22({}, _this4.headers);
16321
16550
  if (options === null || options === void 0 ? void 0 : options.upsert) headers["x-upsert"] = "true";
16322
16551
  const data = await post(_this4.fetch, `${_this4.url}/object/upload/sign/${_path}`, {}, { headers });
@@ -16325,7 +16554,7 @@ var init_dist3 = __esm({
16325
16554
  if (!token) throw new StorageError("No token returned by API");
16326
16555
  return {
16327
16556
  signedUrl: url.toString(),
16328
- path: path21,
16557
+ path: path22,
16329
16558
  token
16330
16559
  };
16331
16560
  });
@@ -16385,8 +16614,8 @@ var init_dist3 = __esm({
16385
16614
  * - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
16386
16615
  * - For React Native, using either `Blob`, `File` or `FormData` does not work as intended. Update file using `ArrayBuffer` from base64 file data instead, see example below.
16387
16616
  */
16388
- async update(path21, fileBody, fileOptions) {
16389
- return this.uploadOrUpdate("PUT", path21, fileBody, fileOptions);
16617
+ async update(path22, fileBody, fileOptions) {
16618
+ return this.uploadOrUpdate("PUT", path22, fileBody, fileOptions);
16390
16619
  }
16391
16620
  /**
16392
16621
  * Moves an existing file to a new path in the same bucket.
@@ -16537,10 +16766,10 @@ var init_dist3 = __esm({
16537
16766
  * - `objects` table permissions: `select`
16538
16767
  * - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
16539
16768
  */
16540
- async createSignedUrl(path21, expiresIn, options) {
16769
+ async createSignedUrl(path22, expiresIn, options) {
16541
16770
  var _this8 = this;
16542
16771
  return _this8.handleOperation(async () => {
16543
- let _path = _this8._getFinalPath(path21);
16772
+ let _path = _this8._getFinalPath(path22);
16544
16773
  const hasTransform = typeof (options === null || options === void 0 ? void 0 : options.transform) === "object" && options.transform !== null && Object.keys(options.transform).length > 0;
16545
16774
  let data = await post(_this8.fetch, `${_this8.url}/object/sign/${_path}`, _objectSpread22({ expiresIn }, hasTransform ? { transform: options.transform } : {}), { headers: _this8.headers });
16546
16775
  const query = new URLSearchParams();
@@ -16676,13 +16905,13 @@ var init_dist3 = __esm({
16676
16905
  * - `objects` table permissions: `select`
16677
16906
  * - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
16678
16907
  */
16679
- download(path21, options, parameters) {
16908
+ download(path22, options, parameters) {
16680
16909
  const renderPath = typeof (options === null || options === void 0 ? void 0 : options.transform) === "object" && options.transform !== null && Object.keys(options.transform).length > 0 ? "render/image/authenticated" : "object";
16681
16910
  const query = new URLSearchParams();
16682
16911
  if (options === null || options === void 0 ? void 0 : options.transform) this.applyTransformOptsToQuery(query, options.transform);
16683
16912
  if ((options === null || options === void 0 ? void 0 : options.cacheNonce) != null) query.set("cacheNonce", String(options.cacheNonce));
16684
16913
  const queryString = query.toString();
16685
- const _path = this._getFinalPath(path21);
16914
+ const _path = this._getFinalPath(path22);
16686
16915
  const downloadFn = () => get(this.fetch, `${this.url}/${renderPath}/${_path}${queryString ? `?${queryString}` : ""}`, {
16687
16916
  headers: this.headers,
16688
16917
  noResolveJson: true
@@ -16713,9 +16942,9 @@ var init_dist3 = __esm({
16713
16942
  * }
16714
16943
  * ```
16715
16944
  */
16716
- async info(path21) {
16945
+ async info(path22) {
16717
16946
  var _this10 = this;
16718
- const _path = _this10._getFinalPath(path21);
16947
+ const _path = _this10._getFinalPath(path22);
16719
16948
  return _this10.handleOperation(async () => {
16720
16949
  return recursiveToCamel(await get(_this10.fetch, `${_this10.url}/object/info/${_path}`, { headers: _this10.headers }));
16721
16950
  });
@@ -16736,9 +16965,9 @@ var init_dist3 = __esm({
16736
16965
  * .exists('folder/avatar1.png')
16737
16966
  * ```
16738
16967
  */
16739
- async exists(path21) {
16968
+ async exists(path22) {
16740
16969
  var _this11 = this;
16741
- const _path = _this11._getFinalPath(path21);
16970
+ const _path = _this11._getFinalPath(path22);
16742
16971
  try {
16743
16972
  await head(_this11.fetch, `${_this11.url}/object/${_path}`, { headers: _this11.headers });
16744
16973
  return {
@@ -16817,8 +17046,8 @@ var init_dist3 = __esm({
16817
17046
  * - `objects` table permissions: none
16818
17047
  * - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
16819
17048
  */
16820
- getPublicUrl(path21, options) {
16821
- const _path = this._getFinalPath(path21);
17049
+ getPublicUrl(path22, options) {
17050
+ const _path = this._getFinalPath(path22);
16822
17051
  const query = new URLSearchParams();
16823
17052
  if (options === null || options === void 0 ? void 0 : options.download) query.set("download", options.download === true ? "" : options.download);
16824
17053
  if (options === null || options === void 0 ? void 0 : options.transform) this.applyTransformOptsToQuery(query, options.transform);
@@ -16957,10 +17186,10 @@ var init_dist3 = __esm({
16957
17186
  * - `objects` table permissions: `select`
16958
17187
  * - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
16959
17188
  */
16960
- async list(path21, options, parameters) {
17189
+ async list(path22, options, parameters) {
16961
17190
  var _this13 = this;
16962
17191
  return _this13.handleOperation(async () => {
16963
- const body = _objectSpread22(_objectSpread22(_objectSpread22({}, DEFAULT_SEARCH_OPTIONS), options), {}, { prefix: path21 || "" });
17192
+ const body = _objectSpread22(_objectSpread22(_objectSpread22({}, DEFAULT_SEARCH_OPTIONS), options), {}, { prefix: path22 || "" });
16964
17193
  return await post(_this13.fetch, `${_this13.url}/object/list/${_this13.bucketId}`, body, { headers: _this13.headers }, parameters);
16965
17194
  });
16966
17195
  }
@@ -17025,11 +17254,11 @@ var init_dist3 = __esm({
17025
17254
  if (typeof Buffer !== "undefined") return Buffer.from(data).toString("base64");
17026
17255
  return btoa(data);
17027
17256
  }
17028
- _getFinalPath(path21) {
17029
- return `${this.bucketId}/${path21.replace(/^\/+/, "")}`;
17257
+ _getFinalPath(path22) {
17258
+ return `${this.bucketId}/${path22.replace(/^\/+/, "")}`;
17030
17259
  }
17031
- _removeEmptyFolders(path21) {
17032
- return path21.replace(/^\/|\/$/g, "").replace(/\/+/g, "/");
17260
+ _removeEmptyFolders(path22) {
17261
+ return path22.replace(/^\/|\/$/g, "").replace(/\/+/g, "/");
17033
17262
  }
17034
17263
  /** Modifies the `query`, appending values the from `transform` */
17035
17264
  applyTransformOptsToQuery(query, transform) {
@@ -27446,8 +27675,8 @@ __export(watch_exports, {
27446
27675
  runWatchCommand: () => runWatchCommand
27447
27676
  });
27448
27677
  import { spawn as spawn2 } from "node:child_process";
27449
- import { mkdir as mkdir8, readFile as readFile16, unlink as unlink4, writeFile as writeFile13 } from "node:fs/promises";
27450
- import { join as join19 } from "node:path";
27678
+ import { mkdir as mkdir8, readFile as readFile17, unlink as unlink4, writeFile as writeFile14 } from "node:fs/promises";
27679
+ import { join as join20 } from "node:path";
27451
27680
  async function resolveIdentity() {
27452
27681
  const found = await findCodebyplanConfig(process.cwd());
27453
27682
  const repoId = found?.contents.repo_id;
@@ -27467,18 +27696,18 @@ async function resolveIdentity() {
27467
27696
  return { repoRoot, repoId, worktreeId };
27468
27697
  }
27469
27698
  function watchDir(repoRoot) {
27470
- return join19(repoRoot, ".codebyplan", "state", "_watch");
27699
+ return join20(repoRoot, ".codebyplan", "state", "_watch");
27471
27700
  }
27472
27701
  function pidFilePath(repoRoot, worktreeId) {
27473
- return join19(watchDir(repoRoot), `${worktreeId ?? "default"}.pid`);
27702
+ return join20(watchDir(repoRoot), `${worktreeId ?? "default"}.pid`);
27474
27703
  }
27475
27704
  function healthFilePath(repoRoot, worktreeId) {
27476
- return join19(watchDir(repoRoot), `${worktreeId ?? "default"}.health.json`);
27705
+ return join20(watchDir(repoRoot), `${worktreeId ?? "default"}.health.json`);
27477
27706
  }
27478
27707
  async function handleStart(repoRoot, repoId, worktreeId, forwardArgs) {
27479
27708
  const pidFile = pidFilePath(repoRoot, worktreeId);
27480
27709
  try {
27481
- const pidStr = await readFile16(pidFile, "utf-8");
27710
+ const pidStr = await readFile17(pidFile, "utf-8");
27482
27711
  const pid = parseInt(pidStr.trim(), 10);
27483
27712
  if (!isNaN(pid)) {
27484
27713
  try {
@@ -27498,7 +27727,7 @@ async function handleStart(repoRoot, repoId, worktreeId, forwardArgs) {
27498
27727
  }
27499
27728
  const lockFile = `${pidFile}.lock`;
27500
27729
  try {
27501
- await writeFile13(lockFile, String(process.pid), { flag: "wx" });
27730
+ await writeFile14(lockFile, String(process.pid), { flag: "wx" });
27502
27731
  } catch {
27503
27732
  process.stdout.write("watch: start already in progress\n");
27504
27733
  process.exit(0);
@@ -27515,7 +27744,7 @@ async function handleStart(repoRoot, repoId, worktreeId, forwardArgs) {
27515
27744
  child.unref();
27516
27745
  if (child.pid !== void 0) {
27517
27746
  try {
27518
- await writeFile13(pidFile, String(child.pid), "utf-8");
27747
+ await writeFile14(pidFile, String(child.pid), "utf-8");
27519
27748
  } catch {
27520
27749
  }
27521
27750
  process.stdout.write(`watch: daemon started (pid ${child.pid})
@@ -27535,7 +27764,7 @@ async function handleStop(repoRoot, worktreeId) {
27535
27764
  const healthFile = healthFilePath(repoRoot, worktreeId);
27536
27765
  let pid;
27537
27766
  try {
27538
- const pidStr = await readFile16(pidFile, "utf-8");
27767
+ const pidStr = await readFile17(pidFile, "utf-8");
27539
27768
  pid = parseInt(pidStr.trim(), 10);
27540
27769
  if (isNaN(pid)) throw new Error("invalid pid in pidfile");
27541
27770
  } catch (err) {
@@ -27571,7 +27800,7 @@ async function handleStatus(repoRoot, worktreeId, subArgs) {
27571
27800
  let pid = null;
27572
27801
  let alive = false;
27573
27802
  try {
27574
- const pidStr = await readFile16(pidFile, "utf-8");
27803
+ const pidStr = await readFile17(pidFile, "utf-8");
27575
27804
  const parsed = parseInt(pidStr.trim(), 10);
27576
27805
  if (!isNaN(parsed)) {
27577
27806
  pid = parsed;
@@ -27586,7 +27815,7 @@ async function handleStatus(repoRoot, worktreeId, subArgs) {
27586
27815
  }
27587
27816
  let health = null;
27588
27817
  try {
27589
- const raw = await readFile16(healthFile, "utf-8");
27818
+ const raw = await readFile17(healthFile, "utf-8");
27590
27819
  health = JSON.parse(raw);
27591
27820
  } catch {
27592
27821
  }
@@ -27610,7 +27839,7 @@ async function handleRun(repoRoot, repoId, worktreeId) {
27610
27839
  const healthFile = healthFilePath(repoRoot, worktreeId);
27611
27840
  try {
27612
27841
  await mkdir8(watchDir(repoRoot), { recursive: true });
27613
- await writeFile13(pidFile, String(process.pid), "utf-8");
27842
+ await writeFile14(pidFile, String(process.pid), "utf-8");
27614
27843
  } catch (err) {
27615
27844
  process.stderr.write(
27616
27845
  `watch: could not write pidfile: ${err instanceof Error ? err.message : String(err)}
@@ -27659,7 +27888,7 @@ async function handleRun(repoRoot, repoId, worktreeId) {
27659
27888
  worktree_id: worktreeId ?? null,
27660
27889
  repo_id: repoId
27661
27890
  };
27662
- void writeFile13(
27891
+ void writeFile14(
27663
27892
  healthFile,
27664
27893
  JSON.stringify(data, null, 2) + "\n",
27665
27894
  "utf-8"
@@ -27748,8 +27977,8 @@ var init_watch = __esm({
27748
27977
  });
27749
27978
 
27750
27979
  // src/lib/state-client.ts
27751
- async function backendRequest(method, path21, body) {
27752
- const url = `${getBackendBase()}${path21}`;
27980
+ async function backendRequest(method, path22, body) {
27981
+ const url = `${getBackendBase()}${path22}`;
27753
27982
  const auth = await getAuthHeaders();
27754
27983
  const res = await fetch(url, {
27755
27984
  method,
@@ -27761,7 +27990,7 @@ async function backendRequest(method, path21, body) {
27761
27990
  signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS2)
27762
27991
  });
27763
27992
  if (!res.ok) {
27764
- let message = `Backend ${method} ${path21} failed with status ${res.status}`;
27993
+ let message = `Backend ${method} ${path22} failed with status ${res.status}`;
27765
27994
  try {
27766
27995
  const errBody = await res.json();
27767
27996
  const msg = typeof errBody.message === "string" ? errBody.message : typeof errBody.error === "string" ? errBody.error : void 0;
@@ -27775,11 +28004,11 @@ async function backendRequest(method, path21, body) {
27775
28004
  }
27776
28005
  return res.json();
27777
28006
  }
27778
- async function apiBackendPost(path21, body) {
27779
- return backendRequest("POST", path21, body);
28007
+ async function apiBackendPost(path22, body) {
28008
+ return backendRequest("POST", path22, body);
27780
28009
  }
27781
- async function apiBackendPatch(path21, body) {
27782
- return backendRequest("PATCH", path21, body);
28010
+ async function apiBackendPatch(path22, body) {
28011
+ return backendRequest("PATCH", path22, body);
27783
28012
  }
27784
28013
  var REQUEST_TIMEOUT_MS2, BackendError;
27785
28014
  var init_state_client = __esm({
@@ -28539,7 +28768,7 @@ __export(round_exports, {
28539
28768
  setRetryDelayMs: () => setRetryDelayMs
28540
28769
  });
28541
28770
  import { access as access4 } from "node:fs/promises";
28542
- import { join as join20 } from "node:path";
28771
+ import { join as join21 } from "node:path";
28543
28772
  import { execSync as execSync3 } from "node:child_process";
28544
28773
  function setRetryDelayMs(ms) {
28545
28774
  RETRY_DELAY_MS = ms;
@@ -28919,7 +29148,7 @@ async function runRoundSyncApprovals(args) {
28919
29148
  "sync-approvals: git status failed; proceeding with empty diff\n"
28920
29149
  );
28921
29150
  }
28922
- const hookPath = join20(
29151
+ const hookPath = join21(
28923
29152
  repoRoot,
28924
29153
  ".claude",
28925
29154
  "hooks",
@@ -29588,8 +29817,8 @@ var init_session = __esm({
29588
29817
  });
29589
29818
 
29590
29819
  // src/lib/migrate-branch-model.ts
29591
- import { readFile as readFile17, writeFile as writeFile14 } from "node:fs/promises";
29592
- import { join as join21 } from "node:path";
29820
+ import { readFile as readFile18, writeFile as writeFile15 } from "node:fs/promises";
29821
+ import { join as join22 } from "node:path";
29593
29822
  import { execSync as execSync4 } from "node:child_process";
29594
29823
  function assertValidBranchName(branch) {
29595
29824
  if (!/^[a-zA-Z0-9/_.-]+$/.test(branch)) {
@@ -29599,7 +29828,7 @@ function assertValidBranchName(branch) {
29599
29828
  }
29600
29829
  }
29601
29830
  async function readJsonFile2(filePath) {
29602
- const raw = await readFile17(filePath, "utf-8");
29831
+ const raw = await readFile18(filePath, "utf-8");
29603
29832
  const parsed = JSON.parse(raw);
29604
29833
  if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
29605
29834
  throw new Error(`${filePath} does not contain a JSON object`);
@@ -29668,12 +29897,12 @@ async function runBranchMigration(opts) {
29668
29897
  if (found) {
29669
29898
  if (found.path.endsWith("/repo.json")) {
29670
29899
  const dir = found.path.slice(0, found.path.lastIndexOf("/"));
29671
- configPath = join21(dir, "git.json");
29900
+ configPath = join22(dir, "git.json");
29672
29901
  } else {
29673
29902
  configPath = found.path;
29674
29903
  }
29675
29904
  } else {
29676
- configPath = join21(cwd, ".codebyplan", "git.json");
29905
+ configPath = join22(cwd, ".codebyplan", "git.json");
29677
29906
  }
29678
29907
  let fileRaw;
29679
29908
  let fileParsed;
@@ -29747,7 +29976,7 @@ async function runBranchMigration(opts) {
29747
29976
  const updatedParsed = { ...fileParsed, branch_config: after };
29748
29977
  const newJson = JSON.stringify(updatedParsed, null, 2) + "\n";
29749
29978
  if (newJson !== fileRaw) {
29750
- await writeFile14(configPath, newJson, "utf-8");
29979
+ await writeFile15(configPath, newJson, "utf-8");
29751
29980
  }
29752
29981
  }
29753
29982
  return {
@@ -29768,10 +29997,10 @@ var init_migrate_branch_model = __esm({
29768
29997
 
29769
29998
  // src/lib/supabase.ts
29770
29999
  import * as fs5 from "node:fs";
29771
- import * as path6 from "node:path";
29772
- import { spawnSync as spawnSync5 } from "node:child_process";
30000
+ import * as path7 from "node:path";
30001
+ import { spawnSync as spawnSync6 } from "node:child_process";
29773
30002
  function defaultRun(cmd, args) {
29774
- const result = spawnSync5(cmd, args, {
30003
+ const result = spawnSync6(cmd, args, {
29775
30004
  encoding: "utf-8",
29776
30005
  stdio: ["pipe", "pipe", "pipe"]
29777
30006
  });
@@ -29848,7 +30077,7 @@ function extractStampToken(filename) {
29848
30077
  }
29849
30078
  function readShipmentConfig(cwd) {
29850
30079
  const dir = cwd ?? process.cwd();
29851
- const obj = readJsonFile3(path6.join(dir, ".codebyplan", "shipment.json"));
30080
+ const obj = readJsonFile3(path7.join(dir, ".codebyplan", "shipment.json"));
29852
30081
  if (!obj) return { parentRef: null, previewBranches: [] };
29853
30082
  const section = getSupabaseSection(obj);
29854
30083
  if (!section) return { parentRef: null, previewBranches: [] };
@@ -29872,7 +30101,7 @@ function readShipmentConfig(cwd) {
29872
30101
  }
29873
30102
  function readGitConfig(cwd) {
29874
30103
  const dir = cwd ?? process.cwd();
29875
- const obj = readJsonFile3(path6.join(dir, ".codebyplan", "git.json"));
30104
+ const obj = readJsonFile3(path7.join(dir, ".codebyplan", "git.json"));
29876
30105
  if (!obj) return { ...GIT_DEFAULTS };
29877
30106
  const bc = obj["branch_config"];
29878
30107
  if (typeof bc !== "object" || bc === null || Array.isArray(bc)) {
@@ -29893,7 +30122,7 @@ function readGitConfig(cwd) {
29893
30122
  }
29894
30123
  function readDbPaths(cwd) {
29895
30124
  const dir = cwd ?? process.cwd();
29896
- const obj = readJsonFile3(path6.join(dir, ".codebyplan", "shipment.json"));
30125
+ const obj = readJsonFile3(path7.join(dir, ".codebyplan", "shipment.json"));
29897
30126
  if (!obj) return [...DEFAULT_DB_PATHS];
29898
30127
  const section = getSupabaseSection(obj);
29899
30128
  if (!section) return [...DEFAULT_DB_PATHS];
@@ -29933,7 +30162,7 @@ function generateMonotonicTimestamp(opts = {}) {
29933
30162
  const cwd = opts.cwd ?? process.cwd();
29934
30163
  const now = opts.now ?? /* @__PURE__ */ new Date();
29935
30164
  const listDir = opts.listDir ?? defaultListDir;
29936
- const migrationsDir = path6.join(cwd, "supabase", "migrations");
30165
+ const migrationsDir = path7.join(cwd, "supabase", "migrations");
29937
30166
  const files = listDir(migrationsDir);
29938
30167
  const existingStamps = /* @__PURE__ */ new Set();
29939
30168
  for (const file of files) {
@@ -30080,9 +30309,9 @@ var init_supabase = __esm({
30080
30309
  });
30081
30310
 
30082
30311
  // src/lib/branch-checkout.ts
30083
- import { spawnSync as spawnSync6 } from "node:child_process";
30312
+ import { spawnSync as spawnSync7 } from "node:child_process";
30084
30313
  function defaultRun2(cmd, args, cwd) {
30085
- const result = spawnSync6(cmd, args, {
30314
+ const result = spawnSync7(cmd, args, {
30086
30315
  cwd,
30087
30316
  encoding: "utf-8",
30088
30317
  stdio: ["pipe", "pipe", "pipe"]
@@ -30332,9 +30561,9 @@ var init_branch = __esm({
30332
30561
  });
30333
30562
 
30334
30563
  // src/lib/bump.ts
30335
- import { readFile as readFile18, writeFile as writeFile15, access as access5, readdir as readdir4 } from "node:fs/promises";
30336
- import { join as join23, relative as relative5, resolve as resolve3 } from "node:path";
30337
- import { spawnSync as spawnSync7 } from "node:child_process";
30564
+ import { readFile as readFile19, writeFile as writeFile16, access as access5, readdir as readdir4 } from "node:fs/promises";
30565
+ import { join as join24, relative as relative5, resolve as resolve3 } from "node:path";
30566
+ import { spawnSync as spawnSync8 } from "node:child_process";
30338
30567
  function parsePnpmWorkspaceGlobs(raw) {
30339
30568
  const lines = raw.split("\n");
30340
30569
  const globs = [];
@@ -30363,18 +30592,18 @@ async function expandGlob(cwd, glob) {
30363
30592
  if (parts.length !== 2 || parts[1] !== "*") {
30364
30593
  return [];
30365
30594
  }
30366
- const parentDir = join23(cwd, parts[0]);
30595
+ const parentDir = join24(cwd, parts[0]);
30367
30596
  let dirs;
30368
30597
  try {
30369
30598
  const entries = await readdir4(parentDir, { withFileTypes: true });
30370
- dirs = entries.filter((e) => e.isDirectory()).map((e) => join23(parentDir, e.name));
30599
+ dirs = entries.filter((e) => e.isDirectory()).map((e) => join24(parentDir, e.name));
30371
30600
  } catch {
30372
30601
  return [];
30373
30602
  }
30374
30603
  const results = [];
30375
30604
  for (const dir of dirs) {
30376
30605
  try {
30377
- await access5(join23(dir, "package.json"));
30606
+ await access5(join24(dir, "package.json"));
30378
30607
  results.push(dir);
30379
30608
  } catch {
30380
30609
  }
@@ -30385,7 +30614,7 @@ async function buildPackageMap(cwd) {
30385
30614
  const map = /* @__PURE__ */ new Map();
30386
30615
  let globs = [];
30387
30616
  try {
30388
- const raw = await readFile18(join23(cwd, "pnpm-workspace.yaml"), "utf-8");
30617
+ const raw = await readFile19(join24(cwd, "pnpm-workspace.yaml"), "utf-8");
30389
30618
  globs = parsePnpmWorkspaceGlobs(raw);
30390
30619
  } catch {
30391
30620
  }
@@ -30393,7 +30622,7 @@ async function buildPackageMap(cwd) {
30393
30622
  const dirs = await expandGlob(cwd, glob);
30394
30623
  for (const dir of dirs) {
30395
30624
  try {
30396
- const pkgRaw = await readFile18(join23(dir, "package.json"), "utf-8");
30625
+ const pkgRaw = await readFile19(join24(dir, "package.json"), "utf-8");
30397
30626
  const pkg = JSON.parse(pkgRaw);
30398
30627
  const name = pkg.name ?? relative5(cwd, dir);
30399
30628
  map.set(dir, { name, dir });
@@ -30471,7 +30700,7 @@ function compareSemver(a, b) {
30471
30700
  return 0;
30472
30701
  }
30473
30702
  function gitShowFile(cwd, ref, relPath) {
30474
- const result = spawnSync7("git", ["show", `${ref}:${relPath}`], {
30703
+ const result = spawnSync8("git", ["show", `${ref}:${relPath}`], {
30475
30704
  cwd,
30476
30705
  encoding: "utf-8",
30477
30706
  stdio: ["pipe", "pipe", "pipe"]
@@ -30512,7 +30741,7 @@ function injectVersion(raw, nextVersion, filePath) {
30512
30741
  async function prependChangelog(changelogPath, packageName, nextVersion, now, dryRun) {
30513
30742
  let existing;
30514
30743
  try {
30515
- existing = await readFile18(changelogPath, "utf-8");
30744
+ existing = await readFile19(changelogPath, "utf-8");
30516
30745
  } catch {
30517
30746
  return false;
30518
30747
  }
@@ -30525,7 +30754,7 @@ async function prependChangelog(changelogPath, packageName, nextVersion, now, dr
30525
30754
  `;
30526
30755
  const updated = entry + existing;
30527
30756
  if (!dryRun) {
30528
- await writeFile15(changelogPath, updated, "utf-8");
30757
+ await writeFile16(changelogPath, updated, "utf-8");
30529
30758
  }
30530
30759
  return true;
30531
30760
  }
@@ -30536,7 +30765,7 @@ async function runBump(opts) {
30536
30765
  const prereleaseId = opts?.prereleaseId;
30537
30766
  const baseBranch = await readBaseBranch(cwd);
30538
30767
  const baseRef = resolveBaseRef(cwd, baseBranch);
30539
- const diffResult = spawnSync7(
30768
+ const diffResult = spawnSync8(
30540
30769
  "git",
30541
30770
  ["diff", "--name-only", `${baseRef}...HEAD`],
30542
30771
  {
@@ -30552,7 +30781,7 @@ async function runBump(opts) {
30552
30781
  const changedFiles = (diffResult.stdout ?? "").trim().split("\n").filter(Boolean).map((f) => resolve3(cwd, f));
30553
30782
  const packageMap = await buildPackageMap(cwd);
30554
30783
  const packageDirs = Array.from(packageMap.keys());
30555
- const rootPkgPath = join23(cwd, "package.json");
30784
+ const rootPkgPath = join24(cwd, "package.json");
30556
30785
  const changedPackageDirs = /* @__PURE__ */ new Set();
30557
30786
  for (const absFile of changedFiles) {
30558
30787
  const owner = findOwningPackage(absFile, packageDirs);
@@ -30563,19 +30792,19 @@ async function runBump(opts) {
30563
30792
  const entries = [];
30564
30793
  for (const pkgDir of changedPackageDirs) {
30565
30794
  const pkgInfo = packageMap.get(pkgDir);
30566
- const pkgJsonPath = join23(pkgDir, "package.json");
30795
+ const pkgJsonPath = join24(pkgDir, "package.json");
30567
30796
  if (pkgJsonPath === rootPkgPath) continue;
30568
30797
  const versionFileCandidates = [
30569
30798
  { abs: pkgJsonPath, rel: relative5(cwd, pkgJsonPath).replace(/\\/g, "/") }
30570
30799
  ];
30571
- const tauriConfPath = join23(pkgDir, "src-tauri", "tauri.conf.json");
30800
+ const tauriConfPath = join24(pkgDir, "src-tauri", "tauri.conf.json");
30572
30801
  const tauriRelPath = relative5(cwd, tauriConfPath).replace(/\\/g, "/");
30573
30802
  try {
30574
30803
  await access5(tauriConfPath);
30575
30804
  versionFileCandidates.push({ abs: tauriConfPath, rel: tauriRelPath });
30576
30805
  } catch {
30577
30806
  }
30578
- const appJsonPath = join23(pkgDir, "app.json");
30807
+ const appJsonPath = join24(pkgDir, "app.json");
30579
30808
  const appJsonRelPath = relative5(cwd, appJsonPath).replace(/\\/g, "/");
30580
30809
  try {
30581
30810
  await access5(appJsonPath);
@@ -30584,7 +30813,7 @@ async function runBump(opts) {
30584
30813
  }
30585
30814
  let currentPkgJsonRaw;
30586
30815
  try {
30587
- currentPkgJsonRaw = await readFile18(pkgJsonPath, "utf-8");
30816
+ currentPkgJsonRaw = await readFile19(pkgJsonPath, "utf-8");
30588
30817
  } catch (err) {
30589
30818
  console.warn(
30590
30819
  `runBump: could not read ${pkgJsonPath}: ${err instanceof Error ? err.message : String(err)}`
@@ -30629,7 +30858,7 @@ async function runBump(opts) {
30629
30858
  for (const { abs, rel } of versionFileCandidates) {
30630
30859
  let raw;
30631
30860
  try {
30632
- raw = await readFile18(abs, "utf-8");
30861
+ raw = await readFile19(abs, "utf-8");
30633
30862
  } catch {
30634
30863
  continue;
30635
30864
  }
@@ -30643,11 +30872,11 @@ async function runBump(opts) {
30643
30872
  }
30644
30873
  const updated = injectVersion(raw, nextVersion, abs);
30645
30874
  if (!dryRun) {
30646
- await writeFile15(abs, updated, "utf-8");
30875
+ await writeFile16(abs, updated, "utf-8");
30647
30876
  }
30648
30877
  updatedVersionFiles.push(rel);
30649
30878
  }
30650
- const changelogPath = join23(pkgDir, "CHANGELOG.md");
30879
+ const changelogPath = join24(pkgDir, "CHANGELOG.md");
30651
30880
  const changelogUpdated = await prependChangelog(
30652
30881
  changelogPath,
30653
30882
  pkgInfo.name,
@@ -30757,7 +30986,7 @@ var init_bump2 = __esm({
30757
30986
  });
30758
30987
 
30759
30988
  // src/lib/ship.ts
30760
- import { execSync as execSync5, spawnSync as spawnSync8 } from "node:child_process";
30989
+ import { execSync as execSync5, spawnSync as spawnSync9 } from "node:child_process";
30761
30990
  import { relative as relative6 } from "node:path";
30762
30991
  function assertValidBranchName2(branch, label) {
30763
30992
  if (!/^[a-zA-Z0-9/_.-]+$/.test(branch)) {
@@ -30789,7 +31018,7 @@ async function pollChecks(feat, timeoutSeconds, cwd, _sleepMs = (ms) => new Prom
30789
31018
  let totalGhErrors = 0;
30790
31019
  let iteration = 0;
30791
31020
  while (Date.now() < deadline) {
30792
- const ghResult = spawnSync8(
31021
+ const ghResult = spawnSync9(
30793
31022
  "gh",
30794
31023
  ["pr", "checks", feat, "--json", "name,state,bucket"],
30795
31024
  {
@@ -30940,7 +31169,7 @@ ${statusOut.trim()}`
30940
31169
  ...e.changelogUpdated ? [relative6(cwd, e.packageDir).replace(/\\/g, "/") + "/CHANGELOG.md"] : []
30941
31170
  ]);
30942
31171
  if (toStage.length > 0) {
30943
- const addResult = spawnSync8("git", ["add", "--", ...toStage], {
31172
+ const addResult = spawnSync9("git", ["add", "--", ...toStage], {
30944
31173
  cwd,
30945
31174
  encoding: "utf-8",
30946
31175
  stdio: ["pipe", "pipe", "pipe"]
@@ -30950,13 +31179,13 @@ ${statusOut.trim()}`
30950
31179
  `Failed to stage bump files: ${addResult.stderr?.trim() ?? addResult.error?.message}`
30951
31180
  );
30952
31181
  }
30953
- const commitResult = spawnSync8(
31182
+ const commitResult = spawnSync9(
30954
31183
  "git",
30955
31184
  ["commit", "-m", "chore(release): bump versions"],
30956
31185
  { cwd, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
30957
31186
  );
30958
31187
  if (commitResult.status !== 0 || commitResult.error) {
30959
- spawnSync8(
31188
+ spawnSync9(
30960
31189
  "git",
30961
31190
  ["restore", "--staged", "--worktree", "--", ...toStage],
30962
31191
  {
@@ -31001,7 +31230,7 @@ ${statusOut.trim()}`
31001
31230
  } else {
31002
31231
  createArgs.push("--body", defaultPrBody(feat, base));
31003
31232
  }
31004
- const createResult = spawnSync8("gh", createArgs, {
31233
+ const createResult = spawnSync9("gh", createArgs, {
31005
31234
  cwd,
31006
31235
  encoding: "utf-8",
31007
31236
  stdio: ["pipe", "pipe", "pipe"]
@@ -31032,7 +31261,7 @@ ${statusOut.trim()}`
31032
31261
  });
31033
31262
  let mergeCommit = null;
31034
31263
  try {
31035
- const prViewResult = spawnSync8(
31264
+ const prViewResult = spawnSync9(
31036
31265
  "gh",
31037
31266
  ["pr", "view", feat, "--json", "state,mergeCommit"],
31038
31267
  {
@@ -31190,14 +31419,14 @@ var init_ship2 = __esm({
31190
31419
 
31191
31420
  // src/lib/scaffold-publish-workflow.ts
31192
31421
  import * as fs6 from "node:fs";
31193
- import * as path7 from "node:path";
31422
+ import * as path8 from "node:path";
31194
31423
  async function runScaffoldPublishWorkflow(opts) {
31195
31424
  await Promise.resolve();
31196
31425
  const dryRun = opts?.dryRun ?? false;
31197
31426
  const force = opts?.force ?? false;
31198
- const projectDir = path7.resolve(opts?.projectDir ?? process.cwd());
31427
+ const projectDir = path8.resolve(opts?.projectDir ?? process.cwd());
31199
31428
  const templatesDir = opts?.templatesDir ?? resolveTemplatesDir();
31200
- const templatePath = path7.join(
31429
+ const templatePath = path8.join(
31201
31430
  templatesDir,
31202
31431
  "github-workflows",
31203
31432
  "publish.yml"
@@ -31208,7 +31437,7 @@ async function runScaffoldPublishWorkflow(opts) {
31208
31437
  );
31209
31438
  }
31210
31439
  const templateContent = fs6.readFileSync(templatePath, "utf-8");
31211
- const targetPath = path7.join(
31440
+ const targetPath = path8.join(
31212
31441
  projectDir,
31213
31442
  ".github",
31214
31443
  "workflows",
@@ -31232,7 +31461,7 @@ async function runScaffoldPublishWorkflow(opts) {
31232
31461
  );
31233
31462
  }
31234
31463
  }
31235
- const targetDir = path7.dirname(targetPath);
31464
+ const targetDir = path8.dirname(targetPath);
31236
31465
  fs6.mkdirSync(targetDir, { recursive: true });
31237
31466
  fs6.writeFileSync(targetPath, templateContent, "utf-8");
31238
31467
  return { status: "written", path: targetPath };
@@ -31329,7 +31558,7 @@ var init_atomic_write = __esm({
31329
31558
 
31330
31559
  // src/lib/ci-init.ts
31331
31560
  import * as fs8 from "node:fs";
31332
- import * as path8 from "node:path";
31561
+ import * as path9 from "node:path";
31333
31562
  function tryReadJson(filePath) {
31334
31563
  try {
31335
31564
  return JSON.parse(fs8.readFileSync(filePath, "utf-8"));
@@ -31351,27 +31580,27 @@ function hasDevDep(pkg, name) {
31351
31580
  function detectPlatforms(projectDir) {
31352
31581
  const detected = /* @__PURE__ */ new Set();
31353
31582
  const dirsToScan = [projectDir];
31354
- const appsDir = path8.join(projectDir, "apps");
31583
+ const appsDir = path9.join(projectDir, "apps");
31355
31584
  if (fs8.existsSync(appsDir)) {
31356
31585
  try {
31357
31586
  const appsEntries = fs8.readdirSync(appsDir, { withFileTypes: true });
31358
31587
  for (const entry of appsEntries) {
31359
31588
  if (entry.isDirectory()) {
31360
- dirsToScan.push(path8.join(appsDir, entry.name));
31589
+ dirsToScan.push(path9.join(appsDir, entry.name));
31361
31590
  }
31362
31591
  }
31363
31592
  } catch {
31364
31593
  }
31365
31594
  }
31366
31595
  for (const dir of dirsToScan) {
31367
- const pkg = tryReadJson(path8.join(dir, "package.json"));
31368
- if (fs8.existsSync(path8.join(dir, "next.config.ts")) || fs8.existsSync(path8.join(dir, "next.config.js")) || fs8.existsSync(path8.join(dir, "next.config.mjs"))) {
31596
+ const pkg = tryReadJson(path9.join(dir, "package.json"));
31597
+ if (fs8.existsSync(path9.join(dir, "next.config.ts")) || fs8.existsSync(path9.join(dir, "next.config.js")) || fs8.existsSync(path9.join(dir, "next.config.mjs"))) {
31369
31598
  detected.add("next_js");
31370
31599
  }
31371
31600
  if (hasDep(pkg, "@nestjs/core")) {
31372
31601
  detected.add("nestjs");
31373
31602
  }
31374
- if (fs8.existsSync(path8.join(dir, "tauri.conf.json")) || fs8.existsSync(path8.join(dir, "src-tauri"))) {
31603
+ if (fs8.existsSync(path9.join(dir, "tauri.conf.json")) || fs8.existsSync(path9.join(dir, "src-tauri"))) {
31375
31604
  detected.add("tauri");
31376
31605
  }
31377
31606
  if (hasDevDep(pkg, "@types/vscode")) {
@@ -31382,7 +31611,7 @@ function detectPlatforms(projectDir) {
31382
31611
  detected.add("expo");
31383
31612
  }
31384
31613
  }
31385
- const packagesDir = path8.join(projectDir, "packages");
31614
+ const packagesDir = path9.join(projectDir, "packages");
31386
31615
  if (fs8.existsSync(packagesDir)) {
31387
31616
  try {
31388
31617
  const pkgEntries = fs8.readdirSync(packagesDir, { withFileTypes: true });
@@ -31419,10 +31648,10 @@ function buildDefaultCiConfig(platforms) {
31419
31648
  }
31420
31649
  async function runCiInit(opts) {
31421
31650
  await Promise.resolve();
31422
- const projectDir = path8.resolve(opts?.projectDir ?? process.cwd());
31651
+ const projectDir = path9.resolve(opts?.projectDir ?? process.cwd());
31423
31652
  const dryRun = opts?.dryRun ?? false;
31424
31653
  const force = opts?.force ?? false;
31425
- const ciPath = path8.join(projectDir, ".codebyplan", "ci.json");
31654
+ const ciPath = path9.join(projectDir, ".codebyplan", "ci.json");
31426
31655
  const platforms = detectPlatforms(projectDir);
31427
31656
  if (dryRun) {
31428
31657
  return { status: "dry_run", path: ciPath, platforms };
@@ -31467,7 +31696,7 @@ async function runCiInit(opts) {
31467
31696
  platforms: newPlatforms.length > 0 ? newPlatforms : platforms
31468
31697
  };
31469
31698
  }
31470
- const codebyplanDir = path8.join(projectDir, ".codebyplan");
31699
+ const codebyplanDir = path9.join(projectDir, ".codebyplan");
31471
31700
  fs8.mkdirSync(codebyplanDir, { recursive: true });
31472
31701
  writeJsonAtomic(ciPath, newConfig);
31473
31702
  return { status: "written", path: ciPath, platforms };
@@ -31676,7 +31905,7 @@ var init_ci_init = __esm({
31676
31905
 
31677
31906
  // src/lib/scaffold-ci-workflow.ts
31678
31907
  import * as fs9 from "node:fs";
31679
- import * as path9 from "node:path";
31908
+ import * as path10 from "node:path";
31680
31909
  function substituteTokens(template, tokens) {
31681
31910
  let result = template;
31682
31911
  for (const [token, value] of Object.entries(tokens)) {
@@ -31686,7 +31915,7 @@ function substituteTokens(template, tokens) {
31686
31915
  }
31687
31916
  function detectPnpmVersionFromPackageJson(projectDir) {
31688
31917
  try {
31689
- const pkgPath = path9.join(projectDir, "package.json");
31918
+ const pkgPath = path10.join(projectDir, "package.json");
31690
31919
  const raw = fs9.readFileSync(pkgPath, "utf-8");
31691
31920
  const pkg = JSON.parse(raw);
31692
31921
  const pm = pkg.packageManager;
@@ -31703,7 +31932,7 @@ function detectPnpmVersionFromPackageJson(projectDir) {
31703
31932
  }
31704
31933
  function detectStrictEnforcedFromCiJson(projectDir) {
31705
31934
  try {
31706
- const ciJsonPath = path9.join(projectDir, ".codebyplan", "ci.json");
31935
+ const ciJsonPath = path10.join(projectDir, ".codebyplan", "ci.json");
31707
31936
  const raw = fs9.readFileSync(ciJsonPath, "utf-8");
31708
31937
  const parsed = JSON.parse(raw);
31709
31938
  return parsed.workflow?.strict_check_enforced === true;
@@ -31715,12 +31944,12 @@ async function runScaffoldCiWorkflow(opts) {
31715
31944
  await Promise.resolve();
31716
31945
  const dryRun = opts?.dryRun ?? false;
31717
31946
  const force = opts?.force ?? false;
31718
- const projectDir = path9.resolve(opts?.projectDir ?? process.cwd());
31947
+ const projectDir = path10.resolve(opts?.projectDir ?? process.cwd());
31719
31948
  const pnpmVersion = opts?.pnpmVersion ?? detectPnpmVersionFromPackageJson(projectDir);
31720
31949
  const nodeVersion = opts?.nodeVersion ?? "22";
31721
31950
  const strictEnforced = opts?.strictEnforced ?? detectStrictEnforcedFromCiJson(projectDir);
31722
31951
  const templatesDir = opts?.templatesDir ?? resolveTemplatesDir();
31723
- const templatePath = path9.join(templatesDir, "github-workflows", "ci.yml");
31952
+ const templatePath = path10.join(templatesDir, "github-workflows", "ci.yml");
31724
31953
  if (!fs9.existsSync(templatePath)) {
31725
31954
  throw new Error(
31726
31955
  `scaffold-ci-workflow: template not found at ${templatePath}`
@@ -31733,7 +31962,7 @@ async function runScaffoldCiWorkflow(opts) {
31733
31962
  STRICT_NAME_SUFFIX: strictEnforced ? "" : " (report-only)",
31734
31963
  STRICT_CONTINUE_ON_ERROR_LINE: strictEnforced ? "" : "\n continue-on-error: true"
31735
31964
  });
31736
- const targetPath = path9.join(projectDir, ".github", "workflows", "ci.yml");
31965
+ const targetPath = path10.join(projectDir, ".github", "workflows", "ci.yml");
31737
31966
  if (dryRun) {
31738
31967
  return { status: "dry_run", path: targetPath };
31739
31968
  }
@@ -31752,7 +31981,7 @@ async function runScaffoldCiWorkflow(opts) {
31752
31981
  );
31753
31982
  }
31754
31983
  }
31755
- const targetDir = path9.dirname(targetPath);
31984
+ const targetDir = path10.dirname(targetPath);
31756
31985
  fs9.mkdirSync(targetDir, { recursive: true });
31757
31986
  const tmpPath = targetPath + ".tmp";
31758
31987
  try {
@@ -31776,10 +32005,10 @@ var init_scaffold_ci_workflow = __esm({
31776
32005
 
31777
32006
  // src/lib/gh-required-checks.ts
31778
32007
  import * as fs10 from "node:fs";
31779
- import * as path10 from "node:path";
32008
+ import * as path11 from "node:path";
31780
32009
  import { execSync as execSync6 } from "node:child_process";
31781
32010
  function readCiJson(projectDir) {
31782
- const ciPath = path10.join(projectDir, ".codebyplan", "ci.json");
32011
+ const ciPath = path11.join(projectDir, ".codebyplan", "ci.json");
31783
32012
  if (!fs10.existsSync(ciPath)) {
31784
32013
  return {
31785
32014
  platforms: {},
@@ -31798,15 +32027,15 @@ function readCiJson(projectDir) {
31798
32027
  }
31799
32028
  }
31800
32029
  function writeCiJsonAtomic(projectDir, config) {
31801
- const ciPath = path10.join(projectDir, ".codebyplan", "ci.json");
32030
+ const ciPath = path11.join(projectDir, ".codebyplan", "ci.json");
31802
32031
  writeJsonAtomic(ciPath, config);
31803
32032
  }
31804
32033
  function enforceRequiredCheck(opts) {
31805
- const projectDir = path10.resolve(opts?.projectDir ?? process.cwd());
32034
+ const projectDir = path11.resolve(opts?.projectDir ?? process.cwd());
31806
32035
  const branch = opts?.branch ?? "main";
31807
32036
  const checkName = opts?.checkName ?? "Lint + typecheck + test + build";
31808
32037
  const dryRun = opts?.dryRun ?? false;
31809
- const ciPath = path10.join(projectDir, ".codebyplan", "ci.json");
32038
+ const ciPath = path11.join(projectDir, ".codebyplan", "ci.json");
31810
32039
  const config = readCiJson(projectDir);
31811
32040
  if (config.workflow?.required_check_enforced === true) {
31812
32041
  return { status: "already_enforced", path: ciPath };
@@ -32213,9 +32442,9 @@ var init_ci = __esm({
32213
32442
 
32214
32443
  // src/lib/cd-init.ts
32215
32444
  import * as fs11 from "node:fs";
32216
- import * as path11 from "node:path";
32445
+ import * as path12 from "node:path";
32217
32446
  function detectSurfaces(projectDir) {
32218
- const shipmentPath = path11.join(projectDir, ".codebyplan", "shipment.json");
32447
+ const shipmentPath = path12.join(projectDir, ".codebyplan", "shipment.json");
32219
32448
  let shipment;
32220
32449
  try {
32221
32450
  shipment = JSON.parse(fs11.readFileSync(shipmentPath, "utf-8"));
@@ -32268,10 +32497,10 @@ function buildDefaultCdConfig(rawSurfaceKeys) {
32268
32497
  }
32269
32498
  async function runCdInit(opts) {
32270
32499
  await Promise.resolve();
32271
- const projectDir = path11.resolve(opts?.projectDir ?? process.cwd());
32500
+ const projectDir = path12.resolve(opts?.projectDir ?? process.cwd());
32272
32501
  const dryRun = opts?.dryRun ?? false;
32273
32502
  const force = opts?.force ?? false;
32274
- const cdPath = path11.join(projectDir, ".codebyplan", "cd.json");
32503
+ const cdPath = path12.join(projectDir, ".codebyplan", "cd.json");
32275
32504
  const rawSurfaceKeys = detectSurfaces(projectDir);
32276
32505
  const seen = /* @__PURE__ */ new Set();
32277
32506
  const surfaces = [];
@@ -32312,7 +32541,7 @@ async function runCdInit(opts) {
32312
32541
  surfaces: newSurfaces
32313
32542
  };
32314
32543
  }
32315
- const codebyplanDir = path11.join(projectDir, ".codebyplan");
32544
+ const codebyplanDir = path12.join(projectDir, ".codebyplan");
32316
32545
  fs11.mkdirSync(codebyplanDir, { recursive: true });
32317
32546
  writeJsonAtomic(cdPath, newConfig);
32318
32547
  return { status: "written", path: cdPath, surfaces };
@@ -32402,14 +32631,14 @@ var init_cd_init = __esm({
32402
32631
 
32403
32632
  // src/lib/scaffold-cd-workflow.ts
32404
32633
  import * as fs12 from "node:fs";
32405
- import * as path12 from "node:path";
32634
+ import * as path13 from "node:path";
32406
32635
  async function scaffoldOneWorkflow(templateName, targetName, opts) {
32407
32636
  await Promise.resolve();
32408
32637
  const dryRun = opts.dryRun ?? false;
32409
32638
  const force = opts.force ?? false;
32410
- const projectDir = path12.resolve(opts.projectDir ?? process.cwd());
32639
+ const projectDir = path13.resolve(opts.projectDir ?? process.cwd());
32411
32640
  const templatesDir = opts.templatesDir ?? resolveTemplatesDir();
32412
- const templatePath = path12.join(
32641
+ const templatePath = path13.join(
32413
32642
  templatesDir,
32414
32643
  "github-workflows",
32415
32644
  templateName
@@ -32420,7 +32649,7 @@ async function scaffoldOneWorkflow(templateName, targetName, opts) {
32420
32649
  );
32421
32650
  }
32422
32651
  const templateContent = fs12.readFileSync(templatePath, "utf-8");
32423
- const targetPath = path12.join(projectDir, ".github", "workflows", targetName);
32652
+ const targetPath = path13.join(projectDir, ".github", "workflows", targetName);
32424
32653
  if (dryRun) {
32425
32654
  return { status: "dry_run", path: targetPath };
32426
32655
  }
@@ -32439,7 +32668,7 @@ async function scaffoldOneWorkflow(templateName, targetName, opts) {
32439
32668
  );
32440
32669
  }
32441
32670
  }
32442
- const targetDir = path12.dirname(targetPath);
32671
+ const targetDir = path13.dirname(targetPath);
32443
32672
  fs12.mkdirSync(targetDir, { recursive: true });
32444
32673
  const tmpPath = targetPath + ".tmp";
32445
32674
  try {
@@ -33115,7 +33344,7 @@ __export(version_status_exports, {
33115
33344
  });
33116
33345
  import { execFileSync, execSync as execSync7 } from "node:child_process";
33117
33346
  import { existsSync as existsSync10, readFileSync as readFileSync11 } from "node:fs";
33118
- import { dirname as dirname12, join as join30 } from "node:path";
33347
+ import { dirname as dirname12, join as join31 } from "node:path";
33119
33348
  function fetchLatestVersion() {
33120
33349
  try {
33121
33350
  return execFileSync("npm", ["view", "codebyplan", "version"], {
@@ -33139,9 +33368,9 @@ function detectPackageManager2(gitRoot) {
33139
33368
  let dir = process.cwd();
33140
33369
  const stopAt = gitRoot ?? null;
33141
33370
  while (true) {
33142
- if (existsSync10(join30(dir, "pnpm-lock.yaml"))) return "pnpm";
33143
- if (existsSync10(join30(dir, "yarn.lock"))) return "yarn";
33144
- if (existsSync10(join30(dir, "package-lock.json"))) return "npm";
33371
+ if (existsSync10(join31(dir, "pnpm-lock.yaml"))) return "pnpm";
33372
+ if (existsSync10(join31(dir, "yarn.lock"))) return "yarn";
33373
+ if (existsSync10(join31(dir, "package-lock.json"))) return "npm";
33145
33374
  if (stopAt !== null && dir === stopAt) break;
33146
33375
  const parent = dirname12(dir);
33147
33376
  if (parent === dir) break;
@@ -33161,7 +33390,7 @@ function buildInstallCommand2(pm) {
33161
33390
  }
33162
33391
  async function resolveGuard(gitRoot, currentBranch) {
33163
33392
  if (gitRoot !== null) {
33164
- const canonicalPkgPath = join30(
33393
+ const canonicalPkgPath = join31(
33165
33394
  gitRoot,
33166
33395
  "packages",
33167
33396
  "codebyplan-package",
@@ -33185,10 +33414,10 @@ async function resolveGuard(gitRoot, currentBranch) {
33185
33414
  let gitJsonPath;
33186
33415
  if (found.path.endsWith("/repo.json")) {
33187
33416
  const dir = found.path.slice(0, found.path.lastIndexOf("/"));
33188
- gitJsonPath = join30(dir, "git.json");
33417
+ gitJsonPath = join31(dir, "git.json");
33189
33418
  } else {
33190
33419
  const legacyDir = found.path.slice(0, found.path.lastIndexOf("/"));
33191
- gitJsonPath = join30(legacyDir, ".codebyplan", "git.json");
33420
+ gitJsonPath = join31(legacyDir, ".codebyplan", "git.json");
33192
33421
  }
33193
33422
  const raw = readFileSync11(gitJsonPath, "utf-8");
33194
33423
  const parsed = JSON.parse(raw);
@@ -33272,8 +33501,8 @@ var upload_e2e_images_exports = {};
33272
33501
  __export(upload_e2e_images_exports, {
33273
33502
  runUploadE2eImagesCommand: () => runUploadE2eImagesCommand
33274
33503
  });
33275
- import { readFile as readFile19 } from "node:fs/promises";
33276
- import { join as join31, basename, resolve as resolve10 } from "node:path";
33504
+ import { readFile as readFile20 } from "node:fs/promises";
33505
+ import { join as join32, basename, resolve as resolve10 } from "node:path";
33277
33506
  import { execSync as execSync8 } from "node:child_process";
33278
33507
  function baseUrl2() {
33279
33508
  return (process.env.CODEBYPLAN_API_URL ?? "https://www.codebyplan.com").replace(/\/$/, "");
@@ -33307,8 +33536,8 @@ function parseArgs(args) {
33307
33536
  }
33308
33537
  async function readE2eConfig(projectPath) {
33309
33538
  try {
33310
- const raw = await readFile19(
33311
- join31(projectPath, ".codebyplan", "e2e.json"),
33539
+ const raw = await readFile20(
33540
+ join32(projectPath, ".codebyplan", "e2e.json"),
33312
33541
  "utf-8"
33313
33542
  );
33314
33543
  return JSON.parse(raw);
@@ -33349,7 +33578,7 @@ function collectPngsFromGitDiff(projectPath, frameworkName, frameworkConfig, bas
33349
33578
  continue;
33350
33579
  const isNew = status === "A";
33351
33580
  results.push({
33352
- absolutePath: join31(projectPath, filePath),
33581
+ absolutePath: join32(projectPath, filePath),
33353
33582
  filename: basename(filePath),
33354
33583
  framework: frameworkName,
33355
33584
  is_new: isNew
@@ -33446,7 +33675,7 @@ async function runUploadE2eImagesCommand(args) {
33446
33675
  for (const png of allPngs) {
33447
33676
  let bytes;
33448
33677
  try {
33449
- bytes = await readFile19(png.absolutePath);
33678
+ bytes = await readFile20(png.absolutePath);
33450
33679
  } catch {
33451
33680
  process.stderr.write(
33452
33681
  `upload-e2e-images: could not read file: ${png.absolutePath}
@@ -33523,10 +33752,10 @@ __export(arch_map_exports, {
33523
33752
  runArchMapCommand: () => runArchMapCommand,
33524
33753
  updateFrontmatterFields: () => updateFrontmatterFields
33525
33754
  });
33526
- import { readFile as readFile20, writeFile as writeFile16 } from "node:fs/promises";
33755
+ import { readFile as readFile21, writeFile as writeFile17 } from "node:fs/promises";
33527
33756
  import { existsSync as existsSync11, readdirSync as readdirSync4 } from "node:fs";
33528
- import { join as join32 } from "node:path";
33529
- import { spawnSync as spawnSync9 } from "node:child_process";
33757
+ import { join as join33 } from "node:path";
33758
+ import { spawnSync as spawnSync10 } from "node:child_process";
33530
33759
  function normalizeModulePath(modulePath) {
33531
33760
  return modulePath.replace(/\/+$/, "");
33532
33761
  }
@@ -33550,9 +33779,9 @@ async function resolveCodebyplanDir(startDir) {
33550
33779
  }
33551
33780
  }
33552
33781
  async function readArchitectureConfig(codebyplanDir) {
33553
- const filePath = join32(codebyplanDir, "architecture.json");
33782
+ const filePath = join33(codebyplanDir, "architecture.json");
33554
33783
  try {
33555
- const raw = await readFile20(filePath, "utf-8");
33784
+ const raw = await readFile21(filePath, "utf-8");
33556
33785
  const parsed = JSON.parse(raw);
33557
33786
  if (typeof parsed !== "object" || parsed === null || !Array.isArray(parsed.modules)) {
33558
33787
  return { version: 1, modules: [] };
@@ -33563,12 +33792,12 @@ async function readArchitectureConfig(codebyplanDir) {
33563
33792
  }
33564
33793
  }
33565
33794
  async function writeArchitectureConfig(codebyplanDir, config) {
33566
- const filePath = join32(codebyplanDir, "architecture.json");
33567
- await writeFile16(filePath, JSON.stringify(config, null, 2) + "\n", "utf-8");
33795
+ const filePath = join33(codebyplanDir, "architecture.json");
33796
+ await writeFile17(filePath, JSON.stringify(config, null, 2) + "\n", "utf-8");
33568
33797
  }
33569
33798
  function resolveGitSha(modulePath, cwd) {
33570
33799
  try {
33571
- const result = spawnSync9(
33800
+ const result = spawnSync10(
33572
33801
  "git",
33573
33802
  ["log", "--format=%H", "-1", "--", modulePath],
33574
33803
  { cwd, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
@@ -33582,10 +33811,10 @@ function resolveGitSha(modulePath, cwd) {
33582
33811
  }
33583
33812
  async function discoverModulePaths(projectRoot) {
33584
33813
  const paths = [];
33585
- const workspacePath = join32(projectRoot, "pnpm-workspace.yaml");
33814
+ const workspacePath = join33(projectRoot, "pnpm-workspace.yaml");
33586
33815
  let patterns = [];
33587
33816
  try {
33588
- const raw = await readFile20(workspacePath, "utf-8");
33817
+ const raw = await readFile21(workspacePath, "utf-8");
33589
33818
  const lines = raw.split("\n");
33590
33819
  let inPackages = false;
33591
33820
  for (const line of lines) {
@@ -33609,7 +33838,7 @@ async function discoverModulePaths(projectRoot) {
33609
33838
  for (const pattern of patterns) {
33610
33839
  if (pattern.endsWith("/*")) {
33611
33840
  const dir = pattern.slice(0, -2);
33612
- const absDir = join32(projectRoot, dir);
33841
+ const absDir = join33(projectRoot, dir);
33613
33842
  try {
33614
33843
  if (existsSync11(absDir)) {
33615
33844
  const entries = readdirSync4(absDir, { withFileTypes: true });
@@ -33622,7 +33851,7 @@ async function discoverModulePaths(projectRoot) {
33622
33851
  } catch {
33623
33852
  }
33624
33853
  } else if (!pattern.includes("*")) {
33625
- const absPath = join32(projectRoot, pattern);
33854
+ const absPath = join33(projectRoot, pattern);
33626
33855
  if (existsSync11(absPath)) {
33627
33856
  paths.push(pattern);
33628
33857
  }
@@ -33630,7 +33859,7 @@ async function discoverModulePaths(projectRoot) {
33630
33859
  }
33631
33860
  const crossCutting = ["supabase", ".github", "scripts"];
33632
33861
  for (const dir of crossCutting) {
33633
- const absPath = join32(projectRoot, dir);
33862
+ const absPath = join33(projectRoot, dir);
33634
33863
  try {
33635
33864
  if (existsSync11(absPath)) {
33636
33865
  paths.push(dir);
@@ -33816,10 +34045,10 @@ async function runStamp(modulePath, sha, depthArg, projectRoot) {
33816
34045
  }
33817
34046
  await writeArchitectureConfig(codebyplanDir, config);
33818
34047
  const stampedEntry = existingIndex >= 0 ? config.modules[existingIndex] : config.modules[config.modules.length - 1];
33819
- const mapAbsPath = join32(repoRoot, stampedEntry.map_file);
34048
+ const mapAbsPath = join33(repoRoot, stampedEntry.map_file);
33820
34049
  let mapContent = null;
33821
34050
  try {
33822
- mapContent = await readFile20(mapAbsPath, "utf-8");
34051
+ mapContent = await readFile21(mapAbsPath, "utf-8");
33823
34052
  } catch {
33824
34053
  console.warn(
33825
34054
  " Warning: map file " + stampedEntry.map_file + " not found \u2014 stamped manifest only"
@@ -33841,7 +34070,7 @@ async function runStamp(modulePath, sha, depthArg, projectRoot) {
33841
34070
  );
33842
34071
  } else {
33843
34072
  try {
33844
- await writeFile16(mapAbsPath, updated, "utf-8");
34073
+ await writeFile17(mapAbsPath, updated, "utf-8");
33845
34074
  } catch (writeErr) {
33846
34075
  console.warn(
33847
34076
  " Warning: could not write map file " + stampedEntry.map_file + " \u2014 " + (writeErr instanceof Error ? writeErr.message : String(writeErr)) + " \u2014 stamped manifest only"
@@ -34021,19 +34250,19 @@ var init_worktree_port_resolver = __esm({
34021
34250
  });
34022
34251
 
34023
34252
  // src/lib/migrate-local-config.ts
34024
- import { mkdir as mkdir9, readFile as readFile21, unlink as unlink5, writeFile as writeFile17 } from "node:fs/promises";
34025
- import { join as join33 } from "node:path";
34253
+ import { mkdir as mkdir9, readFile as readFile22, unlink as unlink5, writeFile as writeFile18 } from "node:fs/promises";
34254
+ import { join as join34 } from "node:path";
34026
34255
  function legacySharedPath(projectPath) {
34027
- return join33(projectPath, ".codebyplan.json");
34256
+ return join34(projectPath, ".codebyplan.json");
34028
34257
  }
34029
34258
  function legacyLocalPath(projectPath) {
34030
- return join33(projectPath, ".codebyplan.local.json");
34259
+ return join34(projectPath, ".codebyplan.local.json");
34031
34260
  }
34032
34261
  function newDirPath(projectPath) {
34033
- return join33(projectPath, ".codebyplan");
34262
+ return join34(projectPath, ".codebyplan");
34034
34263
  }
34035
34264
  function sentinelPath(projectPath) {
34036
- return join33(projectPath, ".codebyplan", "repo.json");
34265
+ return join34(projectPath, ".codebyplan", "repo.json");
34037
34266
  }
34038
34267
  async function statSafe(p) {
34039
34268
  const { stat: stat3 } = await import("node:fs/promises");
@@ -34072,7 +34301,7 @@ async function runLocalMigration(projectPath) {
34072
34301
  }
34073
34302
  let legacyRaw;
34074
34303
  try {
34075
- legacyRaw = await readFile21(legacySharedPath(projectPath), "utf-8");
34304
+ legacyRaw = await readFile22(legacySharedPath(projectPath), "utf-8");
34076
34305
  } catch {
34077
34306
  return {
34078
34307
  migrated: true,
@@ -34099,7 +34328,7 @@ async function runLocalMigration(projectPath) {
34099
34328
  let deviceId;
34100
34329
  let deviceWrittenByHelper = false;
34101
34330
  try {
34102
- const localRaw = await readFile21(legacyLocalPath(projectPath), "utf-8");
34331
+ const localRaw = await readFile22(legacyLocalPath(projectPath), "utf-8");
34103
34332
  const localParsed = JSON.parse(localRaw);
34104
34333
  if (typeof localParsed.device_id === "string") {
34105
34334
  deviceId = localParsed.device_id;
@@ -34126,8 +34355,8 @@ async function runLocalMigration(projectPath) {
34126
34355
  if ("repo_id" in cfg) repoJson.repo_id = cfg.repo_id;
34127
34356
  if ("organization_id" in cfg) repoJson.organization_id = cfg.organization_id;
34128
34357
  if ("project_id" in cfg) repoJson.project_id = cfg.project_id;
34129
- await writeFile17(
34130
- join33(projectPath, ".codebyplan", "repo.json"),
34358
+ await writeFile18(
34359
+ join34(projectPath, ".codebyplan", "repo.json"),
34131
34360
  JSON.stringify(repoJson, null, 2) + "\n",
34132
34361
  "utf-8"
34133
34362
  );
@@ -34139,8 +34368,8 @@ async function runLocalMigration(projectPath) {
34139
34368
  serverJson.auto_push_enabled = cfg.auto_push_enabled;
34140
34369
  if ("port_allocations" in cfg)
34141
34370
  serverJson.port_allocations = cfg.port_allocations;
34142
- await writeFile17(
34143
- join33(projectPath, ".codebyplan", "server.json"),
34371
+ await writeFile18(
34372
+ join34(projectPath, ".codebyplan", "server.json"),
34144
34373
  JSON.stringify(serverJson, null, 2) + "\n",
34145
34374
  "utf-8"
34146
34375
  );
@@ -34148,44 +34377,44 @@ async function runLocalMigration(projectPath) {
34148
34377
  const gitJson = {};
34149
34378
  if ("git_branch" in cfg) gitJson.git_branch = cfg.git_branch;
34150
34379
  if ("branch_config" in cfg) gitJson.branch_config = cfg.branch_config;
34151
- await writeFile17(
34152
- join33(projectPath, ".codebyplan", "git.json"),
34380
+ await writeFile18(
34381
+ join34(projectPath, ".codebyplan", "git.json"),
34153
34382
  JSON.stringify(gitJson, null, 2) + "\n",
34154
34383
  "utf-8"
34155
34384
  );
34156
34385
  filesChanged.push(".codebyplan/git.json");
34157
34386
  const shipmentJson = {};
34158
34387
  if ("shipment" in cfg) shipmentJson.shipment = cfg.shipment;
34159
- await writeFile17(
34160
- join33(projectPath, ".codebyplan", "shipment.json"),
34388
+ await writeFile18(
34389
+ join34(projectPath, ".codebyplan", "shipment.json"),
34161
34390
  JSON.stringify(shipmentJson, null, 2) + "\n",
34162
34391
  "utf-8"
34163
34392
  );
34164
34393
  filesChanged.push(".codebyplan/shipment.json");
34165
34394
  const vendorJson = {};
34166
- await writeFile17(
34167
- join33(projectPath, ".codebyplan", "vendor.json"),
34395
+ await writeFile18(
34396
+ join34(projectPath, ".codebyplan", "vendor.json"),
34168
34397
  JSON.stringify(vendorJson, null, 2) + "\n",
34169
34398
  "utf-8"
34170
34399
  );
34171
34400
  filesChanged.push(".codebyplan/vendor.json");
34172
34401
  const e2eJson = {};
34173
- await writeFile17(
34174
- join33(projectPath, ".codebyplan", "e2e.json"),
34402
+ await writeFile18(
34403
+ join34(projectPath, ".codebyplan", "e2e.json"),
34175
34404
  JSON.stringify(e2eJson, null, 2) + "\n",
34176
34405
  "utf-8"
34177
34406
  );
34178
34407
  filesChanged.push(".codebyplan/e2e.json");
34179
34408
  const eslintJson = {};
34180
- await writeFile17(
34181
- join33(projectPath, ".codebyplan", "eslint.json"),
34409
+ await writeFile18(
34410
+ join34(projectPath, ".codebyplan", "eslint.json"),
34182
34411
  JSON.stringify(eslintJson, null, 2) + "\n",
34183
34412
  "utf-8"
34184
34413
  );
34185
34414
  filesChanged.push(".codebyplan/eslint.json");
34186
34415
  if (!deviceWrittenByHelper) {
34187
- await writeFile17(
34188
- join33(projectPath, ".codebyplan", "device.local.json"),
34416
+ await writeFile18(
34417
+ join34(projectPath, ".codebyplan", "device.local.json"),
34189
34418
  JSON.stringify({ device_id: deviceId }, null, 2) + "\n",
34190
34419
  "utf-8"
34191
34420
  );
@@ -34197,9 +34426,9 @@ async function runLocalMigration(projectPath) {
34197
34426
  "Migration write incomplete: .codebyplan/repo.json was not persisted. Re-run migration to retry from a clean state."
34198
34427
  );
34199
34428
  }
34200
- const gitignorePath = join33(projectPath, ".gitignore");
34429
+ const gitignorePath = join34(projectPath, ".gitignore");
34201
34430
  try {
34202
- const gitignoreContent = await readFile21(gitignorePath, "utf-8");
34431
+ const gitignoreContent = await readFile22(gitignorePath, "utf-8");
34203
34432
  const legacyLine = ".codebyplan.local.json";
34204
34433
  const newLine = ".codebyplan/device.local.json";
34205
34434
  const hasLegacy = gitignoreContent.split("\n").some((l) => l.trimEnd() === legacyLine);
@@ -34218,7 +34447,7 @@ async function runLocalMigration(projectPath) {
34218
34447
  updated = gitignoreContent;
34219
34448
  }
34220
34449
  if (updated !== gitignoreContent) {
34221
- await writeFile17(gitignorePath, updated, "utf-8");
34450
+ await writeFile18(gitignorePath, updated, "utf-8");
34222
34451
  filesChanged.push(".gitignore");
34223
34452
  }
34224
34453
  } catch {
@@ -34260,8 +34489,8 @@ __export(config_exports, {
34260
34489
  runConfig: () => runConfig,
34261
34490
  runConfigMigrate: () => runConfigMigrate
34262
34491
  });
34263
- import { mkdir as mkdir10, readFile as readFile22, writeFile as writeFile18 } from "node:fs/promises";
34264
- import { join as join34 } from "node:path";
34492
+ import { mkdir as mkdir10, readFile as readFile23, writeFile as writeFile19 } from "node:fs/promises";
34493
+ import { join as join35 } from "node:path";
34265
34494
  async function runConfig() {
34266
34495
  const flags = parseFlags(3);
34267
34496
  const dryRun = hasFlag("dry-run", 3);
@@ -34294,7 +34523,7 @@ async function runConfig() {
34294
34523
  console.log("\n Config complete.\n");
34295
34524
  }
34296
34525
  async function syncConfigToFile(repoId, projectPath, dryRun) {
34297
- const codebyplanDir = join34(projectPath, ".codebyplan");
34526
+ const codebyplanDir = join35(projectPath, ".codebyplan");
34298
34527
  const {
34299
34528
  resolvedWorktreeId,
34300
34529
  portAllocations,
@@ -34387,16 +34616,16 @@ async function syncConfigToFile(repoId, projectPath, dryRun) {
34387
34616
  ];
34388
34617
  let anyUpdated = false;
34389
34618
  for (const { name, payload, createOnly } of files) {
34390
- const filePath = join34(codebyplanDir, name);
34619
+ const filePath = join35(codebyplanDir, name);
34391
34620
  const newJson = JSON.stringify(payload, null, 2) + "\n";
34392
34621
  let currentJson = "";
34393
34622
  try {
34394
- currentJson = await readFile22(filePath, "utf-8");
34623
+ currentJson = await readFile23(filePath, "utf-8");
34395
34624
  } catch {
34396
34625
  }
34397
34626
  if (createOnly && currentJson !== "") continue;
34398
34627
  if (currentJson === newJson) continue;
34399
- await writeFile18(filePath, newJson, "utf-8");
34628
+ await writeFile19(filePath, newJson, "utf-8");
34400
34629
  console.log(` Updated .codebyplan/${name}`);
34401
34630
  anyUpdated = true;
34402
34631
  }
@@ -34406,8 +34635,8 @@ async function syncConfigToFile(repoId, projectPath, dryRun) {
34406
34635
  }
34407
34636
  async function readRepoConfig(projectPath) {
34408
34637
  try {
34409
- const raw = await readFile22(
34410
- join34(projectPath, ".codebyplan", "repo.json"),
34638
+ const raw = await readFile23(
34639
+ join35(projectPath, ".codebyplan", "repo.json"),
34411
34640
  "utf-8"
34412
34641
  );
34413
34642
  return JSON.parse(raw);
@@ -34417,8 +34646,8 @@ async function readRepoConfig(projectPath) {
34417
34646
  }
34418
34647
  async function readServerConfig(projectPath) {
34419
34648
  try {
34420
- const raw = await readFile22(
34421
- join34(projectPath, ".codebyplan", "server.json"),
34649
+ const raw = await readFile23(
34650
+ join35(projectPath, ".codebyplan", "server.json"),
34422
34651
  "utf-8"
34423
34652
  );
34424
34653
  return JSON.parse(raw);
@@ -34428,8 +34657,8 @@ async function readServerConfig(projectPath) {
34428
34657
  }
34429
34658
  async function readGitConfig2(projectPath) {
34430
34659
  try {
34431
- const raw = await readFile22(
34432
- join34(projectPath, ".codebyplan", "git.json"),
34660
+ const raw = await readFile23(
34661
+ join35(projectPath, ".codebyplan", "git.json"),
34433
34662
  "utf-8"
34434
34663
  );
34435
34664
  return JSON.parse(raw);
@@ -34439,8 +34668,8 @@ async function readGitConfig2(projectPath) {
34439
34668
  }
34440
34669
  async function readShipmentConfig2(projectPath) {
34441
34670
  try {
34442
- const raw = await readFile22(
34443
- join34(projectPath, ".codebyplan", "shipment.json"),
34671
+ const raw = await readFile23(
34672
+ join35(projectPath, ".codebyplan", "shipment.json"),
34444
34673
  "utf-8"
34445
34674
  );
34446
34675
  return JSON.parse(raw);
@@ -34450,8 +34679,8 @@ async function readShipmentConfig2(projectPath) {
34450
34679
  }
34451
34680
  async function readVendorConfig(projectPath) {
34452
34681
  try {
34453
- const raw = await readFile22(
34454
- join34(projectPath, ".codebyplan", "vendor.json"),
34682
+ const raw = await readFile23(
34683
+ join35(projectPath, ".codebyplan", "vendor.json"),
34455
34684
  "utf-8"
34456
34685
  );
34457
34686
  return JSON.parse(raw);
@@ -34461,8 +34690,8 @@ async function readVendorConfig(projectPath) {
34461
34690
  }
34462
34691
  async function readE2eConfig2(projectPath) {
34463
34692
  try {
34464
- const raw = await readFile22(
34465
- join34(projectPath, ".codebyplan", "e2e.json"),
34693
+ const raw = await readFile23(
34694
+ join35(projectPath, ".codebyplan", "e2e.json"),
34466
34695
  "utf-8"
34467
34696
  );
34468
34697
  return JSON.parse(raw);
@@ -34472,8 +34701,8 @@ async function readE2eConfig2(projectPath) {
34472
34701
  }
34473
34702
  async function readServerLocalConfig(projectPath) {
34474
34703
  try {
34475
- const raw = await readFile22(
34476
- join34(projectPath, ".codebyplan", "server.local.json"),
34704
+ const raw = await readFile23(
34705
+ join35(projectPath, ".codebyplan", "server.local.json"),
34477
34706
  "utf-8"
34478
34707
  );
34479
34708
  return JSON.parse(raw);
@@ -34545,8 +34774,8 @@ var init_config = __esm({
34545
34774
  });
34546
34775
 
34547
34776
  // src/lib/server-detect.ts
34548
- import { readFile as readFile23, readdir as readdir5, access as access6 } from "node:fs/promises";
34549
- import { join as join35 } from "node:path";
34777
+ import { readFile as readFile24, readdir as readdir5, access as access6 } from "node:fs/promises";
34778
+ import { join as join36 } from "node:path";
34550
34779
  async function fileExists4(filePath) {
34551
34780
  try {
34552
34781
  await access6(filePath);
@@ -34557,8 +34786,8 @@ async function fileExists4(filePath) {
34557
34786
  }
34558
34787
  function detectPackageManager3(dir) {
34559
34788
  return (async () => {
34560
- if (await fileExists4(join35(dir, "pnpm-lock.yaml"))) return "pnpm";
34561
- if (await fileExists4(join35(dir, "yarn.lock"))) return "yarn";
34789
+ if (await fileExists4(join36(dir, "pnpm-lock.yaml"))) return "pnpm";
34790
+ if (await fileExists4(join36(dir, "yarn.lock"))) return "yarn";
34562
34791
  return "npm";
34563
34792
  })();
34564
34793
  }
@@ -34590,12 +34819,12 @@ function detectPortFromScripts(pkg) {
34590
34819
  return null;
34591
34820
  }
34592
34821
  async function isMonorepo(dir) {
34593
- return await fileExists4(join35(dir, "turbo.json")) || await fileExists4(join35(dir, "pnpm-workspace.yaml"));
34822
+ return await fileExists4(join36(dir, "turbo.json")) || await fileExists4(join36(dir, "pnpm-workspace.yaml"));
34594
34823
  }
34595
34824
  async function detectServers(projectPath) {
34596
34825
  let pkg;
34597
34826
  try {
34598
- const raw = await readFile23(join35(projectPath, "package.json"), "utf-8");
34827
+ const raw = await readFile24(join36(projectPath, "package.json"), "utf-8");
34599
34828
  pkg = JSON.parse(raw);
34600
34829
  } catch {
34601
34830
  return {
@@ -34611,15 +34840,15 @@ async function detectServers(projectPath) {
34611
34840
  const mono = await isMonorepo(projectPath);
34612
34841
  const servers = [];
34613
34842
  if (mono) {
34614
- const appsDir = join35(projectPath, "apps");
34843
+ const appsDir = join36(projectPath, "apps");
34615
34844
  try {
34616
34845
  const entries = await readdir5(appsDir, { withFileTypes: true });
34617
34846
  const sorted = [...entries].sort((a, b) => a.name.localeCompare(b.name));
34618
34847
  for (const entry of sorted) {
34619
34848
  if (!entry.isDirectory()) continue;
34620
- const appPkgPath = join35(appsDir, entry.name, "package.json");
34849
+ const appPkgPath = join36(appsDir, entry.name, "package.json");
34621
34850
  try {
34622
- const appRaw = await readFile23(appPkgPath, "utf-8");
34851
+ const appRaw = await readFile24(appPkgPath, "utf-8");
34623
34852
  const appPkg = JSON.parse(appRaw);
34624
34853
  const appName = entry.name;
34625
34854
  const framework = detectFramework(appPkg);
@@ -34662,14 +34891,14 @@ var init_server_detect = __esm({
34662
34891
  });
34663
34892
 
34664
34893
  // src/lib/port-verify.ts
34665
- import { readFile as readFile24 } from "node:fs/promises";
34894
+ import { readFile as readFile25 } from "node:fs/promises";
34666
34895
  async function verifyPorts(projectPath, portAllocations) {
34667
34896
  const mismatches = [];
34668
34897
  const allocatedPorts = new Set(portAllocations.map((a) => a.port));
34669
34898
  const packageJsonPaths = await findPackageJsonFiles(projectPath, projectPath);
34670
34899
  for (const pkgPath of packageJsonPaths) {
34671
34900
  try {
34672
- const raw = await readFile24(pkgPath, "utf-8");
34901
+ const raw = await readFile25(pkgPath, "utf-8");
34673
34902
  const pkg = JSON.parse(raw);
34674
34903
  const scriptPort = detectPortFromScripts(pkg);
34675
34904
  if (scriptPort !== null && !allocatedPorts.has(scriptPort)) {
@@ -34732,7 +34961,7 @@ async function findUnallocatedApps(projectPath, portAllocations) {
34732
34961
  }
34733
34962
  let pkg;
34734
34963
  try {
34735
- const raw = await readFile24(`${app.absPath}/package.json`, "utf-8");
34964
+ const raw = await readFile25(`${app.absPath}/package.json`, "utf-8");
34736
34965
  pkg = JSON.parse(raw);
34737
34966
  } catch {
34738
34967
  continue;
@@ -34782,8 +35011,8 @@ __export(ports_exports, {
34782
35011
  parseEnvFile: () => parseEnvFile,
34783
35012
  runPorts: () => runPorts
34784
35013
  });
34785
- import { mkdir as mkdir11, readFile as readFile25, writeFile as writeFile19 } from "node:fs/promises";
34786
- import { join as join36 } from "node:path";
35014
+ import { mkdir as mkdir11, readFile as readFile26, writeFile as writeFile20 } from "node:fs/promises";
35015
+ import { join as join37 } from "node:path";
34787
35016
  function printDetectionResult(result, projectPath) {
34788
35017
  console.log(`
34789
35018
  CodeByPlan Ports - List`);
@@ -34939,12 +35168,12 @@ async function writeServerLocalConfig(repoId, projectPath, dryRun) {
34939
35168
  // and ServerLocalConfig.port_allocations is typed the same — honest end-to-end.
34940
35169
  port_allocations: portAllocations
34941
35170
  };
34942
- const codebyplanDir = join36(projectPath, ".codebyplan");
34943
- const filePath = join36(codebyplanDir, "server.local.json");
35171
+ const codebyplanDir = join37(projectPath, ".codebyplan");
35172
+ const filePath = join37(codebyplanDir, "server.local.json");
34944
35173
  const newJson = JSON.stringify(payload, null, 2) + "\n";
34945
35174
  let currentJson = "";
34946
35175
  try {
34947
- currentJson = await readFile25(filePath, "utf-8");
35176
+ currentJson = await readFile26(filePath, "utf-8");
34948
35177
  } catch {
34949
35178
  }
34950
35179
  if (currentJson === newJson) {
@@ -34956,17 +35185,17 @@ async function writeServerLocalConfig(repoId, projectPath, dryRun) {
34956
35185
  return;
34957
35186
  }
34958
35187
  await mkdir11(codebyplanDir, { recursive: true });
34959
- await writeFile19(filePath, newJson, "utf-8");
35188
+ await writeFile20(filePath, newJson, "utf-8");
34960
35189
  console.log(
34961
35190
  ` Updated .codebyplan/server.local.json (worktree ${resolvedWorktreeId ?? "\u2014"}, ${portAllocations.length} allocation${portAllocations.length === 1 ? "" : "s"}).`
34962
35191
  );
34963
35192
  }
34964
35193
  async function provisionE2eEnv(projectPath, dryRun) {
34965
- const relSource = join36("apps", "web", ".env.local");
34966
- const sourcePath = join36(projectPath, relSource);
35194
+ const relSource = join37("apps", "web", ".env.local");
35195
+ const sourcePath = join37(projectPath, relSource);
34967
35196
  let sourceRaw;
34968
35197
  try {
34969
- sourceRaw = await readFile25(sourcePath, "utf-8");
35198
+ sourceRaw = await readFile26(sourcePath, "utf-8");
34970
35199
  } catch {
34971
35200
  console.warn(
34972
35201
  ` Skipped .codebyplan/e2e.env \u2014 source ${relSource} not found.`
@@ -34995,12 +35224,12 @@ async function provisionE2eEnv(projectPath, dryRun) {
34995
35224
  );
34996
35225
  return;
34997
35226
  }
34998
- const codebyplanDir = join36(projectPath, ".codebyplan");
34999
- const filePath = join36(codebyplanDir, "e2e.env");
35227
+ const codebyplanDir = join37(projectPath, ".codebyplan");
35228
+ const filePath = join37(codebyplanDir, "e2e.env");
35000
35229
  const newContent = lines.join("\n") + "\n";
35001
35230
  let currentContent = "";
35002
35231
  try {
35003
- currentContent = await readFile25(filePath, "utf-8");
35232
+ currentContent = await readFile26(filePath, "utf-8");
35004
35233
  } catch {
35005
35234
  }
35006
35235
  if (currentContent === newContent) {
@@ -35012,7 +35241,7 @@ async function provisionE2eEnv(projectPath, dryRun) {
35012
35241
  return;
35013
35242
  }
35014
35243
  await mkdir11(codebyplanDir, { recursive: true });
35015
- await writeFile19(filePath, newContent, "utf-8");
35244
+ await writeFile20(filePath, newContent, "utf-8");
35016
35245
  console.log(
35017
35246
  ` Provisioned .codebyplan/e2e.env (${lines.length} var${lines.length === 1 ? "" : "s"}).`
35018
35247
  );
@@ -35280,8 +35509,8 @@ __export(docs_exports, {
35280
35509
  stripRangePrefix: () => stripRangePrefix
35281
35510
  });
35282
35511
  import { existsSync as existsSync13 } from "node:fs";
35283
- import { mkdir as mkdir12, readFile as readFile26, readdir as readdir6, rm as rm2, writeFile as writeFile20 } from "node:fs/promises";
35284
- import { dirname as dirname13, isAbsolute, join as join37, relative as relative7, sep as sep2 } from "node:path";
35512
+ import { mkdir as mkdir12, readFile as readFile27, readdir as readdir6, rm as rm2, writeFile as writeFile21 } from "node:fs/promises";
35513
+ import { dirname as dirname13, isAbsolute as isAbsolute2, join as join38, relative as relative7, sep as sep2 } from "node:path";
35285
35514
  function selectDependencies(deps) {
35286
35515
  const byName = /* @__PURE__ */ new Map();
35287
35516
  for (const dep of deps) {
@@ -35335,12 +35564,12 @@ async function mapWithConcurrency(items, limit, fn) {
35335
35564
  }
35336
35565
  async function resolveExactVersion(projectPath, dep) {
35337
35566
  const candidateDirs = [projectPath];
35338
- const sourceDir = join37(projectPath, dirname13(dep.sourcePath));
35567
+ const sourceDir = join38(projectPath, dirname13(dep.sourcePath));
35339
35568
  if (sourceDir !== projectPath) candidateDirs.push(sourceDir);
35340
35569
  for (const base of candidateDirs) {
35341
35570
  try {
35342
- const raw = await readFile26(
35343
- join37(base, "node_modules", dep.name, "package.json"),
35571
+ const raw = await readFile27(
35572
+ join38(base, "node_modules", dep.name, "package.json"),
35344
35573
  "utf-8"
35345
35574
  );
35346
35575
  const pkg = JSON.parse(raw);
@@ -35354,8 +35583,8 @@ async function resolveExactVersion(projectPath, dep) {
35354
35583
  }
35355
35584
  async function readVendorDocsPath(projectPath) {
35356
35585
  try {
35357
- const raw = await readFile26(
35358
- join37(projectPath, ".codebyplan", "vendor.json"),
35586
+ const raw = await readFile27(
35587
+ join38(projectPath, ".codebyplan", "vendor.json"),
35359
35588
  "utf-8"
35360
35589
  );
35361
35590
  const parsed = JSON.parse(raw);
@@ -35368,7 +35597,7 @@ async function readVendorDocsPath(projectPath) {
35368
35597
  }
35369
35598
  async function resolveDocsDir(projectPath, flags) {
35370
35599
  const configured = flags["dir"] ?? await readVendorDocsPath(projectPath) ?? DEFAULT_DOCS_DIR;
35371
- const absDir = isAbsolute(configured) ? configured : join37(projectPath, configured);
35600
+ const absDir = isAbsolute2(configured) ? configured : join38(projectPath, configured);
35372
35601
  const rel = relative7(projectPath, absDir);
35373
35602
  const relDir = rel === "" || rel.startsWith("..") ? null : rel.split(sep2).join("/");
35374
35603
  return { absDir, relDir };
@@ -35377,7 +35606,7 @@ async function readDocsLock(absDir) {
35377
35606
  const empty = { generated_at: "", libraries: {} };
35378
35607
  let raw;
35379
35608
  try {
35380
- raw = await readFile26(join37(absDir, LOCK_FILE), "utf-8");
35609
+ raw = await readFile27(join38(absDir, LOCK_FILE), "utf-8");
35381
35610
  } catch {
35382
35611
  return empty;
35383
35612
  }
@@ -35473,10 +35702,10 @@ function buildTopIndex(outcomes) {
35473
35702
  }
35474
35703
  async function ensureDocsGitignoreEntry(projectPath, relDir, dryRun) {
35475
35704
  const entry = `/${relDir}/`;
35476
- const gitignorePath = join37(projectPath, ".gitignore");
35705
+ const gitignorePath = join38(projectPath, ".gitignore");
35477
35706
  let existing = "";
35478
35707
  try {
35479
- existing = await readFile26(gitignorePath, "utf-8");
35708
+ existing = await readFile27(gitignorePath, "utf-8");
35480
35709
  } catch {
35481
35710
  }
35482
35711
  const lines = existing.split(/\r?\n/).map((l) => l.trim());
@@ -35488,7 +35717,7 @@ async function ensureDocsGitignoreEntry(projectPath, relDir, dryRun) {
35488
35717
  content += `${GITIGNORE_COMMENT}
35489
35718
  ${entry}
35490
35719
  `;
35491
- await writeFile20(gitignorePath, content, "utf-8");
35720
+ await writeFile21(gitignorePath, content, "utf-8");
35492
35721
  }
35493
35722
  return "added";
35494
35723
  }
@@ -35496,7 +35725,7 @@ async function markUncovered(dep, exactVersion, ctx) {
35496
35725
  console.log(
35497
35726
  ` uncovered ${dep.name}@${exactVersion || "?"} \u2014 no docs in the library mirror`
35498
35727
  );
35499
- const libPath = join37(ctx.absDir, libDirName(dep.name));
35728
+ const libPath = join38(ctx.absDir, libDirName(dep.name));
35500
35729
  if (existsSync13(libPath)) {
35501
35730
  if (ctx.dryRun) {
35502
35731
  console.log(` would remove stale mirror dir ${libPath}`);
@@ -35549,14 +35778,14 @@ async function syncOneLibrary(dep, ctx) {
35549
35778
  }
35550
35779
  }
35551
35780
  const lockEntry = ctx.lock.libraries[dep.name];
35552
- const libPath = join37(ctx.absDir, libDirName(dep.name));
35553
- const versionPath = join37(libPath, manifest.resolved_version);
35781
+ const libPath = join38(ctx.absDir, libDirName(dep.name));
35782
+ const versionPath = join38(libPath, manifest.resolved_version);
35554
35783
  if (manifestMatchesLock(manifest, lockEntry)) {
35555
35784
  console.log(` unchanged ${dep.name}@${manifest.resolved_version}`);
35556
- if (!ctx.dryRun && !existsSync13(join37(libPath, "INDEX.md"))) {
35785
+ if (!ctx.dryRun && !existsSync13(join38(libPath, "INDEX.md"))) {
35557
35786
  await mkdir12(libPath, { recursive: true });
35558
- await writeFile20(
35559
- join37(libPath, "INDEX.md"),
35787
+ await writeFile21(
35788
+ join38(libPath, "INDEX.md"),
35560
35789
  buildLibIndex(dep.name, manifest),
35561
35790
  "utf-8"
35562
35791
  );
@@ -35578,14 +35807,14 @@ async function syncOneLibrary(dep, ctx) {
35578
35807
  );
35579
35808
  continue;
35580
35809
  }
35581
- const target = join37(versionPath, rel);
35810
+ const target = join38(versionPath, rel);
35582
35811
  if (sameVersionLockFiles[file.path] === file.content_hash && existsSync13(target)) {
35583
35812
  continue;
35584
35813
  }
35585
35814
  written++;
35586
35815
  if (!ctx.dryRun) {
35587
35816
  await mkdir12(dirname13(target), { recursive: true });
35588
- await writeFile20(target, file.content, "utf-8");
35817
+ await writeFile21(target, file.content, "utf-8");
35589
35818
  }
35590
35819
  }
35591
35820
  let removedFiles = 0;
@@ -35596,7 +35825,7 @@ async function syncOneLibrary(dep, ctx) {
35596
35825
  const rel = sanitizeDocPath(lockedPath);
35597
35826
  if (rel === null) continue;
35598
35827
  removedFiles++;
35599
- if (!ctx.dryRun) await rm2(join37(versionPath, rel), { force: true });
35828
+ if (!ctx.dryRun) await rm2(join38(versionPath, rel), { force: true });
35600
35829
  }
35601
35830
  }
35602
35831
  let removedVersionDirs = 0;
@@ -35611,13 +35840,13 @@ async function syncOneLibrary(dep, ctx) {
35611
35840
  }
35612
35841
  removedVersionDirs++;
35613
35842
  if (!ctx.dryRun) {
35614
- await rm2(join37(libPath, entry.name), { recursive: true, force: true });
35843
+ await rm2(join38(libPath, entry.name), { recursive: true, force: true });
35615
35844
  }
35616
35845
  }
35617
35846
  if (!ctx.dryRun) {
35618
35847
  await mkdir12(libPath, { recursive: true });
35619
- await writeFile20(
35620
- join37(libPath, "INDEX.md"),
35848
+ await writeFile21(
35849
+ join38(libPath, "INDEX.md"),
35621
35850
  buildLibIndex(dep.name, manifest),
35622
35851
  "utf-8"
35623
35852
  );
@@ -35671,7 +35900,7 @@ async function runDocsSync() {
35671
35900
  );
35672
35901
  if (!dryRun) {
35673
35902
  await mkdir12(absDir, { recursive: true });
35674
- await writeFile20(join37(absDir, "INDEX.md"), buildTopIndex(outcomes), "utf-8");
35903
+ await writeFile21(join38(absDir, "INDEX.md"), buildTopIndex(outcomes), "utf-8");
35675
35904
  const libraries = {};
35676
35905
  for (const o of outcomes) {
35677
35906
  if (o.kind === "synced" || o.kind === "unchanged") {
@@ -35696,8 +35925,8 @@ async function runDocsSync() {
35696
35925
  generated_at: (/* @__PURE__ */ new Date()).toISOString(),
35697
35926
  libraries: sortedLibraries
35698
35927
  };
35699
- await writeFile20(
35700
- join37(absDir, LOCK_FILE),
35928
+ await writeFile21(
35929
+ join38(absDir, LOCK_FILE),
35701
35930
  JSON.stringify(newLock, null, 2) + "\n",
35702
35931
  "utf-8"
35703
35932
  );
@@ -35739,7 +35968,7 @@ async function countFilesRecursively(dirPath) {
35739
35968
  let count = 0;
35740
35969
  for (const entry of entries) {
35741
35970
  if (entry.isDirectory()) {
35742
- count += await countFilesRecursively(join37(dirPath, entry.name));
35971
+ count += await countFilesRecursively(join38(dirPath, entry.name));
35743
35972
  } else if (entry.isFile()) {
35744
35973
  count++;
35745
35974
  }
@@ -35756,7 +35985,7 @@ async function runDocsStatus() {
35756
35985
  `);
35757
35986
  let raw;
35758
35987
  try {
35759
- raw = await readFile26(join37(absDir, LOCK_FILE), "utf-8");
35988
+ raw = await readFile27(join38(absDir, LOCK_FILE), "utf-8");
35760
35989
  } catch {
35761
35990
  console.log(
35762
35991
  ` No ${LOCK_FILE} found \u2014 run \`codebyplan docs sync\` first.
@@ -35785,7 +36014,7 @@ async function runDocsStatus() {
35785
36014
  let outOfSync = 0;
35786
36015
  for (const name of names) {
35787
36016
  const entry = lock.libraries[name];
35788
- const versionPath = join37(absDir, libDirName(name), entry.resolved_version);
36017
+ const versionPath = join38(absDir, libDirName(name), entry.resolved_version);
35789
36018
  const expected = Object.keys(entry.files).length;
35790
36019
  if (!existsSync13(versionPath)) {
35791
36020
  outOfSync++;
@@ -35873,7 +36102,7 @@ var init_docs = __esm({
35873
36102
 
35874
36103
  // src/lib/check-baseline.ts
35875
36104
  import { readFileSync as readFileSync12, writeFileSync as writeFileSync7 } from "node:fs";
35876
- import { join as join38 } from "node:path";
36105
+ import { join as join39 } from "node:path";
35877
36106
  function emptyBaseline() {
35878
36107
  return {
35879
36108
  lint: { known_failing: [] },
@@ -35883,7 +36112,7 @@ function emptyBaseline() {
35883
36112
  };
35884
36113
  }
35885
36114
  function loadBaseline(projectRoot) {
35886
- const filePath = join38(projectRoot, BASELINE_FILENAME);
36115
+ const filePath = join39(projectRoot, BASELINE_FILENAME);
35887
36116
  try {
35888
36117
  const raw = readFileSync12(filePath, "utf-8");
35889
36118
  const parsed = JSON.parse(raw);
@@ -35907,7 +36136,7 @@ function loadBaseline(projectRoot) {
35907
36136
  }
35908
36137
  }
35909
36138
  function saveBaseline(projectRoot, baseline) {
35910
- const filePath = join38(projectRoot, BASELINE_FILENAME);
36139
+ const filePath = join39(projectRoot, BASELINE_FILENAME);
35911
36140
  writeFileSync7(filePath, JSON.stringify(baseline, null, 2) + "\n", "utf-8");
35912
36141
  }
35913
36142
  function diffBaseline(check, currentFailingPackages, baseline) {
@@ -35957,8 +36186,8 @@ var init_check_baseline = __esm({
35957
36186
 
35958
36187
  // src/lib/check.ts
35959
36188
  import { readFileSync as readFileSync13, existsSync as existsSync14 } from "node:fs";
35960
- import { join as join39 } from "node:path";
35961
- import { spawnSync as spawnSync10 } from "node:child_process";
36189
+ import { join as join40 } from "node:path";
36190
+ import { spawnSync as spawnSync11 } from "node:child_process";
35962
36191
  function hasSentinelValue(arrays) {
35963
36192
  const SENTINELS = /* @__PURE__ */ new Set([
35964
36193
  SUMMARY_UNREADABLE,
@@ -35973,7 +36202,7 @@ function resolveNewFailures(check, failingPackages, baseline, updateBaseline, no
35973
36202
  return diffBaseline(check, failingPackages, baseline);
35974
36203
  }
35975
36204
  function defaultSpawnFn(command, opts) {
35976
- const result = spawnSync10(command, {
36205
+ const result = spawnSync11(command, {
35977
36206
  shell: true,
35978
36207
  cwd: opts.cwd,
35979
36208
  encoding: "utf-8",
@@ -36025,9 +36254,9 @@ function parseFailingPackagesFromSummary(summaryPath) {
36025
36254
  return Array.from(failing).sort();
36026
36255
  }
36027
36256
  function resolveTurboBin(projectRoot) {
36028
- const localBin = join39(projectRoot, "node_modules", ".bin", "turbo");
36257
+ const localBin = join40(projectRoot, "node_modules", ".bin", "turbo");
36029
36258
  if (existsSync14(localBin)) return localBin;
36030
- const workspaceRootBin = join39(
36259
+ const workspaceRootBin = join40(
36031
36260
  projectRoot,
36032
36261
  "..",
36033
36262
  "..",
@@ -36524,7 +36753,7 @@ var init_check2 = __esm({
36524
36753
 
36525
36754
  // src/lib/claude-plan.ts
36526
36755
  import * as fs13 from "node:fs";
36527
- import * as path13 from "node:path";
36756
+ import * as path14 from "node:path";
36528
36757
  function buildDriftPlan(projectDir, templatesDir, manifest) {
36529
36758
  const packaged = walkTemplates(templatesDir);
36530
36759
  const packagedBySrc = new Map(packaged.map((f) => [f.src, f]));
@@ -36538,8 +36767,8 @@ function buildDriftPlan(projectDir, templatesDir, manifest) {
36538
36767
  };
36539
36768
  for (const pkg of packaged) {
36540
36769
  const inManifest = manifestBySrc.get(pkg.src);
36541
- const absDest = path13.join(projectDir, ".claude", pkg.dest);
36542
- const absSrc = path13.join(templatesDir, pkg.src);
36770
+ const absDest = path14.join(projectDir, ".claude", pkg.dest);
36771
+ const absSrc = path14.join(templatesDir, pkg.src);
36543
36772
  if (!inManifest) {
36544
36773
  plan.newOptIn.push({
36545
36774
  packaged: { src: pkg.src, dest: pkg.dest, hash: pkg.hash },
@@ -36588,7 +36817,7 @@ __export(status_exports, {
36588
36817
  runStatus: () => runStatus2
36589
36818
  });
36590
36819
  import * as fs14 from "node:fs";
36591
- import * as path14 from "node:path";
36820
+ import * as path15 from "node:path";
36592
36821
  import { execSync as execSync9 } from "node:child_process";
36593
36822
  function makeFailSafe(checked_at) {
36594
36823
  return {
@@ -36601,6 +36830,8 @@ function makeFailSafe(checked_at) {
36601
36830
  new_in_package: [],
36602
36831
  removed_from_package: [],
36603
36832
  settings_drift: false,
36833
+ settings_missing: false,
36834
+ settings_ignored: false,
36604
36835
  guarded: true,
36605
36836
  guard_reason: "unknown",
36606
36837
  in_sync: true,
@@ -36666,6 +36897,8 @@ async function runStatus2(argv) {
36666
36897
  new_in_package: [],
36667
36898
  removed_from_package: [],
36668
36899
  settings_drift: false,
36900
+ settings_missing: false,
36901
+ settings_ignored: false,
36669
36902
  guarded: true,
36670
36903
  // guarded:true must always pair with a non-null reason. canonical_source
36671
36904
  // keeps its reason; the bare no-manifest case (never-installed consumer)
@@ -36693,12 +36926,12 @@ async function runStatus2(argv) {
36693
36926
  const latest = fetchLatestVersion();
36694
36927
  const newer = latest !== null && compareSemver(latest, installed) > 0;
36695
36928
  let settings_drift = false;
36696
- const settingsPath = path14.join(projectDir, ".claude", "settings.json");
36697
- const baseSettingsPath = path14.join(
36929
+ const settingsPath = path15.join(projectDir, ".claude", "settings.json");
36930
+ const baseSettingsPath = path15.join(
36698
36931
  templatesDir,
36699
36932
  "settings.project.base.json"
36700
36933
  );
36701
- const hooksJsonPath = path14.join(templatesDir, "hooks", "hooks.json");
36934
+ const hooksJsonPath = path15.join(templatesDir, "hooks", "hooks.json");
36702
36935
  if (fs14.existsSync(settingsPath)) {
36703
36936
  try {
36704
36937
  const settingsRaw = fs14.readFileSync(settingsPath, "utf8");
@@ -36722,6 +36955,8 @@ async function runStatus2(argv) {
36722
36955
  settings_drift = false;
36723
36956
  }
36724
36957
  }
36958
+ const settings_missing = !fs14.existsSync(settingsPath);
36959
+ const settings_ignored = detectSettingsIgnored(projectDir).status === "ignored";
36725
36960
  const in_sync = !version_skip && drifted_files.length === 0 && new_in_package.length === 0 && removed_from_package.length === 0 && !settings_drift;
36726
36961
  let action = null;
36727
36962
  if (guardReason !== "protected_branch") {
@@ -36737,6 +36972,8 @@ async function runStatus2(argv) {
36737
36972
  new_in_package,
36738
36973
  removed_from_package,
36739
36974
  settings_drift,
36975
+ settings_missing,
36976
+ settings_ignored,
36740
36977
  // Always false in the full-detection path: a protected_branch consumer
36741
36978
  // (the only guarded case that reaches here) must still SEE the segment;
36742
36979
  // only canonical_source / no-manifest (Branch A) report guarded:true.
@@ -36764,10 +37001,10 @@ function emitResult(result, writeCache, quiet, projectDir) {
36764
37001
  const json = JSON.stringify(result, null, 2);
36765
37002
  if (writeCache) {
36766
37003
  try {
36767
- const cacheDir = path14.join(projectDir, ".codebyplan");
37004
+ const cacheDir = path15.join(projectDir, ".codebyplan");
36768
37005
  fs14.mkdirSync(cacheDir, { recursive: true });
36769
37006
  fs14.writeFileSync(
36770
- path14.join(cacheDir, "claude-status.local.json"),
37007
+ path15.join(cacheDir, "claude-status.local.json"),
36771
37008
  json + "\n",
36772
37009
  "utf8"
36773
37010
  );
@@ -36789,6 +37026,7 @@ var init_status = __esm({
36789
37026
  init_claude_plan();
36790
37027
  init_settings_merge();
36791
37028
  init_version_status();
37029
+ init_gitignore_detect();
36792
37030
  }
36793
37031
  });
36794
37032
 
@@ -36910,7 +37148,7 @@ __export(update_exports, {
36910
37148
  });
36911
37149
  import * as fs15 from "node:fs";
36912
37150
  import * as os3 from "node:os";
36913
- import * as path15 from "node:path";
37151
+ import * as path16 from "node:path";
36914
37152
  async function runUpdate(opts, deps = {}) {
36915
37153
  await Promise.resolve();
36916
37154
  const scope = opts.scope ?? "project";
@@ -36946,9 +37184,9 @@ async function runUpdate(opts, deps = {}) {
36946
37184
  finalManifestEntries.push(e);
36947
37185
  }
36948
37186
  for (const { packaged, absSrc } of plan.overwriteSafe) {
36949
- const absDest = path15.join(projectDir, ".claude", packaged.dest);
37187
+ const absDest = path16.join(projectDir, ".claude", packaged.dest);
36950
37188
  if (!opts.dryRun) {
36951
- fs15.mkdirSync(path15.dirname(absDest), { recursive: true });
37189
+ fs15.mkdirSync(path16.dirname(absDest), { recursive: true });
36952
37190
  fs15.copyFileSync(absSrc, absDest);
36953
37191
  if (opts.verbose) console.log(`updated ${packaged.dest}`);
36954
37192
  } else if (opts.verbose) {
@@ -36961,7 +37199,7 @@ async function runUpdate(opts, deps = {}) {
36961
37199
  absSrc,
36962
37200
  onDiskContent
36963
37201
  } of plan.overwriteHandEdited) {
36964
- const absDest = path15.join(projectDir, ".claude", packaged.dest);
37202
+ const absDest = path16.join(projectDir, ".claude", packaged.dest);
36965
37203
  const newContent = fs15.readFileSync(absSrc);
36966
37204
  const showDiff = () => {
36967
37205
  console.log(
@@ -36974,7 +37212,7 @@ async function runUpdate(opts, deps = {}) {
36974
37212
  const answer = await promptOverwrite(packaged.dest, opts, showDiff);
36975
37213
  if (answer === "overwrite") {
36976
37214
  if (!opts.dryRun) {
36977
- fs15.mkdirSync(path15.dirname(absDest), { recursive: true });
37215
+ fs15.mkdirSync(path16.dirname(absDest), { recursive: true });
36978
37216
  fs15.copyFileSync(absSrc, absDest);
36979
37217
  }
36980
37218
  finalManifestEntries.push(packaged);
@@ -36990,9 +37228,9 @@ async function runUpdate(opts, deps = {}) {
36990
37228
  for (const { packaged, absSrc } of plan.newOptIn) {
36991
37229
  const answer = await promptOptIn(packaged.dest, opts);
36992
37230
  if (answer === "opt-in") {
36993
- const absDest = path15.join(projectDir, ".claude", packaged.dest);
37231
+ const absDest = path16.join(projectDir, ".claude", packaged.dest);
36994
37232
  if (!opts.dryRun) {
36995
- fs15.mkdirSync(path15.dirname(absDest), { recursive: true });
37233
+ fs15.mkdirSync(path16.dirname(absDest), { recursive: true });
36996
37234
  fs15.copyFileSync(absSrc, absDest);
36997
37235
  }
36998
37236
  finalManifestEntries.push(packaged);
@@ -37004,25 +37242,25 @@ async function runUpdate(opts, deps = {}) {
37004
37242
  for (const e of plan.removedFromPackage) {
37005
37243
  const answer = await promptRemove(e.dest, opts);
37006
37244
  if (answer === "remove") {
37007
- const absDest = path15.join(projectDir, ".claude", e.dest);
37245
+ const absDest = path16.join(projectDir, ".claude", e.dest);
37008
37246
  if (!opts.dryRun && fs15.existsSync(absDest)) {
37009
37247
  fs15.rmSync(absDest);
37010
- const claudeDir = path15.join(projectDir, ".claude");
37011
- let cur = path15.dirname(absDest);
37012
- while (cur !== claudeDir && cur !== path15.dirname(cur)) {
37013
- if (path15.dirname(cur) === claudeDir) break;
37248
+ const claudeDir = path16.join(projectDir, ".claude");
37249
+ let cur = path16.dirname(absDest);
37250
+ while (cur !== claudeDir && cur !== path16.dirname(cur)) {
37251
+ if (path16.dirname(cur) === claudeDir) break;
37014
37252
  try {
37015
37253
  fs15.rmdirSync(cur);
37016
37254
  if (opts.verbose)
37017
37255
  console.log(
37018
- `pruned empty dir ${path15.relative(claudeDir, cur)}`
37256
+ `pruned empty dir ${path16.relative(claudeDir, cur)}`
37019
37257
  );
37020
- cur = path15.dirname(cur);
37258
+ cur = path16.dirname(cur);
37021
37259
  } catch (err) {
37022
37260
  const code = err.code;
37023
37261
  if (code !== "ENOTEMPTY" && code !== "ENOENT") {
37024
37262
  console.warn(
37025
- `codebyplan claude: could not prune empty dir ${path15.relative(claudeDir, cur)}: ${err.message}`
37263
+ `codebyplan claude: could not prune empty dir ${path16.relative(claudeDir, cur)}: ${err.message}`
37026
37264
  );
37027
37265
  }
37028
37266
  break;
@@ -37034,12 +37272,12 @@ async function runUpdate(opts, deps = {}) {
37034
37272
  if (opts.verbose) console.log(`kept (untracked) ${e.dest}`);
37035
37273
  }
37036
37274
  }
37037
- const hooksJsonPath = path15.join(templatesDir, "hooks", "hooks.json");
37038
- const baseSettingsPath = path15.join(
37275
+ const hooksJsonPath = path16.join(templatesDir, "hooks", "hooks.json");
37276
+ const baseSettingsPath = path16.join(
37039
37277
  templatesDir,
37040
37278
  "settings.project.base.json"
37041
37279
  );
37042
- const settingsPath = path15.join(projectDir, ".claude", "settings.json");
37280
+ const settingsPath = path16.join(projectDir, ".claude", "settings.json");
37043
37281
  const existingSettings = fs15.existsSync(settingsPath) ? JSON.parse(fs15.readFileSync(settingsPath, "utf8")) : {};
37044
37282
  if (fs15.existsSync(baseSettingsPath)) {
37045
37283
  const base = JSON.parse(
@@ -37060,21 +37298,29 @@ async function runUpdate(opts, deps = {}) {
37060
37298
  ) : void 0
37061
37299
  );
37062
37300
  }
37301
+ await detectAndHealSettingsGitignore(
37302
+ projectDir,
37303
+ { yes: opts.yes, dryRun: opts.dryRun },
37304
+ deps.detectHealDeps
37305
+ );
37063
37306
  if (!opts.dryRun) {
37064
- fs15.mkdirSync(path15.dirname(settingsPath), { recursive: true });
37307
+ fs15.mkdirSync(path16.dirname(settingsPath), { recursive: true });
37065
37308
  fs15.writeFileSync(
37066
37309
  settingsPath,
37067
37310
  JSON.stringify(existingSettings, null, 2) + "\n",
37068
37311
  "utf8"
37069
37312
  );
37070
37313
  }
37314
+ if (!opts.dryRun) {
37315
+ warnIfSettingsUntracked(projectDir, deps.lsFilesDep);
37316
+ }
37071
37317
  const gitignoreAction = await ensureManagedGitignoreBlock(
37072
37318
  projectDir,
37073
37319
  opts.dryRun
37074
37320
  );
37075
37321
  if (opts.verbose && gitignoreAction !== "unchanged") {
37076
37322
  console.log(
37077
- `${opts.dryRun ? "[dry-run] would " : ""}${gitignoreAction} managed .gitignore block in ${path15.relative(projectDir, path15.join(projectDir, ".gitignore"))}`
37323
+ `${opts.dryRun ? "[dry-run] would " : ""}${gitignoreAction} managed .gitignore block in ${path16.relative(projectDir, path16.join(projectDir, ".gitignore"))}`
37078
37324
  );
37079
37325
  }
37080
37326
  if (!opts.dryRun) {
@@ -37114,9 +37360,9 @@ function runUpdateUser(opts, deps) {
37114
37360
  return;
37115
37361
  }
37116
37362
  try {
37117
- const userDir = deps.userDir ?? path15.join(os3.homedir(), ".claude");
37118
- const settingsPath = path15.join(userDir, "settings.json");
37119
- const userBaseSettingsPath = path15.join(
37363
+ const userDir = deps.userDir ?? path16.join(os3.homedir(), ".claude");
37364
+ const settingsPath = path16.join(userDir, "settings.json");
37365
+ const userBaseSettingsPath = path16.join(
37120
37366
  templatesDir,
37121
37367
  "settings.user.base.json"
37122
37368
  );
@@ -37169,6 +37415,7 @@ var init_update = __esm({
37169
37415
  "src/cli/claude/update.ts"() {
37170
37416
  "use strict";
37171
37417
  init_gitignore_block();
37418
+ init_gitignore_detect();
37172
37419
  init_templates_dir();
37173
37420
  init_manifest();
37174
37421
  init_settings_merge();
@@ -37187,7 +37434,7 @@ __export(uninstall_exports, {
37187
37434
  });
37188
37435
  import * as fs16 from "node:fs";
37189
37436
  import * as os4 from "node:os";
37190
- import * as path16 from "node:path";
37437
+ import * as path17 from "node:path";
37191
37438
  async function runUninstall(opts, deps = {}) {
37192
37439
  await Promise.resolve();
37193
37440
  const scope = opts.scope ?? "project";
@@ -37216,7 +37463,7 @@ async function runUninstall(opts, deps = {}) {
37216
37463
  let removed = 0;
37217
37464
  let warnings = 0;
37218
37465
  for (const entry of manifest.files) {
37219
- const abs = path16.join(projectDir, ".claude", entry.dest);
37466
+ const abs = path17.join(projectDir, ".claude", entry.dest);
37220
37467
  if (!fs16.existsSync(abs)) {
37221
37468
  console.warn(
37222
37469
  `codebyplan claude uninstall: ${entry.dest} already absent (skipping).`
@@ -37240,12 +37487,12 @@ async function runUninstall(opts, deps = {}) {
37240
37487
  if (!opts.dryRun) {
37241
37488
  pruneEmptyManagedDirs(projectDir);
37242
37489
  }
37243
- const settingsPath = path16.join(projectDir, ".claude", "settings.json");
37490
+ const settingsPath = path17.join(projectDir, ".claude", "settings.json");
37244
37491
  if (fs16.existsSync(settingsPath)) {
37245
37492
  const settings = JSON.parse(
37246
37493
  fs16.readFileSync(settingsPath, "utf8")
37247
37494
  );
37248
- const baseSettingsPath = templatesDir ? path16.join(templatesDir, "settings.project.base.json") : null;
37495
+ const baseSettingsPath = templatesDir ? path17.join(templatesDir, "settings.project.base.json") : null;
37249
37496
  if (baseSettingsPath && fs16.existsSync(baseSettingsPath)) {
37250
37497
  const base = JSON.parse(
37251
37498
  fs16.readFileSync(baseSettingsPath, "utf8")
@@ -37303,7 +37550,7 @@ function runUninstallUser(opts, deps) {
37303
37550
  }
37304
37551
  }
37305
37552
  try {
37306
- const userDir = deps.userDir ?? path16.join(os4.homedir(), ".claude");
37553
+ const userDir = deps.userDir ?? path17.join(os4.homedir(), ".claude");
37307
37554
  const existingManifest = readManifestForScope("user", userDir);
37308
37555
  if (!existingManifest) {
37309
37556
  console.error(
@@ -37312,12 +37559,12 @@ function runUninstallUser(opts, deps) {
37312
37559
  process.exitCode = 1;
37313
37560
  return;
37314
37561
  }
37315
- const settingsPath = path16.join(userDir, "settings.json");
37562
+ const settingsPath = path17.join(userDir, "settings.json");
37316
37563
  if (fs16.existsSync(settingsPath)) {
37317
37564
  const settings = JSON.parse(
37318
37565
  fs16.readFileSync(settingsPath, "utf8")
37319
37566
  );
37320
- const userBaseSettingsPath = templatesDir != null ? path16.join(templatesDir, "settings.user.base.json") : null;
37567
+ const userBaseSettingsPath = templatesDir != null ? path17.join(templatesDir, "settings.user.base.json") : null;
37321
37568
  if (userBaseSettingsPath && fs16.existsSync(userBaseSettingsPath)) {
37322
37569
  const userBase = JSON.parse(
37323
37570
  fs16.readFileSync(userBaseSettingsPath, "utf8")
@@ -37358,7 +37605,7 @@ function runUninstallUser(opts, deps) {
37358
37605
  function pruneEmptyManagedDirs(projectDir) {
37359
37606
  const managedRoots = ["skills", "agents", "hooks", "rules"];
37360
37607
  for (const root of managedRoots) {
37361
- const abs = path16.join(projectDir, ".claude", root);
37608
+ const abs = path17.join(projectDir, ".claude", root);
37362
37609
  if (!fs16.existsSync(abs)) continue;
37363
37610
  pruneLeafFirst(abs);
37364
37611
  }
@@ -37369,7 +37616,7 @@ function pruneLeafFirst(dir) {
37369
37616
  if (!stat3.isDirectory()) return;
37370
37617
  for (const entry of fs16.readdirSync(dir, { withFileTypes: true })) {
37371
37618
  if (entry.isDirectory()) {
37372
- pruneLeafFirst(path16.join(dir, entry.name));
37619
+ pruneLeafFirst(path17.join(dir, entry.name));
37373
37620
  }
37374
37621
  }
37375
37622
  const remaining = fs16.readdirSync(dir);
@@ -37390,7 +37637,7 @@ var init_uninstall = __esm({
37390
37637
 
37391
37638
  // src/lib/verify-parity.ts
37392
37639
  import * as fs17 from "node:fs";
37393
- import * as path17 from "node:path";
37640
+ import * as path18 from "node:path";
37394
37641
  function isValidScope(s) {
37395
37642
  return s === "org-shared" || s === "project-shared" || REPO_ONLY_RE.test(s);
37396
37643
  }
@@ -37407,25 +37654,25 @@ function checkSiblingParity(opts) {
37407
37654
  expectedOneSided = DEFAULT_EXPECTED_ONE_SIDED,
37408
37655
  ignoredSubtrees
37409
37656
  } = opts;
37410
- const defaultIgnored = [path17.join(claudeDir, "hooks", "__test-fixtures__")];
37657
+ const defaultIgnored = [path18.join(claudeDir, "hooks", "__test-fixtures__")];
37411
37658
  const ignored = ignoredSubtrees ?? defaultIgnored;
37412
37659
  const violations = [];
37413
37660
  const claudeSideRels = /* @__PURE__ */ new Set();
37414
37661
  for (const scanDir of SCAN_DIRS) {
37415
- const baseDir = path17.join(claudeDir, scanDir);
37662
+ const baseDir = path18.join(claudeDir, scanDir);
37416
37663
  if (!fs17.existsSync(baseDir)) continue;
37417
37664
  const entries = readdirRecursive(baseDir);
37418
37665
  for (const entry of entries) {
37419
- const absPath = path17.join(baseDir, entry);
37666
+ const absPath = path18.join(baseDir, entry);
37420
37667
  if (!fs17.lstatSync(absPath).isFile()) continue;
37421
37668
  if (ignored.some(
37422
- (ig) => absPath.startsWith(ig + path17.sep) || absPath === ig
37669
+ (ig) => absPath.startsWith(ig + path18.sep) || absPath === ig
37423
37670
  )) {
37424
37671
  continue;
37425
37672
  }
37426
- const relPath = path17.join(scanDir, entry).split(path17.sep).join("/");
37673
+ const relPath = path18.join(scanDir, entry).split(path18.sep).join("/");
37427
37674
  claudeSideRels.add(relPath);
37428
- const templatePath = path17.join(templatesDir, relPath);
37675
+ const templatePath = path18.join(templatesDir, relPath);
37429
37676
  if (!fs17.existsSync(templatePath)) {
37430
37677
  if (!expectedOneSided.has(relPath) && !isScaffoldFile(entry)) {
37431
37678
  violations.push({ type: "missing-twin", path: relPath });
@@ -37440,14 +37687,14 @@ function checkSiblingParity(opts) {
37440
37687
  }
37441
37688
  }
37442
37689
  for (const scanDir of SCAN_DIRS) {
37443
- const tplBase = path17.join(templatesDir, scanDir);
37690
+ const tplBase = path18.join(templatesDir, scanDir);
37444
37691
  if (!fs17.existsSync(tplBase)) continue;
37445
37692
  const entries = readdirRecursive(tplBase);
37446
37693
  for (const entry of entries) {
37447
- const absPath = path17.join(tplBase, entry);
37694
+ const absPath = path18.join(tplBase, entry);
37448
37695
  if (!fs17.lstatSync(absPath).isFile()) continue;
37449
37696
  if (isScaffoldFile(entry)) continue;
37450
- const relPath = path17.join(scanDir, entry).split(path17.sep).join("/");
37697
+ const relPath = path18.join(scanDir, entry).split(path18.sep).join("/");
37451
37698
  if (!claudeSideRels.has(relPath) && !expectedOneSided.has(relPath)) {
37452
37699
  violations.push({ type: "extra-twin", path: relPath });
37453
37700
  }
@@ -37483,18 +37730,18 @@ function checkScopeMarkers(opts) {
37483
37730
  const twinDetectionActive = templatesDir != null && fs17.existsSync(templatesDir);
37484
37731
  const violations = [];
37485
37732
  for (const scanDir of scanDirs) {
37486
- const baseDir = path17.join(claudeDir, scanDir);
37733
+ const baseDir = path18.join(claudeDir, scanDir);
37487
37734
  if (!fs17.existsSync(baseDir)) continue;
37488
37735
  const entries = readdirRecursive(baseDir);
37489
37736
  for (const entry of entries) {
37490
- const absPath = path17.join(baseDir, entry);
37737
+ const absPath = path18.join(baseDir, entry);
37491
37738
  if (!fs17.lstatSync(absPath).isFile()) continue;
37492
37739
  if (!isStructuralEntry(scanDir, entry)) continue;
37493
- const ext = path17.extname(entry).toLowerCase();
37740
+ const ext = path18.extname(entry).toLowerCase();
37494
37741
  const isMd = ext === ".md";
37495
37742
  const isSh = ext === ".sh";
37496
37743
  if (!isMd && !isSh) continue;
37497
- const relPath = path17.join(scanDir, entry).split(path17.sep).join("/");
37744
+ const relPath = path18.join(scanDir, entry).split(path18.sep).join("/");
37498
37745
  if (allowlist.has(relPath)) continue;
37499
37746
  let content;
37500
37747
  try {
@@ -37508,7 +37755,7 @@ function checkScopeMarkers(opts) {
37508
37755
  continue;
37509
37756
  }
37510
37757
  const scopeValue = isMd ? extractFrontmatterScope(content) : extractShScope(content);
37511
- const managed = twinDetectionActive && fs17.existsSync(path17.join(templatesDir, relPath));
37758
+ const managed = twinDetectionActive && fs17.existsSync(path18.join(templatesDir, relPath));
37512
37759
  if (managed) {
37513
37760
  if (scopeValue === null) {
37514
37761
  } else if (scopeValue === "org-shared") {
@@ -37562,7 +37809,7 @@ function readdirRecursive(dir, rel = "", visited = /* @__PURE__ */ new Set()) {
37562
37809
  visited.add(realDir);
37563
37810
  const results = [];
37564
37811
  for (const name of fs17.readdirSync(dir)) {
37565
- const full = path17.join(dir, name);
37812
+ const full = path18.join(dir, name);
37566
37813
  const relName = rel ? `${rel}/${name}` : name;
37567
37814
  if (fs17.lstatSync(full).isDirectory()) {
37568
37815
  results.push(...readdirRecursive(full, relName, visited));
@@ -37635,12 +37882,12 @@ __export(verify_parity_exports, {
37635
37882
  verifyParity: () => verifyParity
37636
37883
  });
37637
37884
  import * as fs18 from "node:fs";
37638
- import * as path18 from "node:path";
37885
+ import * as path19 from "node:path";
37639
37886
  function verifyParity(args, deps = {}) {
37640
37887
  const warnOnly = args.includes("--warn-only");
37641
37888
  const jsonMode = args.includes("--json");
37642
37889
  const projectDir = deps.cwd ?? process.cwd();
37643
- const claudeDir = path18.join(projectDir, ".claude");
37890
+ const claudeDir = path19.join(projectDir, ".claude");
37644
37891
  if (!fs18.existsSync(claudeDir)) {
37645
37892
  const msg = "codebyplan claude verify-parity: .claude/ not found in cwd \u2014 run from the project root.\n";
37646
37893
  process.stderr.write(msg);
@@ -38147,11 +38394,11 @@ var generate_exports = {};
38147
38394
  __export(generate_exports, {
38148
38395
  runGenerate: () => runGenerate
38149
38396
  });
38150
- import { readFile as readFile27, mkdir as mkdir13, writeFile as writeFile21 } from "node:fs/promises";
38151
- import { join as join46, resolve as resolve11 } from "node:path";
38397
+ import { readFile as readFile28, mkdir as mkdir13, writeFile as writeFile22 } from "node:fs/promises";
38398
+ import { join as join47, resolve as resolve11 } from "node:path";
38152
38399
  async function readJsonFile4(filePath) {
38153
38400
  try {
38154
- const raw = await readFile27(filePath, "utf-8");
38401
+ const raw = await readFile28(filePath, "utf-8");
38155
38402
  return JSON.parse(raw);
38156
38403
  } catch {
38157
38404
  return null;
@@ -38159,7 +38406,7 @@ async function readJsonFile4(filePath) {
38159
38406
  }
38160
38407
  async function readPkgName(absPath) {
38161
38408
  try {
38162
- const raw = await readFile27(join46(absPath, "package.json"), "utf-8");
38409
+ const raw = await readFile28(join47(absPath, "package.json"), "utf-8");
38163
38410
  const pkg = JSON.parse(raw);
38164
38411
  return typeof pkg.name === "string" ? pkg.name : null;
38165
38412
  } catch {
@@ -38173,7 +38420,7 @@ async function runGenerate(opts) {
38173
38420
  const rootDir = resolve11(projectDir);
38174
38421
  let packageManager;
38175
38422
  try {
38176
- const raw = await readFile27(join46(rootDir, "package.json"), "utf-8");
38423
+ const raw = await readFile28(join47(rootDir, "package.json"), "utf-8");
38177
38424
  const pkg = JSON.parse(raw);
38178
38425
  if (typeof pkg.packageManager === "string") {
38179
38426
  packageManager = pkg.packageManager;
@@ -38181,7 +38428,7 @@ async function runGenerate(opts) {
38181
38428
  } catch {
38182
38429
  }
38183
38430
  const serverJson = await readJsonFile4(
38184
- join46(rootDir, ".codebyplan", "server.json")
38431
+ join47(rootDir, ".codebyplan", "server.json")
38185
38432
  );
38186
38433
  const ports = [];
38187
38434
  for (const alloc of serverJson?.port_allocations ?? []) {
@@ -38194,7 +38441,7 @@ async function runGenerate(opts) {
38194
38441
  }
38195
38442
  }
38196
38443
  const gitJson = await readJsonFile4(
38197
- join46(rootDir, ".codebyplan", "git.json")
38444
+ join47(rootDir, ".codebyplan", "git.json")
38198
38445
  );
38199
38446
  const branchModel = gitJson?.branch_config?.production ? {
38200
38447
  production: gitJson.branch_config.production,
@@ -38203,7 +38450,7 @@ async function runGenerate(opts) {
38203
38450
  )
38204
38451
  } : void 0;
38205
38452
  const shipmentJson = await readJsonFile4(
38206
- join46(rootDir, ".codebyplan", "shipment.json")
38453
+ join47(rootDir, ".codebyplan", "shipment.json")
38207
38454
  );
38208
38455
  const shipmentSurfaces = [];
38209
38456
  const rawSurfaces = shipmentJson?.shipment?.surfaces ?? shipmentJson?.surfaces ?? {};
@@ -38274,10 +38521,10 @@ async function runGenerate(opts) {
38274
38521
  const structureMdContent = generateStructureMd(config);
38275
38522
  const agentsContent = generateAgentsMd(structureMdContent);
38276
38523
  if (check) {
38277
- const agentsMdPath2 = join46(rootDir, "AGENTS.md");
38524
+ const agentsMdPath2 = join47(rootDir, "AGENTS.md");
38278
38525
  let existingAgents = null;
38279
38526
  try {
38280
- existingAgents = await readFile27(agentsMdPath2, "utf-8");
38527
+ existingAgents = await readFile28(agentsMdPath2, "utf-8");
38281
38528
  } catch {
38282
38529
  existingAgents = null;
38283
38530
  }
@@ -38313,16 +38560,16 @@ async function runGenerate(opts) {
38313
38560
  process.stdout.write(agentsContent);
38314
38561
  return;
38315
38562
  }
38316
- const outputDir = join46(rootDir, ".claude", "generated");
38563
+ const outputDir = join47(rootDir, ".claude", "generated");
38317
38564
  await mkdir13(outputDir, { recursive: true });
38318
- const outputPath = join46(outputDir, "structure.md");
38319
- await writeFile21(outputPath, structureMdContent, "utf-8");
38565
+ const outputPath = join47(outputDir, "structure.md");
38566
+ await writeFile22(outputPath, structureMdContent, "utf-8");
38320
38567
  process.stdout.write(`Wrote: .claude/generated/structure.md
38321
38568
  `);
38322
- const agentsMdPath = join46(rootDir, "AGENTS.md");
38569
+ const agentsMdPath = join47(rootDir, "AGENTS.md");
38323
38570
  let existingAgentsContent = null;
38324
38571
  try {
38325
- existingAgentsContent = await readFile27(agentsMdPath, "utf-8");
38572
+ existingAgentsContent = await readFile28(agentsMdPath, "utf-8");
38326
38573
  } catch {
38327
38574
  existingAgentsContent = null;
38328
38575
  }
@@ -38330,7 +38577,7 @@ async function runGenerate(opts) {
38330
38577
  process.stdout.write(`Up to date: AGENTS.md
38331
38578
  `);
38332
38579
  } else {
38333
- await writeFile21(agentsMdPath, agentsContent, "utf-8");
38580
+ await writeFile22(agentsMdPath, agentsContent, "utf-8");
38334
38581
  process.stdout.write(`Wrote: AGENTS.md
38335
38582
  `);
38336
38583
  }
@@ -38350,11 +38597,11 @@ __export(readme_exports, {
38350
38597
  runReadme: () => runReadme,
38351
38598
  runReadmeCommand: () => runReadmeCommand
38352
38599
  });
38353
- import { readFile as readFile28, writeFile as writeFile22 } from "node:fs/promises";
38354
- import { join as join47, resolve as resolve12, relative as relative9 } from "node:path";
38600
+ import { readFile as readFile29, writeFile as writeFile23 } from "node:fs/promises";
38601
+ import { join as join48, resolve as resolve12, relative as relative9 } from "node:path";
38355
38602
  async function readJsonFile5(filePath) {
38356
38603
  try {
38357
- const raw = await readFile28(filePath, "utf-8");
38604
+ const raw = await readFile29(filePath, "utf-8");
38358
38605
  return JSON.parse(raw);
38359
38606
  } catch {
38360
38607
  return null;
@@ -38423,7 +38670,7 @@ async function discoverUnits(rootDir, rootPkgJson) {
38423
38670
  const discovered = await discoverMonorepoApps(rootDir);
38424
38671
  for (const app of discovered) {
38425
38672
  const pkgJson = await readJsonFile5(
38426
- join47(app.absPath, "package.json")
38673
+ join48(app.absPath, "package.json")
38427
38674
  );
38428
38675
  pkgJsonByPath.set(app.absPath, pkgJson);
38429
38676
  allPackages.push({
@@ -38449,7 +38696,7 @@ async function runReadme(opts) {
38449
38696
  const init = opts.init ?? opts["init"] ?? false;
38450
38697
  const rootDir = resolve12(projectDir);
38451
38698
  const rootPkgJson = await readJsonFile5(
38452
- join47(rootDir, "package.json")
38699
+ join48(rootDir, "package.json")
38453
38700
  );
38454
38701
  const { units, allPackages, pkgJsonByPath } = await discoverUnits(
38455
38702
  rootDir,
@@ -38458,11 +38705,11 @@ async function runReadme(opts) {
38458
38705
  const driftUnits = [];
38459
38706
  const missingUnits = [];
38460
38707
  for (const unit of units) {
38461
- const readmePath = join47(unit.absPath, "README.md");
38462
- const relPath = unit.isRoot ? "README.md" : join47(relative9(rootDir, unit.absPath), "README.md");
38708
+ const readmePath = join48(unit.absPath, "README.md");
38709
+ const relPath = unit.isRoot ? "README.md" : join48(relative9(rootDir, unit.absPath), "README.md");
38463
38710
  let existingContent = null;
38464
38711
  try {
38465
- existingContent = await readFile28(readmePath, "utf-8");
38712
+ existingContent = await readFile29(readmePath, "utf-8");
38466
38713
  } catch {
38467
38714
  existingContent = null;
38468
38715
  }
@@ -38497,7 +38744,7 @@ ${newContent}
38497
38744
  `
38498
38745
  );
38499
38746
  } else {
38500
- await writeFile22(readmePath, newContent, "utf-8");
38747
+ await writeFile23(readmePath, newContent, "utf-8");
38501
38748
  process.stdout.write(`Wrote (scaffold): ${relPath}
38502
38749
  `);
38503
38750
  }
@@ -38535,7 +38782,7 @@ ${newContent}
38535
38782
  `
38536
38783
  );
38537
38784
  } else {
38538
- await writeFile22(readmePath, newContent, "utf-8");
38785
+ await writeFile23(readmePath, newContent, "utf-8");
38539
38786
  process.stdout.write(`Wrote (refresh): ${relPath}
38540
38787
  `);
38541
38788
  }
@@ -38554,7 +38801,7 @@ ${newContent}
38554
38801
  `
38555
38802
  );
38556
38803
  } else {
38557
- await writeFile22(readmePath, newContent, "utf-8");
38804
+ await writeFile23(readmePath, newContent, "utf-8");
38558
38805
  process.stdout.write(`Wrote (init): ${relPath}
38559
38806
  `);
38560
38807
  }
@@ -38642,15 +38889,15 @@ __export(migrate_memory_exports, {
38642
38889
  runMigrateMemory: () => runMigrateMemory
38643
38890
  });
38644
38891
  import {
38645
- readFile as readFile29,
38646
- writeFile as writeFile23,
38892
+ readFile as readFile30,
38893
+ writeFile as writeFile24,
38647
38894
  mkdir as mkdir14,
38648
38895
  unlink as unlink6,
38649
38896
  rmdir,
38650
38897
  readdir as readdir7
38651
38898
  } from "node:fs/promises";
38652
38899
  import { existsSync as existsSync21 } from "node:fs";
38653
- import { join as join48, resolve as resolve13, dirname as dirname15, sep as sep4 } from "node:path";
38900
+ import { join as join49, resolve as resolve13, dirname as dirname15, sep as sep4 } from "node:path";
38654
38901
  import { homedir as homedir8 } from "node:os";
38655
38902
  function encodeProjectPath(absPath) {
38656
38903
  return resolve13(absPath).replace(/[/\\]/g, "-");
@@ -38661,7 +38908,7 @@ function resolveAutoMemoryDir(opts) {
38661
38908
  }
38662
38909
  const projectDir = opts.projectDir ?? process.cwd();
38663
38910
  const encoded = encodeProjectPath(projectDir);
38664
- return join48(homedir8(), ".claude", "projects", encoded, "memory");
38911
+ return join49(homedir8(), ".claude", "projects", encoded, "memory");
38665
38912
  }
38666
38913
  function parseFrontmatter(content) {
38667
38914
  content = content.replace(/\r\n/g, "\n");
@@ -38727,10 +38974,10 @@ async function inventoryFiles(dir) {
38727
38974
  }
38728
38975
  const results = [];
38729
38976
  for (const filename of filenames) {
38730
- const sourcePath = join48(dir, filename);
38977
+ const sourcePath = join49(dir, filename);
38731
38978
  let raw;
38732
38979
  try {
38733
- raw = await readFile29(sourcePath, "utf-8");
38980
+ raw = await readFile30(sourcePath, "utf-8");
38734
38981
  } catch (err) {
38735
38982
  const msg = err instanceof Error ? err.message : String(err);
38736
38983
  results.push({
@@ -38816,8 +39063,8 @@ async function applyPlan(plan, opts) {
38816
39063
  if (entry.suggested_action !== "keep") continue;
38817
39064
  if (!entry.suggested_target?.startsWith("nested:")) continue;
38818
39065
  const relPath = entry.suggested_target.slice("nested:".length);
38819
- const targetDir = resolve13(join48(projectDir, relPath));
38820
- const targetFile = join48(targetDir, "CLAUDE.md");
39066
+ const targetDir = resolve13(join49(projectDir, relPath));
39067
+ const targetFile = join49(targetDir, "CLAUDE.md");
38821
39068
  if (!targetDir.startsWith(resolve13(projectDir) + sep4)) {
38822
39069
  process.stderr.write(
38823
39070
  `migrate-memory: skipping unsafe suggested_target "${entry.suggested_target}" \u2014 resolves outside projectDir
@@ -38849,11 +39096,11 @@ ${anchor}
38849
39096
  await mkdir14(targetDir, { recursive: true });
38850
39097
  let existing = "";
38851
39098
  try {
38852
- existing = await readFile29(targetFile, "utf-8");
39099
+ existing = await readFile30(targetFile, "utf-8");
38853
39100
  } catch {
38854
39101
  }
38855
39102
  if (!existing.includes(anchor)) {
38856
- await writeFile23(targetFile, existing + appendContent, "utf-8");
39103
+ await writeFile24(targetFile, existing + appendContent, "utf-8");
38857
39104
  }
38858
39105
  if (resolve13(entry.source_path).startsWith(resolve13(plan.auto_memory_dir) + sep4)) {
38859
39106
  try {
@@ -38867,7 +39114,7 @@ ${anchor}
38867
39114
  );
38868
39115
  }
38869
39116
  }
38870
- const rootClaudeMd = join48(projectDir, ".claude", "CLAUDE.md");
39117
+ const rootClaudeMd = join49(projectDir, ".claude", "CLAUDE.md");
38871
39118
  if (dryRun) {
38872
39119
  process.stdout.write(
38873
39120
  `[dry-run] Would ensure ${rootClaudeMd} contains: ${IMPORT_LINE}
@@ -38876,12 +39123,12 @@ ${anchor}
38876
39123
  } else {
38877
39124
  let claudeMdContent = "";
38878
39125
  try {
38879
- claudeMdContent = await readFile29(rootClaudeMd, "utf-8");
39126
+ claudeMdContent = await readFile30(rootClaudeMd, "utf-8");
38880
39127
  } catch {
38881
39128
  await mkdir14(dirname15(rootClaudeMd), { recursive: true });
38882
39129
  }
38883
39130
  if (!claudeMdContent.includes(IMPORT_LINE)) {
38884
- await writeFile23(
39131
+ await writeFile24(
38885
39132
  rootClaudeMd,
38886
39133
  claudeMdContent + `
38887
39134
  ${IMPORT_LINE}
@@ -38911,8 +39158,8 @@ ${IMPORT_LINE}
38911
39158
  } catch {
38912
39159
  }
38913
39160
  }
38914
- const memoryMd = join48(plan.auto_memory_dir, "MEMORY.md");
38915
- const safeRmdirBase = join48(homedir8(), ".claude", "projects");
39161
+ const memoryMd = join49(plan.auto_memory_dir, "MEMORY.md");
39162
+ const safeRmdirBase = join49(homedir8(), ".claude", "projects");
38916
39163
  if (dryRun) {
38917
39164
  process.stdout.write(`[dry-run] Would delete MEMORY.md: ${memoryMd}
38918
39165
  `);
@@ -38965,7 +39212,7 @@ async function runMigrateMemory(opts) {
38965
39212
  if (applyFile) {
38966
39213
  let planJson;
38967
39214
  try {
38968
- planJson = await readFile29(resolve13(applyFile), "utf-8");
39215
+ planJson = await readFile30(resolve13(applyFile), "utf-8");
38969
39216
  } catch (err) {
38970
39217
  const msg = err instanceof Error ? err.message : String(err);
38971
39218
  process.stderr.write(
@@ -39036,7 +39283,7 @@ var init_migrate_memory = __esm({
39036
39283
 
39037
39284
  // src/lib/claude-mode-audit.ts
39038
39285
  import { readdirSync as readdirSync7, readFileSync as readFileSync19, existsSync as existsSync22 } from "node:fs";
39039
- import { join as join49, basename as basename2 } from "node:path";
39286
+ import { join as join50, basename as basename2 } from "node:path";
39040
39287
  function parseFrontmatter2(content) {
39041
39288
  const match = /^---\r?\n([\s\S]*?)\r?\n---/.exec(content);
39042
39289
  if (!match) return {};
@@ -39113,19 +39360,19 @@ function auditSkill(filePath) {
39113
39360
  }
39114
39361
  function auditMode(templatesDir) {
39115
39362
  const entries = [];
39116
- const agentsDir = join49(templatesDir, "agents");
39363
+ const agentsDir = join50(templatesDir, "agents");
39117
39364
  if (existsSync22(agentsDir)) {
39118
39365
  const agentFiles = readdirSync7(agentsDir).filter((f) => f.endsWith(".md")).sort();
39119
39366
  for (const f of agentFiles) {
39120
- entries.push(auditAgent(join49(agentsDir, f)));
39367
+ entries.push(auditAgent(join50(agentsDir, f)));
39121
39368
  }
39122
39369
  }
39123
- const skillsDir = join49(templatesDir, "skills");
39370
+ const skillsDir = join50(templatesDir, "skills");
39124
39371
  if (existsSync22(skillsDir)) {
39125
39372
  const skillDirs = readdirSync7(skillsDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name).sort();
39126
39373
  for (const dir of skillDirs) {
39127
- if (existsSync22(join49(skillsDir, dir, "PROVENANCE.md"))) continue;
39128
- const skillMd = join49(skillsDir, dir, "SKILL.md");
39374
+ if (existsSync22(join50(skillsDir, dir, "PROVENANCE.md"))) continue;
39375
+ const skillMd = join50(skillsDir, dir, "SKILL.md");
39129
39376
  if (existsSync22(skillMd)) {
39130
39377
  entries.push(auditSkill(skillMd));
39131
39378
  }
@@ -39230,9 +39477,9 @@ var resolve_preview_exports = {};
39230
39477
  __export(resolve_preview_exports, {
39231
39478
  resolvePreview: () => resolvePreview
39232
39479
  });
39233
- import { spawnSync as spawnSync11 } from "node:child_process";
39480
+ import { spawnSync as spawnSync12 } from "node:child_process";
39234
39481
  function defaultGetCurrentBranch(cwd) {
39235
- const result = spawnSync11("git", ["rev-parse", "--abbrev-ref", "HEAD"], {
39482
+ const result = spawnSync12("git", ["rev-parse", "--abbrev-ref", "HEAD"], {
39236
39483
  cwd,
39237
39484
  encoding: "utf-8",
39238
39485
  stdio: ["pipe", "pipe", "pipe"]
@@ -39384,7 +39631,7 @@ __export(new_migration_exports, {
39384
39631
  newMigration: () => newMigration
39385
39632
  });
39386
39633
  import * as fs19 from "node:fs";
39387
- import * as path19 from "node:path";
39634
+ import * as path20 from "node:path";
39388
39635
  function slugify(name) {
39389
39636
  return name.trim().toLowerCase().replace(/[^a-z0-9_-]+/g, "_").replace(/^_+|_+$/g, "").replace(/_+/g, "_");
39390
39637
  }
@@ -39405,9 +39652,9 @@ function newMigration(args, deps = {}) {
39405
39652
  }
39406
39653
  const slug = slugify(rawName);
39407
39654
  const stamp = genTimestamp({ cwd });
39408
- const migrationsDir = path19.join(cwd, "supabase", "migrations");
39655
+ const migrationsDir = path20.join(cwd, "supabase", "migrations");
39409
39656
  const filename = `${stamp}_${slug}.sql`;
39410
- const filePath = path19.join(migrationsDir, filename);
39657
+ const filePath = path20.join(migrationsDir, filename);
39411
39658
  mkdirSync11(migrationsDir, { recursive: true });
39412
39659
  writeFileSync12(filePath, "");
39413
39660
  process.stdout.write(JSON.stringify({ path: filePath }) + "\n");
@@ -39425,9 +39672,9 @@ var preview_check_exports = {};
39425
39672
  __export(preview_check_exports, {
39426
39673
  previewCheck: () => previewCheck
39427
39674
  });
39428
- import { spawnSync as spawnSync12 } from "node:child_process";
39675
+ import { spawnSync as spawnSync13 } from "node:child_process";
39429
39676
  function defaultRun3(cmd, args) {
39430
- const result = spawnSync12(cmd, args, {
39677
+ const result = spawnSync13(cmd, args, {
39431
39678
  encoding: "utf-8",
39432
39679
  stdio: ["pipe", "pipe", "pipe"]
39433
39680
  });
@@ -39482,10 +39729,10 @@ var init_preview_check = __esm({
39482
39729
  });
39483
39730
 
39484
39731
  // src/lib/session.ts
39485
- import { spawnSync as spawnSync13 } from "node:child_process";
39486
- import * as path20 from "node:path";
39732
+ import { spawnSync as spawnSync14 } from "node:child_process";
39733
+ import * as path21 from "node:path";
39487
39734
  function defaultRun4(cmd, args, cwd) {
39488
- const result = spawnSync13(cmd, args, {
39735
+ const result = spawnSync14(cmd, args, {
39489
39736
  cwd,
39490
39737
  encoding: "utf-8",
39491
39738
  stdio: ["pipe", "pipe", "pipe"]
@@ -39513,7 +39760,7 @@ function homeFf(opts = {}) {
39513
39760
  reason: "git rev-parse --show-toplevel failed"
39514
39761
  };
39515
39762
  }
39516
- const folder = path20.basename(repoRoot);
39763
+ const folder = path21.basename(repoRoot);
39517
39764
  let current;
39518
39765
  try {
39519
39766
  current = run("git", ["rev-parse", "--abbrev-ref", "HEAD"], cwd).trim();
@@ -39546,7 +39793,7 @@ function homeFf(opts = {}) {
39546
39793
  }
39547
39794
  function spawnVersionStatus(cwd) {
39548
39795
  try {
39549
- const result = spawnSync13("npx", ["codebyplan", "version-status"], {
39796
+ const result = spawnSync14("npx", ["codebyplan", "version-status"], {
39550
39797
  cwd,
39551
39798
  encoding: "utf-8",
39552
39799
  stdio: ["pipe", "pipe", "pipe"]
@@ -39580,7 +39827,7 @@ function defaultRunInstall(installCommand, cwd) {
39580
39827
  const cmd = parts[0];
39581
39828
  const args = parts.slice(1);
39582
39829
  if (!cmd) throw new Error("empty installCommand");
39583
- const result = spawnSync13(cmd, args, {
39830
+ const result = spawnSync14(cmd, args, {
39584
39831
  cwd,
39585
39832
  encoding: "utf-8",
39586
39833
  stdio: ["pipe", "pipe", "pipe"]
@@ -39594,7 +39841,7 @@ function defaultRunInstall(installCommand, cwd) {
39594
39841
  }
39595
39842
  }
39596
39843
  function defaultRunClaudeUpdate(cwd) {
39597
- const result = spawnSync13("npx", ["codebyplan", "claude", "update", "--yes"], {
39844
+ const result = spawnSync14("npx", ["codebyplan", "claude", "update", "--yes"], {
39598
39845
  cwd,
39599
39846
  encoding: "utf-8",
39600
39847
  stdio: ["pipe", "pipe", "pipe"]
@@ -39608,7 +39855,7 @@ function defaultRunClaudeUpdate(cwd) {
39608
39855
  }
39609
39856
  }
39610
39857
  function defaultRunGitStatus(cwd) {
39611
- const result = spawnSync13(
39858
+ const result = spawnSync14(
39612
39859
  "git",
39613
39860
  ["status", "--porcelain", "--", ".claude/", ".codebyplan/"],
39614
39861
  {
@@ -39861,9 +40108,9 @@ var commit_exports = {};
39861
40108
  __export(commit_exports, {
39862
40109
  runCommitCommand: () => runCommitCommand
39863
40110
  });
39864
- import { spawnSync as spawnSync14 } from "node:child_process";
40111
+ import { spawnSync as spawnSync15 } from "node:child_process";
39865
40112
  function defaultRun5(cmd, args) {
39866
- const result = spawnSync14(cmd, args, {
40113
+ const result = spawnSync15(cmd, args, {
39867
40114
  encoding: "utf-8",
39868
40115
  stdio: ["pipe", "pipe", "pipe"]
39869
40116
  });
@@ -39911,7 +40158,7 @@ var init_commit = __esm({
39911
40158
  });
39912
40159
 
39913
40160
  // src/lib/migration-collisions.ts
39914
- import { spawnSync as spawnSync15 } from "node:child_process";
40161
+ import { spawnSync as spawnSync16 } from "node:child_process";
39915
40162
  function extractPrefix(filename) {
39916
40163
  const base = filename.endsWith(".sql") ? filename.slice(0, -4) : filename;
39917
40164
  const underscoreIdx = base.indexOf("_");
@@ -39923,7 +40170,7 @@ function extractPrefix(filename) {
39923
40170
  }
39924
40171
  function makeDefaultRun(cwd) {
39925
40172
  return (cmd, args) => {
39926
- const result = spawnSync15(cmd, args, {
40173
+ const result = spawnSync16(cmd, args, {
39927
40174
  cwd,
39928
40175
  encoding: "utf-8",
39929
40176
  stdio: ["pipe", "pipe", "pipe"]
@@ -40080,13 +40327,13 @@ function validateWaves(waves) {
40080
40327
  pathOwners.set(file, owners);
40081
40328
  }
40082
40329
  }
40083
- for (const [path21, owners] of pathOwners) {
40330
+ for (const [path22, owners] of pathOwners) {
40084
40331
  if (owners.length > 1) {
40085
40332
  violations.push({
40086
40333
  invariant: "I",
40087
40334
  code: "DUPLICATE_FILE",
40088
- message: `File "${path21}" appears in multiple waves: ${owners.join(", ")}.`,
40089
- detail: { path: path21, waves: owners }
40335
+ message: `File "${path22}" appears in multiple waves: ${owners.join(", ")}.`,
40336
+ detail: { path: path22, waves: owners }
40090
40337
  });
40091
40338
  }
40092
40339
  }
@@ -40180,7 +40427,7 @@ var validate_waves_exports = {};
40180
40427
  __export(validate_waves_exports, {
40181
40428
  runValidateWavesCommand: () => runValidateWavesCommand
40182
40429
  });
40183
- import { readFile as readFile30 } from "node:fs/promises";
40430
+ import { readFile as readFile31 } from "node:fs/promises";
40184
40431
  async function readStdin() {
40185
40432
  return new Promise((resolve16, reject) => {
40186
40433
  const chunks = [];
@@ -40199,7 +40446,7 @@ async function runValidateWavesCommand(args) {
40199
40446
  let raw;
40200
40447
  if (filePath) {
40201
40448
  try {
40202
- raw = await readFile30(filePath, "utf-8");
40449
+ raw = await readFile31(filePath, "utf-8");
40203
40450
  } catch (err) {
40204
40451
  const msg = err instanceof Error ? err.message : String(err);
40205
40452
  process.stderr.write(
@@ -40279,12 +40526,12 @@ var init_validate_waves2 = __esm({
40279
40526
  });
40280
40527
 
40281
40528
  // src/cli/worktree/path.ts
40282
- import { dirname as dirname16, basename as basename4, join as join51 } from "node:path";
40529
+ import { dirname as dirname16, basename as basename4, join as join52 } from "node:path";
40283
40530
  function computeWorktreePath(cwd, checkpointNumber) {
40284
40531
  const parent = dirname16(cwd);
40285
40532
  const base = basename4(cwd);
40286
40533
  const nnn = String(checkpointNumber).padStart(3, "0");
40287
- return join51(parent, `${base}-CHK-${nnn}`);
40534
+ return join52(parent, `${base}-CHK-${nnn}`);
40288
40535
  }
40289
40536
  var init_path = __esm({
40290
40537
  "src/cli/worktree/path.ts"() {
@@ -40293,9 +40540,9 @@ var init_path = __esm({
40293
40540
  });
40294
40541
 
40295
40542
  // src/cli/worktree/add.ts
40296
- import { join as join52, basename as basename5 } from "node:path";
40297
- import { mkdir as mkdir15, readFile as readFile31, writeFile as writeFile24 } from "node:fs/promises";
40298
- import { spawnSync as spawnSync16 } from "node:child_process";
40543
+ import { join as join53, basename as basename5 } from "node:path";
40544
+ import { mkdir as mkdir15, readFile as readFile32, writeFile as writeFile25 } from "node:fs/promises";
40545
+ import { spawnSync as spawnSync17 } from "node:child_process";
40299
40546
  async function defaultGetRepoId(cwd) {
40300
40547
  const found = await findCodebyplanConfig(cwd);
40301
40548
  return found?.contents.repo_id ?? null;
@@ -40324,7 +40571,7 @@ async function defaultLookupBranch(repoId, checkpointNumber) {
40324
40571
  return { found: true, branch_name: chk.branch_name };
40325
40572
  }
40326
40573
  function defaultGitRun(args, cwd) {
40327
- const result = spawnSync16("git", args, {
40574
+ const result = spawnSync17("git", args, {
40328
40575
  cwd,
40329
40576
  encoding: "utf-8",
40330
40577
  stdio: ["pipe", "pipe", "pipe"]
@@ -40336,34 +40583,56 @@ function defaultGitRun(args, cwd) {
40336
40583
  error: result.error
40337
40584
  };
40338
40585
  }
40586
+ async function copyClaudeSettings(srcCwd, destPath, deps = {}) {
40587
+ const readFileFn = deps.readFileFn ?? ((p) => readFile32(p, "utf-8"));
40588
+ const writeFileFn = deps.writeFileFn ?? ((p, content) => writeFile25(p, content, "utf-8"));
40589
+ const existsFn = deps.existsFn ?? ((p) => import("node:fs/promises").then(
40590
+ (fsp) => fsp.access(p).then(() => true).catch(() => false)
40591
+ ));
40592
+ const mkdirFn = deps.mkdirFn ?? ((p, opts) => mkdir15(p, opts));
40593
+ await mkdirFn(join53(destPath, ".claude"), { recursive: true });
40594
+ const claudeStubs = ["settings.json", "settings.local.json"];
40595
+ for (const stub of claudeStubs) {
40596
+ const srcFile = join53(srcCwd, ".claude", stub);
40597
+ const destFile = join53(destPath, ".claude", stub);
40598
+ try {
40599
+ const destExists = await existsFn(destFile);
40600
+ if (destExists) continue;
40601
+ const content = await readFileFn(srcFile);
40602
+ await writeFileFn(destFile, content);
40603
+ } catch {
40604
+ }
40605
+ }
40606
+ }
40339
40607
  async function defaultCopyConfigStubs(srcCwd, destPath) {
40340
- await mkdir15(join52(destPath, ".codebyplan"), { recursive: true });
40608
+ await mkdir15(join53(destPath, ".codebyplan"), { recursive: true });
40341
40609
  const topLevelStubs = [".mcp.json", ".env.local"];
40342
40610
  for (const stub of topLevelStubs) {
40343
40611
  try {
40344
- const content = await readFile31(join52(srcCwd, stub), "utf-8");
40345
- await writeFile24(join52(destPath, stub), content, "utf-8");
40612
+ const content = await readFile32(join53(srcCwd, stub), "utf-8");
40613
+ await writeFile25(join53(destPath, stub), content, "utf-8");
40346
40614
  } catch {
40347
40615
  }
40348
40616
  }
40349
40617
  try {
40350
- const content = await readFile31(
40351
- join52(srcCwd, ".codebyplan", "repo.json"),
40618
+ const content = await readFile32(
40619
+ join53(srcCwd, ".codebyplan", "repo.json"),
40352
40620
  "utf-8"
40353
40621
  );
40354
- await writeFile24(
40355
- join52(destPath, ".codebyplan", "repo.json"),
40622
+ await writeFile25(
40623
+ join53(destPath, ".codebyplan", "repo.json"),
40356
40624
  content,
40357
40625
  "utf-8"
40358
40626
  );
40359
40627
  } catch {
40360
40628
  }
40629
+ await copyClaudeSettings(srcCwd, destPath);
40361
40630
  }
40362
- async function defaultRegisterWorktree(repoId, name, path21) {
40631
+ async function defaultRegisterWorktree(repoId, name, path22) {
40363
40632
  const res = await apiPost("/worktrees", {
40364
40633
  repo_id: repoId,
40365
40634
  name,
40366
- path: path21,
40635
+ path: path22,
40367
40636
  status: "active"
40368
40637
  });
40369
40638
  return { worktree_id: res.data.id };
@@ -40461,10 +40730,12 @@ async function runWorktreeAdd(args, deps = {}) {
40461
40730
  );
40462
40731
  return 1;
40463
40732
  }
40733
+ let copyStubsWarn;
40464
40734
  try {
40465
40735
  await copyConfigStubs(cwd, worktreePath);
40466
40736
  } catch (err) {
40467
40737
  const msg = err instanceof Error ? err.message : String(err);
40738
+ copyStubsWarn = `Failed to copy config stubs: ${msg}`;
40468
40739
  process.stderr.write(`Warning: failed to copy config stubs: ${msg}
40469
40740
  `);
40470
40741
  }
@@ -40478,7 +40749,8 @@ async function runWorktreeAdd(args, deps = {}) {
40478
40749
  status: "added",
40479
40750
  worktree_path: worktreePath,
40480
40751
  branch_name: branchName,
40481
- worktree_id
40752
+ worktree_id,
40753
+ ...copyStubsWarn ? { warn: copyStubsWarn } : {}
40482
40754
  };
40483
40755
  process.stdout.write(JSON.stringify(result) + "\n");
40484
40756
  return 0;
@@ -40513,7 +40785,7 @@ var init_add = __esm({
40513
40785
  });
40514
40786
 
40515
40787
  // src/cli/worktree/create.ts
40516
- import { join as join53 } from "node:path";
40788
+ import { join as join54 } from "node:path";
40517
40789
  async function defaultGetRepoIdentity(cwd) {
40518
40790
  const found = await findCodebyplanConfig(cwd);
40519
40791
  const contents = found?.contents ?? null;
@@ -40525,11 +40797,11 @@ async function defaultGetRepoIdentity(cwd) {
40525
40797
  project_id: typeof contents?.["project_id"] === "string" ? contents["project_id"] : void 0
40526
40798
  };
40527
40799
  }
40528
- async function defaultRegisterWorktree2(repoId, name, path21) {
40800
+ async function defaultRegisterWorktree2(repoId, name, path22) {
40529
40801
  const res = await apiPost("/worktrees", {
40530
40802
  repo_id: repoId,
40531
40803
  name,
40532
- path: path21,
40804
+ path: path22,
40533
40805
  status: "active"
40534
40806
  });
40535
40807
  return { worktree_id: res.data.id };
@@ -40558,6 +40830,7 @@ async function runWorktreeCreate(args, deps = {}) {
40558
40830
  const getRepoIdentity = deps.getRepoIdentity ?? defaultGetRepoIdentity;
40559
40831
  const getDeviceId = deps.getDeviceId ?? getOrCreateDeviceId;
40560
40832
  const registerWorktree = deps.registerWorktree ?? defaultRegisterWorktree2;
40833
+ const copyClaudeSettingsFn = deps.copyClaudeSettingsFn ?? ((srcCwd, destPath) => copyClaudeSettings(srcCwd, destPath));
40561
40834
  const identity = await getRepoIdentity(cwd);
40562
40835
  const repoId = identity?.repo_id ?? null;
40563
40836
  if (!identity || !repoId) {
@@ -40568,7 +40841,7 @@ async function runWorktreeCreate(args, deps = {}) {
40568
40841
  );
40569
40842
  return 1;
40570
40843
  }
40571
- const worktreePath = explicitPath ?? join53(cwd, "..", name);
40844
+ const worktreePath = explicitPath ?? join54(cwd, "..", name);
40572
40845
  const deviceId = await getDeviceId(cwd);
40573
40846
  let filesWritten = false;
40574
40847
  try {
@@ -40593,12 +40866,19 @@ async function runWorktreeCreate(args, deps = {}) {
40593
40866
  process.stdout.write(JSON.stringify(result) + "\n");
40594
40867
  return 0;
40595
40868
  }
40869
+ let copyWarn;
40870
+ try {
40871
+ await copyClaudeSettingsFn(cwd, worktreePath);
40872
+ } catch (err) {
40873
+ copyWarn = err instanceof Error ? err.message : String(err);
40874
+ }
40596
40875
  try {
40597
40876
  const { worktree_id } = await registerWorktree(repoId, name, worktreePath);
40598
40877
  const result = {
40599
40878
  worktree_files_written: true,
40600
40879
  mcp_registered: true,
40601
- worktree_id
40880
+ worktree_id,
40881
+ ...copyWarn ? { warn: `Settings copy failed (non-fatal): ${copyWarn}` } : {}
40602
40882
  };
40603
40883
  process.stdout.write(JSON.stringify(result) + "\n");
40604
40884
  return 0;
@@ -40620,12 +40900,13 @@ var init_create = __esm({
40620
40900
  init_local_config();
40621
40901
  init_api();
40622
40902
  init_worktree();
40903
+ init_add();
40623
40904
  }
40624
40905
  });
40625
40906
 
40626
40907
  // src/cli/worktree/remove.ts
40627
40908
  import { basename as basename6 } from "node:path";
40628
- import { spawnSync as spawnSync17 } from "node:child_process";
40909
+ import { spawnSync as spawnSync18 } from "node:child_process";
40629
40910
  async function defaultGetRepoId2(cwd) {
40630
40911
  const found = await findCodebyplanConfig(cwd);
40631
40912
  return found?.contents.repo_id ?? null;
@@ -40647,7 +40928,7 @@ async function defaultDeregisterWorktree(worktreeId) {
40647
40928
  await mcpCall("delete_worktree", { worktree_id: worktreeId });
40648
40929
  }
40649
40930
  function defaultGitRun2(args, cwd) {
40650
- const result = spawnSync17("git", args, {
40931
+ const result = spawnSync18("git", args, {
40651
40932
  cwd,
40652
40933
  encoding: "utf-8",
40653
40934
  stdio: ["pipe", "pipe", "pipe"]
@@ -40660,7 +40941,7 @@ function defaultGitRun2(args, cwd) {
40660
40941
  };
40661
40942
  }
40662
40943
  function defaultGetWorktreeBranchName(worktreePath) {
40663
- const result = spawnSync17("git", ["symbolic-ref", "--short", "HEAD"], {
40944
+ const result = spawnSync18("git", ["symbolic-ref", "--short", "HEAD"], {
40664
40945
  cwd: worktreePath,
40665
40946
  encoding: "utf-8",
40666
40947
  stdio: ["pipe", "pipe", "pipe"]
@@ -41071,7 +41352,7 @@ var init_e2e = __esm({
41071
41352
  });
41072
41353
 
41073
41354
  // src/cli/e2e/verify-round.ts
41074
- import { readFile as readFile32 } from "node:fs/promises";
41355
+ import { readFile as readFile33 } from "node:fs/promises";
41075
41356
  import { resolve as resolve14 } from "node:path";
41076
41357
  async function defaultFetchRounds(taskId) {
41077
41358
  return mcpCall("get_rounds", { task_id: taskId });
@@ -41079,7 +41360,7 @@ async function defaultFetchRounds(taskId) {
41079
41360
  async function defaultReadE2eConfig(cwd) {
41080
41361
  try {
41081
41362
  const p = resolve14(cwd, ".codebyplan", "e2e.json");
41082
- const raw = await readFile32(p, "utf-8");
41363
+ const raw = await readFile33(p, "utf-8");
41083
41364
  return JSON.parse(raw);
41084
41365
  } catch {
41085
41366
  return null;
@@ -41204,6 +41485,8 @@ var doctor_exports = {};
41204
41485
  __export(doctor_exports, {
41205
41486
  runDoctor: () => runDoctor
41206
41487
  });
41488
+ import { existsSync as existsSync23 } from "node:fs";
41489
+ import { join as join55 } from "node:path";
41207
41490
  import { execSync as execSync10 } from "node:child_process";
41208
41491
  async function checkAuth() {
41209
41492
  try {
@@ -41310,6 +41593,75 @@ async function checkWorktree() {
41310
41593
  };
41311
41594
  }
41312
41595
  }
41596
+ function checkSettings() {
41597
+ try {
41598
+ let projectDir;
41599
+ try {
41600
+ projectDir = execSync10("git rev-parse --show-toplevel", {
41601
+ encoding: "utf-8"
41602
+ }).trim();
41603
+ } catch {
41604
+ projectDir = process.cwd();
41605
+ }
41606
+ if (readManifest(projectDir) === null) {
41607
+ return {
41608
+ name: "settings",
41609
+ status: "skip",
41610
+ detail: "codebyplan not installed (no .cbp.manifest.json)"
41611
+ };
41612
+ }
41613
+ if (!existsSync23(join55(projectDir, ".claude", "settings.json"))) {
41614
+ return {
41615
+ name: "settings",
41616
+ status: "warn",
41617
+ detail: ".claude/settings.json missing \u2014 run `codebyplan claude update` to recreate, then git add + commit"
41618
+ };
41619
+ }
41620
+ const ignoreResult = detectSettingsIgnored(projectDir);
41621
+ if (ignoreResult.status === "non-git") {
41622
+ return {
41623
+ name: "settings",
41624
+ status: "skip",
41625
+ detail: "not in a git repo"
41626
+ };
41627
+ }
41628
+ if (ignoreResult.status === "ignored") {
41629
+ const { sourceFile, lineNum, pattern } = ignoreResult.info;
41630
+ return {
41631
+ name: "settings",
41632
+ status: "warn",
41633
+ detail: `.claude/settings.json is gitignored by "${pattern}" (${sourceFile}:${lineNum}) \u2014 remove the rule or run \`codebyplan claude update\` to auto-heal specific rules, then git add + commit`
41634
+ };
41635
+ }
41636
+ const trackedStatus = checkSettingsUntracked(projectDir);
41637
+ if (trackedStatus === "untracked") {
41638
+ return {
41639
+ name: "settings",
41640
+ status: "warn",
41641
+ detail: ".claude/settings.json is untracked \u2014 run `git add .claude/settings.json` and commit it"
41642
+ };
41643
+ }
41644
+ if (trackedStatus === "non-git") {
41645
+ return {
41646
+ name: "settings",
41647
+ status: "skip",
41648
+ detail: "not in a git repo"
41649
+ };
41650
+ }
41651
+ return {
41652
+ name: "settings",
41653
+ status: "ok",
41654
+ detail: ".claude/settings.json present and tracked"
41655
+ };
41656
+ } catch (err) {
41657
+ const msg = err instanceof Error ? err.message : String(err);
41658
+ return {
41659
+ name: "settings",
41660
+ status: "warn",
41661
+ detail: `settings check failed: ${msg}`
41662
+ };
41663
+ }
41664
+ }
41313
41665
  function overallStatus(checks) {
41314
41666
  if (checks.some((c) => c.status === "fail")) return "fail";
41315
41667
  if (checks.some((c) => c.status === "warn")) return "warn";
@@ -41334,7 +41686,7 @@ function printHuman(result) {
41334
41686
  }
41335
41687
  function printHelp6() {
41336
41688
  process.stdout.write(
41337
- "\n codebyplan doctor [--json]\n\n Run diagnostics: auth, version, worktree.\n Always exits 0 \u2014 safe for scripted use.\n\n Flags:\n --json Emit structured JSON instead of the human table\n\n"
41689
+ "\n codebyplan doctor [--json]\n\n Run diagnostics: auth, version, worktree, settings.\n Always exits 0 \u2014 safe for scripted use.\n\n Flags:\n --json Emit structured JSON instead of the human table\n\n"
41338
41690
  );
41339
41691
  }
41340
41692
  async function runDoctor(args) {
@@ -41348,7 +41700,8 @@ async function runDoctor(args) {
41348
41700
  const checks = await Promise.all([
41349
41701
  checkAuth(),
41350
41702
  checkVersion(),
41351
- checkWorktree()
41703
+ checkWorktree(),
41704
+ Promise.resolve(checkSettings())
41352
41705
  ]);
41353
41706
  const result = {
41354
41707
  checks,
@@ -41372,6 +41725,8 @@ var init_doctor = __esm({
41372
41725
  init_flags();
41373
41726
  init_local_config();
41374
41727
  init_resolve_worktree();
41728
+ init_manifest();
41729
+ init_gitignore_detect();
41375
41730
  }
41376
41731
  });
41377
41732