codebyplan 1.13.59 → 1.13.61

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 (3) hide show
  1. package/dist/ci.js +518 -0
  2. package/dist/cli.js +433 -373
  3. package/package.json +12 -2
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.59";
51
+ VERSION = "1.13.61";
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
  }
@@ -880,29 +880,42 @@ async function deleteFallback(filename) {
880
880
  } catch {
881
881
  }
882
882
  }
883
+ function useKeychain() {
884
+ const v = process.env.CODEBYPLAN_USE_KEYCHAIN;
885
+ return v === "1" || v === "true";
886
+ }
883
887
  async function saveTokens(tokens) {
884
- const Keyring = await loadKeyring();
885
- if (Keyring) {
886
- try {
887
- new Keyring(SERVICE, TOKEN_ACCOUNT).setPassword(JSON.stringify(tokens));
888
- return;
889
- } catch {
888
+ if (useKeychain()) {
889
+ const Keyring = await loadKeyring();
890
+ if (Keyring) {
891
+ try {
892
+ new Keyring(SERVICE, TOKEN_ACCOUNT).setPassword(JSON.stringify(tokens));
893
+ return;
894
+ } catch {
895
+ }
890
896
  }
891
897
  }
892
898
  await writeFallback("credentials.json", tokens);
893
899
  }
894
900
  async function loadTokens() {
901
+ const fromFile = await readFallback("credentials.json");
902
+ if (fromFile) return fromFile;
895
903
  const Keyring = await loadKeyring();
896
904
  if (Keyring) {
897
905
  try {
898
906
  const raw = new Keyring(SERVICE, TOKEN_ACCOUNT).getPassword();
899
- if (raw) return JSON.parse(raw);
907
+ if (raw) {
908
+ const tokens = JSON.parse(raw);
909
+ if (!useKeychain()) await writeFallback("credentials.json", tokens);
910
+ return tokens;
911
+ }
900
912
  } catch {
901
913
  }
902
914
  }
903
- return readFallback("credentials.json");
915
+ return null;
904
916
  }
905
917
  async function clearTokens() {
918
+ await deleteFallback("credentials.json");
906
919
  const Keyring = await loadKeyring();
907
920
  if (Keyring) {
908
921
  try {
@@ -910,31 +923,39 @@ async function clearTokens() {
910
923
  } catch {
911
924
  }
912
925
  }
913
- await deleteFallback("credentials.json");
914
926
  }
915
927
  async function saveClientRegistration(reg) {
916
- const Keyring = await loadKeyring();
917
- if (Keyring) {
918
- try {
919
- new Keyring(SERVICE, CLIENT_ACCOUNT).setPassword(JSON.stringify(reg));
920
- return;
921
- } catch {
928
+ if (useKeychain()) {
929
+ const Keyring = await loadKeyring();
930
+ if (Keyring) {
931
+ try {
932
+ new Keyring(SERVICE, CLIENT_ACCOUNT).setPassword(JSON.stringify(reg));
933
+ return;
934
+ } catch {
935
+ }
922
936
  }
923
937
  }
924
938
  await writeFallback("client.json", reg);
925
939
  }
926
940
  async function loadClientRegistration() {
941
+ const fromFile = await readFallback("client.json");
942
+ if (fromFile) return fromFile;
927
943
  const Keyring = await loadKeyring();
928
944
  if (Keyring) {
929
945
  try {
930
946
  const raw = new Keyring(SERVICE, CLIENT_ACCOUNT).getPassword();
931
- if (raw) return JSON.parse(raw);
947
+ if (raw) {
948
+ const reg = JSON.parse(raw);
949
+ if (!useKeychain()) await writeFallback("client.json", reg);
950
+ return reg;
951
+ }
932
952
  } catch {
933
953
  }
934
954
  }
935
- return readFallback("client.json");
955
+ return null;
936
956
  }
937
957
  async function clearClientRegistration() {
958
+ await deleteFallback("client.json");
938
959
  const Keyring = await loadKeyring();
939
960
  if (Keyring) {
940
961
  try {
@@ -942,7 +963,6 @@ async function clearClientRegistration() {
942
963
  } catch {
943
964
  }
944
965
  }
945
- await deleteFallback("client.json");
946
966
  }
947
967
  var SERVICE, TOKEN_ACCOUNT, CLIENT_ACCOUNT, keyringOverride;
948
968
  var init_keychain = __esm({
@@ -1163,8 +1183,8 @@ async function validateConnectivity() {
1163
1183
  );
1164
1184
  }
1165
1185
  }
1166
- function buildUrl(path22, params) {
1167
- const url = new URL(`${baseUrl()}/api${path22}`);
1186
+ function buildUrl(path23, params) {
1187
+ const url = new URL(`${baseUrl()}/api${path23}`);
1168
1188
  if (params) {
1169
1189
  for (const [key, value] of Object.entries(params)) {
1170
1190
  if (value !== void 0) {
@@ -1181,10 +1201,10 @@ function isRetryable(err) {
1181
1201
  return false;
1182
1202
  }
1183
1203
  function delay(ms) {
1184
- return new Promise((resolve16) => setTimeout(resolve16, ms));
1204
+ return new Promise((resolve17) => setTimeout(resolve17, ms));
1185
1205
  }
1186
- async function request(method, path22, options) {
1187
- const url = buildUrl(path22, options?.params);
1206
+ async function request(method, path23, options) {
1207
+ const url = buildUrl(path23, options?.params);
1188
1208
  const auth = await getAuthHeaders();
1189
1209
  let lastError;
1190
1210
  for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
@@ -1204,7 +1224,7 @@ async function request(method, path22, options) {
1204
1224
  signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS)
1205
1225
  });
1206
1226
  if (!res.ok) {
1207
- let message = `API ${method} ${path22} failed with status ${res.status}`;
1227
+ let message = `API ${method} ${path23} failed with status ${res.status}`;
1208
1228
  let code;
1209
1229
  try {
1210
1230
  const body = await res.json();
@@ -1238,20 +1258,20 @@ async function request(method, path22, options) {
1238
1258
  }
1239
1259
  throw lastError;
1240
1260
  }
1241
- async function apiGet(path22, params) {
1242
- return request("GET", path22, { params });
1261
+ async function apiGet(path23, params) {
1262
+ return request("GET", path23, { params });
1243
1263
  }
1244
- async function apiPost(path22, body) {
1245
- return request("POST", path22, { body });
1264
+ async function apiPost(path23, body) {
1265
+ return request("POST", path23, { body });
1246
1266
  }
1247
- async function apiPut(path22, body) {
1248
- return request("PUT", path22, { body });
1267
+ async function apiPut(path23, body) {
1268
+ return request("PUT", path23, { body });
1249
1269
  }
1250
- async function apiPatch(path22, body) {
1251
- return request("PATCH", path22, { body });
1270
+ async function apiPatch(path23, body) {
1271
+ return request("PATCH", path23, { body });
1252
1272
  }
1253
- async function apiDelete(path22, params) {
1254
- await request("DELETE", path22, { params });
1273
+ async function apiDelete(path23, params) {
1274
+ await request("DELETE", path23, { params });
1255
1275
  }
1256
1276
  async function callMcpTool(toolName, params) {
1257
1277
  const url = mcpEndpoint();
@@ -1545,7 +1565,7 @@ var init_device_flow = __esm({
1545
1565
  this.name = "OAuthInvalidClientError";
1546
1566
  }
1547
1567
  };
1548
- defaultSleep = (ms) => new Promise((resolve16) => setTimeout(resolve16, ms));
1568
+ defaultSleep = (ms) => new Promise((resolve17) => setTimeout(resolve17, ms));
1549
1569
  }
1550
1570
  });
1551
1571
 
@@ -2303,7 +2323,7 @@ async function defaultPromptRemoveIgnore(displayLine, opts) {
2303
2323
  });
2304
2324
  try {
2305
2325
  while (true) {
2306
- const answer = await new Promise((resolve16) => {
2326
+ const answer = await new Promise((resolve17) => {
2307
2327
  rl.question(
2308
2328
  `The following gitignore rule matches .claude/settings.json:
2309
2329
  ${displayLine}
@@ -2311,7 +2331,7 @@ Remove this line?
2311
2331
  [r] remove [k] keep
2312
2332
  > `,
2313
2333
  (input) => {
2314
- resolve16(input.trim().toLowerCase());
2334
+ resolve17(input.trim().toLowerCase());
2315
2335
  }
2316
2336
  );
2317
2337
  });
@@ -3673,9 +3693,9 @@ import { createInterface } from "node:readline/promises";
3673
3693
  function getConfigPath(scope) {
3674
3694
  return scope === "user" ? join15(homedir4(), ".claude.json") : join15(process.cwd(), ".mcp.json");
3675
3695
  }
3676
- async function readConfig(path22) {
3696
+ async function readConfig(path23) {
3677
3697
  try {
3678
- const raw = await readFile12(path22, "utf-8");
3698
+ const raw = await readFile12(path23, "utf-8");
3679
3699
  const parsed = JSON.parse(raw);
3680
3700
  if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) {
3681
3701
  return parsed;
@@ -4106,9 +4126,9 @@ import { join as join16 } from "node:path";
4106
4126
  function configPaths() {
4107
4127
  return [join16(homedir5(), ".claude.json"), join16(process.cwd(), ".mcp.json")];
4108
4128
  }
4109
- async function readConfig2(path22) {
4129
+ async function readConfig2(path23) {
4110
4130
  try {
4111
- const raw = await readFile13(path22, "utf-8");
4131
+ const raw = await readFile13(path23, "utf-8");
4112
4132
  const parsed = JSON.parse(raw);
4113
4133
  if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) {
4114
4134
  return parsed;
@@ -4122,7 +4142,7 @@ function entryHasLegacyApiKey(entry) {
4122
4142
  if (!entry || !entry.headers) return false;
4123
4143
  return "x-api-key" in entry.headers;
4124
4144
  }
4125
- async function rewriteConfig(path22, config, newUrl) {
4145
+ async function rewriteConfig(path23, config, newUrl) {
4126
4146
  const servers = config.mcpServers;
4127
4147
  if (!servers) return false;
4128
4148
  const entry = servers.codebyplan;
@@ -4130,7 +4150,7 @@ async function rewriteConfig(path22, config, newUrl) {
4130
4150
  if (!entryHasLegacyApiKey(entry) && entry.url === newUrl && entry.type === "http")
4131
4151
  return false;
4132
4152
  servers.codebyplan = { type: "http", url: newUrl };
4133
- await writeFile10(path22, JSON.stringify(config, null, 2) + "\n", "utf-8");
4153
+ await writeFile10(path23, JSON.stringify(config, null, 2) + "\n", "utf-8");
4134
4154
  return true;
4135
4155
  }
4136
4156
  async function runUpgradeAuth() {
@@ -4138,12 +4158,12 @@ async function runUpgradeAuth() {
4138
4158
  await runLogin();
4139
4159
  const newUrl = mcpEndpoint();
4140
4160
  let migrated = 0;
4141
- for (const path22 of configPaths()) {
4142
- const config = await readConfig2(path22);
4161
+ for (const path23 of configPaths()) {
4162
+ const config = await readConfig2(path23);
4143
4163
  if (!config) continue;
4144
- const changed = await rewriteConfig(path22, config, newUrl);
4164
+ const changed = await rewriteConfig(path23, config, newUrl);
4145
4165
  if (changed) {
4146
- console.log(` Updated ${path22}`);
4166
+ console.log(` Updated ${path23}`);
4147
4167
  migrated++;
4148
4168
  }
4149
4169
  }
@@ -5730,11 +5750,11 @@ function __metadata(metadataKey, metadataValue) {
5730
5750
  }
5731
5751
  function __awaiter(thisArg, _arguments, P, generator) {
5732
5752
  function adopt(value) {
5733
- return value instanceof P ? value : new P(function(resolve16) {
5734
- resolve16(value);
5753
+ return value instanceof P ? value : new P(function(resolve17) {
5754
+ resolve17(value);
5735
5755
  });
5736
5756
  }
5737
- return new (P || (P = Promise))(function(resolve16, reject) {
5757
+ return new (P || (P = Promise))(function(resolve17, reject) {
5738
5758
  function fulfilled(value) {
5739
5759
  try {
5740
5760
  step(generator.next(value));
@@ -5750,7 +5770,7 @@ function __awaiter(thisArg, _arguments, P, generator) {
5750
5770
  }
5751
5771
  }
5752
5772
  function step(result) {
5753
- result.done ? resolve16(result.value) : adopt(result.value).then(fulfilled, rejected);
5773
+ result.done ? resolve17(result.value) : adopt(result.value).then(fulfilled, rejected);
5754
5774
  }
5755
5775
  step((generator = generator.apply(thisArg, _arguments || [])).next());
5756
5776
  });
@@ -5941,14 +5961,14 @@ function __asyncValues(o) {
5941
5961
  }, i);
5942
5962
  function verb(n) {
5943
5963
  i[n] = o[n] && function(v) {
5944
- return new Promise(function(resolve16, reject) {
5945
- 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);
5946
5966
  });
5947
5967
  };
5948
5968
  }
5949
- function settle(resolve16, reject, d, v) {
5969
+ function settle(resolve17, reject, d, v) {
5950
5970
  Promise.resolve(v).then(function(v2) {
5951
- resolve16({ value: v2, done: d });
5971
+ resolve17({ value: v2, done: d });
5952
5972
  }, reject);
5953
5973
  }
5954
5974
  }
@@ -6040,13 +6060,13 @@ function __disposeResources(env) {
6040
6060
  }
6041
6061
  return next();
6042
6062
  }
6043
- function __rewriteRelativeImportExtension(path22, preserveJsx) {
6044
- if (typeof path22 === "string" && /^\.\.?\//.test(path22)) {
6045
- 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) {
6046
6066
  return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : d + ext + "." + cm.toLowerCase() + "js";
6047
6067
  });
6048
6068
  }
6049
- return path22;
6069
+ return path23;
6050
6070
  }
6051
6071
  var extendStatics, __assign, __createBinding, __setModuleDefault, ownKeys, _SuppressedError, tslib_es6_default;
6052
6072
  var init_tslib_es6 = __esm({
@@ -6521,18 +6541,18 @@ var require_main = __commonJS({
6521
6541
 
6522
6542
  // ../../node_modules/.pnpm/@supabase+postgrest-js@2.106.0/node_modules/@supabase/postgrest-js/dist/index.mjs
6523
6543
  function sleep(ms, signal) {
6524
- return new Promise((resolve16) => {
6544
+ return new Promise((resolve17) => {
6525
6545
  if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
6526
- resolve16();
6546
+ resolve17();
6527
6547
  return;
6528
6548
  }
6529
6549
  const id = setTimeout(() => {
6530
6550
  signal === null || signal === void 0 || signal.removeEventListener("abort", onAbort);
6531
- resolve16();
6551
+ resolve17();
6532
6552
  }, ms);
6533
6553
  function onAbort() {
6534
6554
  clearTimeout(id);
6535
- resolve16();
6555
+ resolve17();
6536
6556
  }
6537
6557
  signal === null || signal === void 0 || signal.addEventListener("abort", onAbort);
6538
6558
  });
@@ -14569,15 +14589,15 @@ var require_RealtimeChannel = __commonJS({
14569
14589
  }
14570
14590
  }
14571
14591
  } else {
14572
- return new Promise((resolve16) => {
14592
+ return new Promise((resolve17) => {
14573
14593
  var _a2, _b2, _c;
14574
14594
  const push = this.channelAdapter.push(args.type, args, opts.timeout || this.timeout);
14575
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)) {
14576
- resolve16("ok");
14596
+ resolve17("ok");
14577
14597
  }
14578
- push.receive("ok", () => resolve16("ok"));
14579
- push.receive("error", () => resolve16("error"));
14580
- 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"));
14581
14601
  });
14582
14602
  }
14583
14603
  }
@@ -14602,8 +14622,8 @@ var require_RealtimeChannel = __commonJS({
14602
14622
  * @category Realtime
14603
14623
  */
14604
14624
  async unsubscribe(timeout = this.timeout) {
14605
- return new Promise((resolve16) => {
14606
- 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"));
14607
14627
  });
14608
14628
  }
14609
14629
  /**
@@ -14807,11 +14827,11 @@ var require_socketAdapter = __commonJS({
14807
14827
  this.socket.connect();
14808
14828
  }
14809
14829
  disconnect(callback, code, reason, timeout = 1e4) {
14810
- return new Promise((resolve16) => {
14811
- setTimeout(() => resolve16("timeout"), timeout);
14830
+ return new Promise((resolve17) => {
14831
+ setTimeout(() => resolve17("timeout"), timeout);
14812
14832
  this.socket.disconnect(() => {
14813
14833
  callback();
14814
- resolve16("ok");
14834
+ resolve17("ok");
14815
14835
  }, code, reason);
14816
14836
  });
14817
14837
  }
@@ -15568,8 +15588,8 @@ var require_main2 = __commonJS({
15568
15588
  });
15569
15589
 
15570
15590
  // ../../node_modules/.pnpm/iceberg-js@0.8.1/node_modules/iceberg-js/dist/index.mjs
15571
- function buildUrl2(baseUrl3, path22, query) {
15572
- const url = new URL(path22, baseUrl3);
15591
+ function buildUrl2(baseUrl3, path23, query) {
15592
+ const url = new URL(path23, baseUrl3);
15573
15593
  if (query) {
15574
15594
  for (const [key, value] of Object.entries(query)) {
15575
15595
  if (value !== void 0) {
@@ -15599,12 +15619,12 @@ function createFetchClient(options) {
15599
15619
  return {
15600
15620
  async request({
15601
15621
  method,
15602
- path: path22,
15622
+ path: path23,
15603
15623
  query,
15604
15624
  body,
15605
15625
  headers
15606
15626
  }) {
15607
- const url = buildUrl2(options.baseUrl, path22, query);
15627
+ const url = buildUrl2(options.baseUrl, path23, query);
15608
15628
  const authHeaders = await buildAuthHeaders(options.auth);
15609
15629
  const res = await fetchFn(url, {
15610
15630
  method,
@@ -16173,7 +16193,7 @@ function normalizeHeaders(headers) {
16173
16193
  return result;
16174
16194
  }
16175
16195
  async function _handleRequest(fetcher, method, url, options, parameters, body, namespace) {
16176
- return new Promise((resolve16, reject) => {
16196
+ return new Promise((resolve17, reject) => {
16177
16197
  fetcher(url, _getRequestParams(method, options, parameters, body)).then((result) => {
16178
16198
  if (!result.ok) throw result;
16179
16199
  if (options === null || options === void 0 ? void 0 : options.noResolveJson) return result;
@@ -16183,7 +16203,7 @@ async function _handleRequest(fetcher, method, url, options, parameters, body, n
16183
16203
  if (!contentType || !contentType.includes("application/json")) return {};
16184
16204
  }
16185
16205
  return result.json();
16186
- }).then((data) => resolve16(data)).catch((error) => handleError(error, reject, options, namespace));
16206
+ }).then((data) => resolve17(data)).catch((error) => handleError(error, reject, options, namespace));
16187
16207
  });
16188
16208
  }
16189
16209
  function createFetchApi(namespace = "storage") {
@@ -16502,7 +16522,7 @@ var init_dist3 = __esm({
16502
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.
16503
16523
  * @param fileBody The body of the file to be stored in the bucket.
16504
16524
  */
16505
- async uploadOrUpdate(method, path22, fileBody, fileOptions) {
16525
+ async uploadOrUpdate(method, path23, fileBody, fileOptions) {
16506
16526
  var _this = this;
16507
16527
  return _this.handleOperation(async () => {
16508
16528
  let body;
@@ -16526,7 +16546,7 @@ var init_dist3 = __esm({
16526
16546
  if ((typeof ReadableStream !== "undefined" && body instanceof ReadableStream || body && typeof body === "object" && "pipe" in body && typeof body.pipe === "function") && !options.duplex) options.duplex = "half";
16527
16547
  }
16528
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);
16529
- const cleanPath = _this._removeEmptyFolders(path22);
16549
+ const cleanPath = _this._removeEmptyFolders(path23);
16530
16550
  const _path = _this._getFinalPath(cleanPath);
16531
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 } : {}));
16532
16552
  return {
@@ -16588,8 +16608,8 @@ var init_dist3 = __esm({
16588
16608
  * - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
16589
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.
16590
16610
  */
16591
- async upload(path22, fileBody, fileOptions) {
16592
- return this.uploadOrUpdate("POST", path22, fileBody, fileOptions);
16611
+ async upload(path23, fileBody, fileOptions) {
16612
+ return this.uploadOrUpdate("POST", path23, fileBody, fileOptions);
16593
16613
  }
16594
16614
  /**
16595
16615
  * Upload a file with a token generated from `createSignedUploadUrl`.
@@ -16629,9 +16649,9 @@ var init_dist3 = __esm({
16629
16649
  * - `objects` table permissions: none
16630
16650
  * - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
16631
16651
  */
16632
- async uploadToSignedUrl(path22, token, fileBody, fileOptions) {
16652
+ async uploadToSignedUrl(path23, token, fileBody, fileOptions) {
16633
16653
  var _this3 = this;
16634
- const cleanPath = _this3._removeEmptyFolders(path22);
16654
+ const cleanPath = _this3._removeEmptyFolders(path23);
16635
16655
  const _path = _this3._getFinalPath(cleanPath);
16636
16656
  const url = new URL(_this3.url + `/object/upload/sign/${_path}`);
16637
16657
  url.searchParams.set("token", token);
@@ -16700,10 +16720,10 @@ var init_dist3 = __esm({
16700
16720
  * - `objects` table permissions: `insert`
16701
16721
  * - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
16702
16722
  */
16703
- async createSignedUploadUrl(path22, options) {
16723
+ async createSignedUploadUrl(path23, options) {
16704
16724
  var _this4 = this;
16705
16725
  return _this4.handleOperation(async () => {
16706
- let _path = _this4._getFinalPath(path22);
16726
+ let _path = _this4._getFinalPath(path23);
16707
16727
  const headers = _objectSpread22({}, _this4.headers);
16708
16728
  if (options === null || options === void 0 ? void 0 : options.upsert) headers["x-upsert"] = "true";
16709
16729
  const data = await post(_this4.fetch, `${_this4.url}/object/upload/sign/${_path}`, {}, { headers });
@@ -16712,7 +16732,7 @@ var init_dist3 = __esm({
16712
16732
  if (!token) throw new StorageError("No token returned by API");
16713
16733
  return {
16714
16734
  signedUrl: url.toString(),
16715
- path: path22,
16735
+ path: path23,
16716
16736
  token
16717
16737
  };
16718
16738
  });
@@ -16772,8 +16792,8 @@ var init_dist3 = __esm({
16772
16792
  * - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
16773
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.
16774
16794
  */
16775
- async update(path22, fileBody, fileOptions) {
16776
- return this.uploadOrUpdate("PUT", path22, fileBody, fileOptions);
16795
+ async update(path23, fileBody, fileOptions) {
16796
+ return this.uploadOrUpdate("PUT", path23, fileBody, fileOptions);
16777
16797
  }
16778
16798
  /**
16779
16799
  * Moves an existing file to a new path in the same bucket.
@@ -16924,10 +16944,10 @@ var init_dist3 = __esm({
16924
16944
  * - `objects` table permissions: `select`
16925
16945
  * - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
16926
16946
  */
16927
- async createSignedUrl(path22, expiresIn, options) {
16947
+ async createSignedUrl(path23, expiresIn, options) {
16928
16948
  var _this8 = this;
16929
16949
  return _this8.handleOperation(async () => {
16930
- let _path = _this8._getFinalPath(path22);
16950
+ let _path = _this8._getFinalPath(path23);
16931
16951
  const hasTransform = typeof (options === null || options === void 0 ? void 0 : options.transform) === "object" && options.transform !== null && Object.keys(options.transform).length > 0;
16932
16952
  let data = await post(_this8.fetch, `${_this8.url}/object/sign/${_path}`, _objectSpread22({ expiresIn }, hasTransform ? { transform: options.transform } : {}), { headers: _this8.headers });
16933
16953
  const query = new URLSearchParams();
@@ -17063,13 +17083,13 @@ var init_dist3 = __esm({
17063
17083
  * - `objects` table permissions: `select`
17064
17084
  * - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
17065
17085
  */
17066
- download(path22, options, parameters) {
17086
+ download(path23, options, parameters) {
17067
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";
17068
17088
  const query = new URLSearchParams();
17069
17089
  if (options === null || options === void 0 ? void 0 : options.transform) this.applyTransformOptsToQuery(query, options.transform);
17070
17090
  if ((options === null || options === void 0 ? void 0 : options.cacheNonce) != null) query.set("cacheNonce", String(options.cacheNonce));
17071
17091
  const queryString = query.toString();
17072
- const _path = this._getFinalPath(path22);
17092
+ const _path = this._getFinalPath(path23);
17073
17093
  const downloadFn = () => get(this.fetch, `${this.url}/${renderPath}/${_path}${queryString ? `?${queryString}` : ""}`, {
17074
17094
  headers: this.headers,
17075
17095
  noResolveJson: true
@@ -17100,9 +17120,9 @@ var init_dist3 = __esm({
17100
17120
  * }
17101
17121
  * ```
17102
17122
  */
17103
- async info(path22) {
17123
+ async info(path23) {
17104
17124
  var _this10 = this;
17105
- const _path = _this10._getFinalPath(path22);
17125
+ const _path = _this10._getFinalPath(path23);
17106
17126
  return _this10.handleOperation(async () => {
17107
17127
  return recursiveToCamel(await get(_this10.fetch, `${_this10.url}/object/info/${_path}`, { headers: _this10.headers }));
17108
17128
  });
@@ -17123,9 +17143,9 @@ var init_dist3 = __esm({
17123
17143
  * .exists('folder/avatar1.png')
17124
17144
  * ```
17125
17145
  */
17126
- async exists(path22) {
17146
+ async exists(path23) {
17127
17147
  var _this11 = this;
17128
- const _path = _this11._getFinalPath(path22);
17148
+ const _path = _this11._getFinalPath(path23);
17129
17149
  try {
17130
17150
  await head(_this11.fetch, `${_this11.url}/object/${_path}`, { headers: _this11.headers });
17131
17151
  return {
@@ -17204,8 +17224,8 @@ var init_dist3 = __esm({
17204
17224
  * - `objects` table permissions: none
17205
17225
  * - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
17206
17226
  */
17207
- getPublicUrl(path22, options) {
17208
- const _path = this._getFinalPath(path22);
17227
+ getPublicUrl(path23, options) {
17228
+ const _path = this._getFinalPath(path23);
17209
17229
  const query = new URLSearchParams();
17210
17230
  if (options === null || options === void 0 ? void 0 : options.download) query.set("download", options.download === true ? "" : options.download);
17211
17231
  if (options === null || options === void 0 ? void 0 : options.transform) this.applyTransformOptsToQuery(query, options.transform);
@@ -17344,10 +17364,10 @@ var init_dist3 = __esm({
17344
17364
  * - `objects` table permissions: `select`
17345
17365
  * - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
17346
17366
  */
17347
- async list(path22, options, parameters) {
17367
+ async list(path23, options, parameters) {
17348
17368
  var _this13 = this;
17349
17369
  return _this13.handleOperation(async () => {
17350
- const body = _objectSpread22(_objectSpread22(_objectSpread22({}, DEFAULT_SEARCH_OPTIONS), options), {}, { prefix: path22 || "" });
17370
+ const body = _objectSpread22(_objectSpread22(_objectSpread22({}, DEFAULT_SEARCH_OPTIONS), options), {}, { prefix: path23 || "" });
17351
17371
  return await post(_this13.fetch, `${_this13.url}/object/list/${_this13.bucketId}`, body, { headers: _this13.headers }, parameters);
17352
17372
  });
17353
17373
  }
@@ -17412,11 +17432,11 @@ var init_dist3 = __esm({
17412
17432
  if (typeof Buffer !== "undefined") return Buffer.from(data).toString("base64");
17413
17433
  return btoa(data);
17414
17434
  }
17415
- _getFinalPath(path22) {
17416
- return `${this.bucketId}/${path22.replace(/^\/+/, "")}`;
17435
+ _getFinalPath(path23) {
17436
+ return `${this.bucketId}/${path23.replace(/^\/+/, "")}`;
17417
17437
  }
17418
- _removeEmptyFolders(path22) {
17419
- return path22.replace(/^\/|\/$/g, "").replace(/\/+/g, "/");
17438
+ _removeEmptyFolders(path23) {
17439
+ return path23.replace(/^\/|\/$/g, "").replace(/\/+/g, "/");
17420
17440
  }
17421
17441
  /** Modifies the `query`, appending values the from `transform` */
17422
17442
  applyTransformOptsToQuery(query, transform) {
@@ -26794,11 +26814,11 @@ __export(dist_exports, {
26794
26814
  });
26795
26815
  function __awaiter2(thisArg, _arguments, P, generator) {
26796
26816
  function adopt(value) {
26797
- return value instanceof P ? value : new P(function(resolve16) {
26798
- resolve16(value);
26817
+ return value instanceof P ? value : new P(function(resolve17) {
26818
+ resolve17(value);
26799
26819
  });
26800
26820
  }
26801
- return new (P || (P = Promise))(function(resolve16, reject) {
26821
+ return new (P || (P = Promise))(function(resolve17, reject) {
26802
26822
  function fulfilled(value) {
26803
26823
  try {
26804
26824
  step(generator.next(value));
@@ -26814,7 +26834,7 @@ function __awaiter2(thisArg, _arguments, P, generator) {
26814
26834
  }
26815
26835
  }
26816
26836
  function step(result) {
26817
- result.done ? resolve16(result.value) : adopt(result.value).then(fulfilled, rejected);
26837
+ result.done ? resolve17(result.value) : adopt(result.value).then(fulfilled, rejected);
26818
26838
  }
26819
26839
  step((generator = generator.apply(thisArg, _arguments || [])).next());
26820
26840
  });
@@ -27549,8 +27569,8 @@ var init_watch_daemon = __esm({
27549
27569
  );
27550
27570
  }
27551
27571
  this.startSafetyPoll(repoRoot, repoId, worktreeId);
27552
- await new Promise((resolve16) => {
27553
- this.stopResolve = resolve16;
27572
+ await new Promise((resolve17) => {
27573
+ this.stopResolve = resolve17;
27554
27574
  });
27555
27575
  }
27556
27576
  /**
@@ -27821,7 +27841,7 @@ var init_watch_daemon = __esm({
27821
27841
  }
27822
27842
  /** Sleep for `ms` milliseconds — uses setTimeout so fake timers work in tests. */
27823
27843
  sleep(ms) {
27824
- return new Promise((resolve16) => setTimeout(resolve16, ms));
27844
+ return new Promise((resolve17) => setTimeout(resolve17, ms));
27825
27845
  }
27826
27846
  };
27827
27847
  }
@@ -28138,8 +28158,8 @@ var init_watch = __esm({
28138
28158
  function isConflict(err) {
28139
28159
  return err instanceof BackendError && err.status === 409;
28140
28160
  }
28141
- async function backendRequest(method, path22, body) {
28142
- const url = `${getBackendBase()}${path22}`;
28161
+ async function backendRequest(method, path23, body) {
28162
+ const url = `${getBackendBase()}${path23}`;
28143
28163
  const auth = await getAuthHeaders();
28144
28164
  const res = await fetch(url, {
28145
28165
  method,
@@ -28151,7 +28171,7 @@ async function backendRequest(method, path22, body) {
28151
28171
  signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS2)
28152
28172
  });
28153
28173
  if (!res.ok) {
28154
- let message = `Backend ${method} ${path22} failed with status ${res.status}`;
28174
+ let message = `Backend ${method} ${path23} failed with status ${res.status}`;
28155
28175
  try {
28156
28176
  const errBody = await res.json();
28157
28177
  const msg = typeof errBody.message === "string" ? errBody.message : typeof errBody.error === "string" ? errBody.error : void 0;
@@ -28165,11 +28185,11 @@ async function backendRequest(method, path22, body) {
28165
28185
  }
28166
28186
  return res.json();
28167
28187
  }
28168
- async function apiBackendPost(path22, body) {
28169
- return backendRequest("POST", path22, body);
28188
+ async function apiBackendPost(path23, body) {
28189
+ return backendRequest("POST", path23, body);
28170
28190
  }
28171
- async function apiBackendPatch(path22, body) {
28172
- return backendRequest("PATCH", path22, body);
28191
+ async function apiBackendPatch(path23, body) {
28192
+ return backendRequest("PATCH", path23, body);
28173
28193
  }
28174
28194
  var REQUEST_TIMEOUT_MS2, BackendError;
28175
28195
  var init_state_client = __esm({
@@ -28445,8 +28465,8 @@ ${taskRows}
28445
28465
  for (const task of data.tasks) {
28446
28466
  if (Array.isArray(task.files_changed)) {
28447
28467
  for (const f of task.files_changed) {
28448
- const path22 = typeof f === "string" ? f : f?.path;
28449
- if (path22) allFiles.add(path22);
28468
+ const path23 = typeof f === "string" ? f : f?.path;
28469
+ if (path23) allFiles.add(path23);
28450
28470
  }
28451
28471
  }
28452
28472
  }
@@ -29368,7 +29388,7 @@ function setRetryDelayMs(ms) {
29368
29388
  RETRY_DELAY_MS = ms;
29369
29389
  }
29370
29390
  function sleep2(ms) {
29371
- return new Promise((resolve16) => setTimeout(resolve16, ms));
29391
+ return new Promise((resolve17) => setTimeout(resolve17, ms));
29372
29392
  }
29373
29393
  function isTransientMcpError(err) {
29374
29394
  if (!(err instanceof McpError)) return false;
@@ -30508,7 +30528,7 @@ function generateMonotonicTimestamp(opts = {}) {
30508
30528
  }
30509
30529
  async function pollGhPreviewCheck(opts = {}) {
30510
30530
  const run = opts.run ?? defaultRun;
30511
- const sleep3 = opts.sleep ?? ((ms) => new Promise((resolve16) => setTimeout(resolve16, ms)));
30531
+ const sleep3 = opts.sleep ?? ((ms) => new Promise((resolve17) => setTimeout(resolve17, ms)));
30512
30532
  const maxPolls = opts.maxPolls ?? 20;
30513
30533
  const intervalMs = opts.intervalMs ?? 15e3;
30514
30534
  if (!opts.prNumber) {
@@ -33253,12 +33273,60 @@ var init_atomic_write = __esm({
33253
33273
  }
33254
33274
  });
33255
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
+
33256
33323
  // src/lib/ci-init.ts
33257
33324
  import * as fs8 from "node:fs";
33258
- import * as path10 from "node:path";
33259
- function tryReadJson(filePath) {
33325
+ import * as path11 from "node:path";
33326
+ async function tryReadJson(reader, filePath) {
33260
33327
  try {
33261
- return JSON.parse(fs8.readFileSync(filePath, "utf-8"));
33328
+ const raw = await reader.read(filePath);
33329
+ return JSON.parse(raw);
33262
33330
  } catch {
33263
33331
  return null;
33264
33332
  }
@@ -33274,30 +33342,24 @@ function hasDevDep(pkg, name) {
33274
33342
  const devDeps = pkg["devDependencies"];
33275
33343
  return Boolean(devDeps?.[name]);
33276
33344
  }
33277
- function detectPlatforms(projectDir) {
33345
+ async function detectPlatforms(reader) {
33278
33346
  const detected = /* @__PURE__ */ new Set();
33279
- const dirsToScan = [projectDir];
33280
- const appsDir = path10.join(projectDir, "apps");
33281
- if (fs8.existsSync(appsDir)) {
33282
- try {
33283
- const appsEntries = fs8.readdirSync(appsDir, { withFileTypes: true });
33284
- for (const entry of appsEntries) {
33285
- if (entry.isDirectory()) {
33286
- dirsToScan.push(path10.join(appsDir, entry.name));
33287
- }
33288
- }
33289
- } catch {
33290
- }
33347
+ const dirsToScan = [""];
33348
+ const appsChildren = await reader.list("apps");
33349
+ for (const name of appsChildren) {
33350
+ dirsToScan.push(`apps/${name}`);
33291
33351
  }
33292
33352
  for (const dir of dirsToScan) {
33293
- const pkg = tryReadJson(path10.join(dir, "package.json"));
33294
- 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`)) {
33295
33357
  detected.add("next_js");
33296
33358
  }
33297
33359
  if (hasDep(pkg, "@nestjs/core")) {
33298
33360
  detected.add("nestjs");
33299
33361
  }
33300
- 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`)) {
33301
33363
  detected.add("tauri");
33302
33364
  }
33303
33365
  if (hasDevDep(pkg, "@types/vscode")) {
@@ -33308,15 +33370,9 @@ function detectPlatforms(projectDir) {
33308
33370
  detected.add("expo");
33309
33371
  }
33310
33372
  }
33311
- const packagesDir = path10.join(projectDir, "packages");
33312
- if (fs8.existsSync(packagesDir)) {
33313
- try {
33314
- const pkgEntries = fs8.readdirSync(packagesDir, { withFileTypes: true });
33315
- if (pkgEntries.some((e) => e.isDirectory())) {
33316
- detected.add("package");
33317
- }
33318
- } catch {
33319
- }
33373
+ const packagesChildren = await reader.list("packages");
33374
+ if (packagesChildren.length > 0) {
33375
+ detected.add("package");
33320
33376
  }
33321
33377
  if (detected.size === 0) {
33322
33378
  detected.add("package");
@@ -33344,12 +33400,12 @@ function buildDefaultCiConfig(platforms) {
33344
33400
  return config;
33345
33401
  }
33346
33402
  async function runCiInit(opts) {
33347
- await Promise.resolve();
33348
- const projectDir = path10.resolve(opts?.projectDir ?? process.cwd());
33403
+ const projectDir = path11.resolve(opts?.projectDir ?? process.cwd());
33349
33404
  const dryRun = opts?.dryRun ?? false;
33350
33405
  const force = opts?.force ?? false;
33351
- const ciPath = path10.join(projectDir, ".codebyplan", "ci.json");
33352
- 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);
33353
33409
  if (dryRun) {
33354
33410
  return { status: "dry_run", path: ciPath, platforms };
33355
33411
  }
@@ -33393,7 +33449,7 @@ async function runCiInit(opts) {
33393
33449
  platforms: newPlatforms.length > 0 ? newPlatforms : platforms
33394
33450
  };
33395
33451
  }
33396
- const codebyplanDir = path10.join(projectDir, ".codebyplan");
33452
+ const codebyplanDir = path11.join(projectDir, ".codebyplan");
33397
33453
  fs8.mkdirSync(codebyplanDir, { recursive: true });
33398
33454
  writeJsonAtomic(ciPath, newConfig);
33399
33455
  return { status: "written", path: ciPath, platforms };
@@ -33403,6 +33459,7 @@ var init_ci_init = __esm({
33403
33459
  "src/lib/ci-init.ts"() {
33404
33460
  "use strict";
33405
33461
  init_atomic_write();
33462
+ init_repo_reader();
33406
33463
  PLATFORM_COMMAND_MAP = {
33407
33464
  next_js: {
33408
33465
  unit_test: {
@@ -33602,7 +33659,7 @@ var init_ci_init = __esm({
33602
33659
 
33603
33660
  // src/lib/scaffold-ci-workflow.ts
33604
33661
  import * as fs9 from "node:fs";
33605
- import * as path11 from "node:path";
33662
+ import * as path12 from "node:path";
33606
33663
  function substituteTokens(template, tokens) {
33607
33664
  let result = template;
33608
33665
  for (const [token, value] of Object.entries(tokens)) {
@@ -33610,10 +33667,9 @@ function substituteTokens(template, tokens) {
33610
33667
  }
33611
33668
  return result;
33612
33669
  }
33613
- function detectPnpmVersionFromPackageJson(projectDir) {
33670
+ async function detectPnpmVersionFromPackageJson(reader) {
33614
33671
  try {
33615
- const pkgPath = path11.join(projectDir, "package.json");
33616
- const raw = fs9.readFileSync(pkgPath, "utf-8");
33672
+ const raw = await reader.read("package.json");
33617
33673
  const pkg = JSON.parse(raw);
33618
33674
  const pm = pkg.packageManager;
33619
33675
  if (typeof pm === "string" && pm.startsWith("pnpm@")) {
@@ -33627,39 +33683,42 @@ function detectPnpmVersionFromPackageJson(projectDir) {
33627
33683
  return "10";
33628
33684
  }
33629
33685
  }
33630
- function detectStrictEnforcedFromCiJson(projectDir) {
33686
+ async function detectStrictEnforcedFromCiJson(reader) {
33631
33687
  try {
33632
- const ciJsonPath = path11.join(projectDir, ".codebyplan", "ci.json");
33633
- const raw = fs9.readFileSync(ciJsonPath, "utf-8");
33688
+ const raw = await reader.read(".codebyplan/ci.json");
33634
33689
  const parsed = JSON.parse(raw);
33635
33690
  return parsed.workflow?.strict_check_enforced === true;
33636
33691
  } catch {
33637
33692
  return false;
33638
33693
  }
33639
33694
  }
33640
- async function runScaffoldCiWorkflow(opts) {
33641
- await Promise.resolve();
33642
- const dryRun = opts?.dryRun ?? false;
33643
- const force = opts?.force ?? false;
33644
- const projectDir = path11.resolve(opts?.projectDir ?? process.cwd());
33645
- 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);
33646
33699
  const nodeVersion = opts?.nodeVersion ?? "22";
33647
- const strictEnforced = opts?.strictEnforced ?? detectStrictEnforcedFromCiJson(projectDir);
33700
+ const strictEnforced = opts?.strictEnforced ?? await detectStrictEnforcedFromCiJson(reader);
33648
33701
  const templatesDir = opts?.templatesDir ?? resolveTemplatesDir();
33649
- const templatePath = path11.join(templatesDir, "github-workflows", "ci.yml");
33702
+ const templatePath = path12.join(templatesDir, "github-workflows", "ci.yml");
33650
33703
  if (!fs9.existsSync(templatePath)) {
33651
33704
  throw new Error(
33652
33705
  `scaffold-ci-workflow: template not found at ${templatePath}`
33653
33706
  );
33654
33707
  }
33655
33708
  const rawTemplate = fs9.readFileSync(templatePath, "utf-8");
33656
- const renderedContent = substituteTokens(rawTemplate, {
33709
+ return substituteTokens(rawTemplate, {
33657
33710
  PNPM_VERSION: pnpmVersion,
33658
33711
  NODE_VERSION: nodeVersion,
33659
33712
  STRICT_NAME_SUFFIX: strictEnforced ? "" : " (report-only)",
33660
33713
  STRICT_CONTINUE_ON_ERROR_LINE: strictEnforced ? "" : "\n continue-on-error: true"
33661
33714
  });
33662
- 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");
33663
33722
  if (dryRun) {
33664
33723
  return { status: "dry_run", path: targetPath };
33665
33724
  }
@@ -33678,7 +33737,7 @@ async function runScaffoldCiWorkflow(opts) {
33678
33737
  );
33679
33738
  }
33680
33739
  }
33681
- const targetDir = path11.dirname(targetPath);
33740
+ const targetDir = path12.dirname(targetPath);
33682
33741
  fs9.mkdirSync(targetDir, { recursive: true });
33683
33742
  const tmpPath = targetPath + ".tmp";
33684
33743
  try {
@@ -33696,16 +33755,17 @@ async function runScaffoldCiWorkflow(opts) {
33696
33755
  var init_scaffold_ci_workflow = __esm({
33697
33756
  "src/lib/scaffold-ci-workflow.ts"() {
33698
33757
  "use strict";
33699
- init_install();
33758
+ init_templates_dir();
33759
+ init_repo_reader();
33700
33760
  }
33701
33761
  });
33702
33762
 
33703
33763
  // src/lib/gh-required-checks.ts
33704
33764
  import * as fs10 from "node:fs";
33705
- import * as path12 from "node:path";
33765
+ import * as path13 from "node:path";
33706
33766
  import { execSync as execSync6 } from "node:child_process";
33707
33767
  function readCiJson(projectDir) {
33708
- const ciPath = path12.join(projectDir, ".codebyplan", "ci.json");
33768
+ const ciPath = path13.join(projectDir, ".codebyplan", "ci.json");
33709
33769
  if (!fs10.existsSync(ciPath)) {
33710
33770
  return {
33711
33771
  platforms: {},
@@ -33724,15 +33784,15 @@ function readCiJson(projectDir) {
33724
33784
  }
33725
33785
  }
33726
33786
  function writeCiJsonAtomic(projectDir, config) {
33727
- const ciPath = path12.join(projectDir, ".codebyplan", "ci.json");
33787
+ const ciPath = path13.join(projectDir, ".codebyplan", "ci.json");
33728
33788
  writeJsonAtomic(ciPath, config);
33729
33789
  }
33730
33790
  function enforceRequiredCheck(opts) {
33731
- const projectDir = path12.resolve(opts?.projectDir ?? process.cwd());
33791
+ const projectDir = path13.resolve(opts?.projectDir ?? process.cwd());
33732
33792
  const branch = opts?.branch ?? "main";
33733
33793
  const checkName = opts?.checkName ?? "Lint + typecheck + test + build";
33734
33794
  const dryRun = opts?.dryRun ?? false;
33735
- const ciPath = path12.join(projectDir, ".codebyplan", "ci.json");
33795
+ const ciPath = path13.join(projectDir, ".codebyplan", "ci.json");
33736
33796
  const config = readCiJson(projectDir);
33737
33797
  if (config.workflow?.required_check_enforced === true) {
33738
33798
  return { status: "already_enforced", path: ciPath };
@@ -34139,9 +34199,9 @@ var init_ci = __esm({
34139
34199
 
34140
34200
  // src/lib/cd-init.ts
34141
34201
  import * as fs11 from "node:fs";
34142
- import * as path13 from "node:path";
34202
+ import * as path14 from "node:path";
34143
34203
  function detectSurfaces(projectDir) {
34144
- const shipmentPath = path13.join(projectDir, ".codebyplan", "shipment.json");
34204
+ const shipmentPath = path14.join(projectDir, ".codebyplan", "shipment.json");
34145
34205
  let shipment;
34146
34206
  try {
34147
34207
  shipment = JSON.parse(fs11.readFileSync(shipmentPath, "utf-8"));
@@ -34194,10 +34254,10 @@ function buildDefaultCdConfig(rawSurfaceKeys) {
34194
34254
  }
34195
34255
  async function runCdInit(opts) {
34196
34256
  await Promise.resolve();
34197
- const projectDir = path13.resolve(opts?.projectDir ?? process.cwd());
34257
+ const projectDir = path14.resolve(opts?.projectDir ?? process.cwd());
34198
34258
  const dryRun = opts?.dryRun ?? false;
34199
34259
  const force = opts?.force ?? false;
34200
- const cdPath = path13.join(projectDir, ".codebyplan", "cd.json");
34260
+ const cdPath = path14.join(projectDir, ".codebyplan", "cd.json");
34201
34261
  const rawSurfaceKeys = detectSurfaces(projectDir);
34202
34262
  const seen = /* @__PURE__ */ new Set();
34203
34263
  const surfaces = [];
@@ -34238,7 +34298,7 @@ async function runCdInit(opts) {
34238
34298
  surfaces: newSurfaces
34239
34299
  };
34240
34300
  }
34241
- const codebyplanDir = path13.join(projectDir, ".codebyplan");
34301
+ const codebyplanDir = path14.join(projectDir, ".codebyplan");
34242
34302
  fs11.mkdirSync(codebyplanDir, { recursive: true });
34243
34303
  writeJsonAtomic(cdPath, newConfig);
34244
34304
  return { status: "written", path: cdPath, surfaces };
@@ -34328,14 +34388,14 @@ var init_cd_init = __esm({
34328
34388
 
34329
34389
  // src/lib/scaffold-cd-workflow.ts
34330
34390
  import * as fs12 from "node:fs";
34331
- import * as path14 from "node:path";
34391
+ import * as path15 from "node:path";
34332
34392
  async function scaffoldOneWorkflow(templateName, targetName, opts) {
34333
34393
  await Promise.resolve();
34334
34394
  const dryRun = opts.dryRun ?? false;
34335
34395
  const force = opts.force ?? false;
34336
- const projectDir = path14.resolve(opts.projectDir ?? process.cwd());
34396
+ const projectDir = path15.resolve(opts.projectDir ?? process.cwd());
34337
34397
  const templatesDir = opts.templatesDir ?? resolveTemplatesDir();
34338
- const templatePath = path14.join(
34398
+ const templatePath = path15.join(
34339
34399
  templatesDir,
34340
34400
  "github-workflows",
34341
34401
  templateName
@@ -34346,7 +34406,7 @@ async function scaffoldOneWorkflow(templateName, targetName, opts) {
34346
34406
  );
34347
34407
  }
34348
34408
  const templateContent = fs12.readFileSync(templatePath, "utf-8");
34349
- const targetPath = path14.join(projectDir, ".github", "workflows", targetName);
34409
+ const targetPath = path15.join(projectDir, ".github", "workflows", targetName);
34350
34410
  if (dryRun) {
34351
34411
  return { status: "dry_run", path: targetPath };
34352
34412
  }
@@ -34365,7 +34425,7 @@ async function scaffoldOneWorkflow(templateName, targetName, opts) {
34365
34425
  );
34366
34426
  }
34367
34427
  }
34368
- const targetDir = path14.dirname(targetPath);
34428
+ const targetDir = path15.dirname(targetPath);
34369
34429
  fs12.mkdirSync(targetDir, { recursive: true });
34370
34430
  const tmpPath = targetPath + ".tmp";
34371
34431
  try {
@@ -35198,8 +35258,8 @@ var upload_e2e_images_exports = {};
35198
35258
  __export(upload_e2e_images_exports, {
35199
35259
  runUploadE2eImagesCommand: () => runUploadE2eImagesCommand
35200
35260
  });
35201
- import { readFile as readFile20 } from "node:fs/promises";
35202
- 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";
35203
35263
  import { execSync as execSync8 } from "node:child_process";
35204
35264
  function baseUrl2() {
35205
35265
  return (process.env.CODEBYPLAN_API_URL ?? "https://www.codebyplan.com").replace(/\/$/, "");
@@ -35233,7 +35293,7 @@ function parseArgs(args) {
35233
35293
  }
35234
35294
  async function readE2eConfig(projectPath) {
35235
35295
  try {
35236
- const raw = await readFile20(
35296
+ const raw = await readFile21(
35237
35297
  join36(projectPath, ".codebyplan", "e2e.json"),
35238
35298
  "utf-8"
35239
35299
  );
@@ -35314,7 +35374,7 @@ async function runUploadE2eImagesCommand(args) {
35314
35374
  process.exit(1);
35315
35375
  }
35316
35376
  const checkpointId = parsed.checkpointId;
35317
- const projectPath = resolve10(process.cwd());
35377
+ const projectPath = resolve11(process.cwd());
35318
35378
  let repoId = parsed.repoId;
35319
35379
  if (!repoId) {
35320
35380
  const found = await findCodebyplanConfig(projectPath);
@@ -35372,7 +35432,7 @@ async function runUploadE2eImagesCommand(args) {
35372
35432
  for (const png of allPngs) {
35373
35433
  let bytes;
35374
35434
  try {
35375
- bytes = await readFile20(png.absolutePath);
35435
+ bytes = await readFile21(png.absolutePath);
35376
35436
  } catch {
35377
35437
  process.stderr.write(
35378
35438
  `upload-e2e-images: could not read file: ${png.absolutePath}
@@ -35449,8 +35509,8 @@ __export(arch_map_exports, {
35449
35509
  runArchMapCommand: () => runArchMapCommand,
35450
35510
  updateFrontmatterFields: () => updateFrontmatterFields
35451
35511
  });
35452
- import { readFile as readFile21, writeFile as writeFile17 } from "node:fs/promises";
35453
- 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";
35454
35514
  import { join as join37 } from "node:path";
35455
35515
  import { spawnSync as spawnSync12 } from "node:child_process";
35456
35516
  function normalizeModulePath(modulePath) {
@@ -35478,7 +35538,7 @@ async function resolveCodebyplanDir(startDir) {
35478
35538
  async function readArchitectureConfig(codebyplanDir) {
35479
35539
  const filePath = join37(codebyplanDir, "architecture.json");
35480
35540
  try {
35481
- const raw = await readFile21(filePath, "utf-8");
35541
+ const raw = await readFile22(filePath, "utf-8");
35482
35542
  const parsed = JSON.parse(raw);
35483
35543
  if (typeof parsed !== "object" || parsed === null || !Array.isArray(parsed.modules)) {
35484
35544
  return { version: 1, modules: [] };
@@ -35511,7 +35571,7 @@ async function discoverModulePaths(projectRoot) {
35511
35571
  const workspacePath = join37(projectRoot, "pnpm-workspace.yaml");
35512
35572
  let patterns = [];
35513
35573
  try {
35514
- const raw = await readFile21(workspacePath, "utf-8");
35574
+ const raw = await readFile22(workspacePath, "utf-8");
35515
35575
  const lines = raw.split("\n");
35516
35576
  let inPackages = false;
35517
35577
  for (const line of lines) {
@@ -35538,7 +35598,7 @@ async function discoverModulePaths(projectRoot) {
35538
35598
  const absDir = join37(projectRoot, dir);
35539
35599
  try {
35540
35600
  if (existsSync11(absDir)) {
35541
- const entries = readdirSync4(absDir, { withFileTypes: true });
35601
+ const entries = readdirSync3(absDir, { withFileTypes: true });
35542
35602
  for (const entry of entries) {
35543
35603
  if (entry.isDirectory()) {
35544
35604
  paths.push(`${dir}/${entry.name}`);
@@ -35745,7 +35805,7 @@ async function runStamp(modulePath, sha, depthArg, projectRoot) {
35745
35805
  const mapAbsPath = join37(repoRoot, stampedEntry.map_file);
35746
35806
  let mapContent = null;
35747
35807
  try {
35748
- mapContent = await readFile21(mapAbsPath, "utf-8");
35808
+ mapContent = await readFile22(mapAbsPath, "utf-8");
35749
35809
  } catch {
35750
35810
  console.warn(
35751
35811
  " Warning: map file " + stampedEntry.map_file + " not found \u2014 stamped manifest only"
@@ -35947,7 +36007,7 @@ var init_worktree_port_resolver = __esm({
35947
36007
  });
35948
36008
 
35949
36009
  // src/lib/migrate-local-config.ts
35950
- 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";
35951
36011
  import { join as join38 } from "node:path";
35952
36012
  function legacySharedPath(projectPath) {
35953
36013
  return join38(projectPath, ".codebyplan.json");
@@ -35998,7 +36058,7 @@ async function runLocalMigration(projectPath) {
35998
36058
  }
35999
36059
  let legacyRaw;
36000
36060
  try {
36001
- legacyRaw = await readFile22(legacySharedPath(projectPath), "utf-8");
36061
+ legacyRaw = await readFile23(legacySharedPath(projectPath), "utf-8");
36002
36062
  } catch {
36003
36063
  return {
36004
36064
  migrated: true,
@@ -36025,7 +36085,7 @@ async function runLocalMigration(projectPath) {
36025
36085
  let deviceId;
36026
36086
  let deviceWrittenByHelper = false;
36027
36087
  try {
36028
- const localRaw = await readFile22(legacyLocalPath(projectPath), "utf-8");
36088
+ const localRaw = await readFile23(legacyLocalPath(projectPath), "utf-8");
36029
36089
  const localParsed = JSON.parse(localRaw);
36030
36090
  if (typeof localParsed.device_id === "string") {
36031
36091
  deviceId = localParsed.device_id;
@@ -36125,7 +36185,7 @@ async function runLocalMigration(projectPath) {
36125
36185
  }
36126
36186
  const gitignorePath = join38(projectPath, ".gitignore");
36127
36187
  try {
36128
- const gitignoreContent = await readFile22(gitignorePath, "utf-8");
36188
+ const gitignoreContent = await readFile23(gitignorePath, "utf-8");
36129
36189
  const legacyLine = ".codebyplan.local.json";
36130
36190
  const newLine = ".codebyplan/device.local.json";
36131
36191
  const hasLegacy = gitignoreContent.split("\n").some((l) => l.trimEnd() === legacyLine);
@@ -36186,7 +36246,7 @@ __export(config_exports, {
36186
36246
  runConfig: () => runConfig,
36187
36247
  runConfigMigrate: () => runConfigMigrate
36188
36248
  });
36189
- 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";
36190
36250
  import { join as join39 } from "node:path";
36191
36251
  async function runConfig() {
36192
36252
  const flags = parseFlags(3);
@@ -36317,7 +36377,7 @@ async function syncConfigToFile(repoId, projectPath, dryRun) {
36317
36377
  const newJson = JSON.stringify(payload, null, 2) + "\n";
36318
36378
  let currentJson = "";
36319
36379
  try {
36320
- currentJson = await readFile23(filePath, "utf-8");
36380
+ currentJson = await readFile24(filePath, "utf-8");
36321
36381
  } catch {
36322
36382
  }
36323
36383
  if (createOnly && currentJson !== "") continue;
@@ -36332,7 +36392,7 @@ async function syncConfigToFile(repoId, projectPath, dryRun) {
36332
36392
  }
36333
36393
  async function readRepoConfig(projectPath) {
36334
36394
  try {
36335
- const raw = await readFile23(
36395
+ const raw = await readFile24(
36336
36396
  join39(projectPath, ".codebyplan", "repo.json"),
36337
36397
  "utf-8"
36338
36398
  );
@@ -36343,7 +36403,7 @@ async function readRepoConfig(projectPath) {
36343
36403
  }
36344
36404
  async function readServerConfig(projectPath) {
36345
36405
  try {
36346
- const raw = await readFile23(
36406
+ const raw = await readFile24(
36347
36407
  join39(projectPath, ".codebyplan", "server.json"),
36348
36408
  "utf-8"
36349
36409
  );
@@ -36354,7 +36414,7 @@ async function readServerConfig(projectPath) {
36354
36414
  }
36355
36415
  async function readGitConfig2(projectPath) {
36356
36416
  try {
36357
- const raw = await readFile23(
36417
+ const raw = await readFile24(
36358
36418
  join39(projectPath, ".codebyplan", "git.json"),
36359
36419
  "utf-8"
36360
36420
  );
@@ -36365,7 +36425,7 @@ async function readGitConfig2(projectPath) {
36365
36425
  }
36366
36426
  async function readShipmentConfig2(projectPath) {
36367
36427
  try {
36368
- const raw = await readFile23(
36428
+ const raw = await readFile24(
36369
36429
  join39(projectPath, ".codebyplan", "shipment.json"),
36370
36430
  "utf-8"
36371
36431
  );
@@ -36376,7 +36436,7 @@ async function readShipmentConfig2(projectPath) {
36376
36436
  }
36377
36437
  async function readVendorConfig(projectPath) {
36378
36438
  try {
36379
- const raw = await readFile23(
36439
+ const raw = await readFile24(
36380
36440
  join39(projectPath, ".codebyplan", "vendor.json"),
36381
36441
  "utf-8"
36382
36442
  );
@@ -36387,7 +36447,7 @@ async function readVendorConfig(projectPath) {
36387
36447
  }
36388
36448
  async function readE2eConfig2(projectPath) {
36389
36449
  try {
36390
- const raw = await readFile23(
36450
+ const raw = await readFile24(
36391
36451
  join39(projectPath, ".codebyplan", "e2e.json"),
36392
36452
  "utf-8"
36393
36453
  );
@@ -36398,7 +36458,7 @@ async function readE2eConfig2(projectPath) {
36398
36458
  }
36399
36459
  async function readServerLocalConfig(projectPath) {
36400
36460
  try {
36401
- const raw = await readFile23(
36461
+ const raw = await readFile24(
36402
36462
  join39(projectPath, ".codebyplan", "server.local.json"),
36403
36463
  "utf-8"
36404
36464
  );
@@ -36471,11 +36531,11 @@ var init_config = __esm({
36471
36531
  });
36472
36532
 
36473
36533
  // src/lib/server-detect.ts
36474
- 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";
36475
36535
  import { join as join40 } from "node:path";
36476
36536
  async function fileExists4(filePath) {
36477
36537
  try {
36478
- await access6(filePath);
36538
+ await access7(filePath);
36479
36539
  return true;
36480
36540
  } catch {
36481
36541
  return false;
@@ -36521,7 +36581,7 @@ async function isMonorepo(dir) {
36521
36581
  async function detectServers(projectPath) {
36522
36582
  let pkg;
36523
36583
  try {
36524
- const raw = await readFile24(join40(projectPath, "package.json"), "utf-8");
36584
+ const raw = await readFile25(join40(projectPath, "package.json"), "utf-8");
36525
36585
  pkg = JSON.parse(raw);
36526
36586
  } catch {
36527
36587
  return {
@@ -36539,13 +36599,13 @@ async function detectServers(projectPath) {
36539
36599
  if (mono) {
36540
36600
  const appsDir = join40(projectPath, "apps");
36541
36601
  try {
36542
- const entries = await readdir5(appsDir, { withFileTypes: true });
36602
+ const entries = await readdir6(appsDir, { withFileTypes: true });
36543
36603
  const sorted = [...entries].sort((a, b) => a.name.localeCompare(b.name));
36544
36604
  for (const entry of sorted) {
36545
36605
  if (!entry.isDirectory()) continue;
36546
36606
  const appPkgPath = join40(appsDir, entry.name, "package.json");
36547
36607
  try {
36548
- const appRaw = await readFile24(appPkgPath, "utf-8");
36608
+ const appRaw = await readFile25(appPkgPath, "utf-8");
36549
36609
  const appPkg = JSON.parse(appRaw);
36550
36610
  const appName = entry.name;
36551
36611
  const framework = detectFramework(appPkg);
@@ -36588,14 +36648,14 @@ var init_server_detect = __esm({
36588
36648
  });
36589
36649
 
36590
36650
  // src/lib/port-verify.ts
36591
- import { readFile as readFile25 } from "node:fs/promises";
36651
+ import { readFile as readFile26 } from "node:fs/promises";
36592
36652
  async function verifyPorts(projectPath, portAllocations) {
36593
36653
  const mismatches = [];
36594
36654
  const allocatedPorts = new Set(portAllocations.map((a) => a.port));
36595
36655
  const packageJsonPaths = await findPackageJsonFiles(projectPath, projectPath);
36596
36656
  for (const pkgPath of packageJsonPaths) {
36597
36657
  try {
36598
- const raw = await readFile25(pkgPath, "utf-8");
36658
+ const raw = await readFile26(pkgPath, "utf-8");
36599
36659
  const pkg = JSON.parse(raw);
36600
36660
  const scriptPort = detectPortFromScripts(pkg);
36601
36661
  if (scriptPort !== null && !allocatedPorts.has(scriptPort)) {
@@ -36658,7 +36718,7 @@ async function findUnallocatedApps(projectPath, portAllocations) {
36658
36718
  }
36659
36719
  let pkg;
36660
36720
  try {
36661
- const raw = await readFile25(`${app.absPath}/package.json`, "utf-8");
36721
+ const raw = await readFile26(`${app.absPath}/package.json`, "utf-8");
36662
36722
  pkg = JSON.parse(raw);
36663
36723
  } catch {
36664
36724
  continue;
@@ -36708,7 +36768,7 @@ __export(ports_exports, {
36708
36768
  parseEnvFile: () => parseEnvFile,
36709
36769
  runPorts: () => runPorts
36710
36770
  });
36711
- 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";
36712
36772
  import { join as join41 } from "node:path";
36713
36773
  function printDetectionResult(result, projectPath) {
36714
36774
  console.log(`
@@ -36870,7 +36930,7 @@ async function writeServerLocalConfig(repoId, projectPath, dryRun) {
36870
36930
  const newJson = JSON.stringify(payload, null, 2) + "\n";
36871
36931
  let currentJson = "";
36872
36932
  try {
36873
- currentJson = await readFile26(filePath, "utf-8");
36933
+ currentJson = await readFile27(filePath, "utf-8");
36874
36934
  } catch {
36875
36935
  }
36876
36936
  if (currentJson === newJson) {
@@ -36892,7 +36952,7 @@ async function provisionE2eEnv(projectPath, dryRun) {
36892
36952
  const sourcePath = join41(projectPath, relSource);
36893
36953
  let sourceRaw;
36894
36954
  try {
36895
- sourceRaw = await readFile26(sourcePath, "utf-8");
36955
+ sourceRaw = await readFile27(sourcePath, "utf-8");
36896
36956
  } catch {
36897
36957
  console.warn(
36898
36958
  ` Skipped .codebyplan/e2e.env \u2014 source ${relSource} not found.`
@@ -36926,7 +36986,7 @@ async function provisionE2eEnv(projectPath, dryRun) {
36926
36986
  const newContent = lines.join("\n") + "\n";
36927
36987
  let currentContent = "";
36928
36988
  try {
36929
- currentContent = await readFile26(filePath, "utf-8");
36989
+ currentContent = await readFile27(filePath, "utf-8");
36930
36990
  } catch {
36931
36991
  }
36932
36992
  if (currentContent === newContent) {
@@ -37206,8 +37266,8 @@ __export(docs_exports, {
37206
37266
  stripRangePrefix: () => stripRangePrefix
37207
37267
  });
37208
37268
  import { existsSync as existsSync13 } from "node:fs";
37209
- import { mkdir as mkdir12, readFile as readFile27, readdir as readdir6, rm as rm2, writeFile as writeFile21 } from "node:fs/promises";
37210
- 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";
37211
37271
  function selectDependencies(deps) {
37212
37272
  const byName = /* @__PURE__ */ new Map();
37213
37273
  for (const dep of deps) {
@@ -37265,7 +37325,7 @@ async function resolveExactVersion(projectPath, dep) {
37265
37325
  if (sourceDir !== projectPath) candidateDirs.push(sourceDir);
37266
37326
  for (const base of candidateDirs) {
37267
37327
  try {
37268
- const raw = await readFile27(
37328
+ const raw = await readFile28(
37269
37329
  join42(base, "node_modules", dep.name, "package.json"),
37270
37330
  "utf-8"
37271
37331
  );
@@ -37280,7 +37340,7 @@ async function resolveExactVersion(projectPath, dep) {
37280
37340
  }
37281
37341
  async function readVendorDocsPath(projectPath) {
37282
37342
  try {
37283
- const raw = await readFile27(
37343
+ const raw = await readFile28(
37284
37344
  join42(projectPath, ".codebyplan", "vendor.json"),
37285
37345
  "utf-8"
37286
37346
  );
@@ -37294,7 +37354,7 @@ async function readVendorDocsPath(projectPath) {
37294
37354
  }
37295
37355
  async function resolveDocsDir(projectPath, flags) {
37296
37356
  const configured = flags["dir"] ?? await readVendorDocsPath(projectPath) ?? DEFAULT_DOCS_DIR;
37297
- const absDir = isAbsolute2(configured) ? configured : join42(projectPath, configured);
37357
+ const absDir = isAbsolute3(configured) ? configured : join42(projectPath, configured);
37298
37358
  const rel = relative7(projectPath, absDir);
37299
37359
  const relDir = rel === "" || rel.startsWith("..") ? null : rel.split(sep2).join("/");
37300
37360
  return { absDir, relDir };
@@ -37303,7 +37363,7 @@ async function readDocsLock(absDir) {
37303
37363
  const empty = { generated_at: "", libraries: {} };
37304
37364
  let raw;
37305
37365
  try {
37306
- raw = await readFile27(join42(absDir, LOCK_FILE), "utf-8");
37366
+ raw = await readFile28(join42(absDir, LOCK_FILE), "utf-8");
37307
37367
  } catch {
37308
37368
  return empty;
37309
37369
  }
@@ -37402,7 +37462,7 @@ async function ensureDocsGitignoreEntry(projectPath, relDir, dryRun) {
37402
37462
  const gitignorePath = join42(projectPath, ".gitignore");
37403
37463
  let existing = "";
37404
37464
  try {
37405
- existing = await readFile27(gitignorePath, "utf-8");
37465
+ existing = await readFile28(gitignorePath, "utf-8");
37406
37466
  } catch {
37407
37467
  }
37408
37468
  const lines = existing.split(/\r?\n/).map((l) => l.trim());
@@ -37528,7 +37588,7 @@ async function syncOneLibrary(dep, ctx) {
37528
37588
  let removedVersionDirs = 0;
37529
37589
  let libEntries = [];
37530
37590
  try {
37531
- libEntries = await readdir6(libPath, { withFileTypes: true });
37591
+ libEntries = await readdir7(libPath, { withFileTypes: true });
37532
37592
  } catch {
37533
37593
  }
37534
37594
  for (const entry of libEntries) {
@@ -37658,7 +37718,7 @@ async function runDocsSync() {
37658
37718
  async function countFilesRecursively(dirPath) {
37659
37719
  let entries;
37660
37720
  try {
37661
- entries = await readdir6(dirPath, { withFileTypes: true });
37721
+ entries = await readdir7(dirPath, { withFileTypes: true });
37662
37722
  } catch {
37663
37723
  return 0;
37664
37724
  }
@@ -37682,7 +37742,7 @@ async function runDocsStatus() {
37682
37742
  `);
37683
37743
  let raw;
37684
37744
  try {
37685
- raw = await readFile27(join42(absDir, LOCK_FILE), "utf-8");
37745
+ raw = await readFile28(join42(absDir, LOCK_FILE), "utf-8");
37686
37746
  } catch {
37687
37747
  console.log(
37688
37748
  ` No ${LOCK_FILE} found \u2014 run \`codebyplan docs sync\` first.
@@ -38450,7 +38510,7 @@ var init_check2 = __esm({
38450
38510
 
38451
38511
  // src/lib/claude-plan.ts
38452
38512
  import * as fs13 from "node:fs";
38453
- import * as path15 from "node:path";
38513
+ import * as path16 from "node:path";
38454
38514
  function buildDriftPlan(projectDir, templatesDir, manifest) {
38455
38515
  const packaged = walkTemplates(templatesDir);
38456
38516
  const packagedBySrc = new Map(packaged.map((f) => [f.src, f]));
@@ -38464,8 +38524,8 @@ function buildDriftPlan(projectDir, templatesDir, manifest) {
38464
38524
  };
38465
38525
  for (const pkg of packaged) {
38466
38526
  const inManifest = manifestBySrc.get(pkg.src);
38467
- const absDest = path15.join(projectDir, ".claude", pkg.dest);
38468
- const absSrc = path15.join(templatesDir, pkg.src);
38527
+ const absDest = path16.join(projectDir, ".claude", pkg.dest);
38528
+ const absSrc = path16.join(templatesDir, pkg.src);
38469
38529
  if (!inManifest) {
38470
38530
  plan.newOptIn.push({
38471
38531
  packaged: { src: pkg.src, dest: pkg.dest, hash: pkg.hash },
@@ -38514,7 +38574,7 @@ __export(status_exports, {
38514
38574
  runStatus: () => runStatus2
38515
38575
  });
38516
38576
  import * as fs14 from "node:fs";
38517
- import * as path16 from "node:path";
38577
+ import * as path17 from "node:path";
38518
38578
  import { execSync as execSync9 } from "node:child_process";
38519
38579
  function makeFailSafe(checked_at) {
38520
38580
  return {
@@ -38623,12 +38683,12 @@ async function runStatus2(argv) {
38623
38683
  const latest = fetchLatestVersion();
38624
38684
  const newer = latest !== null && compareSemver(latest, installed) > 0;
38625
38685
  let settings_drift = false;
38626
- const settingsPath = path16.join(projectDir, ".claude", "settings.json");
38627
- const baseSettingsPath = path16.join(
38686
+ const settingsPath = path17.join(projectDir, ".claude", "settings.json");
38687
+ const baseSettingsPath = path17.join(
38628
38688
  templatesDir,
38629
38689
  "settings.project.base.json"
38630
38690
  );
38631
- const hooksJsonPath = path16.join(templatesDir, "hooks", "hooks.json");
38691
+ const hooksJsonPath = path17.join(templatesDir, "hooks", "hooks.json");
38632
38692
  if (fs14.existsSync(settingsPath)) {
38633
38693
  try {
38634
38694
  const settingsRaw = fs14.readFileSync(settingsPath, "utf8");
@@ -38698,10 +38758,10 @@ function emitResult(result, writeCache, quiet, projectDir) {
38698
38758
  const json = JSON.stringify(result, null, 2);
38699
38759
  if (writeCache) {
38700
38760
  try {
38701
- const cacheDir = path16.join(projectDir, ".codebyplan");
38761
+ const cacheDir = path17.join(projectDir, ".codebyplan");
38702
38762
  fs14.mkdirSync(cacheDir, { recursive: true });
38703
38763
  fs14.writeFileSync(
38704
- path16.join(cacheDir, "claude-status.local.json"),
38764
+ path17.join(cacheDir, "claude-status.local.json"),
38705
38765
  json + "\n",
38706
38766
  "utf8"
38707
38767
  );
@@ -38745,11 +38805,11 @@ async function ask(q, opts) {
38745
38805
  try {
38746
38806
  while (true) {
38747
38807
  const choices = q.choices.map((c) => `[${c.key}] ${c.label}`).join(" ");
38748
- const answer = await new Promise((resolve16) => {
38808
+ const answer = await new Promise((resolve17) => {
38749
38809
  rl.question(`${q.message}
38750
38810
  ${choices}
38751
38811
  > `, (input) => {
38752
- resolve16(input.trim().toLowerCase());
38812
+ resolve17(input.trim().toLowerCase());
38753
38813
  });
38754
38814
  });
38755
38815
  const match = q.choices.find(
@@ -38845,7 +38905,7 @@ __export(update_exports, {
38845
38905
  });
38846
38906
  import * as fs15 from "node:fs";
38847
38907
  import * as os3 from "node:os";
38848
- import * as path17 from "node:path";
38908
+ import * as path18 from "node:path";
38849
38909
  async function runUpdate(opts, deps = {}) {
38850
38910
  await Promise.resolve();
38851
38911
  const scope = opts.scope ?? "project";
@@ -38881,9 +38941,9 @@ async function runUpdate(opts, deps = {}) {
38881
38941
  finalManifestEntries.push(e);
38882
38942
  }
38883
38943
  for (const { packaged, absSrc } of plan.overwriteSafe) {
38884
- const absDest = path17.join(projectDir, ".claude", packaged.dest);
38944
+ const absDest = path18.join(projectDir, ".claude", packaged.dest);
38885
38945
  if (!opts.dryRun) {
38886
- fs15.mkdirSync(path17.dirname(absDest), { recursive: true });
38946
+ fs15.mkdirSync(path18.dirname(absDest), { recursive: true });
38887
38947
  fs15.copyFileSync(absSrc, absDest);
38888
38948
  if (opts.verbose) console.log(`updated ${packaged.dest}`);
38889
38949
  } else if (opts.verbose) {
@@ -38896,7 +38956,7 @@ async function runUpdate(opts, deps = {}) {
38896
38956
  absSrc,
38897
38957
  onDiskContent
38898
38958
  } of plan.overwriteHandEdited) {
38899
- const absDest = path17.join(projectDir, ".claude", packaged.dest);
38959
+ const absDest = path18.join(projectDir, ".claude", packaged.dest);
38900
38960
  const newContent = fs15.readFileSync(absSrc);
38901
38961
  const showDiff = () => {
38902
38962
  console.log(
@@ -38909,7 +38969,7 @@ async function runUpdate(opts, deps = {}) {
38909
38969
  const answer = await promptOverwrite(packaged.dest, opts, showDiff);
38910
38970
  if (answer === "overwrite") {
38911
38971
  if (!opts.dryRun) {
38912
- fs15.mkdirSync(path17.dirname(absDest), { recursive: true });
38972
+ fs15.mkdirSync(path18.dirname(absDest), { recursive: true });
38913
38973
  fs15.copyFileSync(absSrc, absDest);
38914
38974
  }
38915
38975
  finalManifestEntries.push(packaged);
@@ -38925,9 +38985,9 @@ async function runUpdate(opts, deps = {}) {
38925
38985
  for (const { packaged, absSrc } of plan.newOptIn) {
38926
38986
  const answer = await promptOptIn(packaged.dest, opts);
38927
38987
  if (answer === "opt-in") {
38928
- const absDest = path17.join(projectDir, ".claude", packaged.dest);
38988
+ const absDest = path18.join(projectDir, ".claude", packaged.dest);
38929
38989
  if (!opts.dryRun) {
38930
- fs15.mkdirSync(path17.dirname(absDest), { recursive: true });
38990
+ fs15.mkdirSync(path18.dirname(absDest), { recursive: true });
38931
38991
  fs15.copyFileSync(absSrc, absDest);
38932
38992
  }
38933
38993
  finalManifestEntries.push(packaged);
@@ -38939,25 +38999,25 @@ async function runUpdate(opts, deps = {}) {
38939
38999
  for (const e of plan.removedFromPackage) {
38940
39000
  const answer = await promptRemove(e.dest, opts);
38941
39001
  if (answer === "remove") {
38942
- const absDest = path17.join(projectDir, ".claude", e.dest);
39002
+ const absDest = path18.join(projectDir, ".claude", e.dest);
38943
39003
  if (!opts.dryRun && fs15.existsSync(absDest)) {
38944
39004
  fs15.rmSync(absDest);
38945
- const claudeDir = path17.join(projectDir, ".claude");
38946
- let cur = path17.dirname(absDest);
38947
- while (cur !== claudeDir && cur !== path17.dirname(cur)) {
38948
- if (path17.dirname(cur) === claudeDir) break;
39005
+ const claudeDir = path18.join(projectDir, ".claude");
39006
+ let cur = path18.dirname(absDest);
39007
+ while (cur !== claudeDir && cur !== path18.dirname(cur)) {
39008
+ if (path18.dirname(cur) === claudeDir) break;
38949
39009
  try {
38950
39010
  fs15.rmdirSync(cur);
38951
39011
  if (opts.verbose)
38952
39012
  console.log(
38953
- `pruned empty dir ${path17.relative(claudeDir, cur)}`
39013
+ `pruned empty dir ${path18.relative(claudeDir, cur)}`
38954
39014
  );
38955
- cur = path17.dirname(cur);
39015
+ cur = path18.dirname(cur);
38956
39016
  } catch (err) {
38957
39017
  const code = err.code;
38958
39018
  if (code !== "ENOTEMPTY" && code !== "ENOENT") {
38959
39019
  console.warn(
38960
- `codebyplan claude: could not prune empty dir ${path17.relative(claudeDir, cur)}: ${err.message}`
39020
+ `codebyplan claude: could not prune empty dir ${path18.relative(claudeDir, cur)}: ${err.message}`
38961
39021
  );
38962
39022
  }
38963
39023
  break;
@@ -38969,12 +39029,12 @@ async function runUpdate(opts, deps = {}) {
38969
39029
  if (opts.verbose) console.log(`kept (untracked) ${e.dest}`);
38970
39030
  }
38971
39031
  }
38972
- const hooksJsonPath = path17.join(templatesDir, "hooks", "hooks.json");
38973
- const baseSettingsPath = path17.join(
39032
+ const hooksJsonPath = path18.join(templatesDir, "hooks", "hooks.json");
39033
+ const baseSettingsPath = path18.join(
38974
39034
  templatesDir,
38975
39035
  "settings.project.base.json"
38976
39036
  );
38977
- const settingsPath = path17.join(projectDir, ".claude", "settings.json");
39037
+ const settingsPath = path18.join(projectDir, ".claude", "settings.json");
38978
39038
  const existingSettings = fs15.existsSync(settingsPath) ? JSON.parse(fs15.readFileSync(settingsPath, "utf8")) : {};
38979
39039
  if (fs15.existsSync(baseSettingsPath)) {
38980
39040
  const base = JSON.parse(
@@ -39001,7 +39061,7 @@ async function runUpdate(opts, deps = {}) {
39001
39061
  deps.detectHealDeps
39002
39062
  );
39003
39063
  if (!opts.dryRun) {
39004
- fs15.mkdirSync(path17.dirname(settingsPath), { recursive: true });
39064
+ fs15.mkdirSync(path18.dirname(settingsPath), { recursive: true });
39005
39065
  fs15.writeFileSync(
39006
39066
  settingsPath,
39007
39067
  JSON.stringify(existingSettings, null, 2) + "\n",
@@ -39017,7 +39077,7 @@ async function runUpdate(opts, deps = {}) {
39017
39077
  );
39018
39078
  if (opts.verbose && gitignoreAction !== "unchanged") {
39019
39079
  console.log(
39020
- `${opts.dryRun ? "[dry-run] would " : ""}${gitignoreAction} managed .gitignore block in ${path17.relative(projectDir, path17.join(projectDir, ".gitignore"))}`
39080
+ `${opts.dryRun ? "[dry-run] would " : ""}${gitignoreAction} managed .gitignore block in ${path18.relative(projectDir, path18.join(projectDir, ".gitignore"))}`
39021
39081
  );
39022
39082
  }
39023
39083
  if (!opts.dryRun) {
@@ -39057,9 +39117,9 @@ function runUpdateUser(opts, deps) {
39057
39117
  return;
39058
39118
  }
39059
39119
  try {
39060
- const userDir = deps.userDir ?? path17.join(os3.homedir(), ".claude");
39061
- const settingsPath = path17.join(userDir, "settings.json");
39062
- const userBaseSettingsPath = path17.join(
39120
+ const userDir = deps.userDir ?? path18.join(os3.homedir(), ".claude");
39121
+ const settingsPath = path18.join(userDir, "settings.json");
39122
+ const userBaseSettingsPath = path18.join(
39063
39123
  templatesDir,
39064
39124
  "settings.user.base.json"
39065
39125
  );
@@ -39131,7 +39191,7 @@ __export(uninstall_exports, {
39131
39191
  });
39132
39192
  import * as fs16 from "node:fs";
39133
39193
  import * as os4 from "node:os";
39134
- import * as path18 from "node:path";
39194
+ import * as path19 from "node:path";
39135
39195
  async function runUninstall(opts, deps = {}) {
39136
39196
  await Promise.resolve();
39137
39197
  const scope = opts.scope ?? "project";
@@ -39160,7 +39220,7 @@ async function runUninstall(opts, deps = {}) {
39160
39220
  let removed = 0;
39161
39221
  let warnings = 0;
39162
39222
  for (const entry of manifest.files) {
39163
- const abs = path18.join(projectDir, ".claude", entry.dest);
39223
+ const abs = path19.join(projectDir, ".claude", entry.dest);
39164
39224
  if (!fs16.existsSync(abs)) {
39165
39225
  console.warn(
39166
39226
  `codebyplan claude uninstall: ${entry.dest} already absent (skipping).`
@@ -39184,12 +39244,12 @@ async function runUninstall(opts, deps = {}) {
39184
39244
  if (!opts.dryRun) {
39185
39245
  pruneEmptyManagedDirs(projectDir);
39186
39246
  }
39187
- const settingsPath = path18.join(projectDir, ".claude", "settings.json");
39247
+ const settingsPath = path19.join(projectDir, ".claude", "settings.json");
39188
39248
  if (fs16.existsSync(settingsPath)) {
39189
39249
  const settings = JSON.parse(
39190
39250
  fs16.readFileSync(settingsPath, "utf8")
39191
39251
  );
39192
- const baseSettingsPath = templatesDir ? path18.join(templatesDir, "settings.project.base.json") : null;
39252
+ const baseSettingsPath = templatesDir ? path19.join(templatesDir, "settings.project.base.json") : null;
39193
39253
  if (baseSettingsPath && fs16.existsSync(baseSettingsPath)) {
39194
39254
  const base = JSON.parse(
39195
39255
  fs16.readFileSync(baseSettingsPath, "utf8")
@@ -39247,7 +39307,7 @@ function runUninstallUser(opts, deps) {
39247
39307
  }
39248
39308
  }
39249
39309
  try {
39250
- const userDir = deps.userDir ?? path18.join(os4.homedir(), ".claude");
39310
+ const userDir = deps.userDir ?? path19.join(os4.homedir(), ".claude");
39251
39311
  const existingManifest = readManifestForScope("user", userDir);
39252
39312
  if (!existingManifest) {
39253
39313
  console.error(
@@ -39256,12 +39316,12 @@ function runUninstallUser(opts, deps) {
39256
39316
  process.exitCode = 1;
39257
39317
  return;
39258
39318
  }
39259
- const settingsPath = path18.join(userDir, "settings.json");
39319
+ const settingsPath = path19.join(userDir, "settings.json");
39260
39320
  if (fs16.existsSync(settingsPath)) {
39261
39321
  const settings = JSON.parse(
39262
39322
  fs16.readFileSync(settingsPath, "utf8")
39263
39323
  );
39264
- const userBaseSettingsPath = templatesDir != null ? path18.join(templatesDir, "settings.user.base.json") : null;
39324
+ const userBaseSettingsPath = templatesDir != null ? path19.join(templatesDir, "settings.user.base.json") : null;
39265
39325
  if (userBaseSettingsPath && fs16.existsSync(userBaseSettingsPath)) {
39266
39326
  const userBase = JSON.parse(
39267
39327
  fs16.readFileSync(userBaseSettingsPath, "utf8")
@@ -39302,7 +39362,7 @@ function runUninstallUser(opts, deps) {
39302
39362
  function pruneEmptyManagedDirs(projectDir) {
39303
39363
  const managedRoots = ["skills", "agents", "hooks", "rules"];
39304
39364
  for (const root of managedRoots) {
39305
- const abs = path18.join(projectDir, ".claude", root);
39365
+ const abs = path19.join(projectDir, ".claude", root);
39306
39366
  if (!fs16.existsSync(abs)) continue;
39307
39367
  pruneLeafFirst(abs);
39308
39368
  }
@@ -39313,7 +39373,7 @@ function pruneLeafFirst(dir) {
39313
39373
  if (!stat3.isDirectory()) return;
39314
39374
  for (const entry of fs16.readdirSync(dir, { withFileTypes: true })) {
39315
39375
  if (entry.isDirectory()) {
39316
- pruneLeafFirst(path18.join(dir, entry.name));
39376
+ pruneLeafFirst(path19.join(dir, entry.name));
39317
39377
  }
39318
39378
  }
39319
39379
  const remaining = fs16.readdirSync(dir);
@@ -39334,7 +39394,7 @@ var init_uninstall = __esm({
39334
39394
 
39335
39395
  // src/lib/verify-parity.ts
39336
39396
  import * as fs17 from "node:fs";
39337
- import * as path19 from "node:path";
39397
+ import * as path20 from "node:path";
39338
39398
  function isValidScope(s) {
39339
39399
  return s === "org-shared" || s === "project-shared" || REPO_ONLY_RE.test(s);
39340
39400
  }
@@ -39351,25 +39411,25 @@ function checkSiblingParity(opts) {
39351
39411
  expectedOneSided = DEFAULT_EXPECTED_ONE_SIDED,
39352
39412
  ignoredSubtrees
39353
39413
  } = opts;
39354
- const defaultIgnored = [path19.join(claudeDir, "hooks", "__test-fixtures__")];
39414
+ const defaultIgnored = [path20.join(claudeDir, "hooks", "__test-fixtures__")];
39355
39415
  const ignored = ignoredSubtrees ?? defaultIgnored;
39356
39416
  const violations = [];
39357
39417
  const claudeSideRels = /* @__PURE__ */ new Set();
39358
39418
  for (const scanDir of SCAN_DIRS) {
39359
- const baseDir = path19.join(claudeDir, scanDir);
39419
+ const baseDir = path20.join(claudeDir, scanDir);
39360
39420
  if (!fs17.existsSync(baseDir)) continue;
39361
39421
  const entries = readdirRecursive(baseDir);
39362
39422
  for (const entry of entries) {
39363
- const absPath = path19.join(baseDir, entry);
39423
+ const absPath = path20.join(baseDir, entry);
39364
39424
  if (!fs17.lstatSync(absPath).isFile()) continue;
39365
39425
  if (ignored.some(
39366
- (ig) => absPath.startsWith(ig + path19.sep) || absPath === ig
39426
+ (ig) => absPath.startsWith(ig + path20.sep) || absPath === ig
39367
39427
  )) {
39368
39428
  continue;
39369
39429
  }
39370
- const relPath = path19.join(scanDir, entry).split(path19.sep).join("/");
39430
+ const relPath = path20.join(scanDir, entry).split(path20.sep).join("/");
39371
39431
  claudeSideRels.add(relPath);
39372
- const templatePath = path19.join(templatesDir, relPath);
39432
+ const templatePath = path20.join(templatesDir, relPath);
39373
39433
  if (!fs17.existsSync(templatePath)) {
39374
39434
  if (!expectedOneSided.has(relPath) && !isScaffoldFile(entry)) {
39375
39435
  violations.push({ type: "missing-twin", path: relPath });
@@ -39384,14 +39444,14 @@ function checkSiblingParity(opts) {
39384
39444
  }
39385
39445
  }
39386
39446
  for (const scanDir of SCAN_DIRS) {
39387
- const tplBase = path19.join(templatesDir, scanDir);
39447
+ const tplBase = path20.join(templatesDir, scanDir);
39388
39448
  if (!fs17.existsSync(tplBase)) continue;
39389
39449
  const entries = readdirRecursive(tplBase);
39390
39450
  for (const entry of entries) {
39391
- const absPath = path19.join(tplBase, entry);
39451
+ const absPath = path20.join(tplBase, entry);
39392
39452
  if (!fs17.lstatSync(absPath).isFile()) continue;
39393
39453
  if (isScaffoldFile(entry)) continue;
39394
- const relPath = path19.join(scanDir, entry).split(path19.sep).join("/");
39454
+ const relPath = path20.join(scanDir, entry).split(path20.sep).join("/");
39395
39455
  if (!claudeSideRels.has(relPath) && !expectedOneSided.has(relPath)) {
39396
39456
  violations.push({ type: "extra-twin", path: relPath });
39397
39457
  }
@@ -39427,18 +39487,18 @@ function checkScopeMarkers(opts) {
39427
39487
  const twinDetectionActive = templatesDir != null && fs17.existsSync(templatesDir);
39428
39488
  const violations = [];
39429
39489
  for (const scanDir of scanDirs) {
39430
- const baseDir = path19.join(claudeDir, scanDir);
39490
+ const baseDir = path20.join(claudeDir, scanDir);
39431
39491
  if (!fs17.existsSync(baseDir)) continue;
39432
39492
  const entries = readdirRecursive(baseDir);
39433
39493
  for (const entry of entries) {
39434
- const absPath = path19.join(baseDir, entry);
39494
+ const absPath = path20.join(baseDir, entry);
39435
39495
  if (!fs17.lstatSync(absPath).isFile()) continue;
39436
39496
  if (!isStructuralEntry(scanDir, entry)) continue;
39437
- const ext = path19.extname(entry).toLowerCase();
39497
+ const ext = path20.extname(entry).toLowerCase();
39438
39498
  const isMd = ext === ".md";
39439
39499
  const isSh = ext === ".sh";
39440
39500
  if (!isMd && !isSh) continue;
39441
- const relPath = path19.join(scanDir, entry).split(path19.sep).join("/");
39501
+ const relPath = path20.join(scanDir, entry).split(path20.sep).join("/");
39442
39502
  if (allowlist.has(relPath)) continue;
39443
39503
  let content;
39444
39504
  try {
@@ -39452,7 +39512,7 @@ function checkScopeMarkers(opts) {
39452
39512
  continue;
39453
39513
  }
39454
39514
  const scopeValue = isMd ? extractFrontmatterScope(content) : extractShScope(content);
39455
- const managed = twinDetectionActive && fs17.existsSync(path19.join(templatesDir, relPath));
39515
+ const managed = twinDetectionActive && fs17.existsSync(path20.join(templatesDir, relPath));
39456
39516
  if (managed) {
39457
39517
  if (scopeValue === null) {
39458
39518
  } else if (scopeValue === "org-shared") {
@@ -39506,7 +39566,7 @@ function readdirRecursive(dir, rel = "", visited = /* @__PURE__ */ new Set()) {
39506
39566
  visited.add(realDir);
39507
39567
  const results = [];
39508
39568
  for (const name of fs17.readdirSync(dir)) {
39509
- const full = path19.join(dir, name);
39569
+ const full = path20.join(dir, name);
39510
39570
  const relName = rel ? `${rel}/${name}` : name;
39511
39571
  if (fs17.lstatSync(full).isDirectory()) {
39512
39572
  results.push(...readdirRecursive(full, relName, visited));
@@ -39579,12 +39639,12 @@ __export(verify_parity_exports, {
39579
39639
  verifyParity: () => verifyParity
39580
39640
  });
39581
39641
  import * as fs18 from "node:fs";
39582
- import * as path20 from "node:path";
39642
+ import * as path21 from "node:path";
39583
39643
  function verifyParity(args, deps = {}) {
39584
39644
  const warnOnly = args.includes("--warn-only");
39585
39645
  const jsonMode = args.includes("--json");
39586
39646
  const projectDir = deps.cwd ?? process.cwd();
39587
- const claudeDir = path20.join(projectDir, ".claude");
39647
+ const claudeDir = path21.join(projectDir, ".claude");
39588
39648
  if (!fs18.existsSync(claudeDir)) {
39589
39649
  const msg = "codebyplan claude verify-parity: .claude/ not found in cwd \u2014 run from the project root.\n";
39590
39650
  process.stderr.write(msg);
@@ -40091,11 +40151,11 @@ var generate_exports = {};
40091
40151
  __export(generate_exports, {
40092
40152
  runGenerate: () => runGenerate
40093
40153
  });
40094
- import { readFile as readFile28, mkdir as mkdir13, writeFile as writeFile22 } from "node:fs/promises";
40095
- import { join as join51, resolve as resolve11 } from "node:path";
40154
+ import { readFile as readFile29, mkdir as mkdir13, writeFile as writeFile22 } from "node:fs/promises";
40155
+ import { join as join51, resolve as resolve12 } from "node:path";
40096
40156
  async function readJsonFile4(filePath) {
40097
40157
  try {
40098
- const raw = await readFile28(filePath, "utf-8");
40158
+ const raw = await readFile29(filePath, "utf-8");
40099
40159
  return JSON.parse(raw);
40100
40160
  } catch {
40101
40161
  return null;
@@ -40103,7 +40163,7 @@ async function readJsonFile4(filePath) {
40103
40163
  }
40104
40164
  async function readPkgName(absPath) {
40105
40165
  try {
40106
- const raw = await readFile28(join51(absPath, "package.json"), "utf-8");
40166
+ const raw = await readFile29(join51(absPath, "package.json"), "utf-8");
40107
40167
  const pkg = JSON.parse(raw);
40108
40168
  return typeof pkg.name === "string" ? pkg.name : null;
40109
40169
  } catch {
@@ -40114,10 +40174,10 @@ async function runGenerate(opts) {
40114
40174
  const projectDir = opts.projectDir ?? opts["project-dir"] ?? process.cwd();
40115
40175
  const dryRun = opts.dryRun ?? opts["dryRun"] ?? false;
40116
40176
  const check = opts.check ?? opts["check"] ?? false;
40117
- const rootDir = resolve11(projectDir);
40177
+ const rootDir = resolve12(projectDir);
40118
40178
  let packageManager;
40119
40179
  try {
40120
- const raw = await readFile28(join51(rootDir, "package.json"), "utf-8");
40180
+ const raw = await readFile29(join51(rootDir, "package.json"), "utf-8");
40121
40181
  const pkg = JSON.parse(raw);
40122
40182
  if (typeof pkg.packageManager === "string") {
40123
40183
  packageManager = pkg.packageManager;
@@ -40221,7 +40281,7 @@ async function runGenerate(opts) {
40221
40281
  const agentsMdPath2 = join51(rootDir, "AGENTS.md");
40222
40282
  let existingAgents = null;
40223
40283
  try {
40224
- existingAgents = await readFile28(agentsMdPath2, "utf-8");
40284
+ existingAgents = await readFile29(agentsMdPath2, "utf-8");
40225
40285
  } catch {
40226
40286
  existingAgents = null;
40227
40287
  }
@@ -40266,7 +40326,7 @@ async function runGenerate(opts) {
40266
40326
  const agentsMdPath = join51(rootDir, "AGENTS.md");
40267
40327
  let existingAgentsContent = null;
40268
40328
  try {
40269
- existingAgentsContent = await readFile28(agentsMdPath, "utf-8");
40329
+ existingAgentsContent = await readFile29(agentsMdPath, "utf-8");
40270
40330
  } catch {
40271
40331
  existingAgentsContent = null;
40272
40332
  }
@@ -40294,11 +40354,11 @@ __export(readme_exports, {
40294
40354
  runReadme: () => runReadme,
40295
40355
  runReadmeCommand: () => runReadmeCommand
40296
40356
  });
40297
- import { readFile as readFile29, writeFile as writeFile23 } from "node:fs/promises";
40298
- import { join as join52, resolve as resolve12, relative as relative9 } from "node:path";
40357
+ import { readFile as readFile30, writeFile as writeFile23 } from "node:fs/promises";
40358
+ import { join as join52, resolve as resolve13, relative as relative9 } from "node:path";
40299
40359
  async function readJsonFile5(filePath) {
40300
40360
  try {
40301
- const raw = await readFile29(filePath, "utf-8");
40361
+ const raw = await readFile30(filePath, "utf-8");
40302
40362
  return JSON.parse(raw);
40303
40363
  } catch {
40304
40364
  return null;
@@ -40391,7 +40451,7 @@ async function runReadme(opts) {
40391
40451
  const dryRun = opts.dryRun ?? opts["dryRun"] ?? false;
40392
40452
  const check = opts.check ?? opts["check"] ?? false;
40393
40453
  const init = opts.init ?? opts["init"] ?? false;
40394
- const rootDir = resolve12(projectDir);
40454
+ const rootDir = resolve13(projectDir);
40395
40455
  const rootPkgJson = await readJsonFile5(
40396
40456
  join52(rootDir, "package.json")
40397
40457
  );
@@ -40406,7 +40466,7 @@ async function runReadme(opts) {
40406
40466
  const relPath = unit.isRoot ? "README.md" : join52(relative9(rootDir, unit.absPath), "README.md");
40407
40467
  let existingContent = null;
40408
40468
  try {
40409
- existingContent = await readFile29(readmePath, "utf-8");
40469
+ existingContent = await readFile30(readmePath, "utf-8");
40410
40470
  } catch {
40411
40471
  existingContent = null;
40412
40472
  }
@@ -40586,18 +40646,18 @@ __export(migrate_memory_exports, {
40586
40646
  runMigrateMemory: () => runMigrateMemory
40587
40647
  });
40588
40648
  import {
40589
- readFile as readFile30,
40649
+ readFile as readFile31,
40590
40650
  writeFile as writeFile24,
40591
40651
  mkdir as mkdir14,
40592
40652
  unlink as unlink6,
40593
40653
  rmdir,
40594
- readdir as readdir7
40654
+ readdir as readdir8
40595
40655
  } from "node:fs/promises";
40596
40656
  import { existsSync as existsSync21 } from "node:fs";
40597
- import { join as join53, resolve as resolve13, dirname as dirname16, sep as sep4 } from "node:path";
40657
+ import { join as join53, resolve as resolve14, dirname as dirname16, sep as sep4 } from "node:path";
40598
40658
  import { homedir as homedir8 } from "node:os";
40599
40659
  function encodeProjectPath(absPath) {
40600
- return resolve13(absPath).replace(/[/\\]/g, "-");
40660
+ return resolve14(absPath).replace(/[/\\]/g, "-");
40601
40661
  }
40602
40662
  function resolveAutoMemoryDir(opts) {
40603
40663
  if (opts.autoMemoryDir) {
@@ -40664,7 +40724,7 @@ function parseFrontmatter(content) {
40664
40724
  async function inventoryFiles(dir) {
40665
40725
  let filenames;
40666
40726
  try {
40667
- const entries = await readdir7(dir);
40727
+ const entries = await readdir8(dir);
40668
40728
  filenames = entries.filter((f) => f.endsWith(".md") && f !== "MEMORY.md").sort();
40669
40729
  } catch {
40670
40730
  return [];
@@ -40674,7 +40734,7 @@ async function inventoryFiles(dir) {
40674
40734
  const sourcePath = join53(dir, filename);
40675
40735
  let raw;
40676
40736
  try {
40677
- raw = await readFile30(sourcePath, "utf-8");
40737
+ raw = await readFile31(sourcePath, "utf-8");
40678
40738
  } catch (err) {
40679
40739
  const msg = err instanceof Error ? err.message : String(err);
40680
40740
  results.push({
@@ -40754,15 +40814,15 @@ function buildPlan(entries, opts) {
40754
40814
  return plan;
40755
40815
  }
40756
40816
  async function applyPlan(plan, opts) {
40757
- const projectDir = resolve13(opts.projectDir);
40817
+ const projectDir = resolve14(opts.projectDir);
40758
40818
  const dryRun = opts.dryRun ?? false;
40759
40819
  for (const entry of plan.entries) {
40760
40820
  if (entry.suggested_action !== "keep") continue;
40761
40821
  if (!entry.suggested_target?.startsWith("nested:")) continue;
40762
40822
  const relPath = entry.suggested_target.slice("nested:".length);
40763
- const targetDir = resolve13(join53(projectDir, relPath));
40823
+ const targetDir = resolve14(join53(projectDir, relPath));
40764
40824
  const targetFile = join53(targetDir, "CLAUDE.md");
40765
- if (!targetDir.startsWith(resolve13(projectDir) + sep4)) {
40825
+ if (!targetDir.startsWith(resolve14(projectDir) + sep4)) {
40766
40826
  process.stderr.write(
40767
40827
  `migrate-memory: skipping unsafe suggested_target "${entry.suggested_target}" \u2014 resolves outside projectDir
40768
40828
  `
@@ -40780,8 +40840,8 @@ ${anchor}
40780
40840
  if (dryRun) {
40781
40841
  process.stdout.write(`[dry-run] Would create/append: ${targetFile}
40782
40842
  `);
40783
- if (resolve13(entry.source_path).startsWith(
40784
- resolve13(plan.auto_memory_dir) + sep4
40843
+ if (resolve14(entry.source_path).startsWith(
40844
+ resolve14(plan.auto_memory_dir) + sep4
40785
40845
  )) {
40786
40846
  process.stdout.write(
40787
40847
  `[dry-run] Would delete migrated keep source: ${entry.source_path}
@@ -40793,13 +40853,13 @@ ${anchor}
40793
40853
  await mkdir14(targetDir, { recursive: true });
40794
40854
  let existing = "";
40795
40855
  try {
40796
- existing = await readFile30(targetFile, "utf-8");
40856
+ existing = await readFile31(targetFile, "utf-8");
40797
40857
  } catch {
40798
40858
  }
40799
40859
  if (!existing.includes(anchor)) {
40800
40860
  await writeFile24(targetFile, existing + appendContent, "utf-8");
40801
40861
  }
40802
- if (resolve13(entry.source_path).startsWith(resolve13(plan.auto_memory_dir) + sep4)) {
40862
+ if (resolve14(entry.source_path).startsWith(resolve14(plan.auto_memory_dir) + sep4)) {
40803
40863
  try {
40804
40864
  await unlink6(entry.source_path);
40805
40865
  } catch {
@@ -40820,7 +40880,7 @@ ${anchor}
40820
40880
  } else {
40821
40881
  let claudeMdContent = "";
40822
40882
  try {
40823
- claudeMdContent = await readFile30(rootClaudeMd, "utf-8");
40883
+ claudeMdContent = await readFile31(rootClaudeMd, "utf-8");
40824
40884
  } catch {
40825
40885
  await mkdir14(dirname16(rootClaudeMd), { recursive: true });
40826
40886
  }
@@ -40836,8 +40896,8 @@ ${IMPORT_LINE}
40836
40896
  }
40837
40897
  for (const entry of plan.entries) {
40838
40898
  if (entry.suggested_action !== "drop") continue;
40839
- if (!resolve13(entry.source_path).startsWith(
40840
- resolve13(plan.auto_memory_dir) + sep4
40899
+ if (!resolve14(entry.source_path).startsWith(
40900
+ resolve14(plan.auto_memory_dir) + sep4
40841
40901
  )) {
40842
40902
  process.stderr.write(
40843
40903
  `migrate-memory: skipping delete of "${entry.source_path}" \u2014 resolves outside auto_memory_dir
@@ -40861,7 +40921,7 @@ ${IMPORT_LINE}
40861
40921
  process.stdout.write(`[dry-run] Would delete MEMORY.md: ${memoryMd}
40862
40922
  `);
40863
40923
  } else {
40864
- if (resolve13(plan.auto_memory_dir).startsWith(safeRmdirBase + sep4)) {
40924
+ if (resolve14(plan.auto_memory_dir).startsWith(safeRmdirBase + sep4)) {
40865
40925
  try {
40866
40926
  await unlink6(memoryMd);
40867
40927
  } catch {
@@ -40879,14 +40939,14 @@ ${IMPORT_LINE}
40879
40939
  `
40880
40940
  );
40881
40941
  } else {
40882
- if (!resolve13(plan.auto_memory_dir).startsWith(safeRmdirBase + sep4)) {
40942
+ if (!resolve14(plan.auto_memory_dir).startsWith(safeRmdirBase + sep4)) {
40883
40943
  process.stderr.write(
40884
40944
  `migrate-memory: skipping rmdir of "${plan.auto_memory_dir}" \u2014 not under ~/.claude/projects
40885
40945
  `
40886
40946
  );
40887
40947
  } else {
40888
40948
  try {
40889
- const remaining = await readdir7(plan.auto_memory_dir);
40949
+ const remaining = await readdir8(plan.auto_memory_dir);
40890
40950
  if (remaining.length === 0) {
40891
40951
  await rmdir(plan.auto_memory_dir);
40892
40952
  }
@@ -40909,7 +40969,7 @@ async function runMigrateMemory(opts) {
40909
40969
  if (applyFile) {
40910
40970
  let planJson;
40911
40971
  try {
40912
- planJson = await readFile30(resolve13(applyFile), "utf-8");
40972
+ planJson = await readFile31(resolve14(applyFile), "utf-8");
40913
40973
  } catch (err) {
40914
40974
  const msg = err instanceof Error ? err.message : String(err);
40915
40975
  process.stderr.write(
@@ -40979,7 +41039,7 @@ var init_migrate_memory = __esm({
40979
41039
  });
40980
41040
 
40981
41041
  // src/lib/claude-mode-audit.ts
40982
- import { readdirSync as readdirSync7, readFileSync as readFileSync19, existsSync as existsSync22 } from "node:fs";
41042
+ import { readdirSync as readdirSync6, readFileSync as readFileSync19, existsSync as existsSync22 } from "node:fs";
40983
41043
  import { join as join54, basename as basename3 } from "node:path";
40984
41044
  function parseFrontmatter2(content) {
40985
41045
  const match = /^---\r?\n([\s\S]*?)\r?\n---/.exec(content);
@@ -41059,14 +41119,14 @@ function auditMode(templatesDir) {
41059
41119
  const entries = [];
41060
41120
  const agentsDir = join54(templatesDir, "agents");
41061
41121
  if (existsSync22(agentsDir)) {
41062
- const agentFiles = readdirSync7(agentsDir).filter((f) => f.endsWith(".md")).sort();
41122
+ const agentFiles = readdirSync6(agentsDir).filter((f) => f.endsWith(".md")).sort();
41063
41123
  for (const f of agentFiles) {
41064
41124
  entries.push(auditAgent(join54(agentsDir, f)));
41065
41125
  }
41066
41126
  }
41067
41127
  const skillsDir = join54(templatesDir, "skills");
41068
41128
  if (existsSync22(skillsDir)) {
41069
- const skillDirs = readdirSync7(skillsDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name).sort();
41129
+ const skillDirs = readdirSync6(skillsDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name).sort();
41070
41130
  for (const dir of skillDirs) {
41071
41131
  if (existsSync22(join54(skillsDir, dir, "PROVENANCE.md"))) continue;
41072
41132
  const skillMd = join54(skillsDir, dir, "SKILL.md");
@@ -41328,7 +41388,7 @@ __export(new_migration_exports, {
41328
41388
  newMigration: () => newMigration
41329
41389
  });
41330
41390
  import * as fs19 from "node:fs";
41331
- import * as path21 from "node:path";
41391
+ import * as path22 from "node:path";
41332
41392
  function slugify(name) {
41333
41393
  return name.trim().toLowerCase().replace(/[^a-z0-9_-]+/g, "_").replace(/^_+|_+$/g, "").replace(/_+/g, "_");
41334
41394
  }
@@ -41349,9 +41409,9 @@ function newMigration(args, deps = {}) {
41349
41409
  }
41350
41410
  const slug = slugify(rawName);
41351
41411
  const stamp = genTimestamp({ cwd });
41352
- const migrationsDir = path21.join(cwd, "supabase", "migrations");
41412
+ const migrationsDir = path22.join(cwd, "supabase", "migrations");
41353
41413
  const filename = `${stamp}_${slug}.sql`;
41354
- const filePath = path21.join(migrationsDir, filename);
41414
+ const filePath = path22.join(migrationsDir, filename);
41355
41415
  mkdirSync12(migrationsDir, { recursive: true });
41356
41416
  writeFileSync13(filePath, "");
41357
41417
  process.stdout.write(JSON.stringify({ path: filePath }) + "\n");
@@ -41397,7 +41457,7 @@ function defaultGetPrNumber(cwd, run) {
41397
41457
  async function previewCheck(args, deps = {}) {
41398
41458
  const cwd = deps.cwd ?? process.cwd();
41399
41459
  const run = deps.run ?? defaultRun4;
41400
- const sleep3 = deps.sleep ?? ((ms) => new Promise((resolve16) => setTimeout(resolve16, ms)));
41460
+ const sleep3 = deps.sleep ?? ((ms) => new Promise((resolve17) => setTimeout(resolve17, ms)));
41401
41461
  const getPrNumber = deps.getPrNumber ?? defaultGetPrNumber;
41402
41462
  const poll = deps.pollCheck ?? pollGhPreviewCheck;
41403
41463
  let mode = "pre_merge";
@@ -41717,13 +41777,13 @@ function validateWaves(waves) {
41717
41777
  pathOwners.set(file, owners);
41718
41778
  }
41719
41779
  }
41720
- for (const [path22, owners] of pathOwners) {
41780
+ for (const [path23, owners] of pathOwners) {
41721
41781
  if (owners.length > 1) {
41722
41782
  violations.push({
41723
41783
  invariant: "I",
41724
41784
  code: "DUPLICATE_FILE",
41725
- message: `File "${path22}" appears in multiple waves: ${owners.join(", ")}.`,
41726
- detail: { path: path22, waves: owners }
41785
+ message: `File "${path23}" appears in multiple waves: ${owners.join(", ")}.`,
41786
+ detail: { path: path23, waves: owners }
41727
41787
  });
41728
41788
  }
41729
41789
  }
@@ -41817,14 +41877,14 @@ var validate_waves_exports = {};
41817
41877
  __export(validate_waves_exports, {
41818
41878
  runValidateWavesCommand: () => runValidateWavesCommand
41819
41879
  });
41820
- import { readFile as readFile31 } from "node:fs/promises";
41880
+ import { readFile as readFile32 } from "node:fs/promises";
41821
41881
  async function readStdin() {
41822
- return new Promise((resolve16, reject) => {
41882
+ return new Promise((resolve17, reject) => {
41823
41883
  const chunks = [];
41824
41884
  process.stdin.on("data", (chunk) => chunks.push(chunk));
41825
41885
  process.stdin.on(
41826
41886
  "end",
41827
- () => resolve16(Buffer.concat(chunks).toString("utf-8"))
41887
+ () => resolve17(Buffer.concat(chunks).toString("utf-8"))
41828
41888
  );
41829
41889
  process.stdin.on("error", reject);
41830
41890
  });
@@ -41836,7 +41896,7 @@ async function runValidateWavesCommand(args) {
41836
41896
  let raw;
41837
41897
  if (filePath) {
41838
41898
  try {
41839
- raw = await readFile31(filePath, "utf-8");
41899
+ raw = await readFile32(filePath, "utf-8");
41840
41900
  } catch (err) {
41841
41901
  const msg = err instanceof Error ? err.message : String(err);
41842
41902
  process.stderr.write(
@@ -41931,7 +41991,7 @@ var init_path = __esm({
41931
41991
 
41932
41992
  // src/cli/worktree/add.ts
41933
41993
  import { join as join57, basename as basename5 } from "node:path";
41934
- import { mkdir as mkdir15, readFile as readFile32, writeFile as writeFile25 } from "node:fs/promises";
41994
+ import { mkdir as mkdir15, readFile as readFile33, writeFile as writeFile25 } from "node:fs/promises";
41935
41995
  import { spawnSync as spawnSync18 } from "node:child_process";
41936
41996
  async function defaultGetRepoId(cwd) {
41937
41997
  const found = await findCodebyplanConfig(cwd);
@@ -41974,7 +42034,7 @@ function defaultGitRun(args, cwd) {
41974
42034
  };
41975
42035
  }
41976
42036
  async function copyClaudeSettings(srcCwd, destPath, deps = {}) {
41977
- const readFileFn = deps.readFileFn ?? ((p) => readFile32(p, "utf-8"));
42037
+ const readFileFn = deps.readFileFn ?? ((p) => readFile33(p, "utf-8"));
41978
42038
  const writeFileFn = deps.writeFileFn ?? ((p, content) => writeFile25(p, content, "utf-8"));
41979
42039
  const existsFn = deps.existsFn ?? ((p) => import("node:fs/promises").then(
41980
42040
  (fsp) => fsp.access(p).then(() => true).catch(() => false)
@@ -41999,13 +42059,13 @@ async function defaultCopyConfigStubs(srcCwd, destPath) {
41999
42059
  const topLevelStubs = [".mcp.json", ".env.local"];
42000
42060
  for (const stub of topLevelStubs) {
42001
42061
  try {
42002
- const content = await readFile32(join57(srcCwd, stub), "utf-8");
42062
+ const content = await readFile33(join57(srcCwd, stub), "utf-8");
42003
42063
  await writeFile25(join57(destPath, stub), content, "utf-8");
42004
42064
  } catch {
42005
42065
  }
42006
42066
  }
42007
42067
  try {
42008
- const content = await readFile32(
42068
+ const content = await readFile33(
42009
42069
  join57(srcCwd, ".codebyplan", "repo.json"),
42010
42070
  "utf-8"
42011
42071
  );
@@ -42018,11 +42078,11 @@ async function defaultCopyConfigStubs(srcCwd, destPath) {
42018
42078
  }
42019
42079
  await copyClaudeSettings(srcCwd, destPath);
42020
42080
  }
42021
- async function defaultRegisterWorktree(repoId, name, path22) {
42081
+ async function defaultRegisterWorktree(repoId, name, path23) {
42022
42082
  const res = await apiPost("/worktrees", {
42023
42083
  repo_id: repoId,
42024
42084
  name,
42025
- path: path22,
42085
+ path: path23,
42026
42086
  status: "active"
42027
42087
  });
42028
42088
  return { worktree_id: res.data.id };
@@ -42056,7 +42116,7 @@ async function runWorktreeAdd(args, deps = {}) {
42056
42116
  const getRepoId = deps.getRepoId ?? defaultGetRepoId;
42057
42117
  const lookupBranch = deps.lookupBranch ?? defaultLookupBranch;
42058
42118
  const gitRun = deps.gitRun ?? defaultGitRun;
42059
- const sleep3 = deps.sleep ?? ((ms) => new Promise((resolve16) => setTimeout(resolve16, ms)));
42119
+ const sleep3 = deps.sleep ?? ((ms) => new Promise((resolve17) => setTimeout(resolve17, ms)));
42060
42120
  const copyConfigStubs = deps.copyConfigStubs ?? defaultCopyConfigStubs;
42061
42121
  const registerWorktree = deps.registerWorktree ?? defaultRegisterWorktree;
42062
42122
  try {
@@ -42187,11 +42247,11 @@ async function defaultGetRepoIdentity(cwd) {
42187
42247
  project_id: typeof contents?.["project_id"] === "string" ? contents["project_id"] : void 0
42188
42248
  };
42189
42249
  }
42190
- async function defaultRegisterWorktree2(repoId, name, path22) {
42250
+ async function defaultRegisterWorktree2(repoId, name, path23) {
42191
42251
  const res = await apiPost("/worktrees", {
42192
42252
  repo_id: repoId,
42193
42253
  name,
42194
- path: path22,
42254
+ path: path23,
42195
42255
  status: "active"
42196
42256
  });
42197
42257
  return { worktree_id: res.data.id };
@@ -42742,15 +42802,15 @@ var init_e2e = __esm({
42742
42802
  });
42743
42803
 
42744
42804
  // src/cli/e2e/verify-round.ts
42745
- import { readFile as readFile33 } from "node:fs/promises";
42746
- import { resolve as resolve14 } from "node:path";
42805
+ import { readFile as readFile34 } from "node:fs/promises";
42806
+ import { resolve as resolve15 } from "node:path";
42747
42807
  async function defaultFetchRounds(taskId) {
42748
42808
  return mcpCall("get_rounds", { task_id: taskId });
42749
42809
  }
42750
42810
  async function defaultReadE2eConfig(cwd) {
42751
42811
  try {
42752
- const p = resolve14(cwd, ".codebyplan", "e2e.json");
42753
- const raw = await readFile33(p, "utf-8");
42812
+ const p = resolve15(cwd, ".codebyplan", "e2e.json");
42813
+ const raw = await readFile34(p, "utf-8");
42754
42814
  return JSON.parse(raw);
42755
42815
  } catch {
42756
42816
  return null;
@@ -43164,11 +43224,11 @@ var init_doctor = __esm({
43164
43224
  // src/index.ts
43165
43225
  init_version();
43166
43226
  import { readFileSync as readFileSync20 } from "node:fs";
43167
- import { resolve as resolve15 } from "node:path";
43227
+ import { resolve as resolve16 } from "node:path";
43168
43228
  void (async () => {
43169
43229
  if (!process.env.CODEBYPLAN_API_KEY) {
43170
43230
  try {
43171
- const envPath = resolve15(process.cwd(), ".env.local");
43231
+ const envPath = resolve16(process.cwd(), ".env.local");
43172
43232
  const content = readFileSync20(envPath, "utf-8");
43173
43233
  for (const line of content.split("\n")) {
43174
43234
  const trimmed = line.trim();