codebyplan 1.13.55 → 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.55";
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;
@@ -31701,15 +31930,26 @@ function detectPnpmVersionFromPackageJson(projectDir) {
31701
31930
  return "10";
31702
31931
  }
31703
31932
  }
31933
+ function detectStrictEnforcedFromCiJson(projectDir) {
31934
+ try {
31935
+ const ciJsonPath = path10.join(projectDir, ".codebyplan", "ci.json");
31936
+ const raw = fs9.readFileSync(ciJsonPath, "utf-8");
31937
+ const parsed = JSON.parse(raw);
31938
+ return parsed.workflow?.strict_check_enforced === true;
31939
+ } catch {
31940
+ return false;
31941
+ }
31942
+ }
31704
31943
  async function runScaffoldCiWorkflow(opts) {
31705
31944
  await Promise.resolve();
31706
31945
  const dryRun = opts?.dryRun ?? false;
31707
31946
  const force = opts?.force ?? false;
31708
- const projectDir = path9.resolve(opts?.projectDir ?? process.cwd());
31947
+ const projectDir = path10.resolve(opts?.projectDir ?? process.cwd());
31709
31948
  const pnpmVersion = opts?.pnpmVersion ?? detectPnpmVersionFromPackageJson(projectDir);
31710
31949
  const nodeVersion = opts?.nodeVersion ?? "22";
31950
+ const strictEnforced = opts?.strictEnforced ?? detectStrictEnforcedFromCiJson(projectDir);
31711
31951
  const templatesDir = opts?.templatesDir ?? resolveTemplatesDir();
31712
- const templatePath = path9.join(templatesDir, "github-workflows", "ci.yml");
31952
+ const templatePath = path10.join(templatesDir, "github-workflows", "ci.yml");
31713
31953
  if (!fs9.existsSync(templatePath)) {
31714
31954
  throw new Error(
31715
31955
  `scaffold-ci-workflow: template not found at ${templatePath}`
@@ -31718,9 +31958,11 @@ async function runScaffoldCiWorkflow(opts) {
31718
31958
  const rawTemplate = fs9.readFileSync(templatePath, "utf-8");
31719
31959
  const renderedContent = substituteTokens(rawTemplate, {
31720
31960
  PNPM_VERSION: pnpmVersion,
31721
- NODE_VERSION: nodeVersion
31961
+ NODE_VERSION: nodeVersion,
31962
+ STRICT_NAME_SUFFIX: strictEnforced ? "" : " (report-only)",
31963
+ STRICT_CONTINUE_ON_ERROR_LINE: strictEnforced ? "" : "\n continue-on-error: true"
31722
31964
  });
31723
- const targetPath = path9.join(projectDir, ".github", "workflows", "ci.yml");
31965
+ const targetPath = path10.join(projectDir, ".github", "workflows", "ci.yml");
31724
31966
  if (dryRun) {
31725
31967
  return { status: "dry_run", path: targetPath };
31726
31968
  }
@@ -31739,7 +31981,7 @@ async function runScaffoldCiWorkflow(opts) {
31739
31981
  );
31740
31982
  }
31741
31983
  }
31742
- const targetDir = path9.dirname(targetPath);
31984
+ const targetDir = path10.dirname(targetPath);
31743
31985
  fs9.mkdirSync(targetDir, { recursive: true });
31744
31986
  const tmpPath = targetPath + ".tmp";
31745
31987
  try {
@@ -31763,10 +32005,10 @@ var init_scaffold_ci_workflow = __esm({
31763
32005
 
31764
32006
  // src/lib/gh-required-checks.ts
31765
32007
  import * as fs10 from "node:fs";
31766
- import * as path10 from "node:path";
32008
+ import * as path11 from "node:path";
31767
32009
  import { execSync as execSync6 } from "node:child_process";
31768
32010
  function readCiJson(projectDir) {
31769
- const ciPath = path10.join(projectDir, ".codebyplan", "ci.json");
32011
+ const ciPath = path11.join(projectDir, ".codebyplan", "ci.json");
31770
32012
  if (!fs10.existsSync(ciPath)) {
31771
32013
  return {
31772
32014
  platforms: {},
@@ -31785,15 +32027,15 @@ function readCiJson(projectDir) {
31785
32027
  }
31786
32028
  }
31787
32029
  function writeCiJsonAtomic(projectDir, config) {
31788
- const ciPath = path10.join(projectDir, ".codebyplan", "ci.json");
32030
+ const ciPath = path11.join(projectDir, ".codebyplan", "ci.json");
31789
32031
  writeJsonAtomic(ciPath, config);
31790
32032
  }
31791
32033
  function enforceRequiredCheck(opts) {
31792
- const projectDir = path10.resolve(opts?.projectDir ?? process.cwd());
32034
+ const projectDir = path11.resolve(opts?.projectDir ?? process.cwd());
31793
32035
  const branch = opts?.branch ?? "main";
31794
32036
  const checkName = opts?.checkName ?? "Lint + typecheck + test + build";
31795
32037
  const dryRun = opts?.dryRun ?? false;
31796
- const ciPath = path10.join(projectDir, ".codebyplan", "ci.json");
32038
+ const ciPath = path11.join(projectDir, ".codebyplan", "ci.json");
31797
32039
  const config = readCiJson(projectDir);
31798
32040
  if (config.workflow?.required_check_enforced === true) {
31799
32041
  return { status: "already_enforced", path: ciPath };
@@ -31963,7 +32205,7 @@ function parseFlagsFromArgs2(args) {
31963
32205
  }
31964
32206
  function printHelp3() {
31965
32207
  process.stdout.write(
31966
- '\n codebyplan ci\n\n CI configuration management \u2014 detect platforms, scaffold workflow, enforce required check.\n\n Subcommands:\n init Detect platforms and write/update .codebyplan/ci.json\n scaffold-workflow Write .github/workflows/ci.yml from the bundled template\n enforce-check Enforce the required CI status check on a GitHub branch\n resolve <category> Resolve the shell command for a CI check category (unit_test|typecheck|build|lint|e2e|audit)\n\n Flags (all subcommands):\n --dry-run Preview the operation without writing any files\n --force Overwrite existing content that differs\n --project-dir <p> Target project root (default: current directory)\n --json Emit structured JSON to stdout\n\n Flags (scaffold-workflow only):\n --pnpm-version <v> pnpm version for {{PNPM_VERSION}} token (default: auto-detected from package.json packageManager, falls back to "10")\n --node-version <v> Node.js version for {{NODE_VERSION}} token (default: "22")\n\n Flags (enforce-check only):\n --branch <b> Branch to enforce (default: "main")\n --check-name <n> Status check name (default: "Lint + typecheck + test + build")\n\n Flags (resolve only):\n --platform <slug> Platform slug to resolve against (e.g. next_js, nestjs, package)\n --json Emit the full CiResolveResult as JSON\n\n'
32208
+ '\n codebyplan ci\n\n CI configuration management \u2014 detect platforms, scaffold workflow, enforce required check.\n\n Subcommands:\n init Detect platforms and write/update .codebyplan/ci.json\n scaffold-workflow Write .github/workflows/ci.yml from the bundled template\n enforce-check Enforce the required CI status check on a GitHub branch\n resolve <category> Resolve the shell command for a CI check category (unit_test|typecheck|build|lint|e2e|audit)\n\n Flags (all subcommands):\n --dry-run Preview the operation without writing any files\n --force Overwrite existing content that differs\n --project-dir <p> Target project root (default: current directory)\n --json Emit structured JSON to stdout\n\n Flags (scaffold-workflow only):\n --pnpm-version <v> pnpm version for {{PNPM_VERSION}} token (default: auto-detected from package.json packageManager, falls back to "10")\n --node-version <v> Node.js version for {{NODE_VERSION}} token (default: "22")\n --strict-enforced Emit ci-strict as an enforced gate (continue-on-error:false, no\n report-only suffix). Default: read .codebyplan/ci.json\n workflow.strict_check_enforced (falls back to report-only)\n\n Flags (enforce-check only):\n --branch <b> Branch to enforce (default: "main")\n --check-name <n> Status check name (default: "Lint + typecheck + test + build")\n\n Flags (resolve only):\n --platform <slug> Platform slug to resolve against (e.g. next_js, nestjs, package)\n --json Emit the full CiResolveResult as JSON\n\n'
31967
32209
  );
31968
32210
  }
31969
32211
  function printInitResult(result) {
@@ -32062,6 +32304,7 @@ async function runCiCommand(args) {
32062
32304
  if (subcommand === "scaffold-workflow") {
32063
32305
  const pnpmVersion = flags["pnpm-version"];
32064
32306
  const nodeVersion = flags["node-version"];
32307
+ const strictEnforced = flags["strict-enforced"] ? true : void 0;
32065
32308
  let result;
32066
32309
  try {
32067
32310
  result = await runScaffoldCiWorkflow({
@@ -32069,7 +32312,8 @@ async function runCiCommand(args) {
32069
32312
  force,
32070
32313
  projectDir,
32071
32314
  pnpmVersion,
32072
- nodeVersion
32315
+ nodeVersion,
32316
+ strictEnforced
32073
32317
  });
32074
32318
  } catch (err) {
32075
32319
  process.stderr.write(
@@ -32198,9 +32442,9 @@ var init_ci = __esm({
32198
32442
 
32199
32443
  // src/lib/cd-init.ts
32200
32444
  import * as fs11 from "node:fs";
32201
- import * as path11 from "node:path";
32445
+ import * as path12 from "node:path";
32202
32446
  function detectSurfaces(projectDir) {
32203
- const shipmentPath = path11.join(projectDir, ".codebyplan", "shipment.json");
32447
+ const shipmentPath = path12.join(projectDir, ".codebyplan", "shipment.json");
32204
32448
  let shipment;
32205
32449
  try {
32206
32450
  shipment = JSON.parse(fs11.readFileSync(shipmentPath, "utf-8"));
@@ -32253,10 +32497,10 @@ function buildDefaultCdConfig(rawSurfaceKeys) {
32253
32497
  }
32254
32498
  async function runCdInit(opts) {
32255
32499
  await Promise.resolve();
32256
- const projectDir = path11.resolve(opts?.projectDir ?? process.cwd());
32500
+ const projectDir = path12.resolve(opts?.projectDir ?? process.cwd());
32257
32501
  const dryRun = opts?.dryRun ?? false;
32258
32502
  const force = opts?.force ?? false;
32259
- const cdPath = path11.join(projectDir, ".codebyplan", "cd.json");
32503
+ const cdPath = path12.join(projectDir, ".codebyplan", "cd.json");
32260
32504
  const rawSurfaceKeys = detectSurfaces(projectDir);
32261
32505
  const seen = /* @__PURE__ */ new Set();
32262
32506
  const surfaces = [];
@@ -32297,7 +32541,7 @@ async function runCdInit(opts) {
32297
32541
  surfaces: newSurfaces
32298
32542
  };
32299
32543
  }
32300
- const codebyplanDir = path11.join(projectDir, ".codebyplan");
32544
+ const codebyplanDir = path12.join(projectDir, ".codebyplan");
32301
32545
  fs11.mkdirSync(codebyplanDir, { recursive: true });
32302
32546
  writeJsonAtomic(cdPath, newConfig);
32303
32547
  return { status: "written", path: cdPath, surfaces };
@@ -32387,14 +32631,14 @@ var init_cd_init = __esm({
32387
32631
 
32388
32632
  // src/lib/scaffold-cd-workflow.ts
32389
32633
  import * as fs12 from "node:fs";
32390
- import * as path12 from "node:path";
32634
+ import * as path13 from "node:path";
32391
32635
  async function scaffoldOneWorkflow(templateName, targetName, opts) {
32392
32636
  await Promise.resolve();
32393
32637
  const dryRun = opts.dryRun ?? false;
32394
32638
  const force = opts.force ?? false;
32395
- const projectDir = path12.resolve(opts.projectDir ?? process.cwd());
32639
+ const projectDir = path13.resolve(opts.projectDir ?? process.cwd());
32396
32640
  const templatesDir = opts.templatesDir ?? resolveTemplatesDir();
32397
- const templatePath = path12.join(
32641
+ const templatePath = path13.join(
32398
32642
  templatesDir,
32399
32643
  "github-workflows",
32400
32644
  templateName
@@ -32405,7 +32649,7 @@ async function scaffoldOneWorkflow(templateName, targetName, opts) {
32405
32649
  );
32406
32650
  }
32407
32651
  const templateContent = fs12.readFileSync(templatePath, "utf-8");
32408
- const targetPath = path12.join(projectDir, ".github", "workflows", targetName);
32652
+ const targetPath = path13.join(projectDir, ".github", "workflows", targetName);
32409
32653
  if (dryRun) {
32410
32654
  return { status: "dry_run", path: targetPath };
32411
32655
  }
@@ -32424,7 +32668,7 @@ async function scaffoldOneWorkflow(templateName, targetName, opts) {
32424
32668
  );
32425
32669
  }
32426
32670
  }
32427
- const targetDir = path12.dirname(targetPath);
32671
+ const targetDir = path13.dirname(targetPath);
32428
32672
  fs12.mkdirSync(targetDir, { recursive: true });
32429
32673
  const tmpPath = targetPath + ".tmp";
32430
32674
  try {
@@ -33100,7 +33344,7 @@ __export(version_status_exports, {
33100
33344
  });
33101
33345
  import { execFileSync, execSync as execSync7 } from "node:child_process";
33102
33346
  import { existsSync as existsSync10, readFileSync as readFileSync11 } from "node:fs";
33103
- import { dirname as dirname12, join as join30 } from "node:path";
33347
+ import { dirname as dirname12, join as join31 } from "node:path";
33104
33348
  function fetchLatestVersion() {
33105
33349
  try {
33106
33350
  return execFileSync("npm", ["view", "codebyplan", "version"], {
@@ -33124,9 +33368,9 @@ function detectPackageManager2(gitRoot) {
33124
33368
  let dir = process.cwd();
33125
33369
  const stopAt = gitRoot ?? null;
33126
33370
  while (true) {
33127
- if (existsSync10(join30(dir, "pnpm-lock.yaml"))) return "pnpm";
33128
- if (existsSync10(join30(dir, "yarn.lock"))) return "yarn";
33129
- 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";
33130
33374
  if (stopAt !== null && dir === stopAt) break;
33131
33375
  const parent = dirname12(dir);
33132
33376
  if (parent === dir) break;
@@ -33146,7 +33390,7 @@ function buildInstallCommand2(pm) {
33146
33390
  }
33147
33391
  async function resolveGuard(gitRoot, currentBranch) {
33148
33392
  if (gitRoot !== null) {
33149
- const canonicalPkgPath = join30(
33393
+ const canonicalPkgPath = join31(
33150
33394
  gitRoot,
33151
33395
  "packages",
33152
33396
  "codebyplan-package",
@@ -33170,10 +33414,10 @@ async function resolveGuard(gitRoot, currentBranch) {
33170
33414
  let gitJsonPath;
33171
33415
  if (found.path.endsWith("/repo.json")) {
33172
33416
  const dir = found.path.slice(0, found.path.lastIndexOf("/"));
33173
- gitJsonPath = join30(dir, "git.json");
33417
+ gitJsonPath = join31(dir, "git.json");
33174
33418
  } else {
33175
33419
  const legacyDir = found.path.slice(0, found.path.lastIndexOf("/"));
33176
- gitJsonPath = join30(legacyDir, ".codebyplan", "git.json");
33420
+ gitJsonPath = join31(legacyDir, ".codebyplan", "git.json");
33177
33421
  }
33178
33422
  const raw = readFileSync11(gitJsonPath, "utf-8");
33179
33423
  const parsed = JSON.parse(raw);
@@ -33257,8 +33501,8 @@ var upload_e2e_images_exports = {};
33257
33501
  __export(upload_e2e_images_exports, {
33258
33502
  runUploadE2eImagesCommand: () => runUploadE2eImagesCommand
33259
33503
  });
33260
- import { readFile as readFile19 } from "node:fs/promises";
33261
- 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";
33262
33506
  import { execSync as execSync8 } from "node:child_process";
33263
33507
  function baseUrl2() {
33264
33508
  return (process.env.CODEBYPLAN_API_URL ?? "https://www.codebyplan.com").replace(/\/$/, "");
@@ -33292,8 +33536,8 @@ function parseArgs(args) {
33292
33536
  }
33293
33537
  async function readE2eConfig(projectPath) {
33294
33538
  try {
33295
- const raw = await readFile19(
33296
- join31(projectPath, ".codebyplan", "e2e.json"),
33539
+ const raw = await readFile20(
33540
+ join32(projectPath, ".codebyplan", "e2e.json"),
33297
33541
  "utf-8"
33298
33542
  );
33299
33543
  return JSON.parse(raw);
@@ -33334,7 +33578,7 @@ function collectPngsFromGitDiff(projectPath, frameworkName, frameworkConfig, bas
33334
33578
  continue;
33335
33579
  const isNew = status === "A";
33336
33580
  results.push({
33337
- absolutePath: join31(projectPath, filePath),
33581
+ absolutePath: join32(projectPath, filePath),
33338
33582
  filename: basename(filePath),
33339
33583
  framework: frameworkName,
33340
33584
  is_new: isNew
@@ -33431,7 +33675,7 @@ async function runUploadE2eImagesCommand(args) {
33431
33675
  for (const png of allPngs) {
33432
33676
  let bytes;
33433
33677
  try {
33434
- bytes = await readFile19(png.absolutePath);
33678
+ bytes = await readFile20(png.absolutePath);
33435
33679
  } catch {
33436
33680
  process.stderr.write(
33437
33681
  `upload-e2e-images: could not read file: ${png.absolutePath}
@@ -33508,10 +33752,10 @@ __export(arch_map_exports, {
33508
33752
  runArchMapCommand: () => runArchMapCommand,
33509
33753
  updateFrontmatterFields: () => updateFrontmatterFields
33510
33754
  });
33511
- import { readFile as readFile20, writeFile as writeFile16 } from "node:fs/promises";
33755
+ import { readFile as readFile21, writeFile as writeFile17 } from "node:fs/promises";
33512
33756
  import { existsSync as existsSync11, readdirSync as readdirSync4 } from "node:fs";
33513
- import { join as join32 } from "node:path";
33514
- 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";
33515
33759
  function normalizeModulePath(modulePath) {
33516
33760
  return modulePath.replace(/\/+$/, "");
33517
33761
  }
@@ -33535,9 +33779,9 @@ async function resolveCodebyplanDir(startDir) {
33535
33779
  }
33536
33780
  }
33537
33781
  async function readArchitectureConfig(codebyplanDir) {
33538
- const filePath = join32(codebyplanDir, "architecture.json");
33782
+ const filePath = join33(codebyplanDir, "architecture.json");
33539
33783
  try {
33540
- const raw = await readFile20(filePath, "utf-8");
33784
+ const raw = await readFile21(filePath, "utf-8");
33541
33785
  const parsed = JSON.parse(raw);
33542
33786
  if (typeof parsed !== "object" || parsed === null || !Array.isArray(parsed.modules)) {
33543
33787
  return { version: 1, modules: [] };
@@ -33548,12 +33792,12 @@ async function readArchitectureConfig(codebyplanDir) {
33548
33792
  }
33549
33793
  }
33550
33794
  async function writeArchitectureConfig(codebyplanDir, config) {
33551
- const filePath = join32(codebyplanDir, "architecture.json");
33552
- 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");
33553
33797
  }
33554
33798
  function resolveGitSha(modulePath, cwd) {
33555
33799
  try {
33556
- const result = spawnSync9(
33800
+ const result = spawnSync10(
33557
33801
  "git",
33558
33802
  ["log", "--format=%H", "-1", "--", modulePath],
33559
33803
  { cwd, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
@@ -33567,10 +33811,10 @@ function resolveGitSha(modulePath, cwd) {
33567
33811
  }
33568
33812
  async function discoverModulePaths(projectRoot) {
33569
33813
  const paths = [];
33570
- const workspacePath = join32(projectRoot, "pnpm-workspace.yaml");
33814
+ const workspacePath = join33(projectRoot, "pnpm-workspace.yaml");
33571
33815
  let patterns = [];
33572
33816
  try {
33573
- const raw = await readFile20(workspacePath, "utf-8");
33817
+ const raw = await readFile21(workspacePath, "utf-8");
33574
33818
  const lines = raw.split("\n");
33575
33819
  let inPackages = false;
33576
33820
  for (const line of lines) {
@@ -33594,7 +33838,7 @@ async function discoverModulePaths(projectRoot) {
33594
33838
  for (const pattern of patterns) {
33595
33839
  if (pattern.endsWith("/*")) {
33596
33840
  const dir = pattern.slice(0, -2);
33597
- const absDir = join32(projectRoot, dir);
33841
+ const absDir = join33(projectRoot, dir);
33598
33842
  try {
33599
33843
  if (existsSync11(absDir)) {
33600
33844
  const entries = readdirSync4(absDir, { withFileTypes: true });
@@ -33607,7 +33851,7 @@ async function discoverModulePaths(projectRoot) {
33607
33851
  } catch {
33608
33852
  }
33609
33853
  } else if (!pattern.includes("*")) {
33610
- const absPath = join32(projectRoot, pattern);
33854
+ const absPath = join33(projectRoot, pattern);
33611
33855
  if (existsSync11(absPath)) {
33612
33856
  paths.push(pattern);
33613
33857
  }
@@ -33615,7 +33859,7 @@ async function discoverModulePaths(projectRoot) {
33615
33859
  }
33616
33860
  const crossCutting = ["supabase", ".github", "scripts"];
33617
33861
  for (const dir of crossCutting) {
33618
- const absPath = join32(projectRoot, dir);
33862
+ const absPath = join33(projectRoot, dir);
33619
33863
  try {
33620
33864
  if (existsSync11(absPath)) {
33621
33865
  paths.push(dir);
@@ -33801,10 +34045,10 @@ async function runStamp(modulePath, sha, depthArg, projectRoot) {
33801
34045
  }
33802
34046
  await writeArchitectureConfig(codebyplanDir, config);
33803
34047
  const stampedEntry = existingIndex >= 0 ? config.modules[existingIndex] : config.modules[config.modules.length - 1];
33804
- const mapAbsPath = join32(repoRoot, stampedEntry.map_file);
34048
+ const mapAbsPath = join33(repoRoot, stampedEntry.map_file);
33805
34049
  let mapContent = null;
33806
34050
  try {
33807
- mapContent = await readFile20(mapAbsPath, "utf-8");
34051
+ mapContent = await readFile21(mapAbsPath, "utf-8");
33808
34052
  } catch {
33809
34053
  console.warn(
33810
34054
  " Warning: map file " + stampedEntry.map_file + " not found \u2014 stamped manifest only"
@@ -33826,7 +34070,7 @@ async function runStamp(modulePath, sha, depthArg, projectRoot) {
33826
34070
  );
33827
34071
  } else {
33828
34072
  try {
33829
- await writeFile16(mapAbsPath, updated, "utf-8");
34073
+ await writeFile17(mapAbsPath, updated, "utf-8");
33830
34074
  } catch (writeErr) {
33831
34075
  console.warn(
33832
34076
  " Warning: could not write map file " + stampedEntry.map_file + " \u2014 " + (writeErr instanceof Error ? writeErr.message : String(writeErr)) + " \u2014 stamped manifest only"
@@ -34006,19 +34250,19 @@ var init_worktree_port_resolver = __esm({
34006
34250
  });
34007
34251
 
34008
34252
  // src/lib/migrate-local-config.ts
34009
- import { mkdir as mkdir9, readFile as readFile21, unlink as unlink5, writeFile as writeFile17 } from "node:fs/promises";
34010
- 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";
34011
34255
  function legacySharedPath(projectPath) {
34012
- return join33(projectPath, ".codebyplan.json");
34256
+ return join34(projectPath, ".codebyplan.json");
34013
34257
  }
34014
34258
  function legacyLocalPath(projectPath) {
34015
- return join33(projectPath, ".codebyplan.local.json");
34259
+ return join34(projectPath, ".codebyplan.local.json");
34016
34260
  }
34017
34261
  function newDirPath(projectPath) {
34018
- return join33(projectPath, ".codebyplan");
34262
+ return join34(projectPath, ".codebyplan");
34019
34263
  }
34020
34264
  function sentinelPath(projectPath) {
34021
- return join33(projectPath, ".codebyplan", "repo.json");
34265
+ return join34(projectPath, ".codebyplan", "repo.json");
34022
34266
  }
34023
34267
  async function statSafe(p) {
34024
34268
  const { stat: stat3 } = await import("node:fs/promises");
@@ -34057,7 +34301,7 @@ async function runLocalMigration(projectPath) {
34057
34301
  }
34058
34302
  let legacyRaw;
34059
34303
  try {
34060
- legacyRaw = await readFile21(legacySharedPath(projectPath), "utf-8");
34304
+ legacyRaw = await readFile22(legacySharedPath(projectPath), "utf-8");
34061
34305
  } catch {
34062
34306
  return {
34063
34307
  migrated: true,
@@ -34084,7 +34328,7 @@ async function runLocalMigration(projectPath) {
34084
34328
  let deviceId;
34085
34329
  let deviceWrittenByHelper = false;
34086
34330
  try {
34087
- const localRaw = await readFile21(legacyLocalPath(projectPath), "utf-8");
34331
+ const localRaw = await readFile22(legacyLocalPath(projectPath), "utf-8");
34088
34332
  const localParsed = JSON.parse(localRaw);
34089
34333
  if (typeof localParsed.device_id === "string") {
34090
34334
  deviceId = localParsed.device_id;
@@ -34111,8 +34355,8 @@ async function runLocalMigration(projectPath) {
34111
34355
  if ("repo_id" in cfg) repoJson.repo_id = cfg.repo_id;
34112
34356
  if ("organization_id" in cfg) repoJson.organization_id = cfg.organization_id;
34113
34357
  if ("project_id" in cfg) repoJson.project_id = cfg.project_id;
34114
- await writeFile17(
34115
- join33(projectPath, ".codebyplan", "repo.json"),
34358
+ await writeFile18(
34359
+ join34(projectPath, ".codebyplan", "repo.json"),
34116
34360
  JSON.stringify(repoJson, null, 2) + "\n",
34117
34361
  "utf-8"
34118
34362
  );
@@ -34124,8 +34368,8 @@ async function runLocalMigration(projectPath) {
34124
34368
  serverJson.auto_push_enabled = cfg.auto_push_enabled;
34125
34369
  if ("port_allocations" in cfg)
34126
34370
  serverJson.port_allocations = cfg.port_allocations;
34127
- await writeFile17(
34128
- join33(projectPath, ".codebyplan", "server.json"),
34371
+ await writeFile18(
34372
+ join34(projectPath, ".codebyplan", "server.json"),
34129
34373
  JSON.stringify(serverJson, null, 2) + "\n",
34130
34374
  "utf-8"
34131
34375
  );
@@ -34133,44 +34377,44 @@ async function runLocalMigration(projectPath) {
34133
34377
  const gitJson = {};
34134
34378
  if ("git_branch" in cfg) gitJson.git_branch = cfg.git_branch;
34135
34379
  if ("branch_config" in cfg) gitJson.branch_config = cfg.branch_config;
34136
- await writeFile17(
34137
- join33(projectPath, ".codebyplan", "git.json"),
34380
+ await writeFile18(
34381
+ join34(projectPath, ".codebyplan", "git.json"),
34138
34382
  JSON.stringify(gitJson, null, 2) + "\n",
34139
34383
  "utf-8"
34140
34384
  );
34141
34385
  filesChanged.push(".codebyplan/git.json");
34142
34386
  const shipmentJson = {};
34143
34387
  if ("shipment" in cfg) shipmentJson.shipment = cfg.shipment;
34144
- await writeFile17(
34145
- join33(projectPath, ".codebyplan", "shipment.json"),
34388
+ await writeFile18(
34389
+ join34(projectPath, ".codebyplan", "shipment.json"),
34146
34390
  JSON.stringify(shipmentJson, null, 2) + "\n",
34147
34391
  "utf-8"
34148
34392
  );
34149
34393
  filesChanged.push(".codebyplan/shipment.json");
34150
34394
  const vendorJson = {};
34151
- await writeFile17(
34152
- join33(projectPath, ".codebyplan", "vendor.json"),
34395
+ await writeFile18(
34396
+ join34(projectPath, ".codebyplan", "vendor.json"),
34153
34397
  JSON.stringify(vendorJson, null, 2) + "\n",
34154
34398
  "utf-8"
34155
34399
  );
34156
34400
  filesChanged.push(".codebyplan/vendor.json");
34157
34401
  const e2eJson = {};
34158
- await writeFile17(
34159
- join33(projectPath, ".codebyplan", "e2e.json"),
34402
+ await writeFile18(
34403
+ join34(projectPath, ".codebyplan", "e2e.json"),
34160
34404
  JSON.stringify(e2eJson, null, 2) + "\n",
34161
34405
  "utf-8"
34162
34406
  );
34163
34407
  filesChanged.push(".codebyplan/e2e.json");
34164
34408
  const eslintJson = {};
34165
- await writeFile17(
34166
- join33(projectPath, ".codebyplan", "eslint.json"),
34409
+ await writeFile18(
34410
+ join34(projectPath, ".codebyplan", "eslint.json"),
34167
34411
  JSON.stringify(eslintJson, null, 2) + "\n",
34168
34412
  "utf-8"
34169
34413
  );
34170
34414
  filesChanged.push(".codebyplan/eslint.json");
34171
34415
  if (!deviceWrittenByHelper) {
34172
- await writeFile17(
34173
- join33(projectPath, ".codebyplan", "device.local.json"),
34416
+ await writeFile18(
34417
+ join34(projectPath, ".codebyplan", "device.local.json"),
34174
34418
  JSON.stringify({ device_id: deviceId }, null, 2) + "\n",
34175
34419
  "utf-8"
34176
34420
  );
@@ -34182,9 +34426,9 @@ async function runLocalMigration(projectPath) {
34182
34426
  "Migration write incomplete: .codebyplan/repo.json was not persisted. Re-run migration to retry from a clean state."
34183
34427
  );
34184
34428
  }
34185
- const gitignorePath = join33(projectPath, ".gitignore");
34429
+ const gitignorePath = join34(projectPath, ".gitignore");
34186
34430
  try {
34187
- const gitignoreContent = await readFile21(gitignorePath, "utf-8");
34431
+ const gitignoreContent = await readFile22(gitignorePath, "utf-8");
34188
34432
  const legacyLine = ".codebyplan.local.json";
34189
34433
  const newLine = ".codebyplan/device.local.json";
34190
34434
  const hasLegacy = gitignoreContent.split("\n").some((l) => l.trimEnd() === legacyLine);
@@ -34203,7 +34447,7 @@ async function runLocalMigration(projectPath) {
34203
34447
  updated = gitignoreContent;
34204
34448
  }
34205
34449
  if (updated !== gitignoreContent) {
34206
- await writeFile17(gitignorePath, updated, "utf-8");
34450
+ await writeFile18(gitignorePath, updated, "utf-8");
34207
34451
  filesChanged.push(".gitignore");
34208
34452
  }
34209
34453
  } catch {
@@ -34245,8 +34489,8 @@ __export(config_exports, {
34245
34489
  runConfig: () => runConfig,
34246
34490
  runConfigMigrate: () => runConfigMigrate
34247
34491
  });
34248
- import { mkdir as mkdir10, readFile as readFile22, writeFile as writeFile18 } from "node:fs/promises";
34249
- 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";
34250
34494
  async function runConfig() {
34251
34495
  const flags = parseFlags(3);
34252
34496
  const dryRun = hasFlag("dry-run", 3);
@@ -34279,7 +34523,7 @@ async function runConfig() {
34279
34523
  console.log("\n Config complete.\n");
34280
34524
  }
34281
34525
  async function syncConfigToFile(repoId, projectPath, dryRun) {
34282
- const codebyplanDir = join34(projectPath, ".codebyplan");
34526
+ const codebyplanDir = join35(projectPath, ".codebyplan");
34283
34527
  const {
34284
34528
  resolvedWorktreeId,
34285
34529
  portAllocations,
@@ -34372,16 +34616,16 @@ async function syncConfigToFile(repoId, projectPath, dryRun) {
34372
34616
  ];
34373
34617
  let anyUpdated = false;
34374
34618
  for (const { name, payload, createOnly } of files) {
34375
- const filePath = join34(codebyplanDir, name);
34619
+ const filePath = join35(codebyplanDir, name);
34376
34620
  const newJson = JSON.stringify(payload, null, 2) + "\n";
34377
34621
  let currentJson = "";
34378
34622
  try {
34379
- currentJson = await readFile22(filePath, "utf-8");
34623
+ currentJson = await readFile23(filePath, "utf-8");
34380
34624
  } catch {
34381
34625
  }
34382
34626
  if (createOnly && currentJson !== "") continue;
34383
34627
  if (currentJson === newJson) continue;
34384
- await writeFile18(filePath, newJson, "utf-8");
34628
+ await writeFile19(filePath, newJson, "utf-8");
34385
34629
  console.log(` Updated .codebyplan/${name}`);
34386
34630
  anyUpdated = true;
34387
34631
  }
@@ -34391,8 +34635,8 @@ async function syncConfigToFile(repoId, projectPath, dryRun) {
34391
34635
  }
34392
34636
  async function readRepoConfig(projectPath) {
34393
34637
  try {
34394
- const raw = await readFile22(
34395
- join34(projectPath, ".codebyplan", "repo.json"),
34638
+ const raw = await readFile23(
34639
+ join35(projectPath, ".codebyplan", "repo.json"),
34396
34640
  "utf-8"
34397
34641
  );
34398
34642
  return JSON.parse(raw);
@@ -34402,8 +34646,8 @@ async function readRepoConfig(projectPath) {
34402
34646
  }
34403
34647
  async function readServerConfig(projectPath) {
34404
34648
  try {
34405
- const raw = await readFile22(
34406
- join34(projectPath, ".codebyplan", "server.json"),
34649
+ const raw = await readFile23(
34650
+ join35(projectPath, ".codebyplan", "server.json"),
34407
34651
  "utf-8"
34408
34652
  );
34409
34653
  return JSON.parse(raw);
@@ -34413,8 +34657,8 @@ async function readServerConfig(projectPath) {
34413
34657
  }
34414
34658
  async function readGitConfig2(projectPath) {
34415
34659
  try {
34416
- const raw = await readFile22(
34417
- join34(projectPath, ".codebyplan", "git.json"),
34660
+ const raw = await readFile23(
34661
+ join35(projectPath, ".codebyplan", "git.json"),
34418
34662
  "utf-8"
34419
34663
  );
34420
34664
  return JSON.parse(raw);
@@ -34424,8 +34668,8 @@ async function readGitConfig2(projectPath) {
34424
34668
  }
34425
34669
  async function readShipmentConfig2(projectPath) {
34426
34670
  try {
34427
- const raw = await readFile22(
34428
- join34(projectPath, ".codebyplan", "shipment.json"),
34671
+ const raw = await readFile23(
34672
+ join35(projectPath, ".codebyplan", "shipment.json"),
34429
34673
  "utf-8"
34430
34674
  );
34431
34675
  return JSON.parse(raw);
@@ -34435,8 +34679,8 @@ async function readShipmentConfig2(projectPath) {
34435
34679
  }
34436
34680
  async function readVendorConfig(projectPath) {
34437
34681
  try {
34438
- const raw = await readFile22(
34439
- join34(projectPath, ".codebyplan", "vendor.json"),
34682
+ const raw = await readFile23(
34683
+ join35(projectPath, ".codebyplan", "vendor.json"),
34440
34684
  "utf-8"
34441
34685
  );
34442
34686
  return JSON.parse(raw);
@@ -34446,8 +34690,8 @@ async function readVendorConfig(projectPath) {
34446
34690
  }
34447
34691
  async function readE2eConfig2(projectPath) {
34448
34692
  try {
34449
- const raw = await readFile22(
34450
- join34(projectPath, ".codebyplan", "e2e.json"),
34693
+ const raw = await readFile23(
34694
+ join35(projectPath, ".codebyplan", "e2e.json"),
34451
34695
  "utf-8"
34452
34696
  );
34453
34697
  return JSON.parse(raw);
@@ -34457,8 +34701,8 @@ async function readE2eConfig2(projectPath) {
34457
34701
  }
34458
34702
  async function readServerLocalConfig(projectPath) {
34459
34703
  try {
34460
- const raw = await readFile22(
34461
- join34(projectPath, ".codebyplan", "server.local.json"),
34704
+ const raw = await readFile23(
34705
+ join35(projectPath, ".codebyplan", "server.local.json"),
34462
34706
  "utf-8"
34463
34707
  );
34464
34708
  return JSON.parse(raw);
@@ -34530,8 +34774,8 @@ var init_config = __esm({
34530
34774
  });
34531
34775
 
34532
34776
  // src/lib/server-detect.ts
34533
- import { readFile as readFile23, readdir as readdir5, access as access6 } from "node:fs/promises";
34534
- 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";
34535
34779
  async function fileExists4(filePath) {
34536
34780
  try {
34537
34781
  await access6(filePath);
@@ -34542,8 +34786,8 @@ async function fileExists4(filePath) {
34542
34786
  }
34543
34787
  function detectPackageManager3(dir) {
34544
34788
  return (async () => {
34545
- if (await fileExists4(join35(dir, "pnpm-lock.yaml"))) return "pnpm";
34546
- 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";
34547
34791
  return "npm";
34548
34792
  })();
34549
34793
  }
@@ -34575,12 +34819,12 @@ function detectPortFromScripts(pkg) {
34575
34819
  return null;
34576
34820
  }
34577
34821
  async function isMonorepo(dir) {
34578
- 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"));
34579
34823
  }
34580
34824
  async function detectServers(projectPath) {
34581
34825
  let pkg;
34582
34826
  try {
34583
- const raw = await readFile23(join35(projectPath, "package.json"), "utf-8");
34827
+ const raw = await readFile24(join36(projectPath, "package.json"), "utf-8");
34584
34828
  pkg = JSON.parse(raw);
34585
34829
  } catch {
34586
34830
  return {
@@ -34596,15 +34840,15 @@ async function detectServers(projectPath) {
34596
34840
  const mono = await isMonorepo(projectPath);
34597
34841
  const servers = [];
34598
34842
  if (mono) {
34599
- const appsDir = join35(projectPath, "apps");
34843
+ const appsDir = join36(projectPath, "apps");
34600
34844
  try {
34601
34845
  const entries = await readdir5(appsDir, { withFileTypes: true });
34602
34846
  const sorted = [...entries].sort((a, b) => a.name.localeCompare(b.name));
34603
34847
  for (const entry of sorted) {
34604
34848
  if (!entry.isDirectory()) continue;
34605
- const appPkgPath = join35(appsDir, entry.name, "package.json");
34849
+ const appPkgPath = join36(appsDir, entry.name, "package.json");
34606
34850
  try {
34607
- const appRaw = await readFile23(appPkgPath, "utf-8");
34851
+ const appRaw = await readFile24(appPkgPath, "utf-8");
34608
34852
  const appPkg = JSON.parse(appRaw);
34609
34853
  const appName = entry.name;
34610
34854
  const framework = detectFramework(appPkg);
@@ -34647,14 +34891,14 @@ var init_server_detect = __esm({
34647
34891
  });
34648
34892
 
34649
34893
  // src/lib/port-verify.ts
34650
- import { readFile as readFile24 } from "node:fs/promises";
34894
+ import { readFile as readFile25 } from "node:fs/promises";
34651
34895
  async function verifyPorts(projectPath, portAllocations) {
34652
34896
  const mismatches = [];
34653
34897
  const allocatedPorts = new Set(portAllocations.map((a) => a.port));
34654
34898
  const packageJsonPaths = await findPackageJsonFiles(projectPath, projectPath);
34655
34899
  for (const pkgPath of packageJsonPaths) {
34656
34900
  try {
34657
- const raw = await readFile24(pkgPath, "utf-8");
34901
+ const raw = await readFile25(pkgPath, "utf-8");
34658
34902
  const pkg = JSON.parse(raw);
34659
34903
  const scriptPort = detectPortFromScripts(pkg);
34660
34904
  if (scriptPort !== null && !allocatedPorts.has(scriptPort)) {
@@ -34717,7 +34961,7 @@ async function findUnallocatedApps(projectPath, portAllocations) {
34717
34961
  }
34718
34962
  let pkg;
34719
34963
  try {
34720
- const raw = await readFile24(`${app.absPath}/package.json`, "utf-8");
34964
+ const raw = await readFile25(`${app.absPath}/package.json`, "utf-8");
34721
34965
  pkg = JSON.parse(raw);
34722
34966
  } catch {
34723
34967
  continue;
@@ -34767,8 +35011,8 @@ __export(ports_exports, {
34767
35011
  parseEnvFile: () => parseEnvFile,
34768
35012
  runPorts: () => runPorts
34769
35013
  });
34770
- import { mkdir as mkdir11, readFile as readFile25, writeFile as writeFile19 } from "node:fs/promises";
34771
- 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";
34772
35016
  function printDetectionResult(result, projectPath) {
34773
35017
  console.log(`
34774
35018
  CodeByPlan Ports - List`);
@@ -34924,12 +35168,12 @@ async function writeServerLocalConfig(repoId, projectPath, dryRun) {
34924
35168
  // and ServerLocalConfig.port_allocations is typed the same — honest end-to-end.
34925
35169
  port_allocations: portAllocations
34926
35170
  };
34927
- const codebyplanDir = join36(projectPath, ".codebyplan");
34928
- const filePath = join36(codebyplanDir, "server.local.json");
35171
+ const codebyplanDir = join37(projectPath, ".codebyplan");
35172
+ const filePath = join37(codebyplanDir, "server.local.json");
34929
35173
  const newJson = JSON.stringify(payload, null, 2) + "\n";
34930
35174
  let currentJson = "";
34931
35175
  try {
34932
- currentJson = await readFile25(filePath, "utf-8");
35176
+ currentJson = await readFile26(filePath, "utf-8");
34933
35177
  } catch {
34934
35178
  }
34935
35179
  if (currentJson === newJson) {
@@ -34941,17 +35185,17 @@ async function writeServerLocalConfig(repoId, projectPath, dryRun) {
34941
35185
  return;
34942
35186
  }
34943
35187
  await mkdir11(codebyplanDir, { recursive: true });
34944
- await writeFile19(filePath, newJson, "utf-8");
35188
+ await writeFile20(filePath, newJson, "utf-8");
34945
35189
  console.log(
34946
35190
  ` Updated .codebyplan/server.local.json (worktree ${resolvedWorktreeId ?? "\u2014"}, ${portAllocations.length} allocation${portAllocations.length === 1 ? "" : "s"}).`
34947
35191
  );
34948
35192
  }
34949
35193
  async function provisionE2eEnv(projectPath, dryRun) {
34950
- const relSource = join36("apps", "web", ".env.local");
34951
- const sourcePath = join36(projectPath, relSource);
35194
+ const relSource = join37("apps", "web", ".env.local");
35195
+ const sourcePath = join37(projectPath, relSource);
34952
35196
  let sourceRaw;
34953
35197
  try {
34954
- sourceRaw = await readFile25(sourcePath, "utf-8");
35198
+ sourceRaw = await readFile26(sourcePath, "utf-8");
34955
35199
  } catch {
34956
35200
  console.warn(
34957
35201
  ` Skipped .codebyplan/e2e.env \u2014 source ${relSource} not found.`
@@ -34980,12 +35224,12 @@ async function provisionE2eEnv(projectPath, dryRun) {
34980
35224
  );
34981
35225
  return;
34982
35226
  }
34983
- const codebyplanDir = join36(projectPath, ".codebyplan");
34984
- const filePath = join36(codebyplanDir, "e2e.env");
35227
+ const codebyplanDir = join37(projectPath, ".codebyplan");
35228
+ const filePath = join37(codebyplanDir, "e2e.env");
34985
35229
  const newContent = lines.join("\n") + "\n";
34986
35230
  let currentContent = "";
34987
35231
  try {
34988
- currentContent = await readFile25(filePath, "utf-8");
35232
+ currentContent = await readFile26(filePath, "utf-8");
34989
35233
  } catch {
34990
35234
  }
34991
35235
  if (currentContent === newContent) {
@@ -34997,7 +35241,7 @@ async function provisionE2eEnv(projectPath, dryRun) {
34997
35241
  return;
34998
35242
  }
34999
35243
  await mkdir11(codebyplanDir, { recursive: true });
35000
- await writeFile19(filePath, newContent, "utf-8");
35244
+ await writeFile20(filePath, newContent, "utf-8");
35001
35245
  console.log(
35002
35246
  ` Provisioned .codebyplan/e2e.env (${lines.length} var${lines.length === 1 ? "" : "s"}).`
35003
35247
  );
@@ -35265,8 +35509,8 @@ __export(docs_exports, {
35265
35509
  stripRangePrefix: () => stripRangePrefix
35266
35510
  });
35267
35511
  import { existsSync as existsSync13 } from "node:fs";
35268
- import { mkdir as mkdir12, readFile as readFile26, readdir as readdir6, rm as rm2, writeFile as writeFile20 } from "node:fs/promises";
35269
- 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";
35270
35514
  function selectDependencies(deps) {
35271
35515
  const byName = /* @__PURE__ */ new Map();
35272
35516
  for (const dep of deps) {
@@ -35320,12 +35564,12 @@ async function mapWithConcurrency(items, limit, fn) {
35320
35564
  }
35321
35565
  async function resolveExactVersion(projectPath, dep) {
35322
35566
  const candidateDirs = [projectPath];
35323
- const sourceDir = join37(projectPath, dirname13(dep.sourcePath));
35567
+ const sourceDir = join38(projectPath, dirname13(dep.sourcePath));
35324
35568
  if (sourceDir !== projectPath) candidateDirs.push(sourceDir);
35325
35569
  for (const base of candidateDirs) {
35326
35570
  try {
35327
- const raw = await readFile26(
35328
- join37(base, "node_modules", dep.name, "package.json"),
35571
+ const raw = await readFile27(
35572
+ join38(base, "node_modules", dep.name, "package.json"),
35329
35573
  "utf-8"
35330
35574
  );
35331
35575
  const pkg = JSON.parse(raw);
@@ -35339,8 +35583,8 @@ async function resolveExactVersion(projectPath, dep) {
35339
35583
  }
35340
35584
  async function readVendorDocsPath(projectPath) {
35341
35585
  try {
35342
- const raw = await readFile26(
35343
- join37(projectPath, ".codebyplan", "vendor.json"),
35586
+ const raw = await readFile27(
35587
+ join38(projectPath, ".codebyplan", "vendor.json"),
35344
35588
  "utf-8"
35345
35589
  );
35346
35590
  const parsed = JSON.parse(raw);
@@ -35353,7 +35597,7 @@ async function readVendorDocsPath(projectPath) {
35353
35597
  }
35354
35598
  async function resolveDocsDir(projectPath, flags) {
35355
35599
  const configured = flags["dir"] ?? await readVendorDocsPath(projectPath) ?? DEFAULT_DOCS_DIR;
35356
- const absDir = isAbsolute(configured) ? configured : join37(projectPath, configured);
35600
+ const absDir = isAbsolute2(configured) ? configured : join38(projectPath, configured);
35357
35601
  const rel = relative7(projectPath, absDir);
35358
35602
  const relDir = rel === "" || rel.startsWith("..") ? null : rel.split(sep2).join("/");
35359
35603
  return { absDir, relDir };
@@ -35362,7 +35606,7 @@ async function readDocsLock(absDir) {
35362
35606
  const empty = { generated_at: "", libraries: {} };
35363
35607
  let raw;
35364
35608
  try {
35365
- raw = await readFile26(join37(absDir, LOCK_FILE), "utf-8");
35609
+ raw = await readFile27(join38(absDir, LOCK_FILE), "utf-8");
35366
35610
  } catch {
35367
35611
  return empty;
35368
35612
  }
@@ -35458,10 +35702,10 @@ function buildTopIndex(outcomes) {
35458
35702
  }
35459
35703
  async function ensureDocsGitignoreEntry(projectPath, relDir, dryRun) {
35460
35704
  const entry = `/${relDir}/`;
35461
- const gitignorePath = join37(projectPath, ".gitignore");
35705
+ const gitignorePath = join38(projectPath, ".gitignore");
35462
35706
  let existing = "";
35463
35707
  try {
35464
- existing = await readFile26(gitignorePath, "utf-8");
35708
+ existing = await readFile27(gitignorePath, "utf-8");
35465
35709
  } catch {
35466
35710
  }
35467
35711
  const lines = existing.split(/\r?\n/).map((l) => l.trim());
@@ -35473,7 +35717,7 @@ async function ensureDocsGitignoreEntry(projectPath, relDir, dryRun) {
35473
35717
  content += `${GITIGNORE_COMMENT}
35474
35718
  ${entry}
35475
35719
  `;
35476
- await writeFile20(gitignorePath, content, "utf-8");
35720
+ await writeFile21(gitignorePath, content, "utf-8");
35477
35721
  }
35478
35722
  return "added";
35479
35723
  }
@@ -35481,7 +35725,7 @@ async function markUncovered(dep, exactVersion, ctx) {
35481
35725
  console.log(
35482
35726
  ` uncovered ${dep.name}@${exactVersion || "?"} \u2014 no docs in the library mirror`
35483
35727
  );
35484
- const libPath = join37(ctx.absDir, libDirName(dep.name));
35728
+ const libPath = join38(ctx.absDir, libDirName(dep.name));
35485
35729
  if (existsSync13(libPath)) {
35486
35730
  if (ctx.dryRun) {
35487
35731
  console.log(` would remove stale mirror dir ${libPath}`);
@@ -35534,14 +35778,14 @@ async function syncOneLibrary(dep, ctx) {
35534
35778
  }
35535
35779
  }
35536
35780
  const lockEntry = ctx.lock.libraries[dep.name];
35537
- const libPath = join37(ctx.absDir, libDirName(dep.name));
35538
- const versionPath = join37(libPath, manifest.resolved_version);
35781
+ const libPath = join38(ctx.absDir, libDirName(dep.name));
35782
+ const versionPath = join38(libPath, manifest.resolved_version);
35539
35783
  if (manifestMatchesLock(manifest, lockEntry)) {
35540
35784
  console.log(` unchanged ${dep.name}@${manifest.resolved_version}`);
35541
- if (!ctx.dryRun && !existsSync13(join37(libPath, "INDEX.md"))) {
35785
+ if (!ctx.dryRun && !existsSync13(join38(libPath, "INDEX.md"))) {
35542
35786
  await mkdir12(libPath, { recursive: true });
35543
- await writeFile20(
35544
- join37(libPath, "INDEX.md"),
35787
+ await writeFile21(
35788
+ join38(libPath, "INDEX.md"),
35545
35789
  buildLibIndex(dep.name, manifest),
35546
35790
  "utf-8"
35547
35791
  );
@@ -35563,14 +35807,14 @@ async function syncOneLibrary(dep, ctx) {
35563
35807
  );
35564
35808
  continue;
35565
35809
  }
35566
- const target = join37(versionPath, rel);
35810
+ const target = join38(versionPath, rel);
35567
35811
  if (sameVersionLockFiles[file.path] === file.content_hash && existsSync13(target)) {
35568
35812
  continue;
35569
35813
  }
35570
35814
  written++;
35571
35815
  if (!ctx.dryRun) {
35572
35816
  await mkdir12(dirname13(target), { recursive: true });
35573
- await writeFile20(target, file.content, "utf-8");
35817
+ await writeFile21(target, file.content, "utf-8");
35574
35818
  }
35575
35819
  }
35576
35820
  let removedFiles = 0;
@@ -35581,7 +35825,7 @@ async function syncOneLibrary(dep, ctx) {
35581
35825
  const rel = sanitizeDocPath(lockedPath);
35582
35826
  if (rel === null) continue;
35583
35827
  removedFiles++;
35584
- if (!ctx.dryRun) await rm2(join37(versionPath, rel), { force: true });
35828
+ if (!ctx.dryRun) await rm2(join38(versionPath, rel), { force: true });
35585
35829
  }
35586
35830
  }
35587
35831
  let removedVersionDirs = 0;
@@ -35596,13 +35840,13 @@ async function syncOneLibrary(dep, ctx) {
35596
35840
  }
35597
35841
  removedVersionDirs++;
35598
35842
  if (!ctx.dryRun) {
35599
- await rm2(join37(libPath, entry.name), { recursive: true, force: true });
35843
+ await rm2(join38(libPath, entry.name), { recursive: true, force: true });
35600
35844
  }
35601
35845
  }
35602
35846
  if (!ctx.dryRun) {
35603
35847
  await mkdir12(libPath, { recursive: true });
35604
- await writeFile20(
35605
- join37(libPath, "INDEX.md"),
35848
+ await writeFile21(
35849
+ join38(libPath, "INDEX.md"),
35606
35850
  buildLibIndex(dep.name, manifest),
35607
35851
  "utf-8"
35608
35852
  );
@@ -35656,7 +35900,7 @@ async function runDocsSync() {
35656
35900
  );
35657
35901
  if (!dryRun) {
35658
35902
  await mkdir12(absDir, { recursive: true });
35659
- await writeFile20(join37(absDir, "INDEX.md"), buildTopIndex(outcomes), "utf-8");
35903
+ await writeFile21(join38(absDir, "INDEX.md"), buildTopIndex(outcomes), "utf-8");
35660
35904
  const libraries = {};
35661
35905
  for (const o of outcomes) {
35662
35906
  if (o.kind === "synced" || o.kind === "unchanged") {
@@ -35681,8 +35925,8 @@ async function runDocsSync() {
35681
35925
  generated_at: (/* @__PURE__ */ new Date()).toISOString(),
35682
35926
  libraries: sortedLibraries
35683
35927
  };
35684
- await writeFile20(
35685
- join37(absDir, LOCK_FILE),
35928
+ await writeFile21(
35929
+ join38(absDir, LOCK_FILE),
35686
35930
  JSON.stringify(newLock, null, 2) + "\n",
35687
35931
  "utf-8"
35688
35932
  );
@@ -35724,7 +35968,7 @@ async function countFilesRecursively(dirPath) {
35724
35968
  let count = 0;
35725
35969
  for (const entry of entries) {
35726
35970
  if (entry.isDirectory()) {
35727
- count += await countFilesRecursively(join37(dirPath, entry.name));
35971
+ count += await countFilesRecursively(join38(dirPath, entry.name));
35728
35972
  } else if (entry.isFile()) {
35729
35973
  count++;
35730
35974
  }
@@ -35741,7 +35985,7 @@ async function runDocsStatus() {
35741
35985
  `);
35742
35986
  let raw;
35743
35987
  try {
35744
- raw = await readFile26(join37(absDir, LOCK_FILE), "utf-8");
35988
+ raw = await readFile27(join38(absDir, LOCK_FILE), "utf-8");
35745
35989
  } catch {
35746
35990
  console.log(
35747
35991
  ` No ${LOCK_FILE} found \u2014 run \`codebyplan docs sync\` first.
@@ -35770,7 +36014,7 @@ async function runDocsStatus() {
35770
36014
  let outOfSync = 0;
35771
36015
  for (const name of names) {
35772
36016
  const entry = lock.libraries[name];
35773
- const versionPath = join37(absDir, libDirName(name), entry.resolved_version);
36017
+ const versionPath = join38(absDir, libDirName(name), entry.resolved_version);
35774
36018
  const expected = Object.keys(entry.files).length;
35775
36019
  if (!existsSync13(versionPath)) {
35776
36020
  outOfSync++;
@@ -35858,7 +36102,7 @@ var init_docs = __esm({
35858
36102
 
35859
36103
  // src/lib/check-baseline.ts
35860
36104
  import { readFileSync as readFileSync12, writeFileSync as writeFileSync7 } from "node:fs";
35861
- import { join as join38 } from "node:path";
36105
+ import { join as join39 } from "node:path";
35862
36106
  function emptyBaseline() {
35863
36107
  return {
35864
36108
  lint: { known_failing: [] },
@@ -35868,7 +36112,7 @@ function emptyBaseline() {
35868
36112
  };
35869
36113
  }
35870
36114
  function loadBaseline(projectRoot) {
35871
- const filePath = join38(projectRoot, BASELINE_FILENAME);
36115
+ const filePath = join39(projectRoot, BASELINE_FILENAME);
35872
36116
  try {
35873
36117
  const raw = readFileSync12(filePath, "utf-8");
35874
36118
  const parsed = JSON.parse(raw);
@@ -35892,7 +36136,7 @@ function loadBaseline(projectRoot) {
35892
36136
  }
35893
36137
  }
35894
36138
  function saveBaseline(projectRoot, baseline) {
35895
- const filePath = join38(projectRoot, BASELINE_FILENAME);
36139
+ const filePath = join39(projectRoot, BASELINE_FILENAME);
35896
36140
  writeFileSync7(filePath, JSON.stringify(baseline, null, 2) + "\n", "utf-8");
35897
36141
  }
35898
36142
  function diffBaseline(check, currentFailingPackages, baseline) {
@@ -35942,8 +36186,8 @@ var init_check_baseline = __esm({
35942
36186
 
35943
36187
  // src/lib/check.ts
35944
36188
  import { readFileSync as readFileSync13, existsSync as existsSync14 } from "node:fs";
35945
- import { join as join39 } from "node:path";
35946
- 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";
35947
36191
  function hasSentinelValue(arrays) {
35948
36192
  const SENTINELS = /* @__PURE__ */ new Set([
35949
36193
  SUMMARY_UNREADABLE,
@@ -35958,7 +36202,7 @@ function resolveNewFailures(check, failingPackages, baseline, updateBaseline, no
35958
36202
  return diffBaseline(check, failingPackages, baseline);
35959
36203
  }
35960
36204
  function defaultSpawnFn(command, opts) {
35961
- const result = spawnSync10(command, {
36205
+ const result = spawnSync11(command, {
35962
36206
  shell: true,
35963
36207
  cwd: opts.cwd,
35964
36208
  encoding: "utf-8",
@@ -36010,9 +36254,9 @@ function parseFailingPackagesFromSummary(summaryPath) {
36010
36254
  return Array.from(failing).sort();
36011
36255
  }
36012
36256
  function resolveTurboBin(projectRoot) {
36013
- const localBin = join39(projectRoot, "node_modules", ".bin", "turbo");
36257
+ const localBin = join40(projectRoot, "node_modules", ".bin", "turbo");
36014
36258
  if (existsSync14(localBin)) return localBin;
36015
- const workspaceRootBin = join39(
36259
+ const workspaceRootBin = join40(
36016
36260
  projectRoot,
36017
36261
  "..",
36018
36262
  "..",
@@ -36023,9 +36267,10 @@ function resolveTurboBin(projectRoot) {
36023
36267
  if (existsSync14(workspaceRootBin)) return workspaceRootBin;
36024
36268
  return TURBO_NOT_FOUND_SENTINEL;
36025
36269
  }
36026
- function runTurboWithSummary(task, projectRoot, spawnFn) {
36270
+ function runTurboWithSummary(task, projectRoot, spawnFn, concurrency) {
36027
36271
  const turboBin = resolveTurboBin(projectRoot);
36028
- const command = `${turboBin} run ${task} --summarize`;
36272
+ const concurrencyFlag = concurrency !== void 0 ? ` --concurrency=${concurrency}` : "";
36273
+ const command = `${turboBin} run ${task}${concurrencyFlag} --summarize`;
36029
36274
  let spawnResult;
36030
36275
  try {
36031
36276
  spawnResult = spawnFn(command, { cwd: projectRoot });
@@ -36059,6 +36304,7 @@ function runCheck(opts) {
36059
36304
  spawnFn = defaultSpawnFn,
36060
36305
  updateBaseline: updateBaselineOpt = false,
36061
36306
  noBaseline = false,
36307
+ concurrency,
36062
36308
  loadBaselineFn = loadBaseline,
36063
36309
  saveBaselineFn = saveBaseline
36064
36310
  } = opts;
@@ -36107,7 +36353,7 @@ function runCheck(opts) {
36107
36353
  spawnResult,
36108
36354
  failingPackages,
36109
36355
  command: lintCommand
36110
- } = runTurboWithSummary("lint", projectRoot, spawnFn);
36356
+ } = runTurboWithSummary("lint", projectRoot, spawnFn, concurrency);
36111
36357
  currentFailing.lint = failingPackages;
36112
36358
  const newFailures = resolveNewFailures(
36113
36359
  "lint",
@@ -36132,7 +36378,7 @@ function runCheck(opts) {
36132
36378
  spawnResult,
36133
36379
  failingPackages,
36134
36380
  command: typecheckCommand
36135
- } = runTurboWithSummary("typecheck", projectRoot, spawnFn);
36381
+ } = runTurboWithSummary("typecheck", projectRoot, spawnFn, concurrency);
36136
36382
  currentFailing.typecheck = failingPackages;
36137
36383
  const newFailures = resolveNewFailures(
36138
36384
  "typecheck",
@@ -36157,7 +36403,7 @@ function runCheck(opts) {
36157
36403
  spawnResult,
36158
36404
  failingPackages,
36159
36405
  command: testsCommand
36160
- } = runTurboWithSummary("test", projectRoot, spawnFn);
36406
+ } = runTurboWithSummary("test", projectRoot, spawnFn, concurrency);
36161
36407
  currentFailing.tests = failingPackages;
36162
36408
  const newFailures = resolveNewFailures(
36163
36409
  "tests",
@@ -36358,9 +36604,24 @@ function parseCheckArgs(args) {
36358
36604
  let files;
36359
36605
  let updateBaseline = false;
36360
36606
  let noBaseline = false;
36607
+ let concurrency;
36361
36608
  for (let i = 0; i < args.length; i++) {
36362
36609
  const arg = args[i];
36363
- if (arg === "--scope") {
36610
+ if (arg === "--concurrency") {
36611
+ const val = args[i + 1];
36612
+ const parsed = val !== void 0 ? Number(val) : NaN;
36613
+ if (Number.isInteger(parsed) && parsed > 0) {
36614
+ concurrency = parsed;
36615
+ i++;
36616
+ } else {
36617
+ process.stderr.write(
36618
+ `check: --concurrency value must be a positive integer (got: '${val ?? ""}').
36619
+ `
36620
+ );
36621
+ process.exitCode = 1;
36622
+ return null;
36623
+ }
36624
+ } else if (arg === "--scope") {
36364
36625
  const val = args[i + 1];
36365
36626
  if (val === "round" || val === "task" || val === "merged") {
36366
36627
  scope = val;
@@ -36392,7 +36653,7 @@ function parseCheckArgs(args) {
36392
36653
  }
36393
36654
  }
36394
36655
  }
36395
- return { scope, json, files, updateBaseline, noBaseline };
36656
+ return { scope, json, files, updateBaseline, noBaseline, concurrency };
36396
36657
  }
36397
36658
  function emitTable(result) {
36398
36659
  const strict = result.no_baseline === true;
@@ -36465,13 +36726,14 @@ function runCheckCommand(args) {
36465
36726
  if (parsed === null) {
36466
36727
  return;
36467
36728
  }
36468
- const { scope, json, files, updateBaseline, noBaseline } = parsed;
36729
+ const { scope, json, files, updateBaseline, noBaseline, concurrency } = parsed;
36469
36730
  const result = runCheck({
36470
36731
  scope,
36471
36732
  changedFiles: files,
36472
36733
  // NO-OP in whole-repo mode; notice emitted by runCheck
36473
36734
  updateBaseline,
36474
- noBaseline
36735
+ noBaseline,
36736
+ concurrency
36475
36737
  });
36476
36738
  if (json) {
36477
36739
  process.stdout.write(JSON.stringify(result, null, 2) + "\n");
@@ -36491,7 +36753,7 @@ var init_check2 = __esm({
36491
36753
 
36492
36754
  // src/lib/claude-plan.ts
36493
36755
  import * as fs13 from "node:fs";
36494
- import * as path13 from "node:path";
36756
+ import * as path14 from "node:path";
36495
36757
  function buildDriftPlan(projectDir, templatesDir, manifest) {
36496
36758
  const packaged = walkTemplates(templatesDir);
36497
36759
  const packagedBySrc = new Map(packaged.map((f) => [f.src, f]));
@@ -36505,8 +36767,8 @@ function buildDriftPlan(projectDir, templatesDir, manifest) {
36505
36767
  };
36506
36768
  for (const pkg of packaged) {
36507
36769
  const inManifest = manifestBySrc.get(pkg.src);
36508
- const absDest = path13.join(projectDir, ".claude", pkg.dest);
36509
- const absSrc = path13.join(templatesDir, pkg.src);
36770
+ const absDest = path14.join(projectDir, ".claude", pkg.dest);
36771
+ const absSrc = path14.join(templatesDir, pkg.src);
36510
36772
  if (!inManifest) {
36511
36773
  plan.newOptIn.push({
36512
36774
  packaged: { src: pkg.src, dest: pkg.dest, hash: pkg.hash },
@@ -36555,7 +36817,7 @@ __export(status_exports, {
36555
36817
  runStatus: () => runStatus2
36556
36818
  });
36557
36819
  import * as fs14 from "node:fs";
36558
- import * as path14 from "node:path";
36820
+ import * as path15 from "node:path";
36559
36821
  import { execSync as execSync9 } from "node:child_process";
36560
36822
  function makeFailSafe(checked_at) {
36561
36823
  return {
@@ -36568,6 +36830,8 @@ function makeFailSafe(checked_at) {
36568
36830
  new_in_package: [],
36569
36831
  removed_from_package: [],
36570
36832
  settings_drift: false,
36833
+ settings_missing: false,
36834
+ settings_ignored: false,
36571
36835
  guarded: true,
36572
36836
  guard_reason: "unknown",
36573
36837
  in_sync: true,
@@ -36633,6 +36897,8 @@ async function runStatus2(argv) {
36633
36897
  new_in_package: [],
36634
36898
  removed_from_package: [],
36635
36899
  settings_drift: false,
36900
+ settings_missing: false,
36901
+ settings_ignored: false,
36636
36902
  guarded: true,
36637
36903
  // guarded:true must always pair with a non-null reason. canonical_source
36638
36904
  // keeps its reason; the bare no-manifest case (never-installed consumer)
@@ -36660,12 +36926,12 @@ async function runStatus2(argv) {
36660
36926
  const latest = fetchLatestVersion();
36661
36927
  const newer = latest !== null && compareSemver(latest, installed) > 0;
36662
36928
  let settings_drift = false;
36663
- const settingsPath = path14.join(projectDir, ".claude", "settings.json");
36664
- const baseSettingsPath = path14.join(
36929
+ const settingsPath = path15.join(projectDir, ".claude", "settings.json");
36930
+ const baseSettingsPath = path15.join(
36665
36931
  templatesDir,
36666
36932
  "settings.project.base.json"
36667
36933
  );
36668
- const hooksJsonPath = path14.join(templatesDir, "hooks", "hooks.json");
36934
+ const hooksJsonPath = path15.join(templatesDir, "hooks", "hooks.json");
36669
36935
  if (fs14.existsSync(settingsPath)) {
36670
36936
  try {
36671
36937
  const settingsRaw = fs14.readFileSync(settingsPath, "utf8");
@@ -36689,6 +36955,8 @@ async function runStatus2(argv) {
36689
36955
  settings_drift = false;
36690
36956
  }
36691
36957
  }
36958
+ const settings_missing = !fs14.existsSync(settingsPath);
36959
+ const settings_ignored = detectSettingsIgnored(projectDir).status === "ignored";
36692
36960
  const in_sync = !version_skip && drifted_files.length === 0 && new_in_package.length === 0 && removed_from_package.length === 0 && !settings_drift;
36693
36961
  let action = null;
36694
36962
  if (guardReason !== "protected_branch") {
@@ -36704,6 +36972,8 @@ async function runStatus2(argv) {
36704
36972
  new_in_package,
36705
36973
  removed_from_package,
36706
36974
  settings_drift,
36975
+ settings_missing,
36976
+ settings_ignored,
36707
36977
  // Always false in the full-detection path: a protected_branch consumer
36708
36978
  // (the only guarded case that reaches here) must still SEE the segment;
36709
36979
  // only canonical_source / no-manifest (Branch A) report guarded:true.
@@ -36731,10 +37001,10 @@ function emitResult(result, writeCache, quiet, projectDir) {
36731
37001
  const json = JSON.stringify(result, null, 2);
36732
37002
  if (writeCache) {
36733
37003
  try {
36734
- const cacheDir = path14.join(projectDir, ".codebyplan");
37004
+ const cacheDir = path15.join(projectDir, ".codebyplan");
36735
37005
  fs14.mkdirSync(cacheDir, { recursive: true });
36736
37006
  fs14.writeFileSync(
36737
- path14.join(cacheDir, "claude-status.local.json"),
37007
+ path15.join(cacheDir, "claude-status.local.json"),
36738
37008
  json + "\n",
36739
37009
  "utf8"
36740
37010
  );
@@ -36756,6 +37026,7 @@ var init_status = __esm({
36756
37026
  init_claude_plan();
36757
37027
  init_settings_merge();
36758
37028
  init_version_status();
37029
+ init_gitignore_detect();
36759
37030
  }
36760
37031
  });
36761
37032
 
@@ -36877,7 +37148,7 @@ __export(update_exports, {
36877
37148
  });
36878
37149
  import * as fs15 from "node:fs";
36879
37150
  import * as os3 from "node:os";
36880
- import * as path15 from "node:path";
37151
+ import * as path16 from "node:path";
36881
37152
  async function runUpdate(opts, deps = {}) {
36882
37153
  await Promise.resolve();
36883
37154
  const scope = opts.scope ?? "project";
@@ -36913,9 +37184,9 @@ async function runUpdate(opts, deps = {}) {
36913
37184
  finalManifestEntries.push(e);
36914
37185
  }
36915
37186
  for (const { packaged, absSrc } of plan.overwriteSafe) {
36916
- const absDest = path15.join(projectDir, ".claude", packaged.dest);
37187
+ const absDest = path16.join(projectDir, ".claude", packaged.dest);
36917
37188
  if (!opts.dryRun) {
36918
- fs15.mkdirSync(path15.dirname(absDest), { recursive: true });
37189
+ fs15.mkdirSync(path16.dirname(absDest), { recursive: true });
36919
37190
  fs15.copyFileSync(absSrc, absDest);
36920
37191
  if (opts.verbose) console.log(`updated ${packaged.dest}`);
36921
37192
  } else if (opts.verbose) {
@@ -36928,7 +37199,7 @@ async function runUpdate(opts, deps = {}) {
36928
37199
  absSrc,
36929
37200
  onDiskContent
36930
37201
  } of plan.overwriteHandEdited) {
36931
- const absDest = path15.join(projectDir, ".claude", packaged.dest);
37202
+ const absDest = path16.join(projectDir, ".claude", packaged.dest);
36932
37203
  const newContent = fs15.readFileSync(absSrc);
36933
37204
  const showDiff = () => {
36934
37205
  console.log(
@@ -36941,7 +37212,7 @@ async function runUpdate(opts, deps = {}) {
36941
37212
  const answer = await promptOverwrite(packaged.dest, opts, showDiff);
36942
37213
  if (answer === "overwrite") {
36943
37214
  if (!opts.dryRun) {
36944
- fs15.mkdirSync(path15.dirname(absDest), { recursive: true });
37215
+ fs15.mkdirSync(path16.dirname(absDest), { recursive: true });
36945
37216
  fs15.copyFileSync(absSrc, absDest);
36946
37217
  }
36947
37218
  finalManifestEntries.push(packaged);
@@ -36957,9 +37228,9 @@ async function runUpdate(opts, deps = {}) {
36957
37228
  for (const { packaged, absSrc } of plan.newOptIn) {
36958
37229
  const answer = await promptOptIn(packaged.dest, opts);
36959
37230
  if (answer === "opt-in") {
36960
- const absDest = path15.join(projectDir, ".claude", packaged.dest);
37231
+ const absDest = path16.join(projectDir, ".claude", packaged.dest);
36961
37232
  if (!opts.dryRun) {
36962
- fs15.mkdirSync(path15.dirname(absDest), { recursive: true });
37233
+ fs15.mkdirSync(path16.dirname(absDest), { recursive: true });
36963
37234
  fs15.copyFileSync(absSrc, absDest);
36964
37235
  }
36965
37236
  finalManifestEntries.push(packaged);
@@ -36971,25 +37242,25 @@ async function runUpdate(opts, deps = {}) {
36971
37242
  for (const e of plan.removedFromPackage) {
36972
37243
  const answer = await promptRemove(e.dest, opts);
36973
37244
  if (answer === "remove") {
36974
- const absDest = path15.join(projectDir, ".claude", e.dest);
37245
+ const absDest = path16.join(projectDir, ".claude", e.dest);
36975
37246
  if (!opts.dryRun && fs15.existsSync(absDest)) {
36976
37247
  fs15.rmSync(absDest);
36977
- const claudeDir = path15.join(projectDir, ".claude");
36978
- let cur = path15.dirname(absDest);
36979
- while (cur !== claudeDir && cur !== path15.dirname(cur)) {
36980
- 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;
36981
37252
  try {
36982
37253
  fs15.rmdirSync(cur);
36983
37254
  if (opts.verbose)
36984
37255
  console.log(
36985
- `pruned empty dir ${path15.relative(claudeDir, cur)}`
37256
+ `pruned empty dir ${path16.relative(claudeDir, cur)}`
36986
37257
  );
36987
- cur = path15.dirname(cur);
37258
+ cur = path16.dirname(cur);
36988
37259
  } catch (err) {
36989
37260
  const code = err.code;
36990
37261
  if (code !== "ENOTEMPTY" && code !== "ENOENT") {
36991
37262
  console.warn(
36992
- `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}`
36993
37264
  );
36994
37265
  }
36995
37266
  break;
@@ -37001,12 +37272,12 @@ async function runUpdate(opts, deps = {}) {
37001
37272
  if (opts.verbose) console.log(`kept (untracked) ${e.dest}`);
37002
37273
  }
37003
37274
  }
37004
- const hooksJsonPath = path15.join(templatesDir, "hooks", "hooks.json");
37005
- const baseSettingsPath = path15.join(
37275
+ const hooksJsonPath = path16.join(templatesDir, "hooks", "hooks.json");
37276
+ const baseSettingsPath = path16.join(
37006
37277
  templatesDir,
37007
37278
  "settings.project.base.json"
37008
37279
  );
37009
- const settingsPath = path15.join(projectDir, ".claude", "settings.json");
37280
+ const settingsPath = path16.join(projectDir, ".claude", "settings.json");
37010
37281
  const existingSettings = fs15.existsSync(settingsPath) ? JSON.parse(fs15.readFileSync(settingsPath, "utf8")) : {};
37011
37282
  if (fs15.existsSync(baseSettingsPath)) {
37012
37283
  const base = JSON.parse(
@@ -37027,21 +37298,29 @@ async function runUpdate(opts, deps = {}) {
37027
37298
  ) : void 0
37028
37299
  );
37029
37300
  }
37301
+ await detectAndHealSettingsGitignore(
37302
+ projectDir,
37303
+ { yes: opts.yes, dryRun: opts.dryRun },
37304
+ deps.detectHealDeps
37305
+ );
37030
37306
  if (!opts.dryRun) {
37031
- fs15.mkdirSync(path15.dirname(settingsPath), { recursive: true });
37307
+ fs15.mkdirSync(path16.dirname(settingsPath), { recursive: true });
37032
37308
  fs15.writeFileSync(
37033
37309
  settingsPath,
37034
37310
  JSON.stringify(existingSettings, null, 2) + "\n",
37035
37311
  "utf8"
37036
37312
  );
37037
37313
  }
37314
+ if (!opts.dryRun) {
37315
+ warnIfSettingsUntracked(projectDir, deps.lsFilesDep);
37316
+ }
37038
37317
  const gitignoreAction = await ensureManagedGitignoreBlock(
37039
37318
  projectDir,
37040
37319
  opts.dryRun
37041
37320
  );
37042
37321
  if (opts.verbose && gitignoreAction !== "unchanged") {
37043
37322
  console.log(
37044
- `${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"))}`
37045
37324
  );
37046
37325
  }
37047
37326
  if (!opts.dryRun) {
@@ -37081,9 +37360,9 @@ function runUpdateUser(opts, deps) {
37081
37360
  return;
37082
37361
  }
37083
37362
  try {
37084
- const userDir = deps.userDir ?? path15.join(os3.homedir(), ".claude");
37085
- const settingsPath = path15.join(userDir, "settings.json");
37086
- 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(
37087
37366
  templatesDir,
37088
37367
  "settings.user.base.json"
37089
37368
  );
@@ -37136,6 +37415,7 @@ var init_update = __esm({
37136
37415
  "src/cli/claude/update.ts"() {
37137
37416
  "use strict";
37138
37417
  init_gitignore_block();
37418
+ init_gitignore_detect();
37139
37419
  init_templates_dir();
37140
37420
  init_manifest();
37141
37421
  init_settings_merge();
@@ -37154,7 +37434,7 @@ __export(uninstall_exports, {
37154
37434
  });
37155
37435
  import * as fs16 from "node:fs";
37156
37436
  import * as os4 from "node:os";
37157
- import * as path16 from "node:path";
37437
+ import * as path17 from "node:path";
37158
37438
  async function runUninstall(opts, deps = {}) {
37159
37439
  await Promise.resolve();
37160
37440
  const scope = opts.scope ?? "project";
@@ -37183,7 +37463,7 @@ async function runUninstall(opts, deps = {}) {
37183
37463
  let removed = 0;
37184
37464
  let warnings = 0;
37185
37465
  for (const entry of manifest.files) {
37186
- const abs = path16.join(projectDir, ".claude", entry.dest);
37466
+ const abs = path17.join(projectDir, ".claude", entry.dest);
37187
37467
  if (!fs16.existsSync(abs)) {
37188
37468
  console.warn(
37189
37469
  `codebyplan claude uninstall: ${entry.dest} already absent (skipping).`
@@ -37207,12 +37487,12 @@ async function runUninstall(opts, deps = {}) {
37207
37487
  if (!opts.dryRun) {
37208
37488
  pruneEmptyManagedDirs(projectDir);
37209
37489
  }
37210
- const settingsPath = path16.join(projectDir, ".claude", "settings.json");
37490
+ const settingsPath = path17.join(projectDir, ".claude", "settings.json");
37211
37491
  if (fs16.existsSync(settingsPath)) {
37212
37492
  const settings = JSON.parse(
37213
37493
  fs16.readFileSync(settingsPath, "utf8")
37214
37494
  );
37215
- const baseSettingsPath = templatesDir ? path16.join(templatesDir, "settings.project.base.json") : null;
37495
+ const baseSettingsPath = templatesDir ? path17.join(templatesDir, "settings.project.base.json") : null;
37216
37496
  if (baseSettingsPath && fs16.existsSync(baseSettingsPath)) {
37217
37497
  const base = JSON.parse(
37218
37498
  fs16.readFileSync(baseSettingsPath, "utf8")
@@ -37270,7 +37550,7 @@ function runUninstallUser(opts, deps) {
37270
37550
  }
37271
37551
  }
37272
37552
  try {
37273
- const userDir = deps.userDir ?? path16.join(os4.homedir(), ".claude");
37553
+ const userDir = deps.userDir ?? path17.join(os4.homedir(), ".claude");
37274
37554
  const existingManifest = readManifestForScope("user", userDir);
37275
37555
  if (!existingManifest) {
37276
37556
  console.error(
@@ -37279,12 +37559,12 @@ function runUninstallUser(opts, deps) {
37279
37559
  process.exitCode = 1;
37280
37560
  return;
37281
37561
  }
37282
- const settingsPath = path16.join(userDir, "settings.json");
37562
+ const settingsPath = path17.join(userDir, "settings.json");
37283
37563
  if (fs16.existsSync(settingsPath)) {
37284
37564
  const settings = JSON.parse(
37285
37565
  fs16.readFileSync(settingsPath, "utf8")
37286
37566
  );
37287
- 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;
37288
37568
  if (userBaseSettingsPath && fs16.existsSync(userBaseSettingsPath)) {
37289
37569
  const userBase = JSON.parse(
37290
37570
  fs16.readFileSync(userBaseSettingsPath, "utf8")
@@ -37325,7 +37605,7 @@ function runUninstallUser(opts, deps) {
37325
37605
  function pruneEmptyManagedDirs(projectDir) {
37326
37606
  const managedRoots = ["skills", "agents", "hooks", "rules"];
37327
37607
  for (const root of managedRoots) {
37328
- const abs = path16.join(projectDir, ".claude", root);
37608
+ const abs = path17.join(projectDir, ".claude", root);
37329
37609
  if (!fs16.existsSync(abs)) continue;
37330
37610
  pruneLeafFirst(abs);
37331
37611
  }
@@ -37336,7 +37616,7 @@ function pruneLeafFirst(dir) {
37336
37616
  if (!stat3.isDirectory()) return;
37337
37617
  for (const entry of fs16.readdirSync(dir, { withFileTypes: true })) {
37338
37618
  if (entry.isDirectory()) {
37339
- pruneLeafFirst(path16.join(dir, entry.name));
37619
+ pruneLeafFirst(path17.join(dir, entry.name));
37340
37620
  }
37341
37621
  }
37342
37622
  const remaining = fs16.readdirSync(dir);
@@ -37357,7 +37637,7 @@ var init_uninstall = __esm({
37357
37637
 
37358
37638
  // src/lib/verify-parity.ts
37359
37639
  import * as fs17 from "node:fs";
37360
- import * as path17 from "node:path";
37640
+ import * as path18 from "node:path";
37361
37641
  function isValidScope(s) {
37362
37642
  return s === "org-shared" || s === "project-shared" || REPO_ONLY_RE.test(s);
37363
37643
  }
@@ -37374,25 +37654,25 @@ function checkSiblingParity(opts) {
37374
37654
  expectedOneSided = DEFAULT_EXPECTED_ONE_SIDED,
37375
37655
  ignoredSubtrees
37376
37656
  } = opts;
37377
- const defaultIgnored = [path17.join(claudeDir, "hooks", "__test-fixtures__")];
37657
+ const defaultIgnored = [path18.join(claudeDir, "hooks", "__test-fixtures__")];
37378
37658
  const ignored = ignoredSubtrees ?? defaultIgnored;
37379
37659
  const violations = [];
37380
37660
  const claudeSideRels = /* @__PURE__ */ new Set();
37381
37661
  for (const scanDir of SCAN_DIRS) {
37382
- const baseDir = path17.join(claudeDir, scanDir);
37662
+ const baseDir = path18.join(claudeDir, scanDir);
37383
37663
  if (!fs17.existsSync(baseDir)) continue;
37384
37664
  const entries = readdirRecursive(baseDir);
37385
37665
  for (const entry of entries) {
37386
- const absPath = path17.join(baseDir, entry);
37666
+ const absPath = path18.join(baseDir, entry);
37387
37667
  if (!fs17.lstatSync(absPath).isFile()) continue;
37388
37668
  if (ignored.some(
37389
- (ig) => absPath.startsWith(ig + path17.sep) || absPath === ig
37669
+ (ig) => absPath.startsWith(ig + path18.sep) || absPath === ig
37390
37670
  )) {
37391
37671
  continue;
37392
37672
  }
37393
- const relPath = path17.join(scanDir, entry).split(path17.sep).join("/");
37673
+ const relPath = path18.join(scanDir, entry).split(path18.sep).join("/");
37394
37674
  claudeSideRels.add(relPath);
37395
- const templatePath = path17.join(templatesDir, relPath);
37675
+ const templatePath = path18.join(templatesDir, relPath);
37396
37676
  if (!fs17.existsSync(templatePath)) {
37397
37677
  if (!expectedOneSided.has(relPath) && !isScaffoldFile(entry)) {
37398
37678
  violations.push({ type: "missing-twin", path: relPath });
@@ -37407,14 +37687,14 @@ function checkSiblingParity(opts) {
37407
37687
  }
37408
37688
  }
37409
37689
  for (const scanDir of SCAN_DIRS) {
37410
- const tplBase = path17.join(templatesDir, scanDir);
37690
+ const tplBase = path18.join(templatesDir, scanDir);
37411
37691
  if (!fs17.existsSync(tplBase)) continue;
37412
37692
  const entries = readdirRecursive(tplBase);
37413
37693
  for (const entry of entries) {
37414
- const absPath = path17.join(tplBase, entry);
37694
+ const absPath = path18.join(tplBase, entry);
37415
37695
  if (!fs17.lstatSync(absPath).isFile()) continue;
37416
37696
  if (isScaffoldFile(entry)) continue;
37417
- const relPath = path17.join(scanDir, entry).split(path17.sep).join("/");
37697
+ const relPath = path18.join(scanDir, entry).split(path18.sep).join("/");
37418
37698
  if (!claudeSideRels.has(relPath) && !expectedOneSided.has(relPath)) {
37419
37699
  violations.push({ type: "extra-twin", path: relPath });
37420
37700
  }
@@ -37450,18 +37730,18 @@ function checkScopeMarkers(opts) {
37450
37730
  const twinDetectionActive = templatesDir != null && fs17.existsSync(templatesDir);
37451
37731
  const violations = [];
37452
37732
  for (const scanDir of scanDirs) {
37453
- const baseDir = path17.join(claudeDir, scanDir);
37733
+ const baseDir = path18.join(claudeDir, scanDir);
37454
37734
  if (!fs17.existsSync(baseDir)) continue;
37455
37735
  const entries = readdirRecursive(baseDir);
37456
37736
  for (const entry of entries) {
37457
- const absPath = path17.join(baseDir, entry);
37737
+ const absPath = path18.join(baseDir, entry);
37458
37738
  if (!fs17.lstatSync(absPath).isFile()) continue;
37459
37739
  if (!isStructuralEntry(scanDir, entry)) continue;
37460
- const ext = path17.extname(entry).toLowerCase();
37740
+ const ext = path18.extname(entry).toLowerCase();
37461
37741
  const isMd = ext === ".md";
37462
37742
  const isSh = ext === ".sh";
37463
37743
  if (!isMd && !isSh) continue;
37464
- const relPath = path17.join(scanDir, entry).split(path17.sep).join("/");
37744
+ const relPath = path18.join(scanDir, entry).split(path18.sep).join("/");
37465
37745
  if (allowlist.has(relPath)) continue;
37466
37746
  let content;
37467
37747
  try {
@@ -37475,7 +37755,7 @@ function checkScopeMarkers(opts) {
37475
37755
  continue;
37476
37756
  }
37477
37757
  const scopeValue = isMd ? extractFrontmatterScope(content) : extractShScope(content);
37478
- const managed = twinDetectionActive && fs17.existsSync(path17.join(templatesDir, relPath));
37758
+ const managed = twinDetectionActive && fs17.existsSync(path18.join(templatesDir, relPath));
37479
37759
  if (managed) {
37480
37760
  if (scopeValue === null) {
37481
37761
  } else if (scopeValue === "org-shared") {
@@ -37529,7 +37809,7 @@ function readdirRecursive(dir, rel = "", visited = /* @__PURE__ */ new Set()) {
37529
37809
  visited.add(realDir);
37530
37810
  const results = [];
37531
37811
  for (const name of fs17.readdirSync(dir)) {
37532
- const full = path17.join(dir, name);
37812
+ const full = path18.join(dir, name);
37533
37813
  const relName = rel ? `${rel}/${name}` : name;
37534
37814
  if (fs17.lstatSync(full).isDirectory()) {
37535
37815
  results.push(...readdirRecursive(full, relName, visited));
@@ -37602,12 +37882,12 @@ __export(verify_parity_exports, {
37602
37882
  verifyParity: () => verifyParity
37603
37883
  });
37604
37884
  import * as fs18 from "node:fs";
37605
- import * as path18 from "node:path";
37885
+ import * as path19 from "node:path";
37606
37886
  function verifyParity(args, deps = {}) {
37607
37887
  const warnOnly = args.includes("--warn-only");
37608
37888
  const jsonMode = args.includes("--json");
37609
37889
  const projectDir = deps.cwd ?? process.cwd();
37610
- const claudeDir = path18.join(projectDir, ".claude");
37890
+ const claudeDir = path19.join(projectDir, ".claude");
37611
37891
  if (!fs18.existsSync(claudeDir)) {
37612
37892
  const msg = "codebyplan claude verify-parity: .claude/ not found in cwd \u2014 run from the project root.\n";
37613
37893
  process.stderr.write(msg);
@@ -38114,11 +38394,11 @@ var generate_exports = {};
38114
38394
  __export(generate_exports, {
38115
38395
  runGenerate: () => runGenerate
38116
38396
  });
38117
- import { readFile as readFile27, mkdir as mkdir13, writeFile as writeFile21 } from "node:fs/promises";
38118
- 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";
38119
38399
  async function readJsonFile4(filePath) {
38120
38400
  try {
38121
- const raw = await readFile27(filePath, "utf-8");
38401
+ const raw = await readFile28(filePath, "utf-8");
38122
38402
  return JSON.parse(raw);
38123
38403
  } catch {
38124
38404
  return null;
@@ -38126,7 +38406,7 @@ async function readJsonFile4(filePath) {
38126
38406
  }
38127
38407
  async function readPkgName(absPath) {
38128
38408
  try {
38129
- const raw = await readFile27(join46(absPath, "package.json"), "utf-8");
38409
+ const raw = await readFile28(join47(absPath, "package.json"), "utf-8");
38130
38410
  const pkg = JSON.parse(raw);
38131
38411
  return typeof pkg.name === "string" ? pkg.name : null;
38132
38412
  } catch {
@@ -38140,7 +38420,7 @@ async function runGenerate(opts) {
38140
38420
  const rootDir = resolve11(projectDir);
38141
38421
  let packageManager;
38142
38422
  try {
38143
- const raw = await readFile27(join46(rootDir, "package.json"), "utf-8");
38423
+ const raw = await readFile28(join47(rootDir, "package.json"), "utf-8");
38144
38424
  const pkg = JSON.parse(raw);
38145
38425
  if (typeof pkg.packageManager === "string") {
38146
38426
  packageManager = pkg.packageManager;
@@ -38148,7 +38428,7 @@ async function runGenerate(opts) {
38148
38428
  } catch {
38149
38429
  }
38150
38430
  const serverJson = await readJsonFile4(
38151
- join46(rootDir, ".codebyplan", "server.json")
38431
+ join47(rootDir, ".codebyplan", "server.json")
38152
38432
  );
38153
38433
  const ports = [];
38154
38434
  for (const alloc of serverJson?.port_allocations ?? []) {
@@ -38161,7 +38441,7 @@ async function runGenerate(opts) {
38161
38441
  }
38162
38442
  }
38163
38443
  const gitJson = await readJsonFile4(
38164
- join46(rootDir, ".codebyplan", "git.json")
38444
+ join47(rootDir, ".codebyplan", "git.json")
38165
38445
  );
38166
38446
  const branchModel = gitJson?.branch_config?.production ? {
38167
38447
  production: gitJson.branch_config.production,
@@ -38170,7 +38450,7 @@ async function runGenerate(opts) {
38170
38450
  )
38171
38451
  } : void 0;
38172
38452
  const shipmentJson = await readJsonFile4(
38173
- join46(rootDir, ".codebyplan", "shipment.json")
38453
+ join47(rootDir, ".codebyplan", "shipment.json")
38174
38454
  );
38175
38455
  const shipmentSurfaces = [];
38176
38456
  const rawSurfaces = shipmentJson?.shipment?.surfaces ?? shipmentJson?.surfaces ?? {};
@@ -38241,10 +38521,10 @@ async function runGenerate(opts) {
38241
38521
  const structureMdContent = generateStructureMd(config);
38242
38522
  const agentsContent = generateAgentsMd(structureMdContent);
38243
38523
  if (check) {
38244
- const agentsMdPath2 = join46(rootDir, "AGENTS.md");
38524
+ const agentsMdPath2 = join47(rootDir, "AGENTS.md");
38245
38525
  let existingAgents = null;
38246
38526
  try {
38247
- existingAgents = await readFile27(agentsMdPath2, "utf-8");
38527
+ existingAgents = await readFile28(agentsMdPath2, "utf-8");
38248
38528
  } catch {
38249
38529
  existingAgents = null;
38250
38530
  }
@@ -38280,16 +38560,16 @@ async function runGenerate(opts) {
38280
38560
  process.stdout.write(agentsContent);
38281
38561
  return;
38282
38562
  }
38283
- const outputDir = join46(rootDir, ".claude", "generated");
38563
+ const outputDir = join47(rootDir, ".claude", "generated");
38284
38564
  await mkdir13(outputDir, { recursive: true });
38285
- const outputPath = join46(outputDir, "structure.md");
38286
- await writeFile21(outputPath, structureMdContent, "utf-8");
38565
+ const outputPath = join47(outputDir, "structure.md");
38566
+ await writeFile22(outputPath, structureMdContent, "utf-8");
38287
38567
  process.stdout.write(`Wrote: .claude/generated/structure.md
38288
38568
  `);
38289
- const agentsMdPath = join46(rootDir, "AGENTS.md");
38569
+ const agentsMdPath = join47(rootDir, "AGENTS.md");
38290
38570
  let existingAgentsContent = null;
38291
38571
  try {
38292
- existingAgentsContent = await readFile27(agentsMdPath, "utf-8");
38572
+ existingAgentsContent = await readFile28(agentsMdPath, "utf-8");
38293
38573
  } catch {
38294
38574
  existingAgentsContent = null;
38295
38575
  }
@@ -38297,7 +38577,7 @@ async function runGenerate(opts) {
38297
38577
  process.stdout.write(`Up to date: AGENTS.md
38298
38578
  `);
38299
38579
  } else {
38300
- await writeFile21(agentsMdPath, agentsContent, "utf-8");
38580
+ await writeFile22(agentsMdPath, agentsContent, "utf-8");
38301
38581
  process.stdout.write(`Wrote: AGENTS.md
38302
38582
  `);
38303
38583
  }
@@ -38317,11 +38597,11 @@ __export(readme_exports, {
38317
38597
  runReadme: () => runReadme,
38318
38598
  runReadmeCommand: () => runReadmeCommand
38319
38599
  });
38320
- import { readFile as readFile28, writeFile as writeFile22 } from "node:fs/promises";
38321
- 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";
38322
38602
  async function readJsonFile5(filePath) {
38323
38603
  try {
38324
- const raw = await readFile28(filePath, "utf-8");
38604
+ const raw = await readFile29(filePath, "utf-8");
38325
38605
  return JSON.parse(raw);
38326
38606
  } catch {
38327
38607
  return null;
@@ -38390,7 +38670,7 @@ async function discoverUnits(rootDir, rootPkgJson) {
38390
38670
  const discovered = await discoverMonorepoApps(rootDir);
38391
38671
  for (const app of discovered) {
38392
38672
  const pkgJson = await readJsonFile5(
38393
- join47(app.absPath, "package.json")
38673
+ join48(app.absPath, "package.json")
38394
38674
  );
38395
38675
  pkgJsonByPath.set(app.absPath, pkgJson);
38396
38676
  allPackages.push({
@@ -38416,7 +38696,7 @@ async function runReadme(opts) {
38416
38696
  const init = opts.init ?? opts["init"] ?? false;
38417
38697
  const rootDir = resolve12(projectDir);
38418
38698
  const rootPkgJson = await readJsonFile5(
38419
- join47(rootDir, "package.json")
38699
+ join48(rootDir, "package.json")
38420
38700
  );
38421
38701
  const { units, allPackages, pkgJsonByPath } = await discoverUnits(
38422
38702
  rootDir,
@@ -38425,11 +38705,11 @@ async function runReadme(opts) {
38425
38705
  const driftUnits = [];
38426
38706
  const missingUnits = [];
38427
38707
  for (const unit of units) {
38428
- const readmePath = join47(unit.absPath, "README.md");
38429
- 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");
38430
38710
  let existingContent = null;
38431
38711
  try {
38432
- existingContent = await readFile28(readmePath, "utf-8");
38712
+ existingContent = await readFile29(readmePath, "utf-8");
38433
38713
  } catch {
38434
38714
  existingContent = null;
38435
38715
  }
@@ -38464,7 +38744,7 @@ ${newContent}
38464
38744
  `
38465
38745
  );
38466
38746
  } else {
38467
- await writeFile22(readmePath, newContent, "utf-8");
38747
+ await writeFile23(readmePath, newContent, "utf-8");
38468
38748
  process.stdout.write(`Wrote (scaffold): ${relPath}
38469
38749
  `);
38470
38750
  }
@@ -38502,7 +38782,7 @@ ${newContent}
38502
38782
  `
38503
38783
  );
38504
38784
  } else {
38505
- await writeFile22(readmePath, newContent, "utf-8");
38785
+ await writeFile23(readmePath, newContent, "utf-8");
38506
38786
  process.stdout.write(`Wrote (refresh): ${relPath}
38507
38787
  `);
38508
38788
  }
@@ -38521,7 +38801,7 @@ ${newContent}
38521
38801
  `
38522
38802
  );
38523
38803
  } else {
38524
- await writeFile22(readmePath, newContent, "utf-8");
38804
+ await writeFile23(readmePath, newContent, "utf-8");
38525
38805
  process.stdout.write(`Wrote (init): ${relPath}
38526
38806
  `);
38527
38807
  }
@@ -38609,15 +38889,15 @@ __export(migrate_memory_exports, {
38609
38889
  runMigrateMemory: () => runMigrateMemory
38610
38890
  });
38611
38891
  import {
38612
- readFile as readFile29,
38613
- writeFile as writeFile23,
38892
+ readFile as readFile30,
38893
+ writeFile as writeFile24,
38614
38894
  mkdir as mkdir14,
38615
38895
  unlink as unlink6,
38616
38896
  rmdir,
38617
38897
  readdir as readdir7
38618
38898
  } from "node:fs/promises";
38619
38899
  import { existsSync as existsSync21 } from "node:fs";
38620
- 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";
38621
38901
  import { homedir as homedir8 } from "node:os";
38622
38902
  function encodeProjectPath(absPath) {
38623
38903
  return resolve13(absPath).replace(/[/\\]/g, "-");
@@ -38628,7 +38908,7 @@ function resolveAutoMemoryDir(opts) {
38628
38908
  }
38629
38909
  const projectDir = opts.projectDir ?? process.cwd();
38630
38910
  const encoded = encodeProjectPath(projectDir);
38631
- return join48(homedir8(), ".claude", "projects", encoded, "memory");
38911
+ return join49(homedir8(), ".claude", "projects", encoded, "memory");
38632
38912
  }
38633
38913
  function parseFrontmatter(content) {
38634
38914
  content = content.replace(/\r\n/g, "\n");
@@ -38694,10 +38974,10 @@ async function inventoryFiles(dir) {
38694
38974
  }
38695
38975
  const results = [];
38696
38976
  for (const filename of filenames) {
38697
- const sourcePath = join48(dir, filename);
38977
+ const sourcePath = join49(dir, filename);
38698
38978
  let raw;
38699
38979
  try {
38700
- raw = await readFile29(sourcePath, "utf-8");
38980
+ raw = await readFile30(sourcePath, "utf-8");
38701
38981
  } catch (err) {
38702
38982
  const msg = err instanceof Error ? err.message : String(err);
38703
38983
  results.push({
@@ -38783,8 +39063,8 @@ async function applyPlan(plan, opts) {
38783
39063
  if (entry.suggested_action !== "keep") continue;
38784
39064
  if (!entry.suggested_target?.startsWith("nested:")) continue;
38785
39065
  const relPath = entry.suggested_target.slice("nested:".length);
38786
- const targetDir = resolve13(join48(projectDir, relPath));
38787
- const targetFile = join48(targetDir, "CLAUDE.md");
39066
+ const targetDir = resolve13(join49(projectDir, relPath));
39067
+ const targetFile = join49(targetDir, "CLAUDE.md");
38788
39068
  if (!targetDir.startsWith(resolve13(projectDir) + sep4)) {
38789
39069
  process.stderr.write(
38790
39070
  `migrate-memory: skipping unsafe suggested_target "${entry.suggested_target}" \u2014 resolves outside projectDir
@@ -38816,11 +39096,11 @@ ${anchor}
38816
39096
  await mkdir14(targetDir, { recursive: true });
38817
39097
  let existing = "";
38818
39098
  try {
38819
- existing = await readFile29(targetFile, "utf-8");
39099
+ existing = await readFile30(targetFile, "utf-8");
38820
39100
  } catch {
38821
39101
  }
38822
39102
  if (!existing.includes(anchor)) {
38823
- await writeFile23(targetFile, existing + appendContent, "utf-8");
39103
+ await writeFile24(targetFile, existing + appendContent, "utf-8");
38824
39104
  }
38825
39105
  if (resolve13(entry.source_path).startsWith(resolve13(plan.auto_memory_dir) + sep4)) {
38826
39106
  try {
@@ -38834,7 +39114,7 @@ ${anchor}
38834
39114
  );
38835
39115
  }
38836
39116
  }
38837
- const rootClaudeMd = join48(projectDir, ".claude", "CLAUDE.md");
39117
+ const rootClaudeMd = join49(projectDir, ".claude", "CLAUDE.md");
38838
39118
  if (dryRun) {
38839
39119
  process.stdout.write(
38840
39120
  `[dry-run] Would ensure ${rootClaudeMd} contains: ${IMPORT_LINE}
@@ -38843,12 +39123,12 @@ ${anchor}
38843
39123
  } else {
38844
39124
  let claudeMdContent = "";
38845
39125
  try {
38846
- claudeMdContent = await readFile29(rootClaudeMd, "utf-8");
39126
+ claudeMdContent = await readFile30(rootClaudeMd, "utf-8");
38847
39127
  } catch {
38848
39128
  await mkdir14(dirname15(rootClaudeMd), { recursive: true });
38849
39129
  }
38850
39130
  if (!claudeMdContent.includes(IMPORT_LINE)) {
38851
- await writeFile23(
39131
+ await writeFile24(
38852
39132
  rootClaudeMd,
38853
39133
  claudeMdContent + `
38854
39134
  ${IMPORT_LINE}
@@ -38878,8 +39158,8 @@ ${IMPORT_LINE}
38878
39158
  } catch {
38879
39159
  }
38880
39160
  }
38881
- const memoryMd = join48(plan.auto_memory_dir, "MEMORY.md");
38882
- const safeRmdirBase = join48(homedir8(), ".claude", "projects");
39161
+ const memoryMd = join49(plan.auto_memory_dir, "MEMORY.md");
39162
+ const safeRmdirBase = join49(homedir8(), ".claude", "projects");
38883
39163
  if (dryRun) {
38884
39164
  process.stdout.write(`[dry-run] Would delete MEMORY.md: ${memoryMd}
38885
39165
  `);
@@ -38932,7 +39212,7 @@ async function runMigrateMemory(opts) {
38932
39212
  if (applyFile) {
38933
39213
  let planJson;
38934
39214
  try {
38935
- planJson = await readFile29(resolve13(applyFile), "utf-8");
39215
+ planJson = await readFile30(resolve13(applyFile), "utf-8");
38936
39216
  } catch (err) {
38937
39217
  const msg = err instanceof Error ? err.message : String(err);
38938
39218
  process.stderr.write(
@@ -39003,7 +39283,7 @@ var init_migrate_memory = __esm({
39003
39283
 
39004
39284
  // src/lib/claude-mode-audit.ts
39005
39285
  import { readdirSync as readdirSync7, readFileSync as readFileSync19, existsSync as existsSync22 } from "node:fs";
39006
- import { join as join49, basename as basename2 } from "node:path";
39286
+ import { join as join50, basename as basename2 } from "node:path";
39007
39287
  function parseFrontmatter2(content) {
39008
39288
  const match = /^---\r?\n([\s\S]*?)\r?\n---/.exec(content);
39009
39289
  if (!match) return {};
@@ -39080,19 +39360,19 @@ function auditSkill(filePath) {
39080
39360
  }
39081
39361
  function auditMode(templatesDir) {
39082
39362
  const entries = [];
39083
- const agentsDir = join49(templatesDir, "agents");
39363
+ const agentsDir = join50(templatesDir, "agents");
39084
39364
  if (existsSync22(agentsDir)) {
39085
39365
  const agentFiles = readdirSync7(agentsDir).filter((f) => f.endsWith(".md")).sort();
39086
39366
  for (const f of agentFiles) {
39087
- entries.push(auditAgent(join49(agentsDir, f)));
39367
+ entries.push(auditAgent(join50(agentsDir, f)));
39088
39368
  }
39089
39369
  }
39090
- const skillsDir = join49(templatesDir, "skills");
39370
+ const skillsDir = join50(templatesDir, "skills");
39091
39371
  if (existsSync22(skillsDir)) {
39092
39372
  const skillDirs = readdirSync7(skillsDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name).sort();
39093
39373
  for (const dir of skillDirs) {
39094
- if (existsSync22(join49(skillsDir, dir, "PROVENANCE.md"))) continue;
39095
- const skillMd = join49(skillsDir, dir, "SKILL.md");
39374
+ if (existsSync22(join50(skillsDir, dir, "PROVENANCE.md"))) continue;
39375
+ const skillMd = join50(skillsDir, dir, "SKILL.md");
39096
39376
  if (existsSync22(skillMd)) {
39097
39377
  entries.push(auditSkill(skillMd));
39098
39378
  }
@@ -39197,9 +39477,9 @@ var resolve_preview_exports = {};
39197
39477
  __export(resolve_preview_exports, {
39198
39478
  resolvePreview: () => resolvePreview
39199
39479
  });
39200
- import { spawnSync as spawnSync11 } from "node:child_process";
39480
+ import { spawnSync as spawnSync12 } from "node:child_process";
39201
39481
  function defaultGetCurrentBranch(cwd) {
39202
- const result = spawnSync11("git", ["rev-parse", "--abbrev-ref", "HEAD"], {
39482
+ const result = spawnSync12("git", ["rev-parse", "--abbrev-ref", "HEAD"], {
39203
39483
  cwd,
39204
39484
  encoding: "utf-8",
39205
39485
  stdio: ["pipe", "pipe", "pipe"]
@@ -39351,7 +39631,7 @@ __export(new_migration_exports, {
39351
39631
  newMigration: () => newMigration
39352
39632
  });
39353
39633
  import * as fs19 from "node:fs";
39354
- import * as path19 from "node:path";
39634
+ import * as path20 from "node:path";
39355
39635
  function slugify(name) {
39356
39636
  return name.trim().toLowerCase().replace(/[^a-z0-9_-]+/g, "_").replace(/^_+|_+$/g, "").replace(/_+/g, "_");
39357
39637
  }
@@ -39372,9 +39652,9 @@ function newMigration(args, deps = {}) {
39372
39652
  }
39373
39653
  const slug = slugify(rawName);
39374
39654
  const stamp = genTimestamp({ cwd });
39375
- const migrationsDir = path19.join(cwd, "supabase", "migrations");
39655
+ const migrationsDir = path20.join(cwd, "supabase", "migrations");
39376
39656
  const filename = `${stamp}_${slug}.sql`;
39377
- const filePath = path19.join(migrationsDir, filename);
39657
+ const filePath = path20.join(migrationsDir, filename);
39378
39658
  mkdirSync11(migrationsDir, { recursive: true });
39379
39659
  writeFileSync12(filePath, "");
39380
39660
  process.stdout.write(JSON.stringify({ path: filePath }) + "\n");
@@ -39392,9 +39672,9 @@ var preview_check_exports = {};
39392
39672
  __export(preview_check_exports, {
39393
39673
  previewCheck: () => previewCheck
39394
39674
  });
39395
- import { spawnSync as spawnSync12 } from "node:child_process";
39675
+ import { spawnSync as spawnSync13 } from "node:child_process";
39396
39676
  function defaultRun3(cmd, args) {
39397
- const result = spawnSync12(cmd, args, {
39677
+ const result = spawnSync13(cmd, args, {
39398
39678
  encoding: "utf-8",
39399
39679
  stdio: ["pipe", "pipe", "pipe"]
39400
39680
  });
@@ -39449,10 +39729,10 @@ var init_preview_check = __esm({
39449
39729
  });
39450
39730
 
39451
39731
  // src/lib/session.ts
39452
- import { spawnSync as spawnSync13 } from "node:child_process";
39453
- import * as path20 from "node:path";
39732
+ import { spawnSync as spawnSync14 } from "node:child_process";
39733
+ import * as path21 from "node:path";
39454
39734
  function defaultRun4(cmd, args, cwd) {
39455
- const result = spawnSync13(cmd, args, {
39735
+ const result = spawnSync14(cmd, args, {
39456
39736
  cwd,
39457
39737
  encoding: "utf-8",
39458
39738
  stdio: ["pipe", "pipe", "pipe"]
@@ -39480,7 +39760,7 @@ function homeFf(opts = {}) {
39480
39760
  reason: "git rev-parse --show-toplevel failed"
39481
39761
  };
39482
39762
  }
39483
- const folder = path20.basename(repoRoot);
39763
+ const folder = path21.basename(repoRoot);
39484
39764
  let current;
39485
39765
  try {
39486
39766
  current = run("git", ["rev-parse", "--abbrev-ref", "HEAD"], cwd).trim();
@@ -39513,7 +39793,7 @@ function homeFf(opts = {}) {
39513
39793
  }
39514
39794
  function spawnVersionStatus(cwd) {
39515
39795
  try {
39516
- const result = spawnSync13("npx", ["codebyplan", "version-status"], {
39796
+ const result = spawnSync14("npx", ["codebyplan", "version-status"], {
39517
39797
  cwd,
39518
39798
  encoding: "utf-8",
39519
39799
  stdio: ["pipe", "pipe", "pipe"]
@@ -39547,7 +39827,7 @@ function defaultRunInstall(installCommand, cwd) {
39547
39827
  const cmd = parts[0];
39548
39828
  const args = parts.slice(1);
39549
39829
  if (!cmd) throw new Error("empty installCommand");
39550
- const result = spawnSync13(cmd, args, {
39830
+ const result = spawnSync14(cmd, args, {
39551
39831
  cwd,
39552
39832
  encoding: "utf-8",
39553
39833
  stdio: ["pipe", "pipe", "pipe"]
@@ -39561,7 +39841,7 @@ function defaultRunInstall(installCommand, cwd) {
39561
39841
  }
39562
39842
  }
39563
39843
  function defaultRunClaudeUpdate(cwd) {
39564
- const result = spawnSync13("npx", ["codebyplan", "claude", "update", "--yes"], {
39844
+ const result = spawnSync14("npx", ["codebyplan", "claude", "update", "--yes"], {
39565
39845
  cwd,
39566
39846
  encoding: "utf-8",
39567
39847
  stdio: ["pipe", "pipe", "pipe"]
@@ -39575,7 +39855,7 @@ function defaultRunClaudeUpdate(cwd) {
39575
39855
  }
39576
39856
  }
39577
39857
  function defaultRunGitStatus(cwd) {
39578
- const result = spawnSync13(
39858
+ const result = spawnSync14(
39579
39859
  "git",
39580
39860
  ["status", "--porcelain", "--", ".claude/", ".codebyplan/"],
39581
39861
  {
@@ -39828,9 +40108,9 @@ var commit_exports = {};
39828
40108
  __export(commit_exports, {
39829
40109
  runCommitCommand: () => runCommitCommand
39830
40110
  });
39831
- import { spawnSync as spawnSync14 } from "node:child_process";
40111
+ import { spawnSync as spawnSync15 } from "node:child_process";
39832
40112
  function defaultRun5(cmd, args) {
39833
- const result = spawnSync14(cmd, args, {
40113
+ const result = spawnSync15(cmd, args, {
39834
40114
  encoding: "utf-8",
39835
40115
  stdio: ["pipe", "pipe", "pipe"]
39836
40116
  });
@@ -39878,7 +40158,7 @@ var init_commit = __esm({
39878
40158
  });
39879
40159
 
39880
40160
  // src/lib/migration-collisions.ts
39881
- import { spawnSync as spawnSync15 } from "node:child_process";
40161
+ import { spawnSync as spawnSync16 } from "node:child_process";
39882
40162
  function extractPrefix(filename) {
39883
40163
  const base = filename.endsWith(".sql") ? filename.slice(0, -4) : filename;
39884
40164
  const underscoreIdx = base.indexOf("_");
@@ -39890,7 +40170,7 @@ function extractPrefix(filename) {
39890
40170
  }
39891
40171
  function makeDefaultRun(cwd) {
39892
40172
  return (cmd, args) => {
39893
- const result = spawnSync15(cmd, args, {
40173
+ const result = spawnSync16(cmd, args, {
39894
40174
  cwd,
39895
40175
  encoding: "utf-8",
39896
40176
  stdio: ["pipe", "pipe", "pipe"]
@@ -40047,13 +40327,13 @@ function validateWaves(waves) {
40047
40327
  pathOwners.set(file, owners);
40048
40328
  }
40049
40329
  }
40050
- for (const [path21, owners] of pathOwners) {
40330
+ for (const [path22, owners] of pathOwners) {
40051
40331
  if (owners.length > 1) {
40052
40332
  violations.push({
40053
40333
  invariant: "I",
40054
40334
  code: "DUPLICATE_FILE",
40055
- message: `File "${path21}" appears in multiple waves: ${owners.join(", ")}.`,
40056
- detail: { path: path21, waves: owners }
40335
+ message: `File "${path22}" appears in multiple waves: ${owners.join(", ")}.`,
40336
+ detail: { path: path22, waves: owners }
40057
40337
  });
40058
40338
  }
40059
40339
  }
@@ -40147,7 +40427,7 @@ var validate_waves_exports = {};
40147
40427
  __export(validate_waves_exports, {
40148
40428
  runValidateWavesCommand: () => runValidateWavesCommand
40149
40429
  });
40150
- import { readFile as readFile30 } from "node:fs/promises";
40430
+ import { readFile as readFile31 } from "node:fs/promises";
40151
40431
  async function readStdin() {
40152
40432
  return new Promise((resolve16, reject) => {
40153
40433
  const chunks = [];
@@ -40166,7 +40446,7 @@ async function runValidateWavesCommand(args) {
40166
40446
  let raw;
40167
40447
  if (filePath) {
40168
40448
  try {
40169
- raw = await readFile30(filePath, "utf-8");
40449
+ raw = await readFile31(filePath, "utf-8");
40170
40450
  } catch (err) {
40171
40451
  const msg = err instanceof Error ? err.message : String(err);
40172
40452
  process.stderr.write(
@@ -40246,12 +40526,12 @@ var init_validate_waves2 = __esm({
40246
40526
  });
40247
40527
 
40248
40528
  // src/cli/worktree/path.ts
40249
- 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";
40250
40530
  function computeWorktreePath(cwd, checkpointNumber) {
40251
40531
  const parent = dirname16(cwd);
40252
40532
  const base = basename4(cwd);
40253
40533
  const nnn = String(checkpointNumber).padStart(3, "0");
40254
- return join51(parent, `${base}-CHK-${nnn}`);
40534
+ return join52(parent, `${base}-CHK-${nnn}`);
40255
40535
  }
40256
40536
  var init_path = __esm({
40257
40537
  "src/cli/worktree/path.ts"() {
@@ -40260,9 +40540,9 @@ var init_path = __esm({
40260
40540
  });
40261
40541
 
40262
40542
  // src/cli/worktree/add.ts
40263
- import { join as join52, basename as basename5 } from "node:path";
40264
- import { mkdir as mkdir15, readFile as readFile31, writeFile as writeFile24 } from "node:fs/promises";
40265
- 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";
40266
40546
  async function defaultGetRepoId(cwd) {
40267
40547
  const found = await findCodebyplanConfig(cwd);
40268
40548
  return found?.contents.repo_id ?? null;
@@ -40291,7 +40571,7 @@ async function defaultLookupBranch(repoId, checkpointNumber) {
40291
40571
  return { found: true, branch_name: chk.branch_name };
40292
40572
  }
40293
40573
  function defaultGitRun(args, cwd) {
40294
- const result = spawnSync16("git", args, {
40574
+ const result = spawnSync17("git", args, {
40295
40575
  cwd,
40296
40576
  encoding: "utf-8",
40297
40577
  stdio: ["pipe", "pipe", "pipe"]
@@ -40303,34 +40583,56 @@ function defaultGitRun(args, cwd) {
40303
40583
  error: result.error
40304
40584
  };
40305
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
+ }
40306
40607
  async function defaultCopyConfigStubs(srcCwd, destPath) {
40307
- await mkdir15(join52(destPath, ".codebyplan"), { recursive: true });
40608
+ await mkdir15(join53(destPath, ".codebyplan"), { recursive: true });
40308
40609
  const topLevelStubs = [".mcp.json", ".env.local"];
40309
40610
  for (const stub of topLevelStubs) {
40310
40611
  try {
40311
- const content = await readFile31(join52(srcCwd, stub), "utf-8");
40312
- 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");
40313
40614
  } catch {
40314
40615
  }
40315
40616
  }
40316
40617
  try {
40317
- const content = await readFile31(
40318
- join52(srcCwd, ".codebyplan", "repo.json"),
40618
+ const content = await readFile32(
40619
+ join53(srcCwd, ".codebyplan", "repo.json"),
40319
40620
  "utf-8"
40320
40621
  );
40321
- await writeFile24(
40322
- join52(destPath, ".codebyplan", "repo.json"),
40622
+ await writeFile25(
40623
+ join53(destPath, ".codebyplan", "repo.json"),
40323
40624
  content,
40324
40625
  "utf-8"
40325
40626
  );
40326
40627
  } catch {
40327
40628
  }
40629
+ await copyClaudeSettings(srcCwd, destPath);
40328
40630
  }
40329
- async function defaultRegisterWorktree(repoId, name, path21) {
40631
+ async function defaultRegisterWorktree(repoId, name, path22) {
40330
40632
  const res = await apiPost("/worktrees", {
40331
40633
  repo_id: repoId,
40332
40634
  name,
40333
- path: path21,
40635
+ path: path22,
40334
40636
  status: "active"
40335
40637
  });
40336
40638
  return { worktree_id: res.data.id };
@@ -40428,10 +40730,12 @@ async function runWorktreeAdd(args, deps = {}) {
40428
40730
  );
40429
40731
  return 1;
40430
40732
  }
40733
+ let copyStubsWarn;
40431
40734
  try {
40432
40735
  await copyConfigStubs(cwd, worktreePath);
40433
40736
  } catch (err) {
40434
40737
  const msg = err instanceof Error ? err.message : String(err);
40738
+ copyStubsWarn = `Failed to copy config stubs: ${msg}`;
40435
40739
  process.stderr.write(`Warning: failed to copy config stubs: ${msg}
40436
40740
  `);
40437
40741
  }
@@ -40445,7 +40749,8 @@ async function runWorktreeAdd(args, deps = {}) {
40445
40749
  status: "added",
40446
40750
  worktree_path: worktreePath,
40447
40751
  branch_name: branchName,
40448
- worktree_id
40752
+ worktree_id,
40753
+ ...copyStubsWarn ? { warn: copyStubsWarn } : {}
40449
40754
  };
40450
40755
  process.stdout.write(JSON.stringify(result) + "\n");
40451
40756
  return 0;
@@ -40480,7 +40785,7 @@ var init_add = __esm({
40480
40785
  });
40481
40786
 
40482
40787
  // src/cli/worktree/create.ts
40483
- import { join as join53 } from "node:path";
40788
+ import { join as join54 } from "node:path";
40484
40789
  async function defaultGetRepoIdentity(cwd) {
40485
40790
  const found = await findCodebyplanConfig(cwd);
40486
40791
  const contents = found?.contents ?? null;
@@ -40492,11 +40797,11 @@ async function defaultGetRepoIdentity(cwd) {
40492
40797
  project_id: typeof contents?.["project_id"] === "string" ? contents["project_id"] : void 0
40493
40798
  };
40494
40799
  }
40495
- async function defaultRegisterWorktree2(repoId, name, path21) {
40800
+ async function defaultRegisterWorktree2(repoId, name, path22) {
40496
40801
  const res = await apiPost("/worktrees", {
40497
40802
  repo_id: repoId,
40498
40803
  name,
40499
- path: path21,
40804
+ path: path22,
40500
40805
  status: "active"
40501
40806
  });
40502
40807
  return { worktree_id: res.data.id };
@@ -40525,6 +40830,7 @@ async function runWorktreeCreate(args, deps = {}) {
40525
40830
  const getRepoIdentity = deps.getRepoIdentity ?? defaultGetRepoIdentity;
40526
40831
  const getDeviceId = deps.getDeviceId ?? getOrCreateDeviceId;
40527
40832
  const registerWorktree = deps.registerWorktree ?? defaultRegisterWorktree2;
40833
+ const copyClaudeSettingsFn = deps.copyClaudeSettingsFn ?? ((srcCwd, destPath) => copyClaudeSettings(srcCwd, destPath));
40528
40834
  const identity = await getRepoIdentity(cwd);
40529
40835
  const repoId = identity?.repo_id ?? null;
40530
40836
  if (!identity || !repoId) {
@@ -40535,7 +40841,7 @@ async function runWorktreeCreate(args, deps = {}) {
40535
40841
  );
40536
40842
  return 1;
40537
40843
  }
40538
- const worktreePath = explicitPath ?? join53(cwd, "..", name);
40844
+ const worktreePath = explicitPath ?? join54(cwd, "..", name);
40539
40845
  const deviceId = await getDeviceId(cwd);
40540
40846
  let filesWritten = false;
40541
40847
  try {
@@ -40560,12 +40866,19 @@ async function runWorktreeCreate(args, deps = {}) {
40560
40866
  process.stdout.write(JSON.stringify(result) + "\n");
40561
40867
  return 0;
40562
40868
  }
40869
+ let copyWarn;
40870
+ try {
40871
+ await copyClaudeSettingsFn(cwd, worktreePath);
40872
+ } catch (err) {
40873
+ copyWarn = err instanceof Error ? err.message : String(err);
40874
+ }
40563
40875
  try {
40564
40876
  const { worktree_id } = await registerWorktree(repoId, name, worktreePath);
40565
40877
  const result = {
40566
40878
  worktree_files_written: true,
40567
40879
  mcp_registered: true,
40568
- worktree_id
40880
+ worktree_id,
40881
+ ...copyWarn ? { warn: `Settings copy failed (non-fatal): ${copyWarn}` } : {}
40569
40882
  };
40570
40883
  process.stdout.write(JSON.stringify(result) + "\n");
40571
40884
  return 0;
@@ -40587,12 +40900,13 @@ var init_create = __esm({
40587
40900
  init_local_config();
40588
40901
  init_api();
40589
40902
  init_worktree();
40903
+ init_add();
40590
40904
  }
40591
40905
  });
40592
40906
 
40593
40907
  // src/cli/worktree/remove.ts
40594
40908
  import { basename as basename6 } from "node:path";
40595
- import { spawnSync as spawnSync17 } from "node:child_process";
40909
+ import { spawnSync as spawnSync18 } from "node:child_process";
40596
40910
  async function defaultGetRepoId2(cwd) {
40597
40911
  const found = await findCodebyplanConfig(cwd);
40598
40912
  return found?.contents.repo_id ?? null;
@@ -40614,7 +40928,7 @@ async function defaultDeregisterWorktree(worktreeId) {
40614
40928
  await mcpCall("delete_worktree", { worktree_id: worktreeId });
40615
40929
  }
40616
40930
  function defaultGitRun2(args, cwd) {
40617
- const result = spawnSync17("git", args, {
40931
+ const result = spawnSync18("git", args, {
40618
40932
  cwd,
40619
40933
  encoding: "utf-8",
40620
40934
  stdio: ["pipe", "pipe", "pipe"]
@@ -40627,7 +40941,7 @@ function defaultGitRun2(args, cwd) {
40627
40941
  };
40628
40942
  }
40629
40943
  function defaultGetWorktreeBranchName(worktreePath) {
40630
- const result = spawnSync17("git", ["symbolic-ref", "--short", "HEAD"], {
40944
+ const result = spawnSync18("git", ["symbolic-ref", "--short", "HEAD"], {
40631
40945
  cwd: worktreePath,
40632
40946
  encoding: "utf-8",
40633
40947
  stdio: ["pipe", "pipe", "pipe"]
@@ -41006,6 +41320,24 @@ function verifyRound(input) {
41006
41320
  }
41007
41321
  }
41008
41322
  }
41323
+ if (output.status === "completed") {
41324
+ const consoleErrors = output.console_errors;
41325
+ if (Array.isArray(consoleErrors) && consoleErrors.length > 0) {
41326
+ failed_checks.push({
41327
+ check: "console_errors_reported",
41328
+ framework,
41329
+ detail: `Framework "${framework}" completed but reported ${consoleErrors.length} console/page error(s) \u2014 a completed run must be console-clean per rules/e2e-mandatory.md.`
41330
+ });
41331
+ }
41332
+ const violations = output.a11y?.violations;
41333
+ if (Array.isArray(violations) && violations.length > 0) {
41334
+ failed_checks.push({
41335
+ check: "a11y_violations_reported",
41336
+ framework,
41337
+ detail: `Framework "${framework}" completed but reported ${violations.length} accessibility violation(s) \u2014 fix in-scope or classify as category 'a11y' failures per rules/e2e-mandatory.md.`
41338
+ });
41339
+ }
41340
+ }
41009
41341
  }
41010
41342
  return {
41011
41343
  pass: failed_checks.length === 0,
@@ -41020,7 +41352,7 @@ var init_e2e = __esm({
41020
41352
  });
41021
41353
 
41022
41354
  // src/cli/e2e/verify-round.ts
41023
- import { readFile as readFile32 } from "node:fs/promises";
41355
+ import { readFile as readFile33 } from "node:fs/promises";
41024
41356
  import { resolve as resolve14 } from "node:path";
41025
41357
  async function defaultFetchRounds(taskId) {
41026
41358
  return mcpCall("get_rounds", { task_id: taskId });
@@ -41028,7 +41360,7 @@ async function defaultFetchRounds(taskId) {
41028
41360
  async function defaultReadE2eConfig(cwd) {
41029
41361
  try {
41030
41362
  const p = resolve14(cwd, ".codebyplan", "e2e.json");
41031
- const raw = await readFile32(p, "utf-8");
41363
+ const raw = await readFile33(p, "utf-8");
41032
41364
  return JSON.parse(raw);
41033
41365
  } catch {
41034
41366
  return null;
@@ -41153,6 +41485,8 @@ var doctor_exports = {};
41153
41485
  __export(doctor_exports, {
41154
41486
  runDoctor: () => runDoctor
41155
41487
  });
41488
+ import { existsSync as existsSync23 } from "node:fs";
41489
+ import { join as join55 } from "node:path";
41156
41490
  import { execSync as execSync10 } from "node:child_process";
41157
41491
  async function checkAuth() {
41158
41492
  try {
@@ -41259,6 +41593,75 @@ async function checkWorktree() {
41259
41593
  };
41260
41594
  }
41261
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
+ }
41262
41665
  function overallStatus(checks) {
41263
41666
  if (checks.some((c) => c.status === "fail")) return "fail";
41264
41667
  if (checks.some((c) => c.status === "warn")) return "warn";
@@ -41283,7 +41686,7 @@ function printHuman(result) {
41283
41686
  }
41284
41687
  function printHelp6() {
41285
41688
  process.stdout.write(
41286
- "\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"
41287
41690
  );
41288
41691
  }
41289
41692
  async function runDoctor(args) {
@@ -41297,7 +41700,8 @@ async function runDoctor(args) {
41297
41700
  const checks = await Promise.all([
41298
41701
  checkAuth(),
41299
41702
  checkVersion(),
41300
- checkWorktree()
41703
+ checkWorktree(),
41704
+ Promise.resolve(checkSettings())
41301
41705
  ]);
41302
41706
  const result = {
41303
41707
  checks,
@@ -41321,6 +41725,8 @@ var init_doctor = __esm({
41321
41725
  init_flags();
41322
41726
  init_local_config();
41323
41727
  init_resolve_worktree();
41728
+ init_manifest();
41729
+ init_gitignore_detect();
41324
41730
  }
41325
41731
  });
41326
41732