codebyplan 1.13.60 → 1.13.62

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.
Files changed (65) hide show
  1. package/dist/ci.js +518 -0
  2. package/dist/cli.js +427 -359
  3. package/package.json +12 -2
  4. package/templates/agents/cbp-e2e-maestro.md +1 -1
  5. package/templates/agents/cbp-e2e-playwright.md +1 -1
  6. package/templates/agents/cbp-e2e-tauri.md +1 -1
  7. package/templates/agents/cbp-e2e-vscode.md +1 -1
  8. package/templates/agents/cbp-e2e-xcuitest.md +1 -1
  9. package/templates/rules/effort-and-ultracode.md +70 -0
  10. package/templates/rules/model-invocation-convention.md +1 -0
  11. package/templates/rules/workflow-orchestration.md +59 -0
  12. package/templates/skills/cbp-build-cc-agent/SKILL.md +1 -0
  13. package/templates/skills/cbp-build-cc-claude-file/SKILL.md +1 -0
  14. package/templates/skills/cbp-build-cc-mode/SKILL.md +25 -17
  15. package/templates/skills/cbp-build-cc-rule/SKILL.md +1 -0
  16. package/templates/skills/cbp-build-cc-settings/SKILL.md +1 -0
  17. package/templates/skills/cbp-build-cc-settings/reference/settings-fields.md +1 -1
  18. package/templates/skills/cbp-build-cc-skill/SKILL.md +2 -1
  19. package/templates/skills/cbp-build-cc-skill/reference/frontmatter-fields.md +1 -1
  20. package/templates/skills/cbp-build-cc-skill/scripts/validate-skill.sh +12 -9
  21. package/templates/skills/cbp-checkpoint-check/SKILL.md +5 -0
  22. package/templates/skills/cbp-checkpoint-complete/SKILL.md +1 -0
  23. package/templates/skills/cbp-checkpoint-create/SKILL.md +1 -0
  24. package/templates/skills/cbp-checkpoint-end/SKILL.md +5 -0
  25. package/templates/skills/cbp-checkpoint-plan/SKILL.md +5 -0
  26. package/templates/skills/cbp-checkpoint-start/SKILL.md +1 -0
  27. package/templates/skills/cbp-checkpoint-update/SKILL.md +2 -1
  28. package/templates/skills/cbp-clear-continue/SKILL.md +2 -1
  29. package/templates/skills/cbp-clear-prep/SKILL.md +2 -1
  30. package/templates/skills/cbp-finalize/SKILL.md +1 -0
  31. package/templates/skills/cbp-frontend-design/SKILL.md +1 -0
  32. package/templates/skills/cbp-frontend-ui/SKILL.md +2 -1
  33. package/templates/skills/cbp-frontend-ux/SKILL.md +2 -1
  34. package/templates/skills/cbp-git-branch-feat-create/SKILL.md +1 -0
  35. package/templates/skills/cbp-git-commit/SKILL.md +1 -0
  36. package/templates/skills/cbp-map-architecture/SKILL.md +5 -0
  37. package/templates/skills/cbp-merge-main/SKILL.md +1 -0
  38. package/templates/skills/cbp-refresh-arch-map/SKILL.md +1 -0
  39. package/templates/skills/cbp-round-build/SKILL.md +5 -0
  40. package/templates/skills/cbp-round-complete/SKILL.md +1 -0
  41. package/templates/skills/cbp-round-plan/SKILL.md +5 -0
  42. package/templates/skills/cbp-session-end/SKILL.md +2 -1
  43. package/templates/skills/cbp-session-start/SKILL.md +1 -0
  44. package/templates/skills/cbp-setup-cd/SKILL.md +2 -1
  45. package/templates/skills/cbp-setup-ci/SKILL.md +2 -1
  46. package/templates/skills/cbp-setup-e2e/SKILL.md +2 -1
  47. package/templates/skills/cbp-setup-eslint/SKILL.md +2 -1
  48. package/templates/skills/cbp-ship/SKILL.md +5 -0
  49. package/templates/skills/cbp-ship-configure/SKILL.md +2 -1
  50. package/templates/skills/cbp-ship-main/SKILL.md +1 -0
  51. package/templates/skills/cbp-standalone-task-check/SKILL.md +1 -0
  52. package/templates/skills/cbp-standalone-task-complete/SKILL.md +1 -0
  53. package/templates/skills/cbp-standalone-task-create/SKILL.md +2 -1
  54. package/templates/skills/cbp-standalone-task-start/SKILL.md +2 -1
  55. package/templates/skills/cbp-standalone-task-testing/SKILL.md +2 -1
  56. package/templates/skills/cbp-stripe/SKILL.md +2 -1
  57. package/templates/skills/cbp-supabase-branch-check/SKILL.md +2 -1
  58. package/templates/skills/cbp-supabase-migrate/SKILL.md +1 -0
  59. package/templates/skills/cbp-supabase-setup/SKILL.md +2 -1
  60. package/templates/skills/cbp-task-create/SKILL.md +2 -1
  61. package/templates/skills/cbp-task-start/SKILL.md +1 -0
  62. package/templates/skills/cbp-todo/SKILL.md +2 -1
  63. package/templates/skills/cbp-verify/SKILL.md +5 -0
  64. package/templates/skills/supabase/SKILL.md +2 -0
  65. package/templates/skills/supabase-postgres-best-practices/SKILL.md +2 -0
package/dist/cli.js CHANGED
@@ -48,7 +48,7 @@ var VERSION, PACKAGE_NAME;
48
48
  var init_version = __esm({
49
49
  "src/lib/version.ts"() {
50
50
  "use strict";
51
- VERSION = "1.13.60";
51
+ VERSION = "1.13.62";
52
52
  PACKAGE_NAME = "codebyplan";
53
53
  }
54
54
  });
@@ -122,8 +122,8 @@ async function readLocalConfig(projectPath, onMigrationNotice) {
122
122
  }
123
123
  async function writeLocalConfig(projectPath, config) {
124
124
  const content = { device_id: config.device_id };
125
- const path22 = localConfigPath(projectPath);
126
- const dirPath = dirname(path22);
125
+ const path23 = localConfigPath(projectPath);
126
+ const dirPath = dirname(path23);
127
127
  let phase = "stat config directory";
128
128
  try {
129
129
  try {
@@ -143,7 +143,7 @@ async function writeLocalConfig(projectPath, config) {
143
143
  phase = "create config directory";
144
144
  await mkdir(dirPath, { recursive: true });
145
145
  phase = "write local config";
146
- await writeFile(path22, JSON.stringify(content, null, 2) + "\n", "utf-8");
146
+ await writeFile(path23, JSON.stringify(content, null, 2) + "\n", "utf-8");
147
147
  } catch (err) {
148
148
  const code = err.code;
149
149
  if (code === "LEGACY_FILE_BLOCKS_DIR") {
@@ -672,8 +672,8 @@ var init_gitignore_block = __esm({
672
672
  // src/lib/worktree.ts
673
673
  import { mkdir as mkdir3, writeFile as writeFile4, readFile as readFile6 } from "node:fs/promises";
674
674
  import { join as join6 } from "node:path";
675
- function defaultExists(path22) {
676
- return readFile6(path22, "utf-8").then(() => true).catch(() => false);
675
+ function defaultExists(path23) {
676
+ return readFile6(path23, "utf-8").then(() => true).catch(() => false);
677
677
  }
678
678
  async function writeRepoJson(codebyplanDir, selectedRepo, deps) {
679
679
  const repoJson = {
@@ -794,9 +794,9 @@ var init_worktree = __esm({
794
794
  init_local_config();
795
795
  init_gitignore_block();
796
796
  defaultFsDeps = {
797
- mkdir: (path22, opts) => mkdir3(path22, opts).then(() => void 0),
798
- writeFile: (path22, data, encoding) => writeFile4(path22, data, encoding),
799
- readFile: (path22, encoding) => readFile6(path22, encoding),
797
+ mkdir: (path23, opts) => mkdir3(path23, opts).then(() => void 0),
798
+ writeFile: (path23, data, encoding) => writeFile4(path23, data, encoding),
799
+ readFile: (path23, encoding) => readFile6(path23, encoding),
800
800
  exists: defaultExists
801
801
  };
802
802
  }
@@ -864,12 +864,12 @@ async function readFallback(filename) {
864
864
  }
865
865
  }
866
866
  async function writeFallback(filename, data) {
867
- const path22 = fallbackFile(filename);
868
- await mkdir4(dirname2(path22), { recursive: true });
869
- await writeFile5(path22, JSON.stringify(data, null, 2) + "\n", "utf-8");
867
+ const path23 = fallbackFile(filename);
868
+ await mkdir4(dirname2(path23), { recursive: true });
869
+ await writeFile5(path23, JSON.stringify(data, null, 2) + "\n", "utf-8");
870
870
  if (platform() !== "win32") {
871
871
  try {
872
- await chmod(path22, 384);
872
+ await chmod(path23, 384);
873
873
  } catch {
874
874
  }
875
875
  }
@@ -1183,8 +1183,8 @@ async function validateConnectivity() {
1183
1183
  );
1184
1184
  }
1185
1185
  }
1186
- function buildUrl(path22, params) {
1187
- const url = new URL(`${baseUrl()}/api${path22}`);
1186
+ function buildUrl(path23, params) {
1187
+ const url = new URL(`${baseUrl()}/api${path23}`);
1188
1188
  if (params) {
1189
1189
  for (const [key, value] of Object.entries(params)) {
1190
1190
  if (value !== void 0) {
@@ -1201,10 +1201,10 @@ function isRetryable(err) {
1201
1201
  return false;
1202
1202
  }
1203
1203
  function delay(ms) {
1204
- return new Promise((resolve16) => setTimeout(resolve16, ms));
1204
+ return new Promise((resolve17) => setTimeout(resolve17, ms));
1205
1205
  }
1206
- async function request(method, path22, options) {
1207
- const url = buildUrl(path22, options?.params);
1206
+ async function request(method, path23, options) {
1207
+ const url = buildUrl(path23, options?.params);
1208
1208
  const auth = await getAuthHeaders();
1209
1209
  let lastError;
1210
1210
  for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
@@ -1224,7 +1224,7 @@ async function request(method, path22, options) {
1224
1224
  signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS)
1225
1225
  });
1226
1226
  if (!res.ok) {
1227
- let message = `API ${method} ${path22} failed with status ${res.status}`;
1227
+ let message = `API ${method} ${path23} failed with status ${res.status}`;
1228
1228
  let code;
1229
1229
  try {
1230
1230
  const body = await res.json();
@@ -1258,20 +1258,20 @@ async function request(method, path22, options) {
1258
1258
  }
1259
1259
  throw lastError;
1260
1260
  }
1261
- async function apiGet(path22, params) {
1262
- return request("GET", path22, { params });
1261
+ async function apiGet(path23, params) {
1262
+ return request("GET", path23, { params });
1263
1263
  }
1264
- async function apiPost(path22, body) {
1265
- return request("POST", path22, { body });
1264
+ async function apiPost(path23, body) {
1265
+ return request("POST", path23, { body });
1266
1266
  }
1267
- async function apiPut(path22, body) {
1268
- return request("PUT", path22, { body });
1267
+ async function apiPut(path23, body) {
1268
+ return request("PUT", path23, { body });
1269
1269
  }
1270
- async function apiPatch(path22, body) {
1271
- return request("PATCH", path22, { body });
1270
+ async function apiPatch(path23, body) {
1271
+ return request("PATCH", path23, { body });
1272
1272
  }
1273
- async function apiDelete(path22, params) {
1274
- await request("DELETE", path22, { params });
1273
+ async function apiDelete(path23, params) {
1274
+ await request("DELETE", path23, { params });
1275
1275
  }
1276
1276
  async function callMcpTool(toolName, params) {
1277
1277
  const url = mcpEndpoint();
@@ -1565,7 +1565,7 @@ var init_device_flow = __esm({
1565
1565
  this.name = "OAuthInvalidClientError";
1566
1566
  }
1567
1567
  };
1568
- defaultSleep = (ms) => new Promise((resolve16) => setTimeout(resolve16, ms));
1568
+ defaultSleep = (ms) => new Promise((resolve17) => setTimeout(resolve17, ms));
1569
1569
  }
1570
1570
  });
1571
1571
 
@@ -2323,7 +2323,7 @@ async function defaultPromptRemoveIgnore(displayLine, opts) {
2323
2323
  });
2324
2324
  try {
2325
2325
  while (true) {
2326
- const answer = await new Promise((resolve16) => {
2326
+ const answer = await new Promise((resolve17) => {
2327
2327
  rl.question(
2328
2328
  `The following gitignore rule matches .claude/settings.json:
2329
2329
  ${displayLine}
@@ -2331,7 +2331,7 @@ Remove this line?
2331
2331
  [r] remove [k] keep
2332
2332
  > `,
2333
2333
  (input) => {
2334
- resolve16(input.trim().toLowerCase());
2334
+ resolve17(input.trim().toLowerCase());
2335
2335
  }
2336
2336
  );
2337
2337
  });
@@ -3693,9 +3693,9 @@ import { createInterface } from "node:readline/promises";
3693
3693
  function getConfigPath(scope) {
3694
3694
  return scope === "user" ? join15(homedir4(), ".claude.json") : join15(process.cwd(), ".mcp.json");
3695
3695
  }
3696
- async function readConfig(path22) {
3696
+ async function readConfig(path23) {
3697
3697
  try {
3698
- const raw = await readFile12(path22, "utf-8");
3698
+ const raw = await readFile12(path23, "utf-8");
3699
3699
  const parsed = JSON.parse(raw);
3700
3700
  if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) {
3701
3701
  return parsed;
@@ -4126,9 +4126,9 @@ import { join as join16 } from "node:path";
4126
4126
  function configPaths() {
4127
4127
  return [join16(homedir5(), ".claude.json"), join16(process.cwd(), ".mcp.json")];
4128
4128
  }
4129
- async function readConfig2(path22) {
4129
+ async function readConfig2(path23) {
4130
4130
  try {
4131
- const raw = await readFile13(path22, "utf-8");
4131
+ const raw = await readFile13(path23, "utf-8");
4132
4132
  const parsed = JSON.parse(raw);
4133
4133
  if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) {
4134
4134
  return parsed;
@@ -4142,7 +4142,7 @@ function entryHasLegacyApiKey(entry) {
4142
4142
  if (!entry || !entry.headers) return false;
4143
4143
  return "x-api-key" in entry.headers;
4144
4144
  }
4145
- async function rewriteConfig(path22, config, newUrl) {
4145
+ async function rewriteConfig(path23, config, newUrl) {
4146
4146
  const servers = config.mcpServers;
4147
4147
  if (!servers) return false;
4148
4148
  const entry = servers.codebyplan;
@@ -4150,7 +4150,7 @@ async function rewriteConfig(path22, config, newUrl) {
4150
4150
  if (!entryHasLegacyApiKey(entry) && entry.url === newUrl && entry.type === "http")
4151
4151
  return false;
4152
4152
  servers.codebyplan = { type: "http", url: newUrl };
4153
- await writeFile10(path22, JSON.stringify(config, null, 2) + "\n", "utf-8");
4153
+ await writeFile10(path23, JSON.stringify(config, null, 2) + "\n", "utf-8");
4154
4154
  return true;
4155
4155
  }
4156
4156
  async function runUpgradeAuth() {
@@ -4158,12 +4158,12 @@ async function runUpgradeAuth() {
4158
4158
  await runLogin();
4159
4159
  const newUrl = mcpEndpoint();
4160
4160
  let migrated = 0;
4161
- for (const path22 of configPaths()) {
4162
- const config = await readConfig2(path22);
4161
+ for (const path23 of configPaths()) {
4162
+ const config = await readConfig2(path23);
4163
4163
  if (!config) continue;
4164
- const changed = await rewriteConfig(path22, config, newUrl);
4164
+ const changed = await rewriteConfig(path23, config, newUrl);
4165
4165
  if (changed) {
4166
- console.log(` Updated ${path22}`);
4166
+ console.log(` Updated ${path23}`);
4167
4167
  migrated++;
4168
4168
  }
4169
4169
  }
@@ -5750,11 +5750,11 @@ function __metadata(metadataKey, metadataValue) {
5750
5750
  }
5751
5751
  function __awaiter(thisArg, _arguments, P, generator) {
5752
5752
  function adopt(value) {
5753
- return value instanceof P ? value : new P(function(resolve16) {
5754
- resolve16(value);
5753
+ return value instanceof P ? value : new P(function(resolve17) {
5754
+ resolve17(value);
5755
5755
  });
5756
5756
  }
5757
- return new (P || (P = Promise))(function(resolve16, reject) {
5757
+ return new (P || (P = Promise))(function(resolve17, reject) {
5758
5758
  function fulfilled(value) {
5759
5759
  try {
5760
5760
  step(generator.next(value));
@@ -5770,7 +5770,7 @@ function __awaiter(thisArg, _arguments, P, generator) {
5770
5770
  }
5771
5771
  }
5772
5772
  function step(result) {
5773
- result.done ? resolve16(result.value) : adopt(result.value).then(fulfilled, rejected);
5773
+ result.done ? resolve17(result.value) : adopt(result.value).then(fulfilled, rejected);
5774
5774
  }
5775
5775
  step((generator = generator.apply(thisArg, _arguments || [])).next());
5776
5776
  });
@@ -5961,14 +5961,14 @@ function __asyncValues(o) {
5961
5961
  }, i);
5962
5962
  function verb(n) {
5963
5963
  i[n] = o[n] && function(v) {
5964
- return new Promise(function(resolve16, reject) {
5965
- v = o[n](v), settle(resolve16, reject, v.done, v.value);
5964
+ return new Promise(function(resolve17, reject) {
5965
+ v = o[n](v), settle(resolve17, reject, v.done, v.value);
5966
5966
  });
5967
5967
  };
5968
5968
  }
5969
- function settle(resolve16, reject, d, v) {
5969
+ function settle(resolve17, reject, d, v) {
5970
5970
  Promise.resolve(v).then(function(v2) {
5971
- resolve16({ value: v2, done: d });
5971
+ resolve17({ value: v2, done: d });
5972
5972
  }, reject);
5973
5973
  }
5974
5974
  }
@@ -6060,13 +6060,13 @@ function __disposeResources(env) {
6060
6060
  }
6061
6061
  return next();
6062
6062
  }
6063
- function __rewriteRelativeImportExtension(path22, preserveJsx) {
6064
- if (typeof path22 === "string" && /^\.\.?\//.test(path22)) {
6065
- return path22.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function(m, tsx, d, ext, cm) {
6063
+ function __rewriteRelativeImportExtension(path23, preserveJsx) {
6064
+ if (typeof path23 === "string" && /^\.\.?\//.test(path23)) {
6065
+ return path23.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function(m, tsx, d, ext, cm) {
6066
6066
  return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : d + ext + "." + cm.toLowerCase() + "js";
6067
6067
  });
6068
6068
  }
6069
- return path22;
6069
+ return path23;
6070
6070
  }
6071
6071
  var extendStatics, __assign, __createBinding, __setModuleDefault, ownKeys, _SuppressedError, tslib_es6_default;
6072
6072
  var init_tslib_es6 = __esm({
@@ -6541,18 +6541,18 @@ var require_main = __commonJS({
6541
6541
 
6542
6542
  // ../../node_modules/.pnpm/@supabase+postgrest-js@2.106.0/node_modules/@supabase/postgrest-js/dist/index.mjs
6543
6543
  function sleep(ms, signal) {
6544
- return new Promise((resolve16) => {
6544
+ return new Promise((resolve17) => {
6545
6545
  if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
6546
- resolve16();
6546
+ resolve17();
6547
6547
  return;
6548
6548
  }
6549
6549
  const id = setTimeout(() => {
6550
6550
  signal === null || signal === void 0 || signal.removeEventListener("abort", onAbort);
6551
- resolve16();
6551
+ resolve17();
6552
6552
  }, ms);
6553
6553
  function onAbort() {
6554
6554
  clearTimeout(id);
6555
- resolve16();
6555
+ resolve17();
6556
6556
  }
6557
6557
  signal === null || signal === void 0 || signal.addEventListener("abort", onAbort);
6558
6558
  });
@@ -14589,15 +14589,15 @@ var require_RealtimeChannel = __commonJS({
14589
14589
  }
14590
14590
  }
14591
14591
  } else {
14592
- return new Promise((resolve16) => {
14592
+ return new Promise((resolve17) => {
14593
14593
  var _a2, _b2, _c;
14594
14594
  const push = this.channelAdapter.push(args.type, args, opts.timeout || this.timeout);
14595
14595
  if (args.type === "broadcast" && !((_c = (_b2 = (_a2 = this.params) === null || _a2 === void 0 ? void 0 : _a2.config) === null || _b2 === void 0 ? void 0 : _b2.broadcast) === null || _c === void 0 ? void 0 : _c.ack)) {
14596
- resolve16("ok");
14596
+ resolve17("ok");
14597
14597
  }
14598
- push.receive("ok", () => resolve16("ok"));
14599
- push.receive("error", () => resolve16("error"));
14600
- push.receive("timeout", () => resolve16("timed out"));
14598
+ push.receive("ok", () => resolve17("ok"));
14599
+ push.receive("error", () => resolve17("error"));
14600
+ push.receive("timeout", () => resolve17("timed out"));
14601
14601
  });
14602
14602
  }
14603
14603
  }
@@ -14622,8 +14622,8 @@ var require_RealtimeChannel = __commonJS({
14622
14622
  * @category Realtime
14623
14623
  */
14624
14624
  async unsubscribe(timeout = this.timeout) {
14625
- return new Promise((resolve16) => {
14626
- this.channelAdapter.unsubscribe(timeout).receive("ok", () => resolve16("ok")).receive("timeout", () => resolve16("timed out")).receive("error", () => resolve16("error"));
14625
+ return new Promise((resolve17) => {
14626
+ this.channelAdapter.unsubscribe(timeout).receive("ok", () => resolve17("ok")).receive("timeout", () => resolve17("timed out")).receive("error", () => resolve17("error"));
14627
14627
  });
14628
14628
  }
14629
14629
  /**
@@ -14827,11 +14827,11 @@ var require_socketAdapter = __commonJS({
14827
14827
  this.socket.connect();
14828
14828
  }
14829
14829
  disconnect(callback, code, reason, timeout = 1e4) {
14830
- return new Promise((resolve16) => {
14831
- setTimeout(() => resolve16("timeout"), timeout);
14830
+ return new Promise((resolve17) => {
14831
+ setTimeout(() => resolve17("timeout"), timeout);
14832
14832
  this.socket.disconnect(() => {
14833
14833
  callback();
14834
- resolve16("ok");
14834
+ resolve17("ok");
14835
14835
  }, code, reason);
14836
14836
  });
14837
14837
  }
@@ -15588,8 +15588,8 @@ var require_main2 = __commonJS({
15588
15588
  });
15589
15589
 
15590
15590
  // ../../node_modules/.pnpm/iceberg-js@0.8.1/node_modules/iceberg-js/dist/index.mjs
15591
- function buildUrl2(baseUrl3, path22, query) {
15592
- const url = new URL(path22, baseUrl3);
15591
+ function buildUrl2(baseUrl3, path23, query) {
15592
+ const url = new URL(path23, baseUrl3);
15593
15593
  if (query) {
15594
15594
  for (const [key, value] of Object.entries(query)) {
15595
15595
  if (value !== void 0) {
@@ -15619,12 +15619,12 @@ function createFetchClient(options) {
15619
15619
  return {
15620
15620
  async request({
15621
15621
  method,
15622
- path: path22,
15622
+ path: path23,
15623
15623
  query,
15624
15624
  body,
15625
15625
  headers
15626
15626
  }) {
15627
- const url = buildUrl2(options.baseUrl, path22, query);
15627
+ const url = buildUrl2(options.baseUrl, path23, query);
15628
15628
  const authHeaders = await buildAuthHeaders(options.auth);
15629
15629
  const res = await fetchFn(url, {
15630
15630
  method,
@@ -16193,7 +16193,7 @@ function normalizeHeaders(headers) {
16193
16193
  return result;
16194
16194
  }
16195
16195
  async function _handleRequest(fetcher, method, url, options, parameters, body, namespace) {
16196
- return new Promise((resolve16, reject) => {
16196
+ return new Promise((resolve17, reject) => {
16197
16197
  fetcher(url, _getRequestParams(method, options, parameters, body)).then((result) => {
16198
16198
  if (!result.ok) throw result;
16199
16199
  if (options === null || options === void 0 ? void 0 : options.noResolveJson) return result;
@@ -16203,7 +16203,7 @@ async function _handleRequest(fetcher, method, url, options, parameters, body, n
16203
16203
  if (!contentType || !contentType.includes("application/json")) return {};
16204
16204
  }
16205
16205
  return result.json();
16206
- }).then((data) => resolve16(data)).catch((error) => handleError(error, reject, options, namespace));
16206
+ }).then((data) => resolve17(data)).catch((error) => handleError(error, reject, options, namespace));
16207
16207
  });
16208
16208
  }
16209
16209
  function createFetchApi(namespace = "storage") {
@@ -16522,7 +16522,7 @@ var init_dist3 = __esm({
16522
16522
  * @param path The relative file path. Should be of the format `folder/subfolder/filename.png`. The bucket must already exist before attempting to upload.
16523
16523
  * @param fileBody The body of the file to be stored in the bucket.
16524
16524
  */
16525
- async uploadOrUpdate(method, path22, fileBody, fileOptions) {
16525
+ async uploadOrUpdate(method, path23, fileBody, fileOptions) {
16526
16526
  var _this = this;
16527
16527
  return _this.handleOperation(async () => {
16528
16528
  let body;
@@ -16546,7 +16546,7 @@ var init_dist3 = __esm({
16546
16546
  if ((typeof ReadableStream !== "undefined" && body instanceof ReadableStream || body && typeof body === "object" && "pipe" in body && typeof body.pipe === "function") && !options.duplex) options.duplex = "half";
16547
16547
  }
16548
16548
  if (fileOptions === null || fileOptions === void 0 ? void 0 : fileOptions.headers) for (const [key, value] of Object.entries(fileOptions.headers)) headers = setHeader(headers, key, value);
16549
- const cleanPath = _this._removeEmptyFolders(path22);
16549
+ const cleanPath = _this._removeEmptyFolders(path23);
16550
16550
  const _path = _this._getFinalPath(cleanPath);
16551
16551
  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 } : {}));
16552
16552
  return {
@@ -16608,8 +16608,8 @@ var init_dist3 = __esm({
16608
16608
  * - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
16609
16609
  * - 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.
16610
16610
  */
16611
- async upload(path22, fileBody, fileOptions) {
16612
- return this.uploadOrUpdate("POST", path22, fileBody, fileOptions);
16611
+ async upload(path23, fileBody, fileOptions) {
16612
+ return this.uploadOrUpdate("POST", path23, fileBody, fileOptions);
16613
16613
  }
16614
16614
  /**
16615
16615
  * Upload a file with a token generated from `createSignedUploadUrl`.
@@ -16649,9 +16649,9 @@ var init_dist3 = __esm({
16649
16649
  * - `objects` table permissions: none
16650
16650
  * - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
16651
16651
  */
16652
- async uploadToSignedUrl(path22, token, fileBody, fileOptions) {
16652
+ async uploadToSignedUrl(path23, token, fileBody, fileOptions) {
16653
16653
  var _this3 = this;
16654
- const cleanPath = _this3._removeEmptyFolders(path22);
16654
+ const cleanPath = _this3._removeEmptyFolders(path23);
16655
16655
  const _path = _this3._getFinalPath(cleanPath);
16656
16656
  const url = new URL(_this3.url + `/object/upload/sign/${_path}`);
16657
16657
  url.searchParams.set("token", token);
@@ -16720,10 +16720,10 @@ var init_dist3 = __esm({
16720
16720
  * - `objects` table permissions: `insert`
16721
16721
  * - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
16722
16722
  */
16723
- async createSignedUploadUrl(path22, options) {
16723
+ async createSignedUploadUrl(path23, options) {
16724
16724
  var _this4 = this;
16725
16725
  return _this4.handleOperation(async () => {
16726
- let _path = _this4._getFinalPath(path22);
16726
+ let _path = _this4._getFinalPath(path23);
16727
16727
  const headers = _objectSpread22({}, _this4.headers);
16728
16728
  if (options === null || options === void 0 ? void 0 : options.upsert) headers["x-upsert"] = "true";
16729
16729
  const data = await post(_this4.fetch, `${_this4.url}/object/upload/sign/${_path}`, {}, { headers });
@@ -16732,7 +16732,7 @@ var init_dist3 = __esm({
16732
16732
  if (!token) throw new StorageError("No token returned by API");
16733
16733
  return {
16734
16734
  signedUrl: url.toString(),
16735
- path: path22,
16735
+ path: path23,
16736
16736
  token
16737
16737
  };
16738
16738
  });
@@ -16792,8 +16792,8 @@ var init_dist3 = __esm({
16792
16792
  * - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
16793
16793
  * - 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.
16794
16794
  */
16795
- async update(path22, fileBody, fileOptions) {
16796
- return this.uploadOrUpdate("PUT", path22, fileBody, fileOptions);
16795
+ async update(path23, fileBody, fileOptions) {
16796
+ return this.uploadOrUpdate("PUT", path23, fileBody, fileOptions);
16797
16797
  }
16798
16798
  /**
16799
16799
  * Moves an existing file to a new path in the same bucket.
@@ -16944,10 +16944,10 @@ var init_dist3 = __esm({
16944
16944
  * - `objects` table permissions: `select`
16945
16945
  * - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
16946
16946
  */
16947
- async createSignedUrl(path22, expiresIn, options) {
16947
+ async createSignedUrl(path23, expiresIn, options) {
16948
16948
  var _this8 = this;
16949
16949
  return _this8.handleOperation(async () => {
16950
- let _path = _this8._getFinalPath(path22);
16950
+ let _path = _this8._getFinalPath(path23);
16951
16951
  const hasTransform = typeof (options === null || options === void 0 ? void 0 : options.transform) === "object" && options.transform !== null && Object.keys(options.transform).length > 0;
16952
16952
  let data = await post(_this8.fetch, `${_this8.url}/object/sign/${_path}`, _objectSpread22({ expiresIn }, hasTransform ? { transform: options.transform } : {}), { headers: _this8.headers });
16953
16953
  const query = new URLSearchParams();
@@ -17083,13 +17083,13 @@ var init_dist3 = __esm({
17083
17083
  * - `objects` table permissions: `select`
17084
17084
  * - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
17085
17085
  */
17086
- download(path22, options, parameters) {
17086
+ download(path23, options, parameters) {
17087
17087
  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";
17088
17088
  const query = new URLSearchParams();
17089
17089
  if (options === null || options === void 0 ? void 0 : options.transform) this.applyTransformOptsToQuery(query, options.transform);
17090
17090
  if ((options === null || options === void 0 ? void 0 : options.cacheNonce) != null) query.set("cacheNonce", String(options.cacheNonce));
17091
17091
  const queryString = query.toString();
17092
- const _path = this._getFinalPath(path22);
17092
+ const _path = this._getFinalPath(path23);
17093
17093
  const downloadFn = () => get(this.fetch, `${this.url}/${renderPath}/${_path}${queryString ? `?${queryString}` : ""}`, {
17094
17094
  headers: this.headers,
17095
17095
  noResolveJson: true
@@ -17120,9 +17120,9 @@ var init_dist3 = __esm({
17120
17120
  * }
17121
17121
  * ```
17122
17122
  */
17123
- async info(path22) {
17123
+ async info(path23) {
17124
17124
  var _this10 = this;
17125
- const _path = _this10._getFinalPath(path22);
17125
+ const _path = _this10._getFinalPath(path23);
17126
17126
  return _this10.handleOperation(async () => {
17127
17127
  return recursiveToCamel(await get(_this10.fetch, `${_this10.url}/object/info/${_path}`, { headers: _this10.headers }));
17128
17128
  });
@@ -17143,9 +17143,9 @@ var init_dist3 = __esm({
17143
17143
  * .exists('folder/avatar1.png')
17144
17144
  * ```
17145
17145
  */
17146
- async exists(path22) {
17146
+ async exists(path23) {
17147
17147
  var _this11 = this;
17148
- const _path = _this11._getFinalPath(path22);
17148
+ const _path = _this11._getFinalPath(path23);
17149
17149
  try {
17150
17150
  await head(_this11.fetch, `${_this11.url}/object/${_path}`, { headers: _this11.headers });
17151
17151
  return {
@@ -17224,8 +17224,8 @@ var init_dist3 = __esm({
17224
17224
  * - `objects` table permissions: none
17225
17225
  * - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
17226
17226
  */
17227
- getPublicUrl(path22, options) {
17228
- const _path = this._getFinalPath(path22);
17227
+ getPublicUrl(path23, options) {
17228
+ const _path = this._getFinalPath(path23);
17229
17229
  const query = new URLSearchParams();
17230
17230
  if (options === null || options === void 0 ? void 0 : options.download) query.set("download", options.download === true ? "" : options.download);
17231
17231
  if (options === null || options === void 0 ? void 0 : options.transform) this.applyTransformOptsToQuery(query, options.transform);
@@ -17364,10 +17364,10 @@ var init_dist3 = __esm({
17364
17364
  * - `objects` table permissions: `select`
17365
17365
  * - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
17366
17366
  */
17367
- async list(path22, options, parameters) {
17367
+ async list(path23, options, parameters) {
17368
17368
  var _this13 = this;
17369
17369
  return _this13.handleOperation(async () => {
17370
- const body = _objectSpread22(_objectSpread22(_objectSpread22({}, DEFAULT_SEARCH_OPTIONS), options), {}, { prefix: path22 || "" });
17370
+ const body = _objectSpread22(_objectSpread22(_objectSpread22({}, DEFAULT_SEARCH_OPTIONS), options), {}, { prefix: path23 || "" });
17371
17371
  return await post(_this13.fetch, `${_this13.url}/object/list/${_this13.bucketId}`, body, { headers: _this13.headers }, parameters);
17372
17372
  });
17373
17373
  }
@@ -17432,11 +17432,11 @@ var init_dist3 = __esm({
17432
17432
  if (typeof Buffer !== "undefined") return Buffer.from(data).toString("base64");
17433
17433
  return btoa(data);
17434
17434
  }
17435
- _getFinalPath(path22) {
17436
- return `${this.bucketId}/${path22.replace(/^\/+/, "")}`;
17435
+ _getFinalPath(path23) {
17436
+ return `${this.bucketId}/${path23.replace(/^\/+/, "")}`;
17437
17437
  }
17438
- _removeEmptyFolders(path22) {
17439
- return path22.replace(/^\/|\/$/g, "").replace(/\/+/g, "/");
17438
+ _removeEmptyFolders(path23) {
17439
+ return path23.replace(/^\/|\/$/g, "").replace(/\/+/g, "/");
17440
17440
  }
17441
17441
  /** Modifies the `query`, appending values the from `transform` */
17442
17442
  applyTransformOptsToQuery(query, transform) {
@@ -26814,11 +26814,11 @@ __export(dist_exports, {
26814
26814
  });
26815
26815
  function __awaiter2(thisArg, _arguments, P, generator) {
26816
26816
  function adopt(value) {
26817
- return value instanceof P ? value : new P(function(resolve16) {
26818
- resolve16(value);
26817
+ return value instanceof P ? value : new P(function(resolve17) {
26818
+ resolve17(value);
26819
26819
  });
26820
26820
  }
26821
- return new (P || (P = Promise))(function(resolve16, reject) {
26821
+ return new (P || (P = Promise))(function(resolve17, reject) {
26822
26822
  function fulfilled(value) {
26823
26823
  try {
26824
26824
  step(generator.next(value));
@@ -26834,7 +26834,7 @@ function __awaiter2(thisArg, _arguments, P, generator) {
26834
26834
  }
26835
26835
  }
26836
26836
  function step(result) {
26837
- result.done ? resolve16(result.value) : adopt(result.value).then(fulfilled, rejected);
26837
+ result.done ? resolve17(result.value) : adopt(result.value).then(fulfilled, rejected);
26838
26838
  }
26839
26839
  step((generator = generator.apply(thisArg, _arguments || [])).next());
26840
26840
  });
@@ -27569,8 +27569,8 @@ var init_watch_daemon = __esm({
27569
27569
  );
27570
27570
  }
27571
27571
  this.startSafetyPoll(repoRoot, repoId, worktreeId);
27572
- await new Promise((resolve16) => {
27573
- this.stopResolve = resolve16;
27572
+ await new Promise((resolve17) => {
27573
+ this.stopResolve = resolve17;
27574
27574
  });
27575
27575
  }
27576
27576
  /**
@@ -27841,7 +27841,7 @@ var init_watch_daemon = __esm({
27841
27841
  }
27842
27842
  /** Sleep for `ms` milliseconds — uses setTimeout so fake timers work in tests. */
27843
27843
  sleep(ms) {
27844
- return new Promise((resolve16) => setTimeout(resolve16, ms));
27844
+ return new Promise((resolve17) => setTimeout(resolve17, ms));
27845
27845
  }
27846
27846
  };
27847
27847
  }
@@ -28158,8 +28158,8 @@ var init_watch = __esm({
28158
28158
  function isConflict(err) {
28159
28159
  return err instanceof BackendError && err.status === 409;
28160
28160
  }
28161
- async function backendRequest(method, path22, body) {
28162
- const url = `${getBackendBase()}${path22}`;
28161
+ async function backendRequest(method, path23, body) {
28162
+ const url = `${getBackendBase()}${path23}`;
28163
28163
  const auth = await getAuthHeaders();
28164
28164
  const res = await fetch(url, {
28165
28165
  method,
@@ -28171,7 +28171,7 @@ async function backendRequest(method, path22, body) {
28171
28171
  signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS2)
28172
28172
  });
28173
28173
  if (!res.ok) {
28174
- let message = `Backend ${method} ${path22} failed with status ${res.status}`;
28174
+ let message = `Backend ${method} ${path23} failed with status ${res.status}`;
28175
28175
  try {
28176
28176
  const errBody = await res.json();
28177
28177
  const msg = typeof errBody.message === "string" ? errBody.message : typeof errBody.error === "string" ? errBody.error : void 0;
@@ -28185,11 +28185,11 @@ async function backendRequest(method, path22, body) {
28185
28185
  }
28186
28186
  return res.json();
28187
28187
  }
28188
- async function apiBackendPost(path22, body) {
28189
- return backendRequest("POST", path22, body);
28188
+ async function apiBackendPost(path23, body) {
28189
+ return backendRequest("POST", path23, body);
28190
28190
  }
28191
- async function apiBackendPatch(path22, body) {
28192
- return backendRequest("PATCH", path22, body);
28191
+ async function apiBackendPatch(path23, body) {
28192
+ return backendRequest("PATCH", path23, body);
28193
28193
  }
28194
28194
  var REQUEST_TIMEOUT_MS2, BackendError;
28195
28195
  var init_state_client = __esm({
@@ -28465,8 +28465,8 @@ ${taskRows}
28465
28465
  for (const task of data.tasks) {
28466
28466
  if (Array.isArray(task.files_changed)) {
28467
28467
  for (const f of task.files_changed) {
28468
- const path22 = typeof f === "string" ? f : f?.path;
28469
- if (path22) allFiles.add(path22);
28468
+ const path23 = typeof f === "string" ? f : f?.path;
28469
+ if (path23) allFiles.add(path23);
28470
28470
  }
28471
28471
  }
28472
28472
  }
@@ -29388,7 +29388,7 @@ function setRetryDelayMs(ms) {
29388
29388
  RETRY_DELAY_MS = ms;
29389
29389
  }
29390
29390
  function sleep2(ms) {
29391
- return new Promise((resolve16) => setTimeout(resolve16, ms));
29391
+ return new Promise((resolve17) => setTimeout(resolve17, ms));
29392
29392
  }
29393
29393
  function isTransientMcpError(err) {
29394
29394
  if (!(err instanceof McpError)) return false;
@@ -30528,7 +30528,7 @@ function generateMonotonicTimestamp(opts = {}) {
30528
30528
  }
30529
30529
  async function pollGhPreviewCheck(opts = {}) {
30530
30530
  const run = opts.run ?? defaultRun;
30531
- const sleep3 = opts.sleep ?? ((ms) => new Promise((resolve16) => setTimeout(resolve16, ms)));
30531
+ const sleep3 = opts.sleep ?? ((ms) => new Promise((resolve17) => setTimeout(resolve17, ms)));
30532
30532
  const maxPolls = opts.maxPolls ?? 20;
30533
30533
  const intervalMs = opts.intervalMs ?? 15e3;
30534
30534
  if (!opts.prNumber) {
@@ -33273,12 +33273,60 @@ var init_atomic_write = __esm({
33273
33273
  }
33274
33274
  });
33275
33275
 
33276
+ // src/lib/repo-reader.ts
33277
+ import * as fsPromises from "node:fs/promises";
33278
+ import * as path10 from "node:path";
33279
+ var LocalFsReader;
33280
+ var init_repo_reader = __esm({
33281
+ "src/lib/repo-reader.ts"() {
33282
+ "use strict";
33283
+ LocalFsReader = class {
33284
+ constructor(rootDir) {
33285
+ this.rootDir = rootDir;
33286
+ }
33287
+ rootDir;
33288
+ resolve(p) {
33289
+ return path10.isAbsolute(p) ? p : path10.resolve(this.rootDir, p);
33290
+ }
33291
+ async list(dir) {
33292
+ const abs = this.resolve(dir);
33293
+ try {
33294
+ const entries = await fsPromises.readdir(abs, { withFileTypes: true });
33295
+ return entries.filter((e) => e.isDirectory()).map((e) => e.name);
33296
+ } catch {
33297
+ return [];
33298
+ }
33299
+ }
33300
+ async read(filePath) {
33301
+ const abs = this.resolve(filePath);
33302
+ try {
33303
+ return await fsPromises.readFile(abs, "utf-8");
33304
+ } catch (err) {
33305
+ throw new Error(
33306
+ `repo-reader: could not read '${abs}': ${err instanceof Error ? err.message : String(err)}`
33307
+ );
33308
+ }
33309
+ }
33310
+ async exists(filePath) {
33311
+ const abs = this.resolve(filePath);
33312
+ try {
33313
+ await fsPromises.access(abs);
33314
+ return true;
33315
+ } catch {
33316
+ return false;
33317
+ }
33318
+ }
33319
+ };
33320
+ }
33321
+ });
33322
+
33276
33323
  // src/lib/ci-init.ts
33277
33324
  import * as fs8 from "node:fs";
33278
- import * as path10 from "node:path";
33279
- function tryReadJson(filePath) {
33325
+ import * as path11 from "node:path";
33326
+ async function tryReadJson(reader, filePath) {
33280
33327
  try {
33281
- return JSON.parse(fs8.readFileSync(filePath, "utf-8"));
33328
+ const raw = await reader.read(filePath);
33329
+ return JSON.parse(raw);
33282
33330
  } catch {
33283
33331
  return null;
33284
33332
  }
@@ -33294,30 +33342,24 @@ function hasDevDep(pkg, name) {
33294
33342
  const devDeps = pkg["devDependencies"];
33295
33343
  return Boolean(devDeps?.[name]);
33296
33344
  }
33297
- function detectPlatforms(projectDir) {
33345
+ async function detectPlatforms(reader) {
33298
33346
  const detected = /* @__PURE__ */ new Set();
33299
- const dirsToScan = [projectDir];
33300
- const appsDir = path10.join(projectDir, "apps");
33301
- if (fs8.existsSync(appsDir)) {
33302
- try {
33303
- const appsEntries = fs8.readdirSync(appsDir, { withFileTypes: true });
33304
- for (const entry of appsEntries) {
33305
- if (entry.isDirectory()) {
33306
- dirsToScan.push(path10.join(appsDir, entry.name));
33307
- }
33308
- }
33309
- } catch {
33310
- }
33347
+ const dirsToScan = [""];
33348
+ const appsChildren = await reader.list("apps");
33349
+ for (const name of appsChildren) {
33350
+ dirsToScan.push(`apps/${name}`);
33311
33351
  }
33312
33352
  for (const dir of dirsToScan) {
33313
- const pkg = tryReadJson(path10.join(dir, "package.json"));
33314
- if (fs8.existsSync(path10.join(dir, "next.config.ts")) || fs8.existsSync(path10.join(dir, "next.config.js")) || fs8.existsSync(path10.join(dir, "next.config.mjs"))) {
33353
+ const pkgPath = dir ? `${dir}/package.json` : "package.json";
33354
+ const pkg = await tryReadJson(reader, pkgPath);
33355
+ const nextBase = dir ? `${dir}/` : "";
33356
+ if (await reader.exists(`${nextBase}next.config.ts`) || await reader.exists(`${nextBase}next.config.js`) || await reader.exists(`${nextBase}next.config.mjs`)) {
33315
33357
  detected.add("next_js");
33316
33358
  }
33317
33359
  if (hasDep(pkg, "@nestjs/core")) {
33318
33360
  detected.add("nestjs");
33319
33361
  }
33320
- if (fs8.existsSync(path10.join(dir, "tauri.conf.json")) || fs8.existsSync(path10.join(dir, "src-tauri"))) {
33362
+ if (await reader.exists(`${nextBase}tauri.conf.json`) || await reader.exists(`${nextBase}src-tauri`)) {
33321
33363
  detected.add("tauri");
33322
33364
  }
33323
33365
  if (hasDevDep(pkg, "@types/vscode")) {
@@ -33328,15 +33370,9 @@ function detectPlatforms(projectDir) {
33328
33370
  detected.add("expo");
33329
33371
  }
33330
33372
  }
33331
- const packagesDir = path10.join(projectDir, "packages");
33332
- if (fs8.existsSync(packagesDir)) {
33333
- try {
33334
- const pkgEntries = fs8.readdirSync(packagesDir, { withFileTypes: true });
33335
- if (pkgEntries.some((e) => e.isDirectory())) {
33336
- detected.add("package");
33337
- }
33338
- } catch {
33339
- }
33373
+ const packagesChildren = await reader.list("packages");
33374
+ if (packagesChildren.length > 0) {
33375
+ detected.add("package");
33340
33376
  }
33341
33377
  if (detected.size === 0) {
33342
33378
  detected.add("package");
@@ -33364,12 +33400,12 @@ function buildDefaultCiConfig(platforms) {
33364
33400
  return config;
33365
33401
  }
33366
33402
  async function runCiInit(opts) {
33367
- await Promise.resolve();
33368
- const projectDir = path10.resolve(opts?.projectDir ?? process.cwd());
33403
+ const projectDir = path11.resolve(opts?.projectDir ?? process.cwd());
33369
33404
  const dryRun = opts?.dryRun ?? false;
33370
33405
  const force = opts?.force ?? false;
33371
- const ciPath = path10.join(projectDir, ".codebyplan", "ci.json");
33372
- const platforms = detectPlatforms(projectDir);
33406
+ const ciPath = path11.join(projectDir, ".codebyplan", "ci.json");
33407
+ const reader = opts?.reader ?? new LocalFsReader(projectDir);
33408
+ const platforms = await detectPlatforms(reader);
33373
33409
  if (dryRun) {
33374
33410
  return { status: "dry_run", path: ciPath, platforms };
33375
33411
  }
@@ -33413,7 +33449,7 @@ async function runCiInit(opts) {
33413
33449
  platforms: newPlatforms.length > 0 ? newPlatforms : platforms
33414
33450
  };
33415
33451
  }
33416
- const codebyplanDir = path10.join(projectDir, ".codebyplan");
33452
+ const codebyplanDir = path11.join(projectDir, ".codebyplan");
33417
33453
  fs8.mkdirSync(codebyplanDir, { recursive: true });
33418
33454
  writeJsonAtomic(ciPath, newConfig);
33419
33455
  return { status: "written", path: ciPath, platforms };
@@ -33423,6 +33459,7 @@ var init_ci_init = __esm({
33423
33459
  "src/lib/ci-init.ts"() {
33424
33460
  "use strict";
33425
33461
  init_atomic_write();
33462
+ init_repo_reader();
33426
33463
  PLATFORM_COMMAND_MAP = {
33427
33464
  next_js: {
33428
33465
  unit_test: {
@@ -33622,7 +33659,7 @@ var init_ci_init = __esm({
33622
33659
 
33623
33660
  // src/lib/scaffold-ci-workflow.ts
33624
33661
  import * as fs9 from "node:fs";
33625
- import * as path11 from "node:path";
33662
+ import * as path12 from "node:path";
33626
33663
  function substituteTokens(template, tokens) {
33627
33664
  let result = template;
33628
33665
  for (const [token, value] of Object.entries(tokens)) {
@@ -33630,10 +33667,9 @@ function substituteTokens(template, tokens) {
33630
33667
  }
33631
33668
  return result;
33632
33669
  }
33633
- function detectPnpmVersionFromPackageJson(projectDir) {
33670
+ async function detectPnpmVersionFromPackageJson(reader) {
33634
33671
  try {
33635
- const pkgPath = path11.join(projectDir, "package.json");
33636
- const raw = fs9.readFileSync(pkgPath, "utf-8");
33672
+ const raw = await reader.read("package.json");
33637
33673
  const pkg = JSON.parse(raw);
33638
33674
  const pm = pkg.packageManager;
33639
33675
  if (typeof pm === "string" && pm.startsWith("pnpm@")) {
@@ -33647,39 +33683,42 @@ function detectPnpmVersionFromPackageJson(projectDir) {
33647
33683
  return "10";
33648
33684
  }
33649
33685
  }
33650
- function detectStrictEnforcedFromCiJson(projectDir) {
33686
+ async function detectStrictEnforcedFromCiJson(reader) {
33651
33687
  try {
33652
- const ciJsonPath = path11.join(projectDir, ".codebyplan", "ci.json");
33653
- const raw = fs9.readFileSync(ciJsonPath, "utf-8");
33688
+ const raw = await reader.read(".codebyplan/ci.json");
33654
33689
  const parsed = JSON.parse(raw);
33655
33690
  return parsed.workflow?.strict_check_enforced === true;
33656
33691
  } catch {
33657
33692
  return false;
33658
33693
  }
33659
33694
  }
33660
- async function runScaffoldCiWorkflow(opts) {
33661
- await Promise.resolve();
33662
- const dryRun = opts?.dryRun ?? false;
33663
- const force = opts?.force ?? false;
33664
- const projectDir = path11.resolve(opts?.projectDir ?? process.cwd());
33665
- const pnpmVersion = opts?.pnpmVersion ?? detectPnpmVersionFromPackageJson(projectDir);
33695
+ async function renderCiWorkflowContent(opts) {
33696
+ const projectDir = path12.resolve(opts?.projectDir ?? process.cwd());
33697
+ const reader = opts?.reader ?? new LocalFsReader(projectDir);
33698
+ const pnpmVersion = opts?.pnpmVersion ?? await detectPnpmVersionFromPackageJson(reader);
33666
33699
  const nodeVersion = opts?.nodeVersion ?? "22";
33667
- const strictEnforced = opts?.strictEnforced ?? detectStrictEnforcedFromCiJson(projectDir);
33700
+ const strictEnforced = opts?.strictEnforced ?? await detectStrictEnforcedFromCiJson(reader);
33668
33701
  const templatesDir = opts?.templatesDir ?? resolveTemplatesDir();
33669
- const templatePath = path11.join(templatesDir, "github-workflows", "ci.yml");
33702
+ const templatePath = path12.join(templatesDir, "github-workflows", "ci.yml");
33670
33703
  if (!fs9.existsSync(templatePath)) {
33671
33704
  throw new Error(
33672
33705
  `scaffold-ci-workflow: template not found at ${templatePath}`
33673
33706
  );
33674
33707
  }
33675
33708
  const rawTemplate = fs9.readFileSync(templatePath, "utf-8");
33676
- const renderedContent = substituteTokens(rawTemplate, {
33709
+ return substituteTokens(rawTemplate, {
33677
33710
  PNPM_VERSION: pnpmVersion,
33678
33711
  NODE_VERSION: nodeVersion,
33679
33712
  STRICT_NAME_SUFFIX: strictEnforced ? "" : " (report-only)",
33680
33713
  STRICT_CONTINUE_ON_ERROR_LINE: strictEnforced ? "" : "\n continue-on-error: true"
33681
33714
  });
33682
- const targetPath = path11.join(projectDir, ".github", "workflows", "ci.yml");
33715
+ }
33716
+ async function runScaffoldCiWorkflow(opts) {
33717
+ const dryRun = opts?.dryRun ?? false;
33718
+ const force = opts?.force ?? false;
33719
+ const projectDir = path12.resolve(opts?.projectDir ?? process.cwd());
33720
+ const renderedContent = await renderCiWorkflowContent(opts);
33721
+ const targetPath = path12.join(projectDir, ".github", "workflows", "ci.yml");
33683
33722
  if (dryRun) {
33684
33723
  return { status: "dry_run", path: targetPath };
33685
33724
  }
@@ -33698,7 +33737,7 @@ async function runScaffoldCiWorkflow(opts) {
33698
33737
  );
33699
33738
  }
33700
33739
  }
33701
- const targetDir = path11.dirname(targetPath);
33740
+ const targetDir = path12.dirname(targetPath);
33702
33741
  fs9.mkdirSync(targetDir, { recursive: true });
33703
33742
  const tmpPath = targetPath + ".tmp";
33704
33743
  try {
@@ -33716,16 +33755,17 @@ async function runScaffoldCiWorkflow(opts) {
33716
33755
  var init_scaffold_ci_workflow = __esm({
33717
33756
  "src/lib/scaffold-ci-workflow.ts"() {
33718
33757
  "use strict";
33719
- init_install();
33758
+ init_templates_dir();
33759
+ init_repo_reader();
33720
33760
  }
33721
33761
  });
33722
33762
 
33723
33763
  // src/lib/gh-required-checks.ts
33724
33764
  import * as fs10 from "node:fs";
33725
- import * as path12 from "node:path";
33765
+ import * as path13 from "node:path";
33726
33766
  import { execSync as execSync6 } from "node:child_process";
33727
33767
  function readCiJson(projectDir) {
33728
- const ciPath = path12.join(projectDir, ".codebyplan", "ci.json");
33768
+ const ciPath = path13.join(projectDir, ".codebyplan", "ci.json");
33729
33769
  if (!fs10.existsSync(ciPath)) {
33730
33770
  return {
33731
33771
  platforms: {},
@@ -33744,15 +33784,15 @@ function readCiJson(projectDir) {
33744
33784
  }
33745
33785
  }
33746
33786
  function writeCiJsonAtomic(projectDir, config) {
33747
- const ciPath = path12.join(projectDir, ".codebyplan", "ci.json");
33787
+ const ciPath = path13.join(projectDir, ".codebyplan", "ci.json");
33748
33788
  writeJsonAtomic(ciPath, config);
33749
33789
  }
33750
33790
  function enforceRequiredCheck(opts) {
33751
- const projectDir = path12.resolve(opts?.projectDir ?? process.cwd());
33791
+ const projectDir = path13.resolve(opts?.projectDir ?? process.cwd());
33752
33792
  const branch = opts?.branch ?? "main";
33753
33793
  const checkName = opts?.checkName ?? "Lint + typecheck + test + build";
33754
33794
  const dryRun = opts?.dryRun ?? false;
33755
- const ciPath = path12.join(projectDir, ".codebyplan", "ci.json");
33795
+ const ciPath = path13.join(projectDir, ".codebyplan", "ci.json");
33756
33796
  const config = readCiJson(projectDir);
33757
33797
  if (config.workflow?.required_check_enforced === true) {
33758
33798
  return { status: "already_enforced", path: ciPath };
@@ -34159,9 +34199,9 @@ var init_ci = __esm({
34159
34199
 
34160
34200
  // src/lib/cd-init.ts
34161
34201
  import * as fs11 from "node:fs";
34162
- import * as path13 from "node:path";
34202
+ import * as path14 from "node:path";
34163
34203
  function detectSurfaces(projectDir) {
34164
- const shipmentPath = path13.join(projectDir, ".codebyplan", "shipment.json");
34204
+ const shipmentPath = path14.join(projectDir, ".codebyplan", "shipment.json");
34165
34205
  let shipment;
34166
34206
  try {
34167
34207
  shipment = JSON.parse(fs11.readFileSync(shipmentPath, "utf-8"));
@@ -34214,10 +34254,10 @@ function buildDefaultCdConfig(rawSurfaceKeys) {
34214
34254
  }
34215
34255
  async function runCdInit(opts) {
34216
34256
  await Promise.resolve();
34217
- const projectDir = path13.resolve(opts?.projectDir ?? process.cwd());
34257
+ const projectDir = path14.resolve(opts?.projectDir ?? process.cwd());
34218
34258
  const dryRun = opts?.dryRun ?? false;
34219
34259
  const force = opts?.force ?? false;
34220
- const cdPath = path13.join(projectDir, ".codebyplan", "cd.json");
34260
+ const cdPath = path14.join(projectDir, ".codebyplan", "cd.json");
34221
34261
  const rawSurfaceKeys = detectSurfaces(projectDir);
34222
34262
  const seen = /* @__PURE__ */ new Set();
34223
34263
  const surfaces = [];
@@ -34258,7 +34298,7 @@ async function runCdInit(opts) {
34258
34298
  surfaces: newSurfaces
34259
34299
  };
34260
34300
  }
34261
- const codebyplanDir = path13.join(projectDir, ".codebyplan");
34301
+ const codebyplanDir = path14.join(projectDir, ".codebyplan");
34262
34302
  fs11.mkdirSync(codebyplanDir, { recursive: true });
34263
34303
  writeJsonAtomic(cdPath, newConfig);
34264
34304
  return { status: "written", path: cdPath, surfaces };
@@ -34348,14 +34388,14 @@ var init_cd_init = __esm({
34348
34388
 
34349
34389
  // src/lib/scaffold-cd-workflow.ts
34350
34390
  import * as fs12 from "node:fs";
34351
- import * as path14 from "node:path";
34391
+ import * as path15 from "node:path";
34352
34392
  async function scaffoldOneWorkflow(templateName, targetName, opts) {
34353
34393
  await Promise.resolve();
34354
34394
  const dryRun = opts.dryRun ?? false;
34355
34395
  const force = opts.force ?? false;
34356
- const projectDir = path14.resolve(opts.projectDir ?? process.cwd());
34396
+ const projectDir = path15.resolve(opts.projectDir ?? process.cwd());
34357
34397
  const templatesDir = opts.templatesDir ?? resolveTemplatesDir();
34358
- const templatePath = path14.join(
34398
+ const templatePath = path15.join(
34359
34399
  templatesDir,
34360
34400
  "github-workflows",
34361
34401
  templateName
@@ -34366,7 +34406,7 @@ async function scaffoldOneWorkflow(templateName, targetName, opts) {
34366
34406
  );
34367
34407
  }
34368
34408
  const templateContent = fs12.readFileSync(templatePath, "utf-8");
34369
- const targetPath = path14.join(projectDir, ".github", "workflows", targetName);
34409
+ const targetPath = path15.join(projectDir, ".github", "workflows", targetName);
34370
34410
  if (dryRun) {
34371
34411
  return { status: "dry_run", path: targetPath };
34372
34412
  }
@@ -34385,7 +34425,7 @@ async function scaffoldOneWorkflow(templateName, targetName, opts) {
34385
34425
  );
34386
34426
  }
34387
34427
  }
34388
- const targetDir = path14.dirname(targetPath);
34428
+ const targetDir = path15.dirname(targetPath);
34389
34429
  fs12.mkdirSync(targetDir, { recursive: true });
34390
34430
  const tmpPath = targetPath + ".tmp";
34391
34431
  try {
@@ -35218,8 +35258,8 @@ var upload_e2e_images_exports = {};
35218
35258
  __export(upload_e2e_images_exports, {
35219
35259
  runUploadE2eImagesCommand: () => runUploadE2eImagesCommand
35220
35260
  });
35221
- import { readFile as readFile20 } from "node:fs/promises";
35222
- import { join as join36, basename as basename2, resolve as resolve10 } from "node:path";
35261
+ import { readFile as readFile21 } from "node:fs/promises";
35262
+ import { join as join36, basename as basename2, resolve as resolve11 } from "node:path";
35223
35263
  import { execSync as execSync8 } from "node:child_process";
35224
35264
  function baseUrl2() {
35225
35265
  return (process.env.CODEBYPLAN_API_URL ?? "https://www.codebyplan.com").replace(/\/$/, "");
@@ -35253,7 +35293,7 @@ function parseArgs(args) {
35253
35293
  }
35254
35294
  async function readE2eConfig(projectPath) {
35255
35295
  try {
35256
- const raw = await readFile20(
35296
+ const raw = await readFile21(
35257
35297
  join36(projectPath, ".codebyplan", "e2e.json"),
35258
35298
  "utf-8"
35259
35299
  );
@@ -35334,7 +35374,7 @@ async function runUploadE2eImagesCommand(args) {
35334
35374
  process.exit(1);
35335
35375
  }
35336
35376
  const checkpointId = parsed.checkpointId;
35337
- const projectPath = resolve10(process.cwd());
35377
+ const projectPath = resolve11(process.cwd());
35338
35378
  let repoId = parsed.repoId;
35339
35379
  if (!repoId) {
35340
35380
  const found = await findCodebyplanConfig(projectPath);
@@ -35392,7 +35432,7 @@ async function runUploadE2eImagesCommand(args) {
35392
35432
  for (const png of allPngs) {
35393
35433
  let bytes;
35394
35434
  try {
35395
- bytes = await readFile20(png.absolutePath);
35435
+ bytes = await readFile21(png.absolutePath);
35396
35436
  } catch {
35397
35437
  process.stderr.write(
35398
35438
  `upload-e2e-images: could not read file: ${png.absolutePath}
@@ -35469,8 +35509,8 @@ __export(arch_map_exports, {
35469
35509
  runArchMapCommand: () => runArchMapCommand,
35470
35510
  updateFrontmatterFields: () => updateFrontmatterFields
35471
35511
  });
35472
- import { readFile as readFile21, writeFile as writeFile17 } from "node:fs/promises";
35473
- import { existsSync as existsSync11, readdirSync as readdirSync4 } from "node:fs";
35512
+ import { readFile as readFile22, writeFile as writeFile17 } from "node:fs/promises";
35513
+ import { existsSync as existsSync11, readdirSync as readdirSync3 } from "node:fs";
35474
35514
  import { join as join37 } from "node:path";
35475
35515
  import { spawnSync as spawnSync12 } from "node:child_process";
35476
35516
  function normalizeModulePath(modulePath) {
@@ -35498,7 +35538,7 @@ async function resolveCodebyplanDir(startDir) {
35498
35538
  async function readArchitectureConfig(codebyplanDir) {
35499
35539
  const filePath = join37(codebyplanDir, "architecture.json");
35500
35540
  try {
35501
- const raw = await readFile21(filePath, "utf-8");
35541
+ const raw = await readFile22(filePath, "utf-8");
35502
35542
  const parsed = JSON.parse(raw);
35503
35543
  if (typeof parsed !== "object" || parsed === null || !Array.isArray(parsed.modules)) {
35504
35544
  return { version: 1, modules: [] };
@@ -35531,7 +35571,7 @@ async function discoverModulePaths(projectRoot) {
35531
35571
  const workspacePath = join37(projectRoot, "pnpm-workspace.yaml");
35532
35572
  let patterns = [];
35533
35573
  try {
35534
- const raw = await readFile21(workspacePath, "utf-8");
35574
+ const raw = await readFile22(workspacePath, "utf-8");
35535
35575
  const lines = raw.split("\n");
35536
35576
  let inPackages = false;
35537
35577
  for (const line of lines) {
@@ -35558,7 +35598,7 @@ async function discoverModulePaths(projectRoot) {
35558
35598
  const absDir = join37(projectRoot, dir);
35559
35599
  try {
35560
35600
  if (existsSync11(absDir)) {
35561
- const entries = readdirSync4(absDir, { withFileTypes: true });
35601
+ const entries = readdirSync3(absDir, { withFileTypes: true });
35562
35602
  for (const entry of entries) {
35563
35603
  if (entry.isDirectory()) {
35564
35604
  paths.push(`${dir}/${entry.name}`);
@@ -35765,7 +35805,7 @@ async function runStamp(modulePath, sha, depthArg, projectRoot) {
35765
35805
  const mapAbsPath = join37(repoRoot, stampedEntry.map_file);
35766
35806
  let mapContent = null;
35767
35807
  try {
35768
- mapContent = await readFile21(mapAbsPath, "utf-8");
35808
+ mapContent = await readFile22(mapAbsPath, "utf-8");
35769
35809
  } catch {
35770
35810
  console.warn(
35771
35811
  " Warning: map file " + stampedEntry.map_file + " not found \u2014 stamped manifest only"
@@ -35967,7 +36007,7 @@ var init_worktree_port_resolver = __esm({
35967
36007
  });
35968
36008
 
35969
36009
  // src/lib/migrate-local-config.ts
35970
- import { mkdir as mkdir9, readFile as readFile22, unlink as unlink5, writeFile as writeFile18 } from "node:fs/promises";
36010
+ import { mkdir as mkdir9, readFile as readFile23, unlink as unlink5, writeFile as writeFile18 } from "node:fs/promises";
35971
36011
  import { join as join38 } from "node:path";
35972
36012
  function legacySharedPath(projectPath) {
35973
36013
  return join38(projectPath, ".codebyplan.json");
@@ -36018,7 +36058,7 @@ async function runLocalMigration(projectPath) {
36018
36058
  }
36019
36059
  let legacyRaw;
36020
36060
  try {
36021
- legacyRaw = await readFile22(legacySharedPath(projectPath), "utf-8");
36061
+ legacyRaw = await readFile23(legacySharedPath(projectPath), "utf-8");
36022
36062
  } catch {
36023
36063
  return {
36024
36064
  migrated: true,
@@ -36045,7 +36085,7 @@ async function runLocalMigration(projectPath) {
36045
36085
  let deviceId;
36046
36086
  let deviceWrittenByHelper = false;
36047
36087
  try {
36048
- const localRaw = await readFile22(legacyLocalPath(projectPath), "utf-8");
36088
+ const localRaw = await readFile23(legacyLocalPath(projectPath), "utf-8");
36049
36089
  const localParsed = JSON.parse(localRaw);
36050
36090
  if (typeof localParsed.device_id === "string") {
36051
36091
  deviceId = localParsed.device_id;
@@ -36145,7 +36185,7 @@ async function runLocalMigration(projectPath) {
36145
36185
  }
36146
36186
  const gitignorePath = join38(projectPath, ".gitignore");
36147
36187
  try {
36148
- const gitignoreContent = await readFile22(gitignorePath, "utf-8");
36188
+ const gitignoreContent = await readFile23(gitignorePath, "utf-8");
36149
36189
  const legacyLine = ".codebyplan.local.json";
36150
36190
  const newLine = ".codebyplan/device.local.json";
36151
36191
  const hasLegacy = gitignoreContent.split("\n").some((l) => l.trimEnd() === legacyLine);
@@ -36206,7 +36246,7 @@ __export(config_exports, {
36206
36246
  runConfig: () => runConfig,
36207
36247
  runConfigMigrate: () => runConfigMigrate
36208
36248
  });
36209
- import { mkdir as mkdir10, readFile as readFile23, writeFile as writeFile19 } from "node:fs/promises";
36249
+ import { mkdir as mkdir10, readFile as readFile24, writeFile as writeFile19 } from "node:fs/promises";
36210
36250
  import { join as join39 } from "node:path";
36211
36251
  async function runConfig() {
36212
36252
  const flags = parseFlags(3);
@@ -36337,7 +36377,7 @@ async function syncConfigToFile(repoId, projectPath, dryRun) {
36337
36377
  const newJson = JSON.stringify(payload, null, 2) + "\n";
36338
36378
  let currentJson = "";
36339
36379
  try {
36340
- currentJson = await readFile23(filePath, "utf-8");
36380
+ currentJson = await readFile24(filePath, "utf-8");
36341
36381
  } catch {
36342
36382
  }
36343
36383
  if (createOnly && currentJson !== "") continue;
@@ -36352,7 +36392,7 @@ async function syncConfigToFile(repoId, projectPath, dryRun) {
36352
36392
  }
36353
36393
  async function readRepoConfig(projectPath) {
36354
36394
  try {
36355
- const raw = await readFile23(
36395
+ const raw = await readFile24(
36356
36396
  join39(projectPath, ".codebyplan", "repo.json"),
36357
36397
  "utf-8"
36358
36398
  );
@@ -36363,7 +36403,7 @@ async function readRepoConfig(projectPath) {
36363
36403
  }
36364
36404
  async function readServerConfig(projectPath) {
36365
36405
  try {
36366
- const raw = await readFile23(
36406
+ const raw = await readFile24(
36367
36407
  join39(projectPath, ".codebyplan", "server.json"),
36368
36408
  "utf-8"
36369
36409
  );
@@ -36374,7 +36414,7 @@ async function readServerConfig(projectPath) {
36374
36414
  }
36375
36415
  async function readGitConfig2(projectPath) {
36376
36416
  try {
36377
- const raw = await readFile23(
36417
+ const raw = await readFile24(
36378
36418
  join39(projectPath, ".codebyplan", "git.json"),
36379
36419
  "utf-8"
36380
36420
  );
@@ -36385,7 +36425,7 @@ async function readGitConfig2(projectPath) {
36385
36425
  }
36386
36426
  async function readShipmentConfig2(projectPath) {
36387
36427
  try {
36388
- const raw = await readFile23(
36428
+ const raw = await readFile24(
36389
36429
  join39(projectPath, ".codebyplan", "shipment.json"),
36390
36430
  "utf-8"
36391
36431
  );
@@ -36396,7 +36436,7 @@ async function readShipmentConfig2(projectPath) {
36396
36436
  }
36397
36437
  async function readVendorConfig(projectPath) {
36398
36438
  try {
36399
- const raw = await readFile23(
36439
+ const raw = await readFile24(
36400
36440
  join39(projectPath, ".codebyplan", "vendor.json"),
36401
36441
  "utf-8"
36402
36442
  );
@@ -36407,7 +36447,7 @@ async function readVendorConfig(projectPath) {
36407
36447
  }
36408
36448
  async function readE2eConfig2(projectPath) {
36409
36449
  try {
36410
- const raw = await readFile23(
36450
+ const raw = await readFile24(
36411
36451
  join39(projectPath, ".codebyplan", "e2e.json"),
36412
36452
  "utf-8"
36413
36453
  );
@@ -36418,7 +36458,7 @@ async function readE2eConfig2(projectPath) {
36418
36458
  }
36419
36459
  async function readServerLocalConfig(projectPath) {
36420
36460
  try {
36421
- const raw = await readFile23(
36461
+ const raw = await readFile24(
36422
36462
  join39(projectPath, ".codebyplan", "server.local.json"),
36423
36463
  "utf-8"
36424
36464
  );
@@ -36491,11 +36531,11 @@ var init_config = __esm({
36491
36531
  });
36492
36532
 
36493
36533
  // src/lib/server-detect.ts
36494
- import { readFile as readFile24, readdir as readdir5, access as access6 } from "node:fs/promises";
36534
+ import { readFile as readFile25, readdir as readdir6, access as access7 } from "node:fs/promises";
36495
36535
  import { join as join40 } from "node:path";
36496
36536
  async function fileExists4(filePath) {
36497
36537
  try {
36498
- await access6(filePath);
36538
+ await access7(filePath);
36499
36539
  return true;
36500
36540
  } catch {
36501
36541
  return false;
@@ -36541,7 +36581,7 @@ async function isMonorepo(dir) {
36541
36581
  async function detectServers(projectPath) {
36542
36582
  let pkg;
36543
36583
  try {
36544
- const raw = await readFile24(join40(projectPath, "package.json"), "utf-8");
36584
+ const raw = await readFile25(join40(projectPath, "package.json"), "utf-8");
36545
36585
  pkg = JSON.parse(raw);
36546
36586
  } catch {
36547
36587
  return {
@@ -36559,13 +36599,13 @@ async function detectServers(projectPath) {
36559
36599
  if (mono) {
36560
36600
  const appsDir = join40(projectPath, "apps");
36561
36601
  try {
36562
- const entries = await readdir5(appsDir, { withFileTypes: true });
36602
+ const entries = await readdir6(appsDir, { withFileTypes: true });
36563
36603
  const sorted = [...entries].sort((a, b) => a.name.localeCompare(b.name));
36564
36604
  for (const entry of sorted) {
36565
36605
  if (!entry.isDirectory()) continue;
36566
36606
  const appPkgPath = join40(appsDir, entry.name, "package.json");
36567
36607
  try {
36568
- const appRaw = await readFile24(appPkgPath, "utf-8");
36608
+ const appRaw = await readFile25(appPkgPath, "utf-8");
36569
36609
  const appPkg = JSON.parse(appRaw);
36570
36610
  const appName = entry.name;
36571
36611
  const framework = detectFramework(appPkg);
@@ -36608,14 +36648,14 @@ var init_server_detect = __esm({
36608
36648
  });
36609
36649
 
36610
36650
  // src/lib/port-verify.ts
36611
- import { readFile as readFile25 } from "node:fs/promises";
36651
+ import { readFile as readFile26 } from "node:fs/promises";
36612
36652
  async function verifyPorts(projectPath, portAllocations) {
36613
36653
  const mismatches = [];
36614
36654
  const allocatedPorts = new Set(portAllocations.map((a) => a.port));
36615
36655
  const packageJsonPaths = await findPackageJsonFiles(projectPath, projectPath);
36616
36656
  for (const pkgPath of packageJsonPaths) {
36617
36657
  try {
36618
- const raw = await readFile25(pkgPath, "utf-8");
36658
+ const raw = await readFile26(pkgPath, "utf-8");
36619
36659
  const pkg = JSON.parse(raw);
36620
36660
  const scriptPort = detectPortFromScripts(pkg);
36621
36661
  if (scriptPort !== null && !allocatedPorts.has(scriptPort)) {
@@ -36678,7 +36718,7 @@ async function findUnallocatedApps(projectPath, portAllocations) {
36678
36718
  }
36679
36719
  let pkg;
36680
36720
  try {
36681
- const raw = await readFile25(`${app.absPath}/package.json`, "utf-8");
36721
+ const raw = await readFile26(`${app.absPath}/package.json`, "utf-8");
36682
36722
  pkg = JSON.parse(raw);
36683
36723
  } catch {
36684
36724
  continue;
@@ -36728,7 +36768,7 @@ __export(ports_exports, {
36728
36768
  parseEnvFile: () => parseEnvFile,
36729
36769
  runPorts: () => runPorts
36730
36770
  });
36731
- import { mkdir as mkdir11, readFile as readFile26, writeFile as writeFile20 } from "node:fs/promises";
36771
+ import { mkdir as mkdir11, readFile as readFile27, writeFile as writeFile20 } from "node:fs/promises";
36732
36772
  import { join as join41 } from "node:path";
36733
36773
  function printDetectionResult(result, projectPath) {
36734
36774
  console.log(`
@@ -36890,7 +36930,7 @@ async function writeServerLocalConfig(repoId, projectPath, dryRun) {
36890
36930
  const newJson = JSON.stringify(payload, null, 2) + "\n";
36891
36931
  let currentJson = "";
36892
36932
  try {
36893
- currentJson = await readFile26(filePath, "utf-8");
36933
+ currentJson = await readFile27(filePath, "utf-8");
36894
36934
  } catch {
36895
36935
  }
36896
36936
  if (currentJson === newJson) {
@@ -36912,7 +36952,7 @@ async function provisionE2eEnv(projectPath, dryRun) {
36912
36952
  const sourcePath = join41(projectPath, relSource);
36913
36953
  let sourceRaw;
36914
36954
  try {
36915
- sourceRaw = await readFile26(sourcePath, "utf-8");
36955
+ sourceRaw = await readFile27(sourcePath, "utf-8");
36916
36956
  } catch {
36917
36957
  console.warn(
36918
36958
  ` Skipped .codebyplan/e2e.env \u2014 source ${relSource} not found.`
@@ -36946,7 +36986,7 @@ async function provisionE2eEnv(projectPath, dryRun) {
36946
36986
  const newContent = lines.join("\n") + "\n";
36947
36987
  let currentContent = "";
36948
36988
  try {
36949
- currentContent = await readFile26(filePath, "utf-8");
36989
+ currentContent = await readFile27(filePath, "utf-8");
36950
36990
  } catch {
36951
36991
  }
36952
36992
  if (currentContent === newContent) {
@@ -37226,8 +37266,8 @@ __export(docs_exports, {
37226
37266
  stripRangePrefix: () => stripRangePrefix
37227
37267
  });
37228
37268
  import { existsSync as existsSync13 } from "node:fs";
37229
- import { mkdir as mkdir12, readFile as readFile27, readdir as readdir6, rm as rm2, writeFile as writeFile21 } from "node:fs/promises";
37230
- import { dirname as dirname14, isAbsolute as isAbsolute2, join as join42, relative as relative7, sep as sep2 } from "node:path";
37269
+ import { mkdir as mkdir12, readFile as readFile28, readdir as readdir7, rm as rm2, writeFile as writeFile21 } from "node:fs/promises";
37270
+ import { dirname as dirname14, isAbsolute as isAbsolute3, join as join42, relative as relative7, sep as sep2 } from "node:path";
37231
37271
  function selectDependencies(deps) {
37232
37272
  const byName = /* @__PURE__ */ new Map();
37233
37273
  for (const dep of deps) {
@@ -37285,7 +37325,7 @@ async function resolveExactVersion(projectPath, dep) {
37285
37325
  if (sourceDir !== projectPath) candidateDirs.push(sourceDir);
37286
37326
  for (const base of candidateDirs) {
37287
37327
  try {
37288
- const raw = await readFile27(
37328
+ const raw = await readFile28(
37289
37329
  join42(base, "node_modules", dep.name, "package.json"),
37290
37330
  "utf-8"
37291
37331
  );
@@ -37300,7 +37340,7 @@ async function resolveExactVersion(projectPath, dep) {
37300
37340
  }
37301
37341
  async function readVendorDocsPath(projectPath) {
37302
37342
  try {
37303
- const raw = await readFile27(
37343
+ const raw = await readFile28(
37304
37344
  join42(projectPath, ".codebyplan", "vendor.json"),
37305
37345
  "utf-8"
37306
37346
  );
@@ -37314,7 +37354,7 @@ async function readVendorDocsPath(projectPath) {
37314
37354
  }
37315
37355
  async function resolveDocsDir(projectPath, flags) {
37316
37356
  const configured = flags["dir"] ?? await readVendorDocsPath(projectPath) ?? DEFAULT_DOCS_DIR;
37317
- const absDir = isAbsolute2(configured) ? configured : join42(projectPath, configured);
37357
+ const absDir = isAbsolute3(configured) ? configured : join42(projectPath, configured);
37318
37358
  const rel = relative7(projectPath, absDir);
37319
37359
  const relDir = rel === "" || rel.startsWith("..") ? null : rel.split(sep2).join("/");
37320
37360
  return { absDir, relDir };
@@ -37323,7 +37363,7 @@ async function readDocsLock(absDir) {
37323
37363
  const empty = { generated_at: "", libraries: {} };
37324
37364
  let raw;
37325
37365
  try {
37326
- raw = await readFile27(join42(absDir, LOCK_FILE), "utf-8");
37366
+ raw = await readFile28(join42(absDir, LOCK_FILE), "utf-8");
37327
37367
  } catch {
37328
37368
  return empty;
37329
37369
  }
@@ -37422,7 +37462,7 @@ async function ensureDocsGitignoreEntry(projectPath, relDir, dryRun) {
37422
37462
  const gitignorePath = join42(projectPath, ".gitignore");
37423
37463
  let existing = "";
37424
37464
  try {
37425
- existing = await readFile27(gitignorePath, "utf-8");
37465
+ existing = await readFile28(gitignorePath, "utf-8");
37426
37466
  } catch {
37427
37467
  }
37428
37468
  const lines = existing.split(/\r?\n/).map((l) => l.trim());
@@ -37548,7 +37588,7 @@ async function syncOneLibrary(dep, ctx) {
37548
37588
  let removedVersionDirs = 0;
37549
37589
  let libEntries = [];
37550
37590
  try {
37551
- libEntries = await readdir6(libPath, { withFileTypes: true });
37591
+ libEntries = await readdir7(libPath, { withFileTypes: true });
37552
37592
  } catch {
37553
37593
  }
37554
37594
  for (const entry of libEntries) {
@@ -37678,7 +37718,7 @@ async function runDocsSync() {
37678
37718
  async function countFilesRecursively(dirPath) {
37679
37719
  let entries;
37680
37720
  try {
37681
- entries = await readdir6(dirPath, { withFileTypes: true });
37721
+ entries = await readdir7(dirPath, { withFileTypes: true });
37682
37722
  } catch {
37683
37723
  return 0;
37684
37724
  }
@@ -37702,7 +37742,7 @@ async function runDocsStatus() {
37702
37742
  `);
37703
37743
  let raw;
37704
37744
  try {
37705
- raw = await readFile27(join42(absDir, LOCK_FILE), "utf-8");
37745
+ raw = await readFile28(join42(absDir, LOCK_FILE), "utf-8");
37706
37746
  } catch {
37707
37747
  console.log(
37708
37748
  ` No ${LOCK_FILE} found \u2014 run \`codebyplan docs sync\` first.
@@ -38438,6 +38478,25 @@ function emitTable(result) {
38438
38478
  lines.push("");
38439
38479
  process.stdout.write(lines.join("\n") + "\n");
38440
38480
  }
38481
+ function emitFailureDiagnostics(result) {
38482
+ for (const r of result.results) {
38483
+ if (r.status !== "fail" || !r.executed) {
38484
+ continue;
38485
+ }
38486
+ const combined = [r.stdout, r.stderr].filter(Boolean).join("\n").trimEnd();
38487
+ if (combined.length === 0) {
38488
+ continue;
38489
+ }
38490
+ process.stderr.write(
38491
+ `
38492
+ --- check: ${r.check} FAILED (captured output) ---
38493
+ `
38494
+ );
38495
+ process.stderr.write(combined + "\n");
38496
+ process.stderr.write(`--- end: ${r.check} ---
38497
+ `);
38498
+ }
38499
+ }
38441
38500
  function runCheckCommand(args) {
38442
38501
  const parsed = parseCheckArgs(args);
38443
38502
  if (parsed === null) {
@@ -38457,6 +38516,7 @@ function runCheckCommand(args) {
38457
38516
  } else {
38458
38517
  emitTable(result);
38459
38518
  }
38519
+ emitFailureDiagnostics(result);
38460
38520
  if (result.any_failed) {
38461
38521
  process.exitCode = 1;
38462
38522
  }
@@ -38470,7 +38530,7 @@ var init_check2 = __esm({
38470
38530
 
38471
38531
  // src/lib/claude-plan.ts
38472
38532
  import * as fs13 from "node:fs";
38473
- import * as path15 from "node:path";
38533
+ import * as path16 from "node:path";
38474
38534
  function buildDriftPlan(projectDir, templatesDir, manifest) {
38475
38535
  const packaged = walkTemplates(templatesDir);
38476
38536
  const packagedBySrc = new Map(packaged.map((f) => [f.src, f]));
@@ -38484,8 +38544,8 @@ function buildDriftPlan(projectDir, templatesDir, manifest) {
38484
38544
  };
38485
38545
  for (const pkg of packaged) {
38486
38546
  const inManifest = manifestBySrc.get(pkg.src);
38487
- const absDest = path15.join(projectDir, ".claude", pkg.dest);
38488
- const absSrc = path15.join(templatesDir, pkg.src);
38547
+ const absDest = path16.join(projectDir, ".claude", pkg.dest);
38548
+ const absSrc = path16.join(templatesDir, pkg.src);
38489
38549
  if (!inManifest) {
38490
38550
  plan.newOptIn.push({
38491
38551
  packaged: { src: pkg.src, dest: pkg.dest, hash: pkg.hash },
@@ -38534,7 +38594,7 @@ __export(status_exports, {
38534
38594
  runStatus: () => runStatus2
38535
38595
  });
38536
38596
  import * as fs14 from "node:fs";
38537
- import * as path16 from "node:path";
38597
+ import * as path17 from "node:path";
38538
38598
  import { execSync as execSync9 } from "node:child_process";
38539
38599
  function makeFailSafe(checked_at) {
38540
38600
  return {
@@ -38643,12 +38703,12 @@ async function runStatus2(argv) {
38643
38703
  const latest = fetchLatestVersion();
38644
38704
  const newer = latest !== null && compareSemver(latest, installed) > 0;
38645
38705
  let settings_drift = false;
38646
- const settingsPath = path16.join(projectDir, ".claude", "settings.json");
38647
- const baseSettingsPath = path16.join(
38706
+ const settingsPath = path17.join(projectDir, ".claude", "settings.json");
38707
+ const baseSettingsPath = path17.join(
38648
38708
  templatesDir,
38649
38709
  "settings.project.base.json"
38650
38710
  );
38651
- const hooksJsonPath = path16.join(templatesDir, "hooks", "hooks.json");
38711
+ const hooksJsonPath = path17.join(templatesDir, "hooks", "hooks.json");
38652
38712
  if (fs14.existsSync(settingsPath)) {
38653
38713
  try {
38654
38714
  const settingsRaw = fs14.readFileSync(settingsPath, "utf8");
@@ -38718,10 +38778,10 @@ function emitResult(result, writeCache, quiet, projectDir) {
38718
38778
  const json = JSON.stringify(result, null, 2);
38719
38779
  if (writeCache) {
38720
38780
  try {
38721
- const cacheDir = path16.join(projectDir, ".codebyplan");
38781
+ const cacheDir = path17.join(projectDir, ".codebyplan");
38722
38782
  fs14.mkdirSync(cacheDir, { recursive: true });
38723
38783
  fs14.writeFileSync(
38724
- path16.join(cacheDir, "claude-status.local.json"),
38784
+ path17.join(cacheDir, "claude-status.local.json"),
38725
38785
  json + "\n",
38726
38786
  "utf8"
38727
38787
  );
@@ -38765,11 +38825,11 @@ async function ask(q, opts) {
38765
38825
  try {
38766
38826
  while (true) {
38767
38827
  const choices = q.choices.map((c) => `[${c.key}] ${c.label}`).join(" ");
38768
- const answer = await new Promise((resolve16) => {
38828
+ const answer = await new Promise((resolve17) => {
38769
38829
  rl.question(`${q.message}
38770
38830
  ${choices}
38771
38831
  > `, (input) => {
38772
- resolve16(input.trim().toLowerCase());
38832
+ resolve17(input.trim().toLowerCase());
38773
38833
  });
38774
38834
  });
38775
38835
  const match = q.choices.find(
@@ -38865,7 +38925,7 @@ __export(update_exports, {
38865
38925
  });
38866
38926
  import * as fs15 from "node:fs";
38867
38927
  import * as os3 from "node:os";
38868
- import * as path17 from "node:path";
38928
+ import * as path18 from "node:path";
38869
38929
  async function runUpdate(opts, deps = {}) {
38870
38930
  await Promise.resolve();
38871
38931
  const scope = opts.scope ?? "project";
@@ -38901,9 +38961,9 @@ async function runUpdate(opts, deps = {}) {
38901
38961
  finalManifestEntries.push(e);
38902
38962
  }
38903
38963
  for (const { packaged, absSrc } of plan.overwriteSafe) {
38904
- const absDest = path17.join(projectDir, ".claude", packaged.dest);
38964
+ const absDest = path18.join(projectDir, ".claude", packaged.dest);
38905
38965
  if (!opts.dryRun) {
38906
- fs15.mkdirSync(path17.dirname(absDest), { recursive: true });
38966
+ fs15.mkdirSync(path18.dirname(absDest), { recursive: true });
38907
38967
  fs15.copyFileSync(absSrc, absDest);
38908
38968
  if (opts.verbose) console.log(`updated ${packaged.dest}`);
38909
38969
  } else if (opts.verbose) {
@@ -38916,7 +38976,7 @@ async function runUpdate(opts, deps = {}) {
38916
38976
  absSrc,
38917
38977
  onDiskContent
38918
38978
  } of plan.overwriteHandEdited) {
38919
- const absDest = path17.join(projectDir, ".claude", packaged.dest);
38979
+ const absDest = path18.join(projectDir, ".claude", packaged.dest);
38920
38980
  const newContent = fs15.readFileSync(absSrc);
38921
38981
  const showDiff = () => {
38922
38982
  console.log(
@@ -38929,7 +38989,7 @@ async function runUpdate(opts, deps = {}) {
38929
38989
  const answer = await promptOverwrite(packaged.dest, opts, showDiff);
38930
38990
  if (answer === "overwrite") {
38931
38991
  if (!opts.dryRun) {
38932
- fs15.mkdirSync(path17.dirname(absDest), { recursive: true });
38992
+ fs15.mkdirSync(path18.dirname(absDest), { recursive: true });
38933
38993
  fs15.copyFileSync(absSrc, absDest);
38934
38994
  }
38935
38995
  finalManifestEntries.push(packaged);
@@ -38945,9 +39005,9 @@ async function runUpdate(opts, deps = {}) {
38945
39005
  for (const { packaged, absSrc } of plan.newOptIn) {
38946
39006
  const answer = await promptOptIn(packaged.dest, opts);
38947
39007
  if (answer === "opt-in") {
38948
- const absDest = path17.join(projectDir, ".claude", packaged.dest);
39008
+ const absDest = path18.join(projectDir, ".claude", packaged.dest);
38949
39009
  if (!opts.dryRun) {
38950
- fs15.mkdirSync(path17.dirname(absDest), { recursive: true });
39010
+ fs15.mkdirSync(path18.dirname(absDest), { recursive: true });
38951
39011
  fs15.copyFileSync(absSrc, absDest);
38952
39012
  }
38953
39013
  finalManifestEntries.push(packaged);
@@ -38959,25 +39019,25 @@ async function runUpdate(opts, deps = {}) {
38959
39019
  for (const e of plan.removedFromPackage) {
38960
39020
  const answer = await promptRemove(e.dest, opts);
38961
39021
  if (answer === "remove") {
38962
- const absDest = path17.join(projectDir, ".claude", e.dest);
39022
+ const absDest = path18.join(projectDir, ".claude", e.dest);
38963
39023
  if (!opts.dryRun && fs15.existsSync(absDest)) {
38964
39024
  fs15.rmSync(absDest);
38965
- const claudeDir = path17.join(projectDir, ".claude");
38966
- let cur = path17.dirname(absDest);
38967
- while (cur !== claudeDir && cur !== path17.dirname(cur)) {
38968
- if (path17.dirname(cur) === claudeDir) break;
39025
+ const claudeDir = path18.join(projectDir, ".claude");
39026
+ let cur = path18.dirname(absDest);
39027
+ while (cur !== claudeDir && cur !== path18.dirname(cur)) {
39028
+ if (path18.dirname(cur) === claudeDir) break;
38969
39029
  try {
38970
39030
  fs15.rmdirSync(cur);
38971
39031
  if (opts.verbose)
38972
39032
  console.log(
38973
- `pruned empty dir ${path17.relative(claudeDir, cur)}`
39033
+ `pruned empty dir ${path18.relative(claudeDir, cur)}`
38974
39034
  );
38975
- cur = path17.dirname(cur);
39035
+ cur = path18.dirname(cur);
38976
39036
  } catch (err) {
38977
39037
  const code = err.code;
38978
39038
  if (code !== "ENOTEMPTY" && code !== "ENOENT") {
38979
39039
  console.warn(
38980
- `codebyplan claude: could not prune empty dir ${path17.relative(claudeDir, cur)}: ${err.message}`
39040
+ `codebyplan claude: could not prune empty dir ${path18.relative(claudeDir, cur)}: ${err.message}`
38981
39041
  );
38982
39042
  }
38983
39043
  break;
@@ -38989,12 +39049,12 @@ async function runUpdate(opts, deps = {}) {
38989
39049
  if (opts.verbose) console.log(`kept (untracked) ${e.dest}`);
38990
39050
  }
38991
39051
  }
38992
- const hooksJsonPath = path17.join(templatesDir, "hooks", "hooks.json");
38993
- const baseSettingsPath = path17.join(
39052
+ const hooksJsonPath = path18.join(templatesDir, "hooks", "hooks.json");
39053
+ const baseSettingsPath = path18.join(
38994
39054
  templatesDir,
38995
39055
  "settings.project.base.json"
38996
39056
  );
38997
- const settingsPath = path17.join(projectDir, ".claude", "settings.json");
39057
+ const settingsPath = path18.join(projectDir, ".claude", "settings.json");
38998
39058
  const existingSettings = fs15.existsSync(settingsPath) ? JSON.parse(fs15.readFileSync(settingsPath, "utf8")) : {};
38999
39059
  if (fs15.existsSync(baseSettingsPath)) {
39000
39060
  const base = JSON.parse(
@@ -39021,7 +39081,7 @@ async function runUpdate(opts, deps = {}) {
39021
39081
  deps.detectHealDeps
39022
39082
  );
39023
39083
  if (!opts.dryRun) {
39024
- fs15.mkdirSync(path17.dirname(settingsPath), { recursive: true });
39084
+ fs15.mkdirSync(path18.dirname(settingsPath), { recursive: true });
39025
39085
  fs15.writeFileSync(
39026
39086
  settingsPath,
39027
39087
  JSON.stringify(existingSettings, null, 2) + "\n",
@@ -39037,7 +39097,7 @@ async function runUpdate(opts, deps = {}) {
39037
39097
  );
39038
39098
  if (opts.verbose && gitignoreAction !== "unchanged") {
39039
39099
  console.log(
39040
- `${opts.dryRun ? "[dry-run] would " : ""}${gitignoreAction} managed .gitignore block in ${path17.relative(projectDir, path17.join(projectDir, ".gitignore"))}`
39100
+ `${opts.dryRun ? "[dry-run] would " : ""}${gitignoreAction} managed .gitignore block in ${path18.relative(projectDir, path18.join(projectDir, ".gitignore"))}`
39041
39101
  );
39042
39102
  }
39043
39103
  if (!opts.dryRun) {
@@ -39077,9 +39137,9 @@ function runUpdateUser(opts, deps) {
39077
39137
  return;
39078
39138
  }
39079
39139
  try {
39080
- const userDir = deps.userDir ?? path17.join(os3.homedir(), ".claude");
39081
- const settingsPath = path17.join(userDir, "settings.json");
39082
- const userBaseSettingsPath = path17.join(
39140
+ const userDir = deps.userDir ?? path18.join(os3.homedir(), ".claude");
39141
+ const settingsPath = path18.join(userDir, "settings.json");
39142
+ const userBaseSettingsPath = path18.join(
39083
39143
  templatesDir,
39084
39144
  "settings.user.base.json"
39085
39145
  );
@@ -39151,7 +39211,7 @@ __export(uninstall_exports, {
39151
39211
  });
39152
39212
  import * as fs16 from "node:fs";
39153
39213
  import * as os4 from "node:os";
39154
- import * as path18 from "node:path";
39214
+ import * as path19 from "node:path";
39155
39215
  async function runUninstall(opts, deps = {}) {
39156
39216
  await Promise.resolve();
39157
39217
  const scope = opts.scope ?? "project";
@@ -39180,7 +39240,7 @@ async function runUninstall(opts, deps = {}) {
39180
39240
  let removed = 0;
39181
39241
  let warnings = 0;
39182
39242
  for (const entry of manifest.files) {
39183
- const abs = path18.join(projectDir, ".claude", entry.dest);
39243
+ const abs = path19.join(projectDir, ".claude", entry.dest);
39184
39244
  if (!fs16.existsSync(abs)) {
39185
39245
  console.warn(
39186
39246
  `codebyplan claude uninstall: ${entry.dest} already absent (skipping).`
@@ -39204,12 +39264,12 @@ async function runUninstall(opts, deps = {}) {
39204
39264
  if (!opts.dryRun) {
39205
39265
  pruneEmptyManagedDirs(projectDir);
39206
39266
  }
39207
- const settingsPath = path18.join(projectDir, ".claude", "settings.json");
39267
+ const settingsPath = path19.join(projectDir, ".claude", "settings.json");
39208
39268
  if (fs16.existsSync(settingsPath)) {
39209
39269
  const settings = JSON.parse(
39210
39270
  fs16.readFileSync(settingsPath, "utf8")
39211
39271
  );
39212
- const baseSettingsPath = templatesDir ? path18.join(templatesDir, "settings.project.base.json") : null;
39272
+ const baseSettingsPath = templatesDir ? path19.join(templatesDir, "settings.project.base.json") : null;
39213
39273
  if (baseSettingsPath && fs16.existsSync(baseSettingsPath)) {
39214
39274
  const base = JSON.parse(
39215
39275
  fs16.readFileSync(baseSettingsPath, "utf8")
@@ -39267,7 +39327,7 @@ function runUninstallUser(opts, deps) {
39267
39327
  }
39268
39328
  }
39269
39329
  try {
39270
- const userDir = deps.userDir ?? path18.join(os4.homedir(), ".claude");
39330
+ const userDir = deps.userDir ?? path19.join(os4.homedir(), ".claude");
39271
39331
  const existingManifest = readManifestForScope("user", userDir);
39272
39332
  if (!existingManifest) {
39273
39333
  console.error(
@@ -39276,12 +39336,12 @@ function runUninstallUser(opts, deps) {
39276
39336
  process.exitCode = 1;
39277
39337
  return;
39278
39338
  }
39279
- const settingsPath = path18.join(userDir, "settings.json");
39339
+ const settingsPath = path19.join(userDir, "settings.json");
39280
39340
  if (fs16.existsSync(settingsPath)) {
39281
39341
  const settings = JSON.parse(
39282
39342
  fs16.readFileSync(settingsPath, "utf8")
39283
39343
  );
39284
- const userBaseSettingsPath = templatesDir != null ? path18.join(templatesDir, "settings.user.base.json") : null;
39344
+ const userBaseSettingsPath = templatesDir != null ? path19.join(templatesDir, "settings.user.base.json") : null;
39285
39345
  if (userBaseSettingsPath && fs16.existsSync(userBaseSettingsPath)) {
39286
39346
  const userBase = JSON.parse(
39287
39347
  fs16.readFileSync(userBaseSettingsPath, "utf8")
@@ -39322,7 +39382,7 @@ function runUninstallUser(opts, deps) {
39322
39382
  function pruneEmptyManagedDirs(projectDir) {
39323
39383
  const managedRoots = ["skills", "agents", "hooks", "rules"];
39324
39384
  for (const root of managedRoots) {
39325
- const abs = path18.join(projectDir, ".claude", root);
39385
+ const abs = path19.join(projectDir, ".claude", root);
39326
39386
  if (!fs16.existsSync(abs)) continue;
39327
39387
  pruneLeafFirst(abs);
39328
39388
  }
@@ -39333,7 +39393,7 @@ function pruneLeafFirst(dir) {
39333
39393
  if (!stat3.isDirectory()) return;
39334
39394
  for (const entry of fs16.readdirSync(dir, { withFileTypes: true })) {
39335
39395
  if (entry.isDirectory()) {
39336
- pruneLeafFirst(path18.join(dir, entry.name));
39396
+ pruneLeafFirst(path19.join(dir, entry.name));
39337
39397
  }
39338
39398
  }
39339
39399
  const remaining = fs16.readdirSync(dir);
@@ -39354,7 +39414,7 @@ var init_uninstall = __esm({
39354
39414
 
39355
39415
  // src/lib/verify-parity.ts
39356
39416
  import * as fs17 from "node:fs";
39357
- import * as path19 from "node:path";
39417
+ import * as path20 from "node:path";
39358
39418
  function isValidScope(s) {
39359
39419
  return s === "org-shared" || s === "project-shared" || REPO_ONLY_RE.test(s);
39360
39420
  }
@@ -39371,25 +39431,25 @@ function checkSiblingParity(opts) {
39371
39431
  expectedOneSided = DEFAULT_EXPECTED_ONE_SIDED,
39372
39432
  ignoredSubtrees
39373
39433
  } = opts;
39374
- const defaultIgnored = [path19.join(claudeDir, "hooks", "__test-fixtures__")];
39434
+ const defaultIgnored = [path20.join(claudeDir, "hooks", "__test-fixtures__")];
39375
39435
  const ignored = ignoredSubtrees ?? defaultIgnored;
39376
39436
  const violations = [];
39377
39437
  const claudeSideRels = /* @__PURE__ */ new Set();
39378
39438
  for (const scanDir of SCAN_DIRS) {
39379
- const baseDir = path19.join(claudeDir, scanDir);
39439
+ const baseDir = path20.join(claudeDir, scanDir);
39380
39440
  if (!fs17.existsSync(baseDir)) continue;
39381
39441
  const entries = readdirRecursive(baseDir);
39382
39442
  for (const entry of entries) {
39383
- const absPath = path19.join(baseDir, entry);
39443
+ const absPath = path20.join(baseDir, entry);
39384
39444
  if (!fs17.lstatSync(absPath).isFile()) continue;
39385
39445
  if (ignored.some(
39386
- (ig) => absPath.startsWith(ig + path19.sep) || absPath === ig
39446
+ (ig) => absPath.startsWith(ig + path20.sep) || absPath === ig
39387
39447
  )) {
39388
39448
  continue;
39389
39449
  }
39390
- const relPath = path19.join(scanDir, entry).split(path19.sep).join("/");
39450
+ const relPath = path20.join(scanDir, entry).split(path20.sep).join("/");
39391
39451
  claudeSideRels.add(relPath);
39392
- const templatePath = path19.join(templatesDir, relPath);
39452
+ const templatePath = path20.join(templatesDir, relPath);
39393
39453
  if (!fs17.existsSync(templatePath)) {
39394
39454
  if (!expectedOneSided.has(relPath) && !isScaffoldFile(entry)) {
39395
39455
  violations.push({ type: "missing-twin", path: relPath });
@@ -39404,14 +39464,14 @@ function checkSiblingParity(opts) {
39404
39464
  }
39405
39465
  }
39406
39466
  for (const scanDir of SCAN_DIRS) {
39407
- const tplBase = path19.join(templatesDir, scanDir);
39467
+ const tplBase = path20.join(templatesDir, scanDir);
39408
39468
  if (!fs17.existsSync(tplBase)) continue;
39409
39469
  const entries = readdirRecursive(tplBase);
39410
39470
  for (const entry of entries) {
39411
- const absPath = path19.join(tplBase, entry);
39471
+ const absPath = path20.join(tplBase, entry);
39412
39472
  if (!fs17.lstatSync(absPath).isFile()) continue;
39413
39473
  if (isScaffoldFile(entry)) continue;
39414
- const relPath = path19.join(scanDir, entry).split(path19.sep).join("/");
39474
+ const relPath = path20.join(scanDir, entry).split(path20.sep).join("/");
39415
39475
  if (!claudeSideRels.has(relPath) && !expectedOneSided.has(relPath)) {
39416
39476
  violations.push({ type: "extra-twin", path: relPath });
39417
39477
  }
@@ -39447,18 +39507,18 @@ function checkScopeMarkers(opts) {
39447
39507
  const twinDetectionActive = templatesDir != null && fs17.existsSync(templatesDir);
39448
39508
  const violations = [];
39449
39509
  for (const scanDir of scanDirs) {
39450
- const baseDir = path19.join(claudeDir, scanDir);
39510
+ const baseDir = path20.join(claudeDir, scanDir);
39451
39511
  if (!fs17.existsSync(baseDir)) continue;
39452
39512
  const entries = readdirRecursive(baseDir);
39453
39513
  for (const entry of entries) {
39454
- const absPath = path19.join(baseDir, entry);
39514
+ const absPath = path20.join(baseDir, entry);
39455
39515
  if (!fs17.lstatSync(absPath).isFile()) continue;
39456
39516
  if (!isStructuralEntry(scanDir, entry)) continue;
39457
- const ext = path19.extname(entry).toLowerCase();
39517
+ const ext = path20.extname(entry).toLowerCase();
39458
39518
  const isMd = ext === ".md";
39459
39519
  const isSh = ext === ".sh";
39460
39520
  if (!isMd && !isSh) continue;
39461
- const relPath = path19.join(scanDir, entry).split(path19.sep).join("/");
39521
+ const relPath = path20.join(scanDir, entry).split(path20.sep).join("/");
39462
39522
  if (allowlist.has(relPath)) continue;
39463
39523
  let content;
39464
39524
  try {
@@ -39472,7 +39532,7 @@ function checkScopeMarkers(opts) {
39472
39532
  continue;
39473
39533
  }
39474
39534
  const scopeValue = isMd ? extractFrontmatterScope(content) : extractShScope(content);
39475
- const managed = twinDetectionActive && fs17.existsSync(path19.join(templatesDir, relPath));
39535
+ const managed = twinDetectionActive && fs17.existsSync(path20.join(templatesDir, relPath));
39476
39536
  if (managed) {
39477
39537
  if (scopeValue === null) {
39478
39538
  } else if (scopeValue === "org-shared") {
@@ -39526,7 +39586,7 @@ function readdirRecursive(dir, rel = "", visited = /* @__PURE__ */ new Set()) {
39526
39586
  visited.add(realDir);
39527
39587
  const results = [];
39528
39588
  for (const name of fs17.readdirSync(dir)) {
39529
- const full = path19.join(dir, name);
39589
+ const full = path20.join(dir, name);
39530
39590
  const relName = rel ? `${rel}/${name}` : name;
39531
39591
  if (fs17.lstatSync(full).isDirectory()) {
39532
39592
  results.push(...readdirRecursive(full, relName, visited));
@@ -39599,12 +39659,12 @@ __export(verify_parity_exports, {
39599
39659
  verifyParity: () => verifyParity
39600
39660
  });
39601
39661
  import * as fs18 from "node:fs";
39602
- import * as path20 from "node:path";
39662
+ import * as path21 from "node:path";
39603
39663
  function verifyParity(args, deps = {}) {
39604
39664
  const warnOnly = args.includes("--warn-only");
39605
39665
  const jsonMode = args.includes("--json");
39606
39666
  const projectDir = deps.cwd ?? process.cwd();
39607
- const claudeDir = path20.join(projectDir, ".claude");
39667
+ const claudeDir = path21.join(projectDir, ".claude");
39608
39668
  if (!fs18.existsSync(claudeDir)) {
39609
39669
  const msg = "codebyplan claude verify-parity: .claude/ not found in cwd \u2014 run from the project root.\n";
39610
39670
  process.stderr.write(msg);
@@ -40111,11 +40171,11 @@ var generate_exports = {};
40111
40171
  __export(generate_exports, {
40112
40172
  runGenerate: () => runGenerate
40113
40173
  });
40114
- import { readFile as readFile28, mkdir as mkdir13, writeFile as writeFile22 } from "node:fs/promises";
40115
- import { join as join51, resolve as resolve11 } from "node:path";
40174
+ import { readFile as readFile29, mkdir as mkdir13, writeFile as writeFile22 } from "node:fs/promises";
40175
+ import { join as join51, resolve as resolve12 } from "node:path";
40116
40176
  async function readJsonFile4(filePath) {
40117
40177
  try {
40118
- const raw = await readFile28(filePath, "utf-8");
40178
+ const raw = await readFile29(filePath, "utf-8");
40119
40179
  return JSON.parse(raw);
40120
40180
  } catch {
40121
40181
  return null;
@@ -40123,7 +40183,7 @@ async function readJsonFile4(filePath) {
40123
40183
  }
40124
40184
  async function readPkgName(absPath) {
40125
40185
  try {
40126
- const raw = await readFile28(join51(absPath, "package.json"), "utf-8");
40186
+ const raw = await readFile29(join51(absPath, "package.json"), "utf-8");
40127
40187
  const pkg = JSON.parse(raw);
40128
40188
  return typeof pkg.name === "string" ? pkg.name : null;
40129
40189
  } catch {
@@ -40134,10 +40194,10 @@ async function runGenerate(opts) {
40134
40194
  const projectDir = opts.projectDir ?? opts["project-dir"] ?? process.cwd();
40135
40195
  const dryRun = opts.dryRun ?? opts["dryRun"] ?? false;
40136
40196
  const check = opts.check ?? opts["check"] ?? false;
40137
- const rootDir = resolve11(projectDir);
40197
+ const rootDir = resolve12(projectDir);
40138
40198
  let packageManager;
40139
40199
  try {
40140
- const raw = await readFile28(join51(rootDir, "package.json"), "utf-8");
40200
+ const raw = await readFile29(join51(rootDir, "package.json"), "utf-8");
40141
40201
  const pkg = JSON.parse(raw);
40142
40202
  if (typeof pkg.packageManager === "string") {
40143
40203
  packageManager = pkg.packageManager;
@@ -40241,7 +40301,7 @@ async function runGenerate(opts) {
40241
40301
  const agentsMdPath2 = join51(rootDir, "AGENTS.md");
40242
40302
  let existingAgents = null;
40243
40303
  try {
40244
- existingAgents = await readFile28(agentsMdPath2, "utf-8");
40304
+ existingAgents = await readFile29(agentsMdPath2, "utf-8");
40245
40305
  } catch {
40246
40306
  existingAgents = null;
40247
40307
  }
@@ -40286,7 +40346,7 @@ async function runGenerate(opts) {
40286
40346
  const agentsMdPath = join51(rootDir, "AGENTS.md");
40287
40347
  let existingAgentsContent = null;
40288
40348
  try {
40289
- existingAgentsContent = await readFile28(agentsMdPath, "utf-8");
40349
+ existingAgentsContent = await readFile29(agentsMdPath, "utf-8");
40290
40350
  } catch {
40291
40351
  existingAgentsContent = null;
40292
40352
  }
@@ -40314,11 +40374,11 @@ __export(readme_exports, {
40314
40374
  runReadme: () => runReadme,
40315
40375
  runReadmeCommand: () => runReadmeCommand
40316
40376
  });
40317
- import { readFile as readFile29, writeFile as writeFile23 } from "node:fs/promises";
40318
- import { join as join52, resolve as resolve12, relative as relative9 } from "node:path";
40377
+ import { readFile as readFile30, writeFile as writeFile23 } from "node:fs/promises";
40378
+ import { join as join52, resolve as resolve13, relative as relative9 } from "node:path";
40319
40379
  async function readJsonFile5(filePath) {
40320
40380
  try {
40321
- const raw = await readFile29(filePath, "utf-8");
40381
+ const raw = await readFile30(filePath, "utf-8");
40322
40382
  return JSON.parse(raw);
40323
40383
  } catch {
40324
40384
  return null;
@@ -40411,7 +40471,7 @@ async function runReadme(opts) {
40411
40471
  const dryRun = opts.dryRun ?? opts["dryRun"] ?? false;
40412
40472
  const check = opts.check ?? opts["check"] ?? false;
40413
40473
  const init = opts.init ?? opts["init"] ?? false;
40414
- const rootDir = resolve12(projectDir);
40474
+ const rootDir = resolve13(projectDir);
40415
40475
  const rootPkgJson = await readJsonFile5(
40416
40476
  join52(rootDir, "package.json")
40417
40477
  );
@@ -40426,7 +40486,7 @@ async function runReadme(opts) {
40426
40486
  const relPath = unit.isRoot ? "README.md" : join52(relative9(rootDir, unit.absPath), "README.md");
40427
40487
  let existingContent = null;
40428
40488
  try {
40429
- existingContent = await readFile29(readmePath, "utf-8");
40489
+ existingContent = await readFile30(readmePath, "utf-8");
40430
40490
  } catch {
40431
40491
  existingContent = null;
40432
40492
  }
@@ -40606,18 +40666,18 @@ __export(migrate_memory_exports, {
40606
40666
  runMigrateMemory: () => runMigrateMemory
40607
40667
  });
40608
40668
  import {
40609
- readFile as readFile30,
40669
+ readFile as readFile31,
40610
40670
  writeFile as writeFile24,
40611
40671
  mkdir as mkdir14,
40612
40672
  unlink as unlink6,
40613
40673
  rmdir,
40614
- readdir as readdir7
40674
+ readdir as readdir8
40615
40675
  } from "node:fs/promises";
40616
40676
  import { existsSync as existsSync21 } from "node:fs";
40617
- import { join as join53, resolve as resolve13, dirname as dirname16, sep as sep4 } from "node:path";
40677
+ import { join as join53, resolve as resolve14, dirname as dirname16, sep as sep4 } from "node:path";
40618
40678
  import { homedir as homedir8 } from "node:os";
40619
40679
  function encodeProjectPath(absPath) {
40620
- return resolve13(absPath).replace(/[/\\]/g, "-");
40680
+ return resolve14(absPath).replace(/[/\\]/g, "-");
40621
40681
  }
40622
40682
  function resolveAutoMemoryDir(opts) {
40623
40683
  if (opts.autoMemoryDir) {
@@ -40684,7 +40744,7 @@ function parseFrontmatter(content) {
40684
40744
  async function inventoryFiles(dir) {
40685
40745
  let filenames;
40686
40746
  try {
40687
- const entries = await readdir7(dir);
40747
+ const entries = await readdir8(dir);
40688
40748
  filenames = entries.filter((f) => f.endsWith(".md") && f !== "MEMORY.md").sort();
40689
40749
  } catch {
40690
40750
  return [];
@@ -40694,7 +40754,7 @@ async function inventoryFiles(dir) {
40694
40754
  const sourcePath = join53(dir, filename);
40695
40755
  let raw;
40696
40756
  try {
40697
- raw = await readFile30(sourcePath, "utf-8");
40757
+ raw = await readFile31(sourcePath, "utf-8");
40698
40758
  } catch (err) {
40699
40759
  const msg = err instanceof Error ? err.message : String(err);
40700
40760
  results.push({
@@ -40774,15 +40834,15 @@ function buildPlan(entries, opts) {
40774
40834
  return plan;
40775
40835
  }
40776
40836
  async function applyPlan(plan, opts) {
40777
- const projectDir = resolve13(opts.projectDir);
40837
+ const projectDir = resolve14(opts.projectDir);
40778
40838
  const dryRun = opts.dryRun ?? false;
40779
40839
  for (const entry of plan.entries) {
40780
40840
  if (entry.suggested_action !== "keep") continue;
40781
40841
  if (!entry.suggested_target?.startsWith("nested:")) continue;
40782
40842
  const relPath = entry.suggested_target.slice("nested:".length);
40783
- const targetDir = resolve13(join53(projectDir, relPath));
40843
+ const targetDir = resolve14(join53(projectDir, relPath));
40784
40844
  const targetFile = join53(targetDir, "CLAUDE.md");
40785
- if (!targetDir.startsWith(resolve13(projectDir) + sep4)) {
40845
+ if (!targetDir.startsWith(resolve14(projectDir) + sep4)) {
40786
40846
  process.stderr.write(
40787
40847
  `migrate-memory: skipping unsafe suggested_target "${entry.suggested_target}" \u2014 resolves outside projectDir
40788
40848
  `
@@ -40800,8 +40860,8 @@ ${anchor}
40800
40860
  if (dryRun) {
40801
40861
  process.stdout.write(`[dry-run] Would create/append: ${targetFile}
40802
40862
  `);
40803
- if (resolve13(entry.source_path).startsWith(
40804
- resolve13(plan.auto_memory_dir) + sep4
40863
+ if (resolve14(entry.source_path).startsWith(
40864
+ resolve14(plan.auto_memory_dir) + sep4
40805
40865
  )) {
40806
40866
  process.stdout.write(
40807
40867
  `[dry-run] Would delete migrated keep source: ${entry.source_path}
@@ -40813,13 +40873,13 @@ ${anchor}
40813
40873
  await mkdir14(targetDir, { recursive: true });
40814
40874
  let existing = "";
40815
40875
  try {
40816
- existing = await readFile30(targetFile, "utf-8");
40876
+ existing = await readFile31(targetFile, "utf-8");
40817
40877
  } catch {
40818
40878
  }
40819
40879
  if (!existing.includes(anchor)) {
40820
40880
  await writeFile24(targetFile, existing + appendContent, "utf-8");
40821
40881
  }
40822
- if (resolve13(entry.source_path).startsWith(resolve13(plan.auto_memory_dir) + sep4)) {
40882
+ if (resolve14(entry.source_path).startsWith(resolve14(plan.auto_memory_dir) + sep4)) {
40823
40883
  try {
40824
40884
  await unlink6(entry.source_path);
40825
40885
  } catch {
@@ -40840,7 +40900,7 @@ ${anchor}
40840
40900
  } else {
40841
40901
  let claudeMdContent = "";
40842
40902
  try {
40843
- claudeMdContent = await readFile30(rootClaudeMd, "utf-8");
40903
+ claudeMdContent = await readFile31(rootClaudeMd, "utf-8");
40844
40904
  } catch {
40845
40905
  await mkdir14(dirname16(rootClaudeMd), { recursive: true });
40846
40906
  }
@@ -40856,8 +40916,8 @@ ${IMPORT_LINE}
40856
40916
  }
40857
40917
  for (const entry of plan.entries) {
40858
40918
  if (entry.suggested_action !== "drop") continue;
40859
- if (!resolve13(entry.source_path).startsWith(
40860
- resolve13(plan.auto_memory_dir) + sep4
40919
+ if (!resolve14(entry.source_path).startsWith(
40920
+ resolve14(plan.auto_memory_dir) + sep4
40861
40921
  )) {
40862
40922
  process.stderr.write(
40863
40923
  `migrate-memory: skipping delete of "${entry.source_path}" \u2014 resolves outside auto_memory_dir
@@ -40881,7 +40941,7 @@ ${IMPORT_LINE}
40881
40941
  process.stdout.write(`[dry-run] Would delete MEMORY.md: ${memoryMd}
40882
40942
  `);
40883
40943
  } else {
40884
- if (resolve13(plan.auto_memory_dir).startsWith(safeRmdirBase + sep4)) {
40944
+ if (resolve14(plan.auto_memory_dir).startsWith(safeRmdirBase + sep4)) {
40885
40945
  try {
40886
40946
  await unlink6(memoryMd);
40887
40947
  } catch {
@@ -40899,14 +40959,14 @@ ${IMPORT_LINE}
40899
40959
  `
40900
40960
  );
40901
40961
  } else {
40902
- if (!resolve13(plan.auto_memory_dir).startsWith(safeRmdirBase + sep4)) {
40962
+ if (!resolve14(plan.auto_memory_dir).startsWith(safeRmdirBase + sep4)) {
40903
40963
  process.stderr.write(
40904
40964
  `migrate-memory: skipping rmdir of "${plan.auto_memory_dir}" \u2014 not under ~/.claude/projects
40905
40965
  `
40906
40966
  );
40907
40967
  } else {
40908
40968
  try {
40909
- const remaining = await readdir7(plan.auto_memory_dir);
40969
+ const remaining = await readdir8(plan.auto_memory_dir);
40910
40970
  if (remaining.length === 0) {
40911
40971
  await rmdir(plan.auto_memory_dir);
40912
40972
  }
@@ -40929,7 +40989,7 @@ async function runMigrateMemory(opts) {
40929
40989
  if (applyFile) {
40930
40990
  let planJson;
40931
40991
  try {
40932
- planJson = await readFile30(resolve13(applyFile), "utf-8");
40992
+ planJson = await readFile31(resolve14(applyFile), "utf-8");
40933
40993
  } catch (err) {
40934
40994
  const msg = err instanceof Error ? err.message : String(err);
40935
40995
  process.stderr.write(
@@ -40999,7 +41059,7 @@ var init_migrate_memory = __esm({
40999
41059
  });
41000
41060
 
41001
41061
  // src/lib/claude-mode-audit.ts
41002
- import { readdirSync as readdirSync7, readFileSync as readFileSync19, existsSync as existsSync22 } from "node:fs";
41062
+ import { readdirSync as readdirSync6, readFileSync as readFileSync19, existsSync as existsSync22 } from "node:fs";
41003
41063
  import { join as join54, basename as basename3 } from "node:path";
41004
41064
  function parseFrontmatter2(content) {
41005
41065
  const match = /^---\r?\n([\s\S]*?)\r?\n---/.exec(content);
@@ -41055,15 +41115,17 @@ function auditSkill(filePath) {
41055
41115
  const model = fm.model ?? null;
41056
41116
  const effort = fm.effort ?? null;
41057
41117
  const gaps = [];
41058
- if (model !== null) {
41059
- gaps.push("model: must be absent for skills");
41118
+ if (model === null) {
41119
+ gaps.push("model: absent (expected 'inherit')");
41120
+ } else if (model !== "inherit") {
41121
+ gaps.push(`model: expected 'inherit', got '${model}'`);
41060
41122
  }
41061
41123
  if (!effort) {
41062
41124
  gaps.push("effort: absent (default xhigh required)");
41063
41125
  } else if (!VALID_EFFORT_VALUES.has(effort)) {
41064
41126
  gaps.push(`effort: invalid value '${effort}'`);
41065
41127
  }
41066
- const expectedStr = `effort:${effort && VALID_EFFORT_VALUES.has(effort) ? effort : "xhigh"}`;
41128
+ const expectedStr = `model:inherit/effort:${effort && VALID_EFFORT_VALUES.has(effort) ? effort : "xhigh"}`;
41067
41129
  const status = gaps.length === 0 ? "ok" : "gap";
41068
41130
  return {
41069
41131
  path: filePath,
@@ -41079,14 +41141,14 @@ function auditMode(templatesDir) {
41079
41141
  const entries = [];
41080
41142
  const agentsDir = join54(templatesDir, "agents");
41081
41143
  if (existsSync22(agentsDir)) {
41082
- const agentFiles = readdirSync7(agentsDir).filter((f) => f.endsWith(".md")).sort();
41144
+ const agentFiles = readdirSync6(agentsDir).filter((f) => f.endsWith(".md")).sort();
41083
41145
  for (const f of agentFiles) {
41084
41146
  entries.push(auditAgent(join54(agentsDir, f)));
41085
41147
  }
41086
41148
  }
41087
41149
  const skillsDir = join54(templatesDir, "skills");
41088
41150
  if (existsSync22(skillsDir)) {
41089
- const skillDirs = readdirSync7(skillsDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name).sort();
41151
+ const skillDirs = readdirSync6(skillsDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name).sort();
41090
41152
  for (const dir of skillDirs) {
41091
41153
  if (existsSync22(join54(skillsDir, dir, "PROVENANCE.md"))) continue;
41092
41154
  const skillMd = join54(skillsDir, dir, "SKILL.md");
@@ -41105,7 +41167,13 @@ var init_claude_mode_audit = __esm({
41105
41167
  "cbp-mechanical-edits": { model: "haiku", effort: "low" },
41106
41168
  // Read-only module analyzer: bounded structured-map generation, deliberately
41107
41169
  // lighter than the xhigh default. Documented in cbp-build-cc-mode's matrix.
41108
- "cbp-map-architecture": { model: "sonnet", effort: "high" }
41170
+ "cbp-map-architecture": { model: "sonnet", effort: "high" },
41171
+ // E2E specialist: bounded test-execution scope; sonnet+high calibrated in CHK-229.
41172
+ "cbp-e2e-maestro": { model: "sonnet", effort: "high" },
41173
+ "cbp-e2e-playwright": { model: "sonnet", effort: "high" },
41174
+ "cbp-e2e-tauri": { model: "sonnet", effort: "high" },
41175
+ "cbp-e2e-vscode": { model: "sonnet", effort: "high" },
41176
+ "cbp-e2e-xcuitest": { model: "sonnet", effort: "high" }
41109
41177
  };
41110
41178
  AGENT_DEFAULT = { model: "sonnet", effort: "xhigh" };
41111
41179
  VALID_EFFORT_VALUES = /* @__PURE__ */ new Set(["low", "medium", "high", "xhigh", "max"]);
@@ -41348,7 +41416,7 @@ __export(new_migration_exports, {
41348
41416
  newMigration: () => newMigration
41349
41417
  });
41350
41418
  import * as fs19 from "node:fs";
41351
- import * as path21 from "node:path";
41419
+ import * as path22 from "node:path";
41352
41420
  function slugify(name) {
41353
41421
  return name.trim().toLowerCase().replace(/[^a-z0-9_-]+/g, "_").replace(/^_+|_+$/g, "").replace(/_+/g, "_");
41354
41422
  }
@@ -41369,9 +41437,9 @@ function newMigration(args, deps = {}) {
41369
41437
  }
41370
41438
  const slug = slugify(rawName);
41371
41439
  const stamp = genTimestamp({ cwd });
41372
- const migrationsDir = path21.join(cwd, "supabase", "migrations");
41440
+ const migrationsDir = path22.join(cwd, "supabase", "migrations");
41373
41441
  const filename = `${stamp}_${slug}.sql`;
41374
- const filePath = path21.join(migrationsDir, filename);
41442
+ const filePath = path22.join(migrationsDir, filename);
41375
41443
  mkdirSync12(migrationsDir, { recursive: true });
41376
41444
  writeFileSync13(filePath, "");
41377
41445
  process.stdout.write(JSON.stringify({ path: filePath }) + "\n");
@@ -41417,7 +41485,7 @@ function defaultGetPrNumber(cwd, run) {
41417
41485
  async function previewCheck(args, deps = {}) {
41418
41486
  const cwd = deps.cwd ?? process.cwd();
41419
41487
  const run = deps.run ?? defaultRun4;
41420
- const sleep3 = deps.sleep ?? ((ms) => new Promise((resolve16) => setTimeout(resolve16, ms)));
41488
+ const sleep3 = deps.sleep ?? ((ms) => new Promise((resolve17) => setTimeout(resolve17, ms)));
41421
41489
  const getPrNumber = deps.getPrNumber ?? defaultGetPrNumber;
41422
41490
  const poll = deps.pollCheck ?? pollGhPreviewCheck;
41423
41491
  let mode = "pre_merge";
@@ -41737,13 +41805,13 @@ function validateWaves(waves) {
41737
41805
  pathOwners.set(file, owners);
41738
41806
  }
41739
41807
  }
41740
- for (const [path22, owners] of pathOwners) {
41808
+ for (const [path23, owners] of pathOwners) {
41741
41809
  if (owners.length > 1) {
41742
41810
  violations.push({
41743
41811
  invariant: "I",
41744
41812
  code: "DUPLICATE_FILE",
41745
- message: `File "${path22}" appears in multiple waves: ${owners.join(", ")}.`,
41746
- detail: { path: path22, waves: owners }
41813
+ message: `File "${path23}" appears in multiple waves: ${owners.join(", ")}.`,
41814
+ detail: { path: path23, waves: owners }
41747
41815
  });
41748
41816
  }
41749
41817
  }
@@ -41837,14 +41905,14 @@ var validate_waves_exports = {};
41837
41905
  __export(validate_waves_exports, {
41838
41906
  runValidateWavesCommand: () => runValidateWavesCommand
41839
41907
  });
41840
- import { readFile as readFile31 } from "node:fs/promises";
41908
+ import { readFile as readFile32 } from "node:fs/promises";
41841
41909
  async function readStdin() {
41842
- return new Promise((resolve16, reject) => {
41910
+ return new Promise((resolve17, reject) => {
41843
41911
  const chunks = [];
41844
41912
  process.stdin.on("data", (chunk) => chunks.push(chunk));
41845
41913
  process.stdin.on(
41846
41914
  "end",
41847
- () => resolve16(Buffer.concat(chunks).toString("utf-8"))
41915
+ () => resolve17(Buffer.concat(chunks).toString("utf-8"))
41848
41916
  );
41849
41917
  process.stdin.on("error", reject);
41850
41918
  });
@@ -41856,7 +41924,7 @@ async function runValidateWavesCommand(args) {
41856
41924
  let raw;
41857
41925
  if (filePath) {
41858
41926
  try {
41859
- raw = await readFile31(filePath, "utf-8");
41927
+ raw = await readFile32(filePath, "utf-8");
41860
41928
  } catch (err) {
41861
41929
  const msg = err instanceof Error ? err.message : String(err);
41862
41930
  process.stderr.write(
@@ -41951,7 +42019,7 @@ var init_path = __esm({
41951
42019
 
41952
42020
  // src/cli/worktree/add.ts
41953
42021
  import { join as join57, basename as basename5 } from "node:path";
41954
- import { mkdir as mkdir15, readFile as readFile32, writeFile as writeFile25 } from "node:fs/promises";
42022
+ import { mkdir as mkdir15, readFile as readFile33, writeFile as writeFile25 } from "node:fs/promises";
41955
42023
  import { spawnSync as spawnSync18 } from "node:child_process";
41956
42024
  async function defaultGetRepoId(cwd) {
41957
42025
  const found = await findCodebyplanConfig(cwd);
@@ -41994,7 +42062,7 @@ function defaultGitRun(args, cwd) {
41994
42062
  };
41995
42063
  }
41996
42064
  async function copyClaudeSettings(srcCwd, destPath, deps = {}) {
41997
- const readFileFn = deps.readFileFn ?? ((p) => readFile32(p, "utf-8"));
42065
+ const readFileFn = deps.readFileFn ?? ((p) => readFile33(p, "utf-8"));
41998
42066
  const writeFileFn = deps.writeFileFn ?? ((p, content) => writeFile25(p, content, "utf-8"));
41999
42067
  const existsFn = deps.existsFn ?? ((p) => import("node:fs/promises").then(
42000
42068
  (fsp) => fsp.access(p).then(() => true).catch(() => false)
@@ -42019,13 +42087,13 @@ async function defaultCopyConfigStubs(srcCwd, destPath) {
42019
42087
  const topLevelStubs = [".mcp.json", ".env.local"];
42020
42088
  for (const stub of topLevelStubs) {
42021
42089
  try {
42022
- const content = await readFile32(join57(srcCwd, stub), "utf-8");
42090
+ const content = await readFile33(join57(srcCwd, stub), "utf-8");
42023
42091
  await writeFile25(join57(destPath, stub), content, "utf-8");
42024
42092
  } catch {
42025
42093
  }
42026
42094
  }
42027
42095
  try {
42028
- const content = await readFile32(
42096
+ const content = await readFile33(
42029
42097
  join57(srcCwd, ".codebyplan", "repo.json"),
42030
42098
  "utf-8"
42031
42099
  );
@@ -42038,11 +42106,11 @@ async function defaultCopyConfigStubs(srcCwd, destPath) {
42038
42106
  }
42039
42107
  await copyClaudeSettings(srcCwd, destPath);
42040
42108
  }
42041
- async function defaultRegisterWorktree(repoId, name, path22) {
42109
+ async function defaultRegisterWorktree(repoId, name, path23) {
42042
42110
  const res = await apiPost("/worktrees", {
42043
42111
  repo_id: repoId,
42044
42112
  name,
42045
- path: path22,
42113
+ path: path23,
42046
42114
  status: "active"
42047
42115
  });
42048
42116
  return { worktree_id: res.data.id };
@@ -42076,7 +42144,7 @@ async function runWorktreeAdd(args, deps = {}) {
42076
42144
  const getRepoId = deps.getRepoId ?? defaultGetRepoId;
42077
42145
  const lookupBranch = deps.lookupBranch ?? defaultLookupBranch;
42078
42146
  const gitRun = deps.gitRun ?? defaultGitRun;
42079
- const sleep3 = deps.sleep ?? ((ms) => new Promise((resolve16) => setTimeout(resolve16, ms)));
42147
+ const sleep3 = deps.sleep ?? ((ms) => new Promise((resolve17) => setTimeout(resolve17, ms)));
42080
42148
  const copyConfigStubs = deps.copyConfigStubs ?? defaultCopyConfigStubs;
42081
42149
  const registerWorktree = deps.registerWorktree ?? defaultRegisterWorktree;
42082
42150
  try {
@@ -42207,11 +42275,11 @@ async function defaultGetRepoIdentity(cwd) {
42207
42275
  project_id: typeof contents?.["project_id"] === "string" ? contents["project_id"] : void 0
42208
42276
  };
42209
42277
  }
42210
- async function defaultRegisterWorktree2(repoId, name, path22) {
42278
+ async function defaultRegisterWorktree2(repoId, name, path23) {
42211
42279
  const res = await apiPost("/worktrees", {
42212
42280
  repo_id: repoId,
42213
42281
  name,
42214
- path: path22,
42282
+ path: path23,
42215
42283
  status: "active"
42216
42284
  });
42217
42285
  return { worktree_id: res.data.id };
@@ -42762,15 +42830,15 @@ var init_e2e = __esm({
42762
42830
  });
42763
42831
 
42764
42832
  // src/cli/e2e/verify-round.ts
42765
- import { readFile as readFile33 } from "node:fs/promises";
42766
- import { resolve as resolve14 } from "node:path";
42833
+ import { readFile as readFile34 } from "node:fs/promises";
42834
+ import { resolve as resolve15 } from "node:path";
42767
42835
  async function defaultFetchRounds(taskId) {
42768
42836
  return mcpCall("get_rounds", { task_id: taskId });
42769
42837
  }
42770
42838
  async function defaultReadE2eConfig(cwd) {
42771
42839
  try {
42772
- const p = resolve14(cwd, ".codebyplan", "e2e.json");
42773
- const raw = await readFile33(p, "utf-8");
42840
+ const p = resolve15(cwd, ".codebyplan", "e2e.json");
42841
+ const raw = await readFile34(p, "utf-8");
42774
42842
  return JSON.parse(raw);
42775
42843
  } catch {
42776
42844
  return null;
@@ -43184,11 +43252,11 @@ var init_doctor = __esm({
43184
43252
  // src/index.ts
43185
43253
  init_version();
43186
43254
  import { readFileSync as readFileSync20 } from "node:fs";
43187
- import { resolve as resolve15 } from "node:path";
43255
+ import { resolve as resolve16 } from "node:path";
43188
43256
  void (async () => {
43189
43257
  if (!process.env.CODEBYPLAN_API_KEY) {
43190
43258
  try {
43191
- const envPath = resolve15(process.cwd(), ".env.local");
43259
+ const envPath = resolve16(process.cwd(), ".env.local");
43192
43260
  const content = readFileSync20(envPath, "utf-8");
43193
43261
  for (const line of content.split("\n")) {
43194
43262
  const trimmed = line.trim();