codebyplan 1.13.57 → 1.13.58

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -5,11 +5,20 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
6
  var __getProtoOf = Object.getPrototypeOf;
7
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
- var __esm = (fn, res) => function __init() {
9
- return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
8
+ var __esm = (fn, res, err) => function __init() {
9
+ if (err) throw err[0];
10
+ try {
11
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
12
+ } catch (e) {
13
+ throw err = [e], e;
14
+ }
10
15
  };
11
16
  var __commonJS = (cb, mod) => function __require() {
12
- return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
17
+ try {
18
+ return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
19
+ } catch (e) {
20
+ throw mod = 0, e;
21
+ }
13
22
  };
14
23
  var __export = (target, all) => {
15
24
  for (var name in all)
@@ -39,7 +48,7 @@ var VERSION, PACKAGE_NAME;
39
48
  var init_version = __esm({
40
49
  "src/lib/version.ts"() {
41
50
  "use strict";
42
- VERSION = "1.13.57";
51
+ VERSION = "1.13.58";
43
52
  PACKAGE_NAME = "codebyplan";
44
53
  }
45
54
  });
@@ -14526,8 +14535,8 @@ var require_RealtimeChannel = __commonJS({
14526
14535
  }
14527
14536
  /** @internal */
14528
14537
  _notThisChannelEvent(event, ref) {
14529
- const { close, error, leave, join: join56 } = constants_1.CHANNEL_EVENTS;
14530
- const events = [close, error, leave, join56];
14538
+ const { close, error, leave, join: join57 } = constants_1.CHANNEL_EVENTS;
14539
+ const events = [close, error, leave, join57];
14531
14540
  return ref && events.includes(event) && ref !== this.joinPush.ref;
14532
14541
  }
14533
14542
  /** @internal */
@@ -29578,6 +29587,1264 @@ var init_standalone_task = __esm({
29578
29587
  }
29579
29588
  });
29580
29589
 
29590
+ // src/lib/supabase.ts
29591
+ import * as fs5 from "node:fs";
29592
+ import * as path7 from "node:path";
29593
+ import { spawnSync as spawnSync6 } from "node:child_process";
29594
+ function defaultRun(cmd, args) {
29595
+ const result = spawnSync6(cmd, args, {
29596
+ encoding: "utf-8",
29597
+ stdio: ["pipe", "pipe", "pipe"]
29598
+ });
29599
+ if (result.error) throw result.error;
29600
+ return (result.stdout ?? "").toString();
29601
+ }
29602
+ function readJsonFile2(filePath) {
29603
+ try {
29604
+ const raw = fs5.readFileSync(filePath, "utf-8");
29605
+ const parsed = JSON.parse(raw);
29606
+ if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) {
29607
+ return parsed;
29608
+ }
29609
+ return null;
29610
+ } catch {
29611
+ return null;
29612
+ }
29613
+ }
29614
+ function getSupabaseSection(obj) {
29615
+ const tryPath = (root) => {
29616
+ const surfaces = root["surfaces"];
29617
+ if (typeof surfaces !== "object" || surfaces === null || Array.isArray(surfaces))
29618
+ return null;
29619
+ const sb = surfaces["supabase"];
29620
+ if (typeof sb === "object" && sb !== null && !Array.isArray(sb)) {
29621
+ return sb;
29622
+ }
29623
+ return null;
29624
+ };
29625
+ const shipment = obj["shipment"];
29626
+ if (typeof shipment === "object" && shipment !== null && !Array.isArray(shipment)) {
29627
+ const found = tryPath(shipment);
29628
+ if (found) return found;
29629
+ }
29630
+ return tryPath(obj);
29631
+ }
29632
+ function globToRegex(pattern) {
29633
+ const special = ".+^${}()|[]\\";
29634
+ let r = "";
29635
+ for (let i = 0; i < pattern.length; i++) {
29636
+ const ch = pattern[i] ?? "";
29637
+ if (ch === "*") {
29638
+ if (pattern[i + 1] === "*") {
29639
+ r += ".*";
29640
+ i++;
29641
+ } else {
29642
+ r += "[^/]*";
29643
+ }
29644
+ } else if (ch === "?") {
29645
+ r += "[^/]";
29646
+ } else if (special.includes(ch)) {
29647
+ r += "\\" + ch;
29648
+ } else {
29649
+ r += ch;
29650
+ }
29651
+ }
29652
+ return new RegExp(`^${r}$`);
29653
+ }
29654
+ function dateToStamp(d) {
29655
+ const pad2 = (n) => String(n).padStart(2, "0");
29656
+ return String(d.getUTCFullYear()) + pad2(d.getUTCMonth() + 1) + pad2(d.getUTCDate()) + pad2(d.getUTCHours()) + pad2(d.getUTCMinutes()) + pad2(d.getUTCSeconds());
29657
+ }
29658
+ function extractStampToken(filename) {
29659
+ if (!filename.endsWith(".sql")) return null;
29660
+ const base = filename.slice(0, -4);
29661
+ const parts = base.split("_");
29662
+ const first = parts[0];
29663
+ if (!first || !/^\d{14}$/.test(first)) return null;
29664
+ const second = parts[1];
29665
+ if (second && /^\d{2}$/.test(second)) {
29666
+ return `${first}_${second}`;
29667
+ }
29668
+ return first;
29669
+ }
29670
+ function readShipmentConfig(cwd) {
29671
+ const dir = cwd ?? process.cwd();
29672
+ const obj = readJsonFile2(path7.join(dir, ".codebyplan", "shipment.json"));
29673
+ if (!obj) return { parentRef: null, previewBranches: [] };
29674
+ const section = getSupabaseSection(obj);
29675
+ if (!section) return { parentRef: null, previewBranches: [] };
29676
+ const parentRef = typeof section["project_ref"] === "string" ? section["project_ref"] : null;
29677
+ const previewBranches = [];
29678
+ const rawBranches = section["preview_branches"];
29679
+ if (Array.isArray(rawBranches)) {
29680
+ for (const b of rawBranches) {
29681
+ if (typeof b !== "object" || b === null || Array.isArray(b)) continue;
29682
+ const entry = b;
29683
+ if (typeof entry["branch"] !== "string" || typeof entry["project_ref"] !== "string")
29684
+ continue;
29685
+ previewBranches.push({
29686
+ branch: entry["branch"],
29687
+ project_ref: entry["project_ref"],
29688
+ created_at: typeof entry["created_at"] === "string" ? entry["created_at"] : void 0
29689
+ });
29690
+ }
29691
+ }
29692
+ return { parentRef, previewBranches };
29693
+ }
29694
+ function readGitConfig(cwd) {
29695
+ const dir = cwd ?? process.cwd();
29696
+ const obj = readJsonFile2(path7.join(dir, ".codebyplan", "git.json"));
29697
+ if (!obj) return { ...GIT_DEFAULTS };
29698
+ const bc = obj["branch_config"];
29699
+ if (typeof bc !== "object" || bc === null || Array.isArray(bc)) {
29700
+ return { ...GIT_DEFAULTS };
29701
+ }
29702
+ const bcObj = bc;
29703
+ const production = typeof bcObj["production"] === "string" && bcObj["production"] ? bcObj["production"] : "main";
29704
+ const protectedArr = [];
29705
+ const rawProtected = bcObj["protected"];
29706
+ if (Array.isArray(rawProtected)) {
29707
+ for (const p of rawProtected) {
29708
+ if (typeof p === "string" && p) protectedArr.push(p);
29709
+ }
29710
+ }
29711
+ if (protectedArr.length === 0) protectedArr.push(production);
29712
+ const integration = typeof bcObj["integration"] === "string" && bcObj["integration"] ? bcObj["integration"] : null;
29713
+ return { production, protected: protectedArr, integration };
29714
+ }
29715
+ function readDbPaths(cwd) {
29716
+ const dir = cwd ?? process.cwd();
29717
+ const obj = readJsonFile2(path7.join(dir, ".codebyplan", "shipment.json"));
29718
+ if (!obj) return [...DEFAULT_DB_PATHS];
29719
+ const section = getSupabaseSection(obj);
29720
+ if (!section) return [...DEFAULT_DB_PATHS];
29721
+ const rawPaths = section["db_paths"];
29722
+ if (!Array.isArray(rawPaths) || rawPaths.length === 0)
29723
+ return [...DEFAULT_DB_PATHS];
29724
+ const paths = [];
29725
+ for (const p of rawPaths) {
29726
+ if (typeof p === "string" && p) paths.push(p);
29727
+ }
29728
+ return paths.length > 0 ? paths : [...DEFAULT_DB_PATHS];
29729
+ }
29730
+ function detectDbChanged(opts = {}) {
29731
+ const cwd = opts.cwd ?? process.cwd();
29732
+ const run = opts.run ?? defaultRun;
29733
+ const base = opts.base ?? readGitConfig(cwd).production;
29734
+ const dbPaths = opts.dbPaths ?? readDbPaths(cwd);
29735
+ if (dbPaths.length === 0) return false;
29736
+ const regexes = dbPaths.map(globToRegex);
29737
+ let output;
29738
+ try {
29739
+ output = run("git", ["diff", "--name-only", `origin/${base}...HEAD`]);
29740
+ } catch {
29741
+ return false;
29742
+ }
29743
+ const changedFiles = output.split("\n").map((l) => l.trim()).filter(Boolean);
29744
+ return changedFiles.some((file) => regexes.some((re) => re.test(file)));
29745
+ }
29746
+ function defaultListDir(dir) {
29747
+ try {
29748
+ return fs5.readdirSync(dir);
29749
+ } catch {
29750
+ return [];
29751
+ }
29752
+ }
29753
+ function generateMonotonicTimestamp(opts = {}) {
29754
+ const cwd = opts.cwd ?? process.cwd();
29755
+ const now = opts.now ?? /* @__PURE__ */ new Date();
29756
+ const listDir = opts.listDir ?? defaultListDir;
29757
+ const migrationsDir = path7.join(cwd, "supabase", "migrations");
29758
+ const files = listDir(migrationsDir);
29759
+ const existingStamps = /* @__PURE__ */ new Set();
29760
+ for (const file of files) {
29761
+ const token = extractStampToken(file);
29762
+ if (token) existingStamps.add(token);
29763
+ }
29764
+ let maxStamp = "";
29765
+ for (const s of existingStamps) {
29766
+ if (s > maxStamp) maxStamp = s;
29767
+ }
29768
+ const computed = dateToStamp(now);
29769
+ if (computed > maxStamp && !existingStamps.has(computed)) {
29770
+ return computed;
29771
+ }
29772
+ const collisionBase14 = computed > maxStamp ? computed : maxStamp.slice(0, 14);
29773
+ for (let i = 1; i <= 99; i++) {
29774
+ const suffix = String(i).padStart(2, "0");
29775
+ const candidate = `${collisionBase14}_${suffix}`;
29776
+ if (!existingStamps.has(candidate) && candidate > maxStamp) {
29777
+ return candidate;
29778
+ }
29779
+ }
29780
+ return `${collisionBase14}_99`;
29781
+ }
29782
+ async function pollGhPreviewCheck(opts = {}) {
29783
+ const run = opts.run ?? defaultRun;
29784
+ const sleep3 = opts.sleep ?? ((ms) => new Promise((resolve16) => setTimeout(resolve16, ms)));
29785
+ const maxPolls = opts.maxPolls ?? 20;
29786
+ const intervalMs = opts.intervalMs ?? 15e3;
29787
+ if (!opts.prNumber) {
29788
+ return {
29789
+ status: "pending_pr",
29790
+ reason: "No PR number \u2014 branch has no open pull request yet."
29791
+ };
29792
+ }
29793
+ try {
29794
+ run("gh", ["--version"]);
29795
+ } catch {
29796
+ return {
29797
+ status: "blocked",
29798
+ reason: "gh CLI not available"
29799
+ };
29800
+ }
29801
+ const prNumber = opts.prNumber;
29802
+ for (let poll = 0; poll < maxPolls; poll++) {
29803
+ if (poll > 0) {
29804
+ await sleep3(intervalMs);
29805
+ }
29806
+ let checksOutput;
29807
+ try {
29808
+ try {
29809
+ checksOutput = run("gh", [
29810
+ "pr",
29811
+ "checks",
29812
+ prNumber,
29813
+ "--json",
29814
+ "name,bucket,state"
29815
+ ]);
29816
+ } catch {
29817
+ checksOutput = run("gh", [
29818
+ "pr",
29819
+ "checks",
29820
+ prNumber,
29821
+ "--json",
29822
+ "name,state"
29823
+ ]);
29824
+ }
29825
+ } catch {
29826
+ if (poll === maxPolls - 1) {
29827
+ return {
29828
+ status: "blocked",
29829
+ reason: `gh pr checks failed after ${maxPolls} polls`
29830
+ };
29831
+ }
29832
+ continue;
29833
+ }
29834
+ let checks;
29835
+ try {
29836
+ const parsed = JSON.parse(checksOutput);
29837
+ checks = Array.isArray(parsed) ? parsed : [];
29838
+ } catch {
29839
+ checks = [];
29840
+ }
29841
+ const supabaseCheck = checks.find(
29842
+ (c) => typeof c["name"] === "string" && c["name"].toLowerCase().includes("supabase preview")
29843
+ );
29844
+ if (!supabaseCheck) {
29845
+ continue;
29846
+ }
29847
+ const bucket = typeof supabaseCheck["bucket"] === "string" ? supabaseCheck["bucket"].toLowerCase() : null;
29848
+ const state = typeof supabaseCheck["state"] === "string" ? supabaseCheck["state"].toLowerCase() : null;
29849
+ if (bucket === "pass") {
29850
+ return { status: "passed", reason: "Supabase Preview check passed." };
29851
+ }
29852
+ if (bucket === "skipping") {
29853
+ return {
29854
+ status: "skipped",
29855
+ reason: "Supabase Preview check skipped at CI."
29856
+ };
29857
+ }
29858
+ if (bucket === "fail" || bucket === "cancel") {
29859
+ return {
29860
+ status: "blocked",
29861
+ reason: `Supabase Preview check ${bucket}ed.`
29862
+ };
29863
+ }
29864
+ if (state === "success") {
29865
+ return { status: "passed", reason: "Supabase Preview check passed." };
29866
+ }
29867
+ if (state === "skipped" || state === "neutral") {
29868
+ return {
29869
+ status: "skipped",
29870
+ reason: "Supabase Preview check skipped at CI."
29871
+ };
29872
+ }
29873
+ if (state === "failure" || state === "cancelled" || state === "error" || state === "timed_out" || state === "stale" || state === "action_required") {
29874
+ return {
29875
+ status: "blocked",
29876
+ reason: `Supabase Preview check ${state}.`
29877
+ };
29878
+ }
29879
+ }
29880
+ const minutesStr = Math.round(maxPolls * intervalMs / 6e4);
29881
+ return {
29882
+ status: "blocked",
29883
+ reason: `Supabase Preview check still pending after ${minutesStr} min (${maxPolls} polls)`
29884
+ };
29885
+ }
29886
+ var GIT_DEFAULTS, DEFAULT_DB_PATHS;
29887
+ var init_supabase = __esm({
29888
+ "src/lib/supabase.ts"() {
29889
+ "use strict";
29890
+ GIT_DEFAULTS = {
29891
+ production: "main",
29892
+ protected: ["main"],
29893
+ integration: null
29894
+ };
29895
+ DEFAULT_DB_PATHS = [
29896
+ "supabase/**",
29897
+ "apps/backend/**",
29898
+ "packages/**/db/**"
29899
+ ];
29900
+ }
29901
+ });
29902
+
29903
+ // src/lib/session.ts
29904
+ import { spawnSync as spawnSync7 } from "node:child_process";
29905
+ import { existsSync as nodeExistsSync } from "node:fs";
29906
+ import * as path8 from "node:path";
29907
+ function defaultRun2(cmd, args, cwd) {
29908
+ const result = spawnSync7(cmd, args, {
29909
+ cwd,
29910
+ encoding: "utf-8",
29911
+ stdio: ["pipe", "pipe", "pipe"]
29912
+ });
29913
+ if (result.error) throw result.error;
29914
+ if (result.status !== 0) {
29915
+ const stderr = (result.stderr ?? "").toString().trim();
29916
+ throw new Error(
29917
+ `${cmd} ${args.join(" ")} exited ${result.status ?? "null"}${stderr ? `: ${stderr}` : ""}`
29918
+ );
29919
+ }
29920
+ return (result.stdout ?? "").toString();
29921
+ }
29922
+ function homeFf(opts = {}) {
29923
+ const cwd = opts.cwd ?? process.cwd();
29924
+ const run = opts.run ?? defaultRun2;
29925
+ const gitCfg = readGitConfig(cwd);
29926
+ const production = gitCfg.production;
29927
+ let repoRoot;
29928
+ try {
29929
+ repoRoot = run("git", ["rev-parse", "--show-toplevel"], cwd).trim();
29930
+ } catch {
29931
+ return {
29932
+ result: "skipped",
29933
+ reason: "git rev-parse --show-toplevel failed"
29934
+ };
29935
+ }
29936
+ const folder = path8.basename(repoRoot);
29937
+ let current;
29938
+ try {
29939
+ current = run("git", ["rev-parse", "--abbrev-ref", "HEAD"], cwd).trim();
29940
+ } catch {
29941
+ return {
29942
+ result: "skipped",
29943
+ reason: "git rev-parse --abbrev-ref HEAD failed"
29944
+ };
29945
+ }
29946
+ if (current !== folder) {
29947
+ return { result: "skipped", reason: "not on home branch" };
29948
+ }
29949
+ try {
29950
+ run("git", ["fetch", "origin", production], cwd);
29951
+ } catch {
29952
+ return {
29953
+ result: "warn",
29954
+ warn: `fetch failed \u2014 staying on local ${current}`
29955
+ };
29956
+ }
29957
+ try {
29958
+ run("git", ["merge", "--ff-only", `origin/${production}`], cwd);
29959
+ } catch {
29960
+ return {
29961
+ result: "warn",
29962
+ warn: `${current} not fast-forwardable (ahead/diverged) \u2014 left untouched`
29963
+ };
29964
+ }
29965
+ return { result: "fast_forwarded" };
29966
+ }
29967
+ function spawnVersionStatus(cwd) {
29968
+ try {
29969
+ const result = spawnSync7("npx", ["codebyplan", "version-status"], {
29970
+ cwd,
29971
+ encoding: "utf-8",
29972
+ stdio: ["pipe", "pipe", "pipe"]
29973
+ });
29974
+ if (result.error) return null;
29975
+ const raw = (result.stdout ?? "").toString().trim();
29976
+ if (!raw) return null;
29977
+ const parsed = JSON.parse(raw);
29978
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
29979
+ return null;
29980
+ }
29981
+ const obj = parsed;
29982
+ if (typeof obj["installed"] !== "string" || typeof obj["newer"] !== "boolean" || typeof obj["guarded"] !== "boolean" || typeof obj["installCommand"] !== "string") {
29983
+ return null;
29984
+ }
29985
+ return {
29986
+ installed: obj["installed"],
29987
+ latest: typeof obj["latest"] === "string" ? obj["latest"] : null,
29988
+ newer: obj["newer"],
29989
+ packageManager: typeof obj["packageManager"] === "string" ? obj["packageManager"] : "npm",
29990
+ installCommand: obj["installCommand"],
29991
+ guarded: obj["guarded"],
29992
+ guardReason: typeof obj["guardReason"] === "string" ? obj["guardReason"] : null
29993
+ };
29994
+ } catch {
29995
+ return null;
29996
+ }
29997
+ }
29998
+ function defaultRunInstall(installCommand, cwd) {
29999
+ const parts = installCommand.trim().split(/\s+/);
30000
+ const cmd = parts[0];
30001
+ const args = parts.slice(1);
30002
+ if (!cmd) throw new Error("empty installCommand");
30003
+ const result = spawnSync7(cmd, args, {
30004
+ cwd,
30005
+ encoding: "utf-8",
30006
+ stdio: ["pipe", "pipe", "pipe"]
30007
+ });
30008
+ if (result.error) throw result.error;
30009
+ if (result.status !== 0) {
30010
+ const stderr = (result.stderr ?? "").toString().trim();
30011
+ throw new Error(
30012
+ `install exited ${result.status}${stderr ? `: ${stderr}` : ""}`
30013
+ );
30014
+ }
30015
+ }
30016
+ function defaultRunClaudeUpdate(cwd) {
30017
+ const result = spawnSync7("npx", ["codebyplan", "claude", "update", "--yes"], {
30018
+ cwd,
30019
+ encoding: "utf-8",
30020
+ stdio: ["pipe", "pipe", "pipe"]
30021
+ });
30022
+ if (result.error) throw result.error;
30023
+ if (result.status !== 0) {
30024
+ const stderr = (result.stderr ?? "").toString().trim();
30025
+ throw new Error(
30026
+ `claude update exited ${result.status}${stderr ? `: ${stderr}` : ""}`
30027
+ );
30028
+ }
30029
+ }
30030
+ function defaultRunGitStatus(cwd) {
30031
+ const result = spawnSync7(
30032
+ "git",
30033
+ ["status", "--porcelain", "--", ".claude/", ".codebyplan/"],
30034
+ {
30035
+ cwd,
30036
+ encoding: "utf-8",
30037
+ stdio: ["pipe", "pipe", "pipe"]
30038
+ }
30039
+ );
30040
+ if (result.error) throw result.error;
30041
+ return (result.stdout ?? "").toString();
30042
+ }
30043
+ async function freshnessGate(opts = {}) {
30044
+ const cwd = opts.cwd ?? process.cwd();
30045
+ const probeVersionStatus = opts.probeVersionStatus ?? ((c) => spawnVersionStatus(c));
30046
+ const runInstall2 = opts.runInstall ?? defaultRunInstall;
30047
+ const runClaudeUpdate = opts.runClaudeUpdate ?? defaultRunClaudeUpdate;
30048
+ const runGitStatus = opts.runGitStatus ?? defaultRunGitStatus;
30049
+ const haltOnUpdate = opts.haltOnUpdate ?? false;
30050
+ let probe;
30051
+ try {
30052
+ probe = probeVersionStatus(cwd);
30053
+ } catch {
30054
+ probe = null;
30055
+ }
30056
+ if (!probe) {
30057
+ return { result: "skipped", reason: "probe failed (fail-safe)" };
30058
+ }
30059
+ if (probe.guarded) {
30060
+ return { result: "guarded" };
30061
+ }
30062
+ if (!probe.newer) {
30063
+ return { result: "up_to_date" };
30064
+ }
30065
+ try {
30066
+ runInstall2(probe.installCommand, cwd);
30067
+ } catch (err) {
30068
+ const reason = err instanceof Error ? err.message : "install failed (unknown error)";
30069
+ return { result: "error", reason };
30070
+ }
30071
+ try {
30072
+ runClaudeUpdate(cwd);
30073
+ } catch (err) {
30074
+ const reason = err instanceof Error ? err.message : "claude update failed (unknown error)";
30075
+ return { result: "error", reason };
30076
+ }
30077
+ let gitStatusOutput = "";
30078
+ try {
30079
+ gitStatusOutput = runGitStatus(cwd);
30080
+ } catch {
30081
+ gitStatusOutput = "";
30082
+ }
30083
+ const changedFiles = gitStatusOutput.split("\n").map((line) => line.trim()).filter(Boolean).map((line) => {
30084
+ const parts = line.split(/\s+/);
30085
+ return parts.slice(1).join(" ");
30086
+ }).filter(Boolean);
30087
+ return {
30088
+ result: "updated",
30089
+ latest: probe.latest ?? probe.installed,
30090
+ changed_files: changedFiles,
30091
+ halt: haltOnUpdate
30092
+ };
30093
+ }
30094
+ async function infraFiles(opts = {}) {
30095
+ const cwd = opts.cwd ?? process.cwd();
30096
+ const run = opts.run ?? defaultRun2;
30097
+ const getTaskFiles = opts.getTaskFiles ?? (() => Promise.resolve([]));
30098
+ let firstOutput;
30099
+ try {
30100
+ firstOutput = run("git", ["status", "--porcelain"], cwd);
30101
+ } catch {
30102
+ firstOutput = "";
30103
+ }
30104
+ const firstChanged = parseGitStatus2(firstOutput);
30105
+ if (firstChanged.length === 0) {
30106
+ return { infra_files: [], task_files: [], note: "clean tree" };
30107
+ }
30108
+ const taskFiles = await getTaskFiles();
30109
+ const taskSet = new Set(taskFiles);
30110
+ let secondOutput;
30111
+ try {
30112
+ secondOutput = run("git", ["status", "--porcelain"], cwd);
30113
+ } catch {
30114
+ secondOutput = "";
30115
+ }
30116
+ const freshChanged = parseGitStatus2(secondOutput);
30117
+ const infraFilesList = freshChanged.filter((f) => !taskSet.has(f));
30118
+ return {
30119
+ infra_files: infraFilesList,
30120
+ task_files: taskFiles
30121
+ };
30122
+ }
30123
+ function resolveWorktreeJson(opts = {}) {
30124
+ const cwd = opts.cwd ?? process.cwd();
30125
+ const run = opts.run ?? defaultRun2;
30126
+ try {
30127
+ const stdout7 = run(
30128
+ "npx",
30129
+ ["codebyplan", "resolve-worktree", "--json"],
30130
+ cwd
30131
+ );
30132
+ const raw = stdout7.trim();
30133
+ if (!raw) {
30134
+ return { worktree_id: null, error_kind: "tuple_miss" };
30135
+ }
30136
+ const parsed = JSON.parse(raw);
30137
+ const worktree_id = typeof parsed["worktree_id"] === "string" ? parsed["worktree_id"] : null;
30138
+ const error_kind = typeof parsed["error_kind"] === "string" ? parsed["error_kind"] : null;
30139
+ return { worktree_id, error_kind };
30140
+ } catch (err) {
30141
+ process.stderr.write(
30142
+ `session: resolveWorktreeJson failed (non-fatal): ${err instanceof Error ? err.message : String(err)}
30143
+ `
30144
+ );
30145
+ return { worktree_id: null, error_kind: "unhandled" };
30146
+ }
30147
+ }
30148
+ function infraDriftNudge(opts = {}) {
30149
+ const cwd = opts.cwd ?? process.cwd();
30150
+ const run = opts.run ?? defaultRun2;
30151
+ const existsSync24 = opts.existsSync ?? ((p) => {
30152
+ try {
30153
+ return nodeExistsSync(p);
30154
+ } catch {
30155
+ return false;
30156
+ }
30157
+ });
30158
+ try {
30159
+ const driftScript = path8.join(cwd, "scripts", "infra-drift.mjs");
30160
+ const templatesDir = path8.join(
30161
+ cwd,
30162
+ "packages",
30163
+ "codebyplan-package",
30164
+ "templates"
30165
+ );
30166
+ if (!existsSync24(driftScript) || !existsSync24(templatesDir)) {
30167
+ return null;
30168
+ }
30169
+ try {
30170
+ const production = readGitConfig(cwd).production || "main";
30171
+ run("git", ["fetch", "origin", production], cwd);
30172
+ } catch {
30173
+ }
30174
+ let output = "";
30175
+ try {
30176
+ output = run("node", [driftScript], cwd);
30177
+ } catch {
30178
+ return null;
30179
+ }
30180
+ const line = output.trim();
30181
+ return line || null;
30182
+ } catch (err) {
30183
+ process.stderr.write(
30184
+ `session: infraDriftNudge failed (non-fatal): ${err instanceof Error ? err.message : String(err)}
30185
+ `
30186
+ );
30187
+ return null;
30188
+ }
30189
+ }
30190
+ function archMapDriftNudge(opts = {}) {
30191
+ const cwd = opts.cwd ?? process.cwd();
30192
+ const run = opts.run ?? defaultRun2;
30193
+ const existsSync24 = opts.existsSync ?? ((p) => {
30194
+ try {
30195
+ return nodeExistsSync(p);
30196
+ } catch {
30197
+ return false;
30198
+ }
30199
+ });
30200
+ try {
30201
+ const manifestPath2 = path8.join(cwd, ".codebyplan", "architecture.json");
30202
+ if (!existsSync24(manifestPath2)) {
30203
+ return null;
30204
+ }
30205
+ let output = "";
30206
+ try {
30207
+ output = run("npx", ["codebyplan", "arch-map", "drift"], cwd);
30208
+ } catch {
30209
+ return null;
30210
+ }
30211
+ const driftedCount = output.split("\n").filter((line) => /^\s*DRIFTED/.test(line)).length;
30212
+ if (driftedCount > 0) {
30213
+ return `\u26A0 .claude/architecture is ${driftedCount} module(s) stale \u2014 run /cbp-refresh-arch-map`;
30214
+ }
30215
+ return null;
30216
+ } catch (err) {
30217
+ process.stderr.write(
30218
+ `session: archMapDriftNudge failed (non-fatal): ${err instanceof Error ? err.message : String(err)}
30219
+ `
30220
+ );
30221
+ return null;
30222
+ }
30223
+ }
30224
+ function lspNudge(opts = {}) {
30225
+ const cwd = opts.cwd ?? process.cwd();
30226
+ const run = opts.run ?? defaultRun2;
30227
+ try {
30228
+ let output = "";
30229
+ try {
30230
+ output = run("npx", ["codebyplan", "lsp", "--check"], cwd);
30231
+ } catch {
30232
+ return [];
30233
+ }
30234
+ return output.split("\n").map((l) => l.trim()).filter(Boolean);
30235
+ } catch (err) {
30236
+ process.stderr.write(
30237
+ `session: lspNudge failed (non-fatal): ${err instanceof Error ? err.message : String(err)}
30238
+ `
30239
+ );
30240
+ return [];
30241
+ }
30242
+ }
30243
+ async function probeHandoff(opts) {
30244
+ const stale = { fresh: false };
30245
+ try {
30246
+ const {
30247
+ repoRoot,
30248
+ worktreeId,
30249
+ previousSessionRow,
30250
+ freshnessWindowHours = 24,
30251
+ readEntity
30252
+ } = opts;
30253
+ if (!previousSessionRow) return stale;
30254
+ if (!previousSessionRow.closed_at) return stale;
30255
+ if (previousSessionRow.content == null) return stale;
30256
+ let handoff;
30257
+ try {
30258
+ const raw = typeof previousSessionRow.content === "string" ? JSON.parse(previousSessionRow.content) : previousSessionRow.content;
30259
+ if (typeof raw !== "object" || raw === null) return stale;
30260
+ const obj = raw;
30261
+ if (!obj["command"] || typeof obj["command"] !== "string") return stale;
30262
+ if (!obj["command"].trim()) return stale;
30263
+ handoff = {
30264
+ command: obj["command"],
30265
+ captured_at: typeof obj["captured_at"] === "string" ? obj["captured_at"] : void 0,
30266
+ context: typeof obj["context"] === "object" && obj["context"] !== null ? obj["context"] : {},
30267
+ state: obj["state"]
30268
+ };
30269
+ } catch {
30270
+ return stale;
30271
+ }
30272
+ const closedAt = new Date(previousSessionRow.closed_at).getTime();
30273
+ const windowMs = freshnessWindowHours * 60 * 60 * 1e3;
30274
+ if (Date.now() - closedAt > windowMs) return stale;
30275
+ const capturedAt = handoff.captured_at ?? previousSessionRow.closed_at;
30276
+ const ctx = handoff.context ?? {};
30277
+ const resolveEntityPath = (entityType, id) => {
30278
+ const stateDir2 = path8.join(repoRoot, ".codebyplan", "state");
30279
+ if (entityType === "checkpoint") {
30280
+ return path8.join(stateDir2, "checkpoints", `${id}.json`);
30281
+ }
30282
+ if (entityType === "task" && ctx.checkpoint_id) {
30283
+ return path8.join(
30284
+ stateDir2,
30285
+ "checkpoints",
30286
+ ctx.checkpoint_id,
30287
+ "tasks",
30288
+ `${id}.json`
30289
+ );
30290
+ }
30291
+ if (entityType === "round" && ctx.checkpoint_id && ctx.task_id) {
30292
+ return path8.join(
30293
+ stateDir2,
30294
+ "checkpoints",
30295
+ ctx.checkpoint_id,
30296
+ "tasks",
30297
+ ctx.task_id,
30298
+ "rounds",
30299
+ `${id}.json`
30300
+ );
30301
+ }
30302
+ return "";
30303
+ };
30304
+ const reader = readEntity ?? (async (filePath) => {
30305
+ const { readEntityFile: ref } = await Promise.resolve().then(() => (init_state_store(), state_store_exports));
30306
+ return ref(filePath);
30307
+ });
30308
+ if (ctx.checkpoint_id) {
30309
+ const chkPath = resolveEntityPath("checkpoint", ctx.checkpoint_id);
30310
+ if (!chkPath) return stale;
30311
+ const chk = await reader(chkPath);
30312
+ if (!chk) return stale;
30313
+ if (chk.worktree_id != null && (worktreeId === null || worktreeId !== chk.worktree_id)) {
30314
+ return stale;
30315
+ }
30316
+ if (chk.updated_at && capturedAt && chk.updated_at > capturedAt) {
30317
+ return stale;
30318
+ }
30319
+ }
30320
+ if (ctx.task_id) {
30321
+ const taskPath2 = resolveEntityPath("task", ctx.task_id);
30322
+ if (!taskPath2) return stale;
30323
+ const task = await reader(taskPath2);
30324
+ if (!task) return stale;
30325
+ if (task.updated_at && capturedAt && task.updated_at > capturedAt) {
30326
+ return stale;
30327
+ }
30328
+ }
30329
+ if (ctx.round_id) {
30330
+ const roundPath2 = resolveEntityPath("round", ctx.round_id);
30331
+ if (!roundPath2) return stale;
30332
+ const round = await reader(roundPath2);
30333
+ if (!round) return stale;
30334
+ if (round.updated_at && capturedAt && round.updated_at > capturedAt) {
30335
+ return stale;
30336
+ }
30337
+ }
30338
+ return {
30339
+ fresh: true,
30340
+ command: handoff.command,
30341
+ context: ctx,
30342
+ state: handoff.state
30343
+ };
30344
+ } catch (err) {
30345
+ process.stderr.write(
30346
+ `session: probeHandoff failed (non-fatal): ${err instanceof Error ? err.message : String(err)}
30347
+ `
30348
+ );
30349
+ return stale;
30350
+ }
30351
+ }
30352
+ function partitionOwnership(checkpoints, worktreeId) {
30353
+ const owned = [];
30354
+ const cross = [];
30355
+ for (const chk of checkpoints) {
30356
+ const id = chk.id ?? "";
30357
+ const title = chk.title ?? (chk.number != null ? `CHK-${chk.number}` : id);
30358
+ const chkWorktreeId = chk.worktree_id ?? null;
30359
+ if (chkWorktreeId === null || chkWorktreeId === worktreeId) {
30360
+ owned.push({ id, title });
30361
+ } else {
30362
+ cross.push({ id, title });
30363
+ }
30364
+ }
30365
+ return { owned, cross };
30366
+ }
30367
+ function computeNextAction(input) {
30368
+ const { status, owned_count, total_count, handoff_fresh, infra_files_count } = input;
30369
+ if (status === "update_halt") return "mcp_update_halt";
30370
+ if (handoff_fresh) return "resume_handoff";
30371
+ if (infra_files_count > 0 && owned_count >= 1) return "commit_then_todo";
30372
+ if (owned_count >= 1) return "trigger_todo";
30373
+ if (total_count >= 1 && owned_count === 0) return "stop";
30374
+ return "trigger_todo";
30375
+ }
30376
+ function renderBlock(envelope) {
30377
+ const lines = [];
30378
+ const worktreeDisplay = envelope.worktree_id ?? "unregistered";
30379
+ lines.push(`Session active | Worktree: ${worktreeDisplay}`);
30380
+ lines.push("");
30381
+ if (envelope.worktree_error_kind !== null && envelope.worktree_error_kind !== "tuple_miss") {
30382
+ lines.push(
30383
+ `\u26A0 resolve-worktree: ${envelope.worktree_error_kind} \u2014 local state is broken; routing may be unreliable. Run \`npx codebyplan setup\` to repair.`
30384
+ );
30385
+ lines.push("");
30386
+ }
30387
+ if (envelope.infra_drift_nudge) {
30388
+ lines.push(envelope.infra_drift_nudge);
30389
+ }
30390
+ if (envelope.arch_map_nudge) {
30391
+ lines.push(envelope.arch_map_nudge);
30392
+ }
30393
+ if (envelope.infra_drift_nudge || envelope.arch_map_nudge) {
30394
+ lines.push("");
30395
+ }
30396
+ const prevTitle = envelope.previous_session?.title ?? "none";
30397
+ lines.push(`Previous session: ${prevTitle}`);
30398
+ const pending = envelope.previous_session?.pending ?? "\u2014";
30399
+ lines.push(` Pending: ${pending}`);
30400
+ lines.push("");
30401
+ lines.push(
30402
+ `Ownership: ${envelope.total_count} active CHK(s), ${envelope.owned_count} owned by this worktree`
30403
+ );
30404
+ if (envelope.owned_count > 0) {
30405
+ const ownedStr = envelope.owned_checkpoints.map((c) => c.title).join(", ");
30406
+ lines.push(`Owned: ${ownedStr}`);
30407
+ }
30408
+ if (envelope.cross_checkpoints.length > 0) {
30409
+ const crossStr = envelope.cross_checkpoints.map((c) => c.title).join(", ");
30410
+ lines.push(`Cross-worktree: ${crossStr}`);
30411
+ }
30412
+ if (envelope.lsp_nudges.length > 0) {
30413
+ lines.push("");
30414
+ for (const hint of envelope.lsp_nudges) {
30415
+ lines.push(`LSP: ${hint}`);
30416
+ }
30417
+ }
30418
+ if (envelope.worktree_id === null && (envelope.worktree_error_kind === null || envelope.worktree_error_kind === "tuple_miss")) {
30419
+ lines.push("");
30420
+ lines.push(
30421
+ `\u26A0 Worktree unregistered \u2014 run \`npx codebyplan setup\` to register`
30422
+ );
30423
+ }
30424
+ return lines.join("\n");
30425
+ }
30426
+ function parseGitStatus2(output) {
30427
+ return output.split("\n").filter(Boolean).map((line) => {
30428
+ if (line.length > 3) {
30429
+ const rest = line.slice(3);
30430
+ const arrow = rest.indexOf(" -> ");
30431
+ if (arrow !== -1) {
30432
+ return rest.slice(arrow + 4).trim();
30433
+ }
30434
+ return rest.trim();
30435
+ }
30436
+ return "";
30437
+ }).filter(Boolean);
30438
+ }
30439
+ var init_session = __esm({
30440
+ "src/lib/session.ts"() {
30441
+ "use strict";
30442
+ init_supabase();
30443
+ }
30444
+ });
30445
+
30446
+ // src/cli/session/start.ts
30447
+ var start_exports = {};
30448
+ __export(start_exports, {
30449
+ buildCreateLogBody: () => buildCreateLogBody,
30450
+ defaultGetCheckpoints: () => defaultGetCheckpoints,
30451
+ runSessionStartCli: () => runSessionStartCli
30452
+ });
30453
+ import { spawnSync as spawnSync8 } from "node:child_process";
30454
+ import { dirname as dirname9 } from "node:path";
30455
+ async function updateCursorHashLocal(repoRoot, entityId, row) {
30456
+ const cursor = await readCursor(repoRoot);
30457
+ if (!cursor) return;
30458
+ const hash = hashEntity(row);
30459
+ cursor.entity_hashes[entityId] = hash;
30460
+ await writeCursor(repoRoot, cursor);
30461
+ }
30462
+ async function defaultUpdateStateActivate(repoId, repoRoot) {
30463
+ const snakePatch = { action: "activate" };
30464
+ const stateFilePath = sessionLogPath(repoRoot).replace(
30465
+ "current.json",
30466
+ "state.json"
30467
+ );
30468
+ const snapshot = await readEntityFile(stateFilePath);
30469
+ const optimistic = { ...snapshot ?? {}, ...snakePatch, repo_id: repoId };
30470
+ await writeEntityFile(stateFilePath, optimistic);
30471
+ try {
30472
+ const updated = await apiBackendPatch(
30473
+ new URL(backendSessionStateEndpoint(repoId)).pathname,
30474
+ snakePatch
30475
+ );
30476
+ await writeEntityFile(stateFilePath, updated);
30477
+ } catch (err) {
30478
+ if (err instanceof BackendError && err.status < 500) {
30479
+ if (snapshot !== null) {
30480
+ await writeEntityFile(stateFilePath, snapshot);
30481
+ } else {
30482
+ await deleteEntityFile(stateFilePath);
30483
+ }
30484
+ } else {
30485
+ await writeEntityFile(
30486
+ pendingMarkerPath(repoRoot, `session-state-${repoId}`),
30487
+ {
30488
+ entity: "session_state",
30489
+ repo_id: repoId,
30490
+ operation: "update-state",
30491
+ attempted_at: (/* @__PURE__ */ new Date()).toISOString(),
30492
+ error: err instanceof Error ? err.message : String(err)
30493
+ }
30494
+ );
30495
+ }
30496
+ process.stderr.write(
30497
+ `session start: update-state activate failed (non-fatal): ${err instanceof Error ? err.message : String(err)}
30498
+ `
30499
+ );
30500
+ }
30501
+ }
30502
+ function buildCreateLogBody(repoId, worktreeId, now = /* @__PURE__ */ new Date()) {
30503
+ const session_date = now.toISOString().slice(0, 10);
30504
+ const jan1 = Date.UTC(now.getUTCFullYear(), 0, 1);
30505
+ const day_number = Math.floor((now.getTime() - jan1) / 864e5) + 1;
30506
+ return {
30507
+ repo_id: repoId,
30508
+ session_date,
30509
+ day_number,
30510
+ started_at: now.toISOString(),
30511
+ summary: "",
30512
+ ...worktreeId != null ? { worktree_id: worktreeId } : {}
30513
+ };
30514
+ }
30515
+ async function defaultCreateLog(repoId, repoRoot, worktreeId) {
30516
+ const body = buildCreateLogBody(repoId, worktreeId);
30517
+ try {
30518
+ const created = await apiBackendPost(new URL(backendSessionLogsEndpoint()).pathname, body);
30519
+ const sessionLog = created.session_log ?? created;
30520
+ const filePath = sessionLogPath(repoRoot);
30521
+ await writeEntityFile(filePath, sessionLog);
30522
+ const sessionLogId = sessionLog.id;
30523
+ if (sessionLogId) {
30524
+ await updateCursorHashLocal(repoRoot, sessionLogId, sessionLog);
30525
+ }
30526
+ return sessionLogId ?? null;
30527
+ } catch (err) {
30528
+ process.stderr.write(
30529
+ `session start: create-log failed (non-fatal): ${err instanceof Error ? err.message : String(err)}
30530
+ `
30531
+ );
30532
+ return null;
30533
+ }
30534
+ }
30535
+ async function defaultGetCheckpoints(repoId) {
30536
+ try {
30537
+ const result = await apiGet("/checkpoints", {
30538
+ repo_id: repoId,
30539
+ status: "active"
30540
+ });
30541
+ if (Array.isArray(result)) {
30542
+ return result;
30543
+ }
30544
+ const res = result ?? {};
30545
+ if (Array.isArray(res["data"])) {
30546
+ return res["data"];
30547
+ }
30548
+ if (Array.isArray(res["checkpoints"])) {
30549
+ return res["checkpoints"];
30550
+ }
30551
+ return [];
30552
+ } catch {
30553
+ return [];
30554
+ }
30555
+ }
30556
+ function defaultRunSync(cwd) {
30557
+ try {
30558
+ spawnSync8("npx", ["codebyplan", "sync"], {
30559
+ cwd,
30560
+ encoding: "utf-8",
30561
+ stdio: ["pipe", "pipe", "pipe"]
30562
+ });
30563
+ } catch {
30564
+ }
30565
+ }
30566
+ async function resolveRepoInfo(cwd) {
30567
+ const found = await findCodebyplanConfig(cwd);
30568
+ if (!found?.contents.repo_id) return null;
30569
+ const repoRoot = deriveRepoRoot(found.path);
30570
+ return { repoRoot, repoId: found.contents.repo_id };
30571
+ }
30572
+ async function resolveTaskFilesFromState(repoRoot) {
30573
+ try {
30574
+ const todos = await readEntityFile(todosPath(repoRoot));
30575
+ const rows = Array.isArray(todos) ? todos : [];
30576
+ const active = rows.find((t) => t["status"] === "current");
30577
+ if (!active) return [];
30578
+ const checkpoint_id = active["checkpoint_id"];
30579
+ const task_id = active["task_id"];
30580
+ if (!checkpoint_id || !task_id) return [];
30581
+ const roundsDir = dirname9(roundPath(repoRoot, checkpoint_id, task_id, "_"));
30582
+ const roundFiles = await listEntityFiles(roundsDir);
30583
+ const fileSet = /* @__PURE__ */ new Set();
30584
+ for (const rPath of roundFiles) {
30585
+ const round = await readEntityFile(rPath);
30586
+ if (!round) continue;
30587
+ const status = round.status ?? "";
30588
+ if (status === "completed" || status === "cancelled") continue;
30589
+ const files = round.files_changed ?? round.context?.files_changed ?? [];
30590
+ for (const f of files) {
30591
+ if (f.path) fileSet.add(f.path);
30592
+ }
30593
+ }
30594
+ return [...fileSet];
30595
+ } catch {
30596
+ return [];
30597
+ }
30598
+ }
30599
+ async function runSessionStartCli(_args, deps = {}) {
30600
+ const cwd = deps.cwd ?? process.cwd();
30601
+ const repoInfo = await (deps.resolveRepo ?? resolveRepoInfo)(cwd);
30602
+ if (!repoInfo) {
30603
+ const envelope2 = {
30604
+ status: "ok",
30605
+ session_log_id: null,
30606
+ worktree_id: null,
30607
+ worktree_error_kind: "unhandled",
30608
+ infra_drift_nudge: null,
30609
+ arch_map_nudge: null,
30610
+ lsp_nudges: [],
30611
+ handoff: { fresh: false },
30612
+ infra_files_to_commit: [],
30613
+ owned_checkpoints: [],
30614
+ cross_checkpoints: [],
30615
+ owned_count: 0,
30616
+ total_count: 0,
30617
+ next_action: "trigger_todo",
30618
+ rendered_block: "session start: no .codebyplan/repo.json found \u2014 run `codebyplan setup`",
30619
+ previous_session: null
30620
+ };
30621
+ process.stdout.write(JSON.stringify(envelope2) + "\n");
30622
+ return 0;
30623
+ }
30624
+ const { repoRoot, repoId } = repoInfo;
30625
+ const { worktree_id: worktreeId, error_kind: worktreeErrorKind } = resolveWorktreeJson({ cwd, run: deps.resolveWorktreeRunner });
30626
+ const freshnessGateFn = deps.freshnessGate ?? freshnessGate;
30627
+ let freshnessResult;
30628
+ try {
30629
+ freshnessResult = await freshnessGateFn({
30630
+ cwd,
30631
+ haltOnUpdate: true
30632
+ });
30633
+ } catch {
30634
+ freshnessResult = { result: "skipped", reason: "gate error (fail-safe)" };
30635
+ }
30636
+ if (freshnessResult.result === "updated" && "halt" in freshnessResult && freshnessResult.halt) {
30637
+ const haltMsg = "codebyplan updated. Start a FRESH Claude Code session\n(run /clear or open a new window) so the updated .claude/ takes effect.";
30638
+ const envelope2 = {
30639
+ status: "update_halt",
30640
+ session_log_id: null,
30641
+ worktree_id: worktreeId,
30642
+ worktree_error_kind: worktreeErrorKind,
30643
+ infra_drift_nudge: null,
30644
+ arch_map_nudge: null,
30645
+ lsp_nudges: [],
30646
+ handoff: { fresh: false },
30647
+ infra_files_to_commit: "changed_files" in freshnessResult ? freshnessResult.changed_files ?? [] : [],
30648
+ owned_checkpoints: [],
30649
+ cross_checkpoints: [],
30650
+ owned_count: 0,
30651
+ total_count: 0,
30652
+ next_action: "mcp_update_halt",
30653
+ rendered_block: haltMsg,
30654
+ previous_session: null
30655
+ };
30656
+ process.stdout.write(JSON.stringify(envelope2) + "\n");
30657
+ return 0;
30658
+ }
30659
+ const infraDriftNudgeVal = infraDriftNudge({
30660
+ cwd,
30661
+ run: deps.infraDriftRunner,
30662
+ existsSync: deps.infraDriftExistsSync
30663
+ });
30664
+ const archMapNudgeVal = archMapDriftNudge({
30665
+ cwd,
30666
+ run: deps.archMapDriftRunner,
30667
+ existsSync: deps.archMapDriftExistsSync
30668
+ });
30669
+ const lspNudgesVal = lspNudge({ cwd, run: deps.lspRunner });
30670
+ const runSync2 = deps.runSync ?? defaultRunSync;
30671
+ const readPreviousSession = deps.readPreviousSession ?? ((rr) => readEntityFile(sessionLogPath(rr)));
30672
+ let previousSessionRow = await readPreviousSession(repoRoot);
30673
+ if (!previousSessionRow) {
30674
+ runSync2(cwd);
30675
+ previousSessionRow = await readPreviousSession(repoRoot);
30676
+ }
30677
+ const handoffResult = await probeHandoff({
30678
+ repoRoot,
30679
+ worktreeId,
30680
+ previousSessionRow,
30681
+ readEntity: deps.readEntity ?? (async (filePath) => {
30682
+ return readEntityFile(filePath);
30683
+ })
30684
+ });
30685
+ const updateStateActivateFn = deps.updateStateActivate ?? defaultUpdateStateActivate;
30686
+ await updateStateActivateFn(repoId, repoRoot).catch((err) => {
30687
+ process.stderr.write(
30688
+ `session start: update-state activate threw (non-fatal): ${err instanceof Error ? err.message : String(err)}
30689
+ `
30690
+ );
30691
+ });
30692
+ const createLogFn = deps.createLog ?? defaultCreateLog;
30693
+ const sessionLogId = await createLogFn(repoId, repoRoot, worktreeId).catch(
30694
+ (err) => {
30695
+ process.stderr.write(
30696
+ `session start: create-log threw (non-fatal): ${err instanceof Error ? err.message : String(err)}
30697
+ `
30698
+ );
30699
+ return null;
30700
+ }
30701
+ );
30702
+ const resolveTaskFiles = deps.resolveTaskFiles ?? resolveTaskFilesFromState;
30703
+ const taskFilesFromState = await resolveTaskFiles(repoRoot);
30704
+ let infraFilesToCommit = [];
30705
+ try {
30706
+ const infraResult = await infraFiles({
30707
+ cwd,
30708
+ run: deps.infraFilesRunner,
30709
+ getTaskFiles: () => Promise.resolve(taskFilesFromState)
30710
+ });
30711
+ infraFilesToCommit = infraResult.infra_files;
30712
+ } catch {
30713
+ infraFilesToCommit = [];
30714
+ }
30715
+ const getCheckpointsFn = deps.getCheckpoints ?? defaultGetCheckpoints;
30716
+ let checkpoints = [];
30717
+ try {
30718
+ checkpoints = await getCheckpointsFn(repoId);
30719
+ } catch {
30720
+ checkpoints = [];
30721
+ }
30722
+ const { owned, cross } = partitionOwnership(checkpoints, worktreeId);
30723
+ const ownedCount = owned.length;
30724
+ const totalCount = owned.length + cross.length;
30725
+ const nextAction = computeNextAction({
30726
+ status: "ok",
30727
+ owned_count: ownedCount,
30728
+ total_count: totalCount,
30729
+ handoff_fresh: handoffResult.fresh,
30730
+ infra_files_count: infraFilesToCommit.length
30731
+ });
30732
+ let previousSession = null;
30733
+ if (previousSessionRow) {
30734
+ previousSession = {
30735
+ title: typeof previousSessionRow["title"] === "string" ? previousSessionRow["title"] : void 0,
30736
+ summary: typeof previousSessionRow["summary"] === "string" ? previousSessionRow["summary"] : void 0,
30737
+ pending: typeof previousSessionRow["pending"] === "string" ? previousSessionRow["pending"] : void 0
30738
+ };
30739
+ }
30740
+ const envelope = {
30741
+ status: "ok",
30742
+ session_log_id: sessionLogId,
30743
+ worktree_id: worktreeId,
30744
+ worktree_error_kind: worktreeErrorKind,
30745
+ infra_drift_nudge: infraDriftNudgeVal,
30746
+ arch_map_nudge: archMapNudgeVal,
30747
+ lsp_nudges: lspNudgesVal,
30748
+ handoff: handoffResult.fresh ? {
30749
+ fresh: true,
30750
+ command: handoffResult.command,
30751
+ context: handoffResult.context,
30752
+ state: handoffResult.state
30753
+ } : { fresh: false },
30754
+ infra_files_to_commit: infraFilesToCommit,
30755
+ owned_checkpoints: owned,
30756
+ cross_checkpoints: cross,
30757
+ owned_count: ownedCount,
30758
+ total_count: totalCount,
30759
+ next_action: nextAction,
30760
+ rendered_block: "",
30761
+ // filled below
30762
+ previous_session: previousSession
30763
+ };
30764
+ envelope.rendered_block = renderBlock(envelope);
30765
+ process.stdout.write(JSON.stringify(envelope) + "\n");
30766
+ return 0;
30767
+ }
30768
+ var init_start = __esm({
30769
+ "src/cli/session/start.ts"() {
30770
+ "use strict";
30771
+ init_session();
30772
+ init_flags();
30773
+ init_state_store();
30774
+ init_state_client();
30775
+ init_urls();
30776
+ init_api();
30777
+ }
30778
+ });
30779
+
30780
+ // src/cli/session/home-ff.ts
30781
+ var home_ff_exports = {};
30782
+ __export(home_ff_exports, {
30783
+ homeFfCli: () => homeFfCli
30784
+ });
30785
+ function homeFfCli(_args, deps = {}) {
30786
+ const result = homeFf(deps);
30787
+ process.stdout.write(JSON.stringify(result) + "\n");
30788
+ return 0;
30789
+ }
30790
+ var init_home_ff = __esm({
30791
+ "src/cli/session/home-ff.ts"() {
30792
+ "use strict";
30793
+ init_session();
30794
+ }
30795
+ });
30796
+
30797
+ // src/cli/session/freshness-gate.ts
30798
+ var freshness_gate_exports = {};
30799
+ __export(freshness_gate_exports, {
30800
+ freshnessGateCli: () => freshnessGateCli
30801
+ });
30802
+ async function freshnessGateCli(args, deps = {}) {
30803
+ const haltOnUpdate = args.includes("--halt-on-update");
30804
+ const result = await freshnessGate({
30805
+ ...deps,
30806
+ haltOnUpdate: deps.haltOnUpdate ?? haltOnUpdate
30807
+ });
30808
+ process.stdout.write(JSON.stringify(result) + "\n");
30809
+ return 0;
30810
+ }
30811
+ var init_freshness_gate = __esm({
30812
+ "src/cli/session/freshness-gate.ts"() {
30813
+ "use strict";
30814
+ init_session();
30815
+ }
30816
+ });
30817
+
30818
+ // src/cli/session/infra-files.ts
30819
+ var infra_files_exports = {};
30820
+ __export(infra_files_exports, {
30821
+ infraFilesCli: () => infraFilesCli
30822
+ });
30823
+ async function infraFilesCli(args, deps = {}) {
30824
+ let taskFilesFromFlag = [];
30825
+ const tfIdx = args.indexOf("--task-files");
30826
+ if (tfIdx !== -1 && tfIdx + 1 < args.length) {
30827
+ const raw = args[tfIdx + 1];
30828
+ if (raw && !raw.startsWith("--")) {
30829
+ taskFilesFromFlag = raw.split(",").map((f) => f.trim()).filter(Boolean);
30830
+ }
30831
+ }
30832
+ const result = await infraFiles({
30833
+ ...deps,
30834
+ // When the caller passes --task-files, use those as the task file list.
30835
+ // The deps injection wins when explicitly provided (test path).
30836
+ getTaskFiles: deps.getTaskFiles ?? (taskFilesFromFlag.length > 0 ? () => Promise.resolve(taskFilesFromFlag) : () => Promise.resolve([]))
30837
+ });
30838
+ process.stdout.write(JSON.stringify(result) + "\n");
30839
+ return 0;
30840
+ }
30841
+ var init_infra_files = __esm({
30842
+ "src/cli/session/infra-files.ts"() {
30843
+ "use strict";
30844
+ init_session();
30845
+ }
30846
+ });
30847
+
29581
30848
  // src/cli/session.ts
29582
30849
  var session_exports = {};
29583
30850
  __export(session_exports, {
@@ -29774,11 +31041,27 @@ async function runSessionUpdateState(args) {
29774
31041
  }
29775
31042
  function printSessionHelp() {
29776
31043
  process.stdout.write(
29777
- "\n codebyplan session <subcommand>\n\n Subcommands:\n create-log Create a session log (fields as --key value pairs)\n update-log Update a session log (--id <uuid> required, then --key value pairs)\n update-state Update session state for the current repo (--key value pairs)\n\n"
31044
+ "\n codebyplan session <subcommand>\n\n Subcommands:\n start Run the session-start orchestrator; emits one JSON envelope on stdout\n home-ff Fast-forward the home branch to HEAD; emits { result, reason? } JSON\n freshness-gate Check package version freshness [--halt-on-update]; emits { result, ... } JSON\n infra-files Compute the infra-file set for the active session [--task-files <csv>] [--json]\n create-log Create a session log (fields as --key value pairs)\n update-log Update a session log (--id <uuid> required, then --key value pairs)\n update-state Update session state for the current repo (--key value pairs)\n\n"
29778
31045
  );
29779
31046
  }
29780
31047
  async function runSessionCommand(args) {
29781
31048
  const subcommand = args[0];
31049
+ if (subcommand === "start") {
31050
+ const { runSessionStartCli: runSessionStartCli2 } = await Promise.resolve().then(() => (init_start(), start_exports));
31051
+ process.exit(await runSessionStartCli2(args.slice(1)));
31052
+ }
31053
+ if (subcommand === "home-ff") {
31054
+ const { homeFfCli: homeFfCli2 } = await Promise.resolve().then(() => (init_home_ff(), home_ff_exports));
31055
+ process.exit(homeFfCli2(args.slice(1)));
31056
+ }
31057
+ if (subcommand === "freshness-gate") {
31058
+ const { freshnessGateCli: freshnessGateCli2 } = await Promise.resolve().then(() => (init_freshness_gate(), freshness_gate_exports));
31059
+ process.exit(await freshnessGateCli2(args.slice(1)));
31060
+ }
31061
+ if (subcommand === "infra-files") {
31062
+ const { infraFilesCli: infraFilesCli2 } = await Promise.resolve().then(() => (init_infra_files(), infra_files_exports));
31063
+ process.exit(await infraFilesCli2(args.slice(1)));
31064
+ }
29782
31065
  if (subcommand === "create-log") {
29783
31066
  await runSessionCreateLog(args.slice(1));
29784
31067
  return;
@@ -29806,7 +31089,7 @@ Run 'codebyplan session help' for usage.
29806
31089
  }
29807
31090
  process.exit(1);
29808
31091
  }
29809
- var init_session = __esm({
31092
+ var init_session2 = __esm({
29810
31093
  "src/cli/session.ts"() {
29811
31094
  "use strict";
29812
31095
  init_flags();
@@ -29818,7 +31101,7 @@ var init_session = __esm({
29818
31101
 
29819
31102
  // src/lib/migrate-branch-model.ts
29820
31103
  import { readFile as readFile18, writeFile as writeFile15 } from "node:fs/promises";
29821
- import { join as join22 } from "node:path";
31104
+ import { join as join24 } from "node:path";
29822
31105
  import { execSync as execSync4 } from "node:child_process";
29823
31106
  function assertValidBranchName(branch) {
29824
31107
  if (!/^[a-zA-Z0-9/_.-]+$/.test(branch)) {
@@ -29827,7 +31110,7 @@ function assertValidBranchName(branch) {
29827
31110
  );
29828
31111
  }
29829
31112
  }
29830
- async function readJsonFile2(filePath) {
31113
+ async function readJsonFile3(filePath) {
29831
31114
  const raw = await readFile18(filePath, "utf-8");
29832
31115
  const parsed = JSON.parse(raw);
29833
31116
  if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
@@ -29897,17 +31180,17 @@ async function runBranchMigration(opts) {
29897
31180
  if (found) {
29898
31181
  if (found.path.endsWith("/repo.json")) {
29899
31182
  const dir = found.path.slice(0, found.path.lastIndexOf("/"));
29900
- configPath = join22(dir, "git.json");
31183
+ configPath = join24(dir, "git.json");
29901
31184
  } else {
29902
31185
  configPath = found.path;
29903
31186
  }
29904
31187
  } else {
29905
- configPath = join22(cwd, ".codebyplan", "git.json");
31188
+ configPath = join24(cwd, ".codebyplan", "git.json");
29906
31189
  }
29907
31190
  let fileRaw;
29908
31191
  let fileParsed;
29909
31192
  try {
29910
- const result = await readJsonFile2(configPath);
31193
+ const result = await readJsonFile3(configPath);
29911
31194
  fileRaw = result.raw;
29912
31195
  fileParsed = result.parsed;
29913
31196
  } catch (err) {
@@ -29995,323 +31278,10 @@ var init_migrate_branch_model = __esm({
29995
31278
  }
29996
31279
  });
29997
31280
 
29998
- // src/lib/supabase.ts
29999
- import * as fs5 from "node:fs";
30000
- import * as path7 from "node:path";
30001
- import { spawnSync as spawnSync6 } from "node:child_process";
30002
- function defaultRun(cmd, args) {
30003
- const result = spawnSync6(cmd, args, {
30004
- encoding: "utf-8",
30005
- stdio: ["pipe", "pipe", "pipe"]
30006
- });
30007
- if (result.error) throw result.error;
30008
- return (result.stdout ?? "").toString();
30009
- }
30010
- function readJsonFile3(filePath) {
30011
- try {
30012
- const raw = fs5.readFileSync(filePath, "utf-8");
30013
- const parsed = JSON.parse(raw);
30014
- if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) {
30015
- return parsed;
30016
- }
30017
- return null;
30018
- } catch {
30019
- return null;
30020
- }
30021
- }
30022
- function getSupabaseSection(obj) {
30023
- const tryPath = (root) => {
30024
- const surfaces = root["surfaces"];
30025
- if (typeof surfaces !== "object" || surfaces === null || Array.isArray(surfaces))
30026
- return null;
30027
- const sb = surfaces["supabase"];
30028
- if (typeof sb === "object" && sb !== null && !Array.isArray(sb)) {
30029
- return sb;
30030
- }
30031
- return null;
30032
- };
30033
- const shipment = obj["shipment"];
30034
- if (typeof shipment === "object" && shipment !== null && !Array.isArray(shipment)) {
30035
- const found = tryPath(shipment);
30036
- if (found) return found;
30037
- }
30038
- return tryPath(obj);
30039
- }
30040
- function globToRegex(pattern) {
30041
- const special = ".+^${}()|[]\\";
30042
- let r = "";
30043
- for (let i = 0; i < pattern.length; i++) {
30044
- const ch = pattern[i] ?? "";
30045
- if (ch === "*") {
30046
- if (pattern[i + 1] === "*") {
30047
- r += ".*";
30048
- i++;
30049
- } else {
30050
- r += "[^/]*";
30051
- }
30052
- } else if (ch === "?") {
30053
- r += "[^/]";
30054
- } else if (special.includes(ch)) {
30055
- r += "\\" + ch;
30056
- } else {
30057
- r += ch;
30058
- }
30059
- }
30060
- return new RegExp(`^${r}$`);
30061
- }
30062
- function dateToStamp(d) {
30063
- const pad2 = (n) => String(n).padStart(2, "0");
30064
- return String(d.getUTCFullYear()) + pad2(d.getUTCMonth() + 1) + pad2(d.getUTCDate()) + pad2(d.getUTCHours()) + pad2(d.getUTCMinutes()) + pad2(d.getUTCSeconds());
30065
- }
30066
- function extractStampToken(filename) {
30067
- if (!filename.endsWith(".sql")) return null;
30068
- const base = filename.slice(0, -4);
30069
- const parts = base.split("_");
30070
- const first = parts[0];
30071
- if (!first || !/^\d{14}$/.test(first)) return null;
30072
- const second = parts[1];
30073
- if (second && /^\d{2}$/.test(second)) {
30074
- return `${first}_${second}`;
30075
- }
30076
- return first;
30077
- }
30078
- function readShipmentConfig(cwd) {
30079
- const dir = cwd ?? process.cwd();
30080
- const obj = readJsonFile3(path7.join(dir, ".codebyplan", "shipment.json"));
30081
- if (!obj) return { parentRef: null, previewBranches: [] };
30082
- const section = getSupabaseSection(obj);
30083
- if (!section) return { parentRef: null, previewBranches: [] };
30084
- const parentRef = typeof section["project_ref"] === "string" ? section["project_ref"] : null;
30085
- const previewBranches = [];
30086
- const rawBranches = section["preview_branches"];
30087
- if (Array.isArray(rawBranches)) {
30088
- for (const b of rawBranches) {
30089
- if (typeof b !== "object" || b === null || Array.isArray(b)) continue;
30090
- const entry = b;
30091
- if (typeof entry["branch"] !== "string" || typeof entry["project_ref"] !== "string")
30092
- continue;
30093
- previewBranches.push({
30094
- branch: entry["branch"],
30095
- project_ref: entry["project_ref"],
30096
- created_at: typeof entry["created_at"] === "string" ? entry["created_at"] : void 0
30097
- });
30098
- }
30099
- }
30100
- return { parentRef, previewBranches };
30101
- }
30102
- function readGitConfig(cwd) {
30103
- const dir = cwd ?? process.cwd();
30104
- const obj = readJsonFile3(path7.join(dir, ".codebyplan", "git.json"));
30105
- if (!obj) return { ...GIT_DEFAULTS };
30106
- const bc = obj["branch_config"];
30107
- if (typeof bc !== "object" || bc === null || Array.isArray(bc)) {
30108
- return { ...GIT_DEFAULTS };
30109
- }
30110
- const bcObj = bc;
30111
- const production = typeof bcObj["production"] === "string" && bcObj["production"] ? bcObj["production"] : "main";
30112
- const protectedArr = [];
30113
- const rawProtected = bcObj["protected"];
30114
- if (Array.isArray(rawProtected)) {
30115
- for (const p of rawProtected) {
30116
- if (typeof p === "string" && p) protectedArr.push(p);
30117
- }
30118
- }
30119
- if (protectedArr.length === 0) protectedArr.push(production);
30120
- const integration = typeof bcObj["integration"] === "string" && bcObj["integration"] ? bcObj["integration"] : null;
30121
- return { production, protected: protectedArr, integration };
30122
- }
30123
- function readDbPaths(cwd) {
30124
- const dir = cwd ?? process.cwd();
30125
- const obj = readJsonFile3(path7.join(dir, ".codebyplan", "shipment.json"));
30126
- if (!obj) return [...DEFAULT_DB_PATHS];
30127
- const section = getSupabaseSection(obj);
30128
- if (!section) return [...DEFAULT_DB_PATHS];
30129
- const rawPaths = section["db_paths"];
30130
- if (!Array.isArray(rawPaths) || rawPaths.length === 0)
30131
- return [...DEFAULT_DB_PATHS];
30132
- const paths = [];
30133
- for (const p of rawPaths) {
30134
- if (typeof p === "string" && p) paths.push(p);
30135
- }
30136
- return paths.length > 0 ? paths : [...DEFAULT_DB_PATHS];
30137
- }
30138
- function detectDbChanged(opts = {}) {
30139
- const cwd = opts.cwd ?? process.cwd();
30140
- const run = opts.run ?? defaultRun;
30141
- const base = opts.base ?? readGitConfig(cwd).production;
30142
- const dbPaths = opts.dbPaths ?? readDbPaths(cwd);
30143
- if (dbPaths.length === 0) return false;
30144
- const regexes = dbPaths.map(globToRegex);
30145
- let output;
30146
- try {
30147
- output = run("git", ["diff", "--name-only", `origin/${base}...HEAD`]);
30148
- } catch {
30149
- return false;
30150
- }
30151
- const changedFiles = output.split("\n").map((l) => l.trim()).filter(Boolean);
30152
- return changedFiles.some((file) => regexes.some((re) => re.test(file)));
30153
- }
30154
- function defaultListDir(dir) {
30155
- try {
30156
- return fs5.readdirSync(dir);
30157
- } catch {
30158
- return [];
30159
- }
30160
- }
30161
- function generateMonotonicTimestamp(opts = {}) {
30162
- const cwd = opts.cwd ?? process.cwd();
30163
- const now = opts.now ?? /* @__PURE__ */ new Date();
30164
- const listDir = opts.listDir ?? defaultListDir;
30165
- const migrationsDir = path7.join(cwd, "supabase", "migrations");
30166
- const files = listDir(migrationsDir);
30167
- const existingStamps = /* @__PURE__ */ new Set();
30168
- for (const file of files) {
30169
- const token = extractStampToken(file);
30170
- if (token) existingStamps.add(token);
30171
- }
30172
- let maxStamp = "";
30173
- for (const s of existingStamps) {
30174
- if (s > maxStamp) maxStamp = s;
30175
- }
30176
- const computed = dateToStamp(now);
30177
- if (computed > maxStamp && !existingStamps.has(computed)) {
30178
- return computed;
30179
- }
30180
- const collisionBase14 = computed > maxStamp ? computed : maxStamp.slice(0, 14);
30181
- for (let i = 1; i <= 99; i++) {
30182
- const suffix = String(i).padStart(2, "0");
30183
- const candidate = `${collisionBase14}_${suffix}`;
30184
- if (!existingStamps.has(candidate) && candidate > maxStamp) {
30185
- return candidate;
30186
- }
30187
- }
30188
- return `${collisionBase14}_99`;
30189
- }
30190
- async function pollGhPreviewCheck(opts = {}) {
30191
- const run = opts.run ?? defaultRun;
30192
- const sleep3 = opts.sleep ?? ((ms) => new Promise((resolve16) => setTimeout(resolve16, ms)));
30193
- const maxPolls = opts.maxPolls ?? 20;
30194
- const intervalMs = opts.intervalMs ?? 15e3;
30195
- if (!opts.prNumber) {
30196
- return {
30197
- status: "pending_pr",
30198
- reason: "No PR number \u2014 branch has no open pull request yet."
30199
- };
30200
- }
30201
- try {
30202
- run("gh", ["--version"]);
30203
- } catch {
30204
- return {
30205
- status: "blocked",
30206
- reason: "gh CLI not available"
30207
- };
30208
- }
30209
- const prNumber = opts.prNumber;
30210
- for (let poll = 0; poll < maxPolls; poll++) {
30211
- if (poll > 0) {
30212
- await sleep3(intervalMs);
30213
- }
30214
- let checksOutput;
30215
- try {
30216
- try {
30217
- checksOutput = run("gh", [
30218
- "pr",
30219
- "checks",
30220
- prNumber,
30221
- "--json",
30222
- "name,bucket,state"
30223
- ]);
30224
- } catch {
30225
- checksOutput = run("gh", [
30226
- "pr",
30227
- "checks",
30228
- prNumber,
30229
- "--json",
30230
- "name,state"
30231
- ]);
30232
- }
30233
- } catch {
30234
- if (poll === maxPolls - 1) {
30235
- return {
30236
- status: "blocked",
30237
- reason: `gh pr checks failed after ${maxPolls} polls`
30238
- };
30239
- }
30240
- continue;
30241
- }
30242
- let checks;
30243
- try {
30244
- const parsed = JSON.parse(checksOutput);
30245
- checks = Array.isArray(parsed) ? parsed : [];
30246
- } catch {
30247
- checks = [];
30248
- }
30249
- const supabaseCheck = checks.find(
30250
- (c) => typeof c["name"] === "string" && c["name"].toLowerCase().includes("supabase preview")
30251
- );
30252
- if (!supabaseCheck) {
30253
- continue;
30254
- }
30255
- const bucket = typeof supabaseCheck["bucket"] === "string" ? supabaseCheck["bucket"].toLowerCase() : null;
30256
- const state = typeof supabaseCheck["state"] === "string" ? supabaseCheck["state"].toLowerCase() : null;
30257
- if (bucket === "pass") {
30258
- return { status: "passed", reason: "Supabase Preview check passed." };
30259
- }
30260
- if (bucket === "skipping") {
30261
- return {
30262
- status: "skipped",
30263
- reason: "Supabase Preview check skipped at CI."
30264
- };
30265
- }
30266
- if (bucket === "fail" || bucket === "cancel") {
30267
- return {
30268
- status: "blocked",
30269
- reason: `Supabase Preview check ${bucket}ed.`
30270
- };
30271
- }
30272
- if (state === "success") {
30273
- return { status: "passed", reason: "Supabase Preview check passed." };
30274
- }
30275
- if (state === "skipped" || state === "neutral") {
30276
- return {
30277
- status: "skipped",
30278
- reason: "Supabase Preview check skipped at CI."
30279
- };
30280
- }
30281
- if (state === "failure" || state === "cancelled" || state === "error" || state === "timed_out" || state === "stale" || state === "action_required") {
30282
- return {
30283
- status: "blocked",
30284
- reason: `Supabase Preview check ${state}.`
30285
- };
30286
- }
30287
- }
30288
- const minutesStr = Math.round(maxPolls * intervalMs / 6e4);
30289
- return {
30290
- status: "blocked",
30291
- reason: `Supabase Preview check still pending after ${minutesStr} min (${maxPolls} polls)`
30292
- };
30293
- }
30294
- var GIT_DEFAULTS, DEFAULT_DB_PATHS;
30295
- var init_supabase = __esm({
30296
- "src/lib/supabase.ts"() {
30297
- "use strict";
30298
- GIT_DEFAULTS = {
30299
- production: "main",
30300
- protected: ["main"],
30301
- integration: null
30302
- };
30303
- DEFAULT_DB_PATHS = [
30304
- "supabase/**",
30305
- "apps/backend/**",
30306
- "packages/**/db/**"
30307
- ];
30308
- }
30309
- });
30310
-
30311
31281
  // src/lib/branch-checkout.ts
30312
- import { spawnSync as spawnSync7 } from "node:child_process";
30313
- function defaultRun2(cmd, args, cwd) {
30314
- const result = spawnSync7(cmd, args, {
31282
+ import { spawnSync as spawnSync9 } from "node:child_process";
31283
+ function defaultRun3(cmd, args, cwd) {
31284
+ const result = spawnSync9(cmd, args, {
30315
31285
  cwd,
30316
31286
  encoding: "utf-8",
30317
31287
  stdio: ["pipe", "pipe", "pipe"]
@@ -30325,7 +31295,7 @@ function defaultRun2(cmd, args, cwd) {
30325
31295
  function makeRun(cwd, userRun) {
30326
31296
  if (userRun) return userRun;
30327
31297
  return (cmd, args) => {
30328
- const r = defaultRun2(cmd, args, cwd);
31298
+ const r = defaultRun3(cmd, args, cwd);
30329
31299
  if (r.status !== 0) {
30330
31300
  const msg = r.stderr.trim();
30331
31301
  throw new Error(
@@ -30346,7 +31316,7 @@ function makeRunRaw(cwd, userRun) {
30346
31316
  }
30347
31317
  };
30348
31318
  }
30349
- return (cmd, args) => defaultRun2(cmd, args, cwd);
31319
+ return (cmd, args) => defaultRun3(cmd, args, cwd);
30350
31320
  }
30351
31321
  function checkoutBranch(opts) {
30352
31322
  const cwd = opts.cwd ?? process.cwd();
@@ -30562,8 +31532,8 @@ var init_branch = __esm({
30562
31532
 
30563
31533
  // src/lib/bump.ts
30564
31534
  import { readFile as readFile19, writeFile as writeFile16, access as access5, readdir as readdir4 } from "node:fs/promises";
30565
- import { join as join24, relative as relative5, resolve as resolve3 } from "node:path";
30566
- import { spawnSync as spawnSync8 } from "node:child_process";
31535
+ import { join as join25, relative as relative5, resolve as resolve3 } from "node:path";
31536
+ import { spawnSync as spawnSync10 } from "node:child_process";
30567
31537
  function parsePnpmWorkspaceGlobs(raw) {
30568
31538
  const lines = raw.split("\n");
30569
31539
  const globs = [];
@@ -30592,18 +31562,18 @@ async function expandGlob(cwd, glob) {
30592
31562
  if (parts.length !== 2 || parts[1] !== "*") {
30593
31563
  return [];
30594
31564
  }
30595
- const parentDir = join24(cwd, parts[0]);
31565
+ const parentDir = join25(cwd, parts[0]);
30596
31566
  let dirs;
30597
31567
  try {
30598
31568
  const entries = await readdir4(parentDir, { withFileTypes: true });
30599
- dirs = entries.filter((e) => e.isDirectory()).map((e) => join24(parentDir, e.name));
31569
+ dirs = entries.filter((e) => e.isDirectory()).map((e) => join25(parentDir, e.name));
30600
31570
  } catch {
30601
31571
  return [];
30602
31572
  }
30603
31573
  const results = [];
30604
31574
  for (const dir of dirs) {
30605
31575
  try {
30606
- await access5(join24(dir, "package.json"));
31576
+ await access5(join25(dir, "package.json"));
30607
31577
  results.push(dir);
30608
31578
  } catch {
30609
31579
  }
@@ -30614,7 +31584,7 @@ async function buildPackageMap(cwd) {
30614
31584
  const map = /* @__PURE__ */ new Map();
30615
31585
  let globs = [];
30616
31586
  try {
30617
- const raw = await readFile19(join24(cwd, "pnpm-workspace.yaml"), "utf-8");
31587
+ const raw = await readFile19(join25(cwd, "pnpm-workspace.yaml"), "utf-8");
30618
31588
  globs = parsePnpmWorkspaceGlobs(raw);
30619
31589
  } catch {
30620
31590
  }
@@ -30622,7 +31592,7 @@ async function buildPackageMap(cwd) {
30622
31592
  const dirs = await expandGlob(cwd, glob);
30623
31593
  for (const dir of dirs) {
30624
31594
  try {
30625
- const pkgRaw = await readFile19(join24(dir, "package.json"), "utf-8");
31595
+ const pkgRaw = await readFile19(join25(dir, "package.json"), "utf-8");
30626
31596
  const pkg = JSON.parse(pkgRaw);
30627
31597
  const name = pkg.name ?? relative5(cwd, dir);
30628
31598
  map.set(dir, { name, dir });
@@ -30700,7 +31670,7 @@ function compareSemver(a, b) {
30700
31670
  return 0;
30701
31671
  }
30702
31672
  function gitShowFile(cwd, ref, relPath) {
30703
- const result = spawnSync8("git", ["show", `${ref}:${relPath}`], {
31673
+ const result = spawnSync10("git", ["show", `${ref}:${relPath}`], {
30704
31674
  cwd,
30705
31675
  encoding: "utf-8",
30706
31676
  stdio: ["pipe", "pipe", "pipe"]
@@ -30765,7 +31735,7 @@ async function runBump(opts) {
30765
31735
  const prereleaseId = opts?.prereleaseId;
30766
31736
  const baseBranch = await readBaseBranch(cwd);
30767
31737
  const baseRef = resolveBaseRef(cwd, baseBranch);
30768
- const diffResult = spawnSync8(
31738
+ const diffResult = spawnSync10(
30769
31739
  "git",
30770
31740
  ["diff", "--name-only", `${baseRef}...HEAD`],
30771
31741
  {
@@ -30781,7 +31751,7 @@ async function runBump(opts) {
30781
31751
  const changedFiles = (diffResult.stdout ?? "").trim().split("\n").filter(Boolean).map((f) => resolve3(cwd, f));
30782
31752
  const packageMap = await buildPackageMap(cwd);
30783
31753
  const packageDirs = Array.from(packageMap.keys());
30784
- const rootPkgPath = join24(cwd, "package.json");
31754
+ const rootPkgPath = join25(cwd, "package.json");
30785
31755
  const changedPackageDirs = /* @__PURE__ */ new Set();
30786
31756
  for (const absFile of changedFiles) {
30787
31757
  const owner = findOwningPackage(absFile, packageDirs);
@@ -30792,19 +31762,19 @@ async function runBump(opts) {
30792
31762
  const entries = [];
30793
31763
  for (const pkgDir of changedPackageDirs) {
30794
31764
  const pkgInfo = packageMap.get(pkgDir);
30795
- const pkgJsonPath = join24(pkgDir, "package.json");
31765
+ const pkgJsonPath = join25(pkgDir, "package.json");
30796
31766
  if (pkgJsonPath === rootPkgPath) continue;
30797
31767
  const versionFileCandidates = [
30798
31768
  { abs: pkgJsonPath, rel: relative5(cwd, pkgJsonPath).replace(/\\/g, "/") }
30799
31769
  ];
30800
- const tauriConfPath = join24(pkgDir, "src-tauri", "tauri.conf.json");
31770
+ const tauriConfPath = join25(pkgDir, "src-tauri", "tauri.conf.json");
30801
31771
  const tauriRelPath = relative5(cwd, tauriConfPath).replace(/\\/g, "/");
30802
31772
  try {
30803
31773
  await access5(tauriConfPath);
30804
31774
  versionFileCandidates.push({ abs: tauriConfPath, rel: tauriRelPath });
30805
31775
  } catch {
30806
31776
  }
30807
- const appJsonPath = join24(pkgDir, "app.json");
31777
+ const appJsonPath = join25(pkgDir, "app.json");
30808
31778
  const appJsonRelPath = relative5(cwd, appJsonPath).replace(/\\/g, "/");
30809
31779
  try {
30810
31780
  await access5(appJsonPath);
@@ -30876,7 +31846,7 @@ async function runBump(opts) {
30876
31846
  }
30877
31847
  updatedVersionFiles.push(rel);
30878
31848
  }
30879
- const changelogPath = join24(pkgDir, "CHANGELOG.md");
31849
+ const changelogPath = join25(pkgDir, "CHANGELOG.md");
30880
31850
  const changelogUpdated = await prependChangelog(
30881
31851
  changelogPath,
30882
31852
  pkgInfo.name,
@@ -30986,7 +31956,7 @@ var init_bump2 = __esm({
30986
31956
  });
30987
31957
 
30988
31958
  // src/lib/ship.ts
30989
- import { execSync as execSync5, spawnSync as spawnSync9 } from "node:child_process";
31959
+ import { execSync as execSync5, spawnSync as spawnSync11 } from "node:child_process";
30990
31960
  import { relative as relative6 } from "node:path";
30991
31961
  function assertValidBranchName2(branch, label) {
30992
31962
  if (!/^[a-zA-Z0-9/_.-]+$/.test(branch)) {
@@ -31018,7 +31988,7 @@ async function pollChecks(feat, timeoutSeconds, cwd, _sleepMs = (ms) => new Prom
31018
31988
  let totalGhErrors = 0;
31019
31989
  let iteration = 0;
31020
31990
  while (Date.now() < deadline) {
31021
- const ghResult = spawnSync9(
31991
+ const ghResult = spawnSync11(
31022
31992
  "gh",
31023
31993
  ["pr", "checks", feat, "--json", "name,state,bucket"],
31024
31994
  {
@@ -31169,7 +32139,7 @@ ${statusOut.trim()}`
31169
32139
  ...e.changelogUpdated ? [relative6(cwd, e.packageDir).replace(/\\/g, "/") + "/CHANGELOG.md"] : []
31170
32140
  ]);
31171
32141
  if (toStage.length > 0) {
31172
- const addResult = spawnSync9("git", ["add", "--", ...toStage], {
32142
+ const addResult = spawnSync11("git", ["add", "--", ...toStage], {
31173
32143
  cwd,
31174
32144
  encoding: "utf-8",
31175
32145
  stdio: ["pipe", "pipe", "pipe"]
@@ -31179,13 +32149,13 @@ ${statusOut.trim()}`
31179
32149
  `Failed to stage bump files: ${addResult.stderr?.trim() ?? addResult.error?.message}`
31180
32150
  );
31181
32151
  }
31182
- const commitResult = spawnSync9(
32152
+ const commitResult = spawnSync11(
31183
32153
  "git",
31184
32154
  ["commit", "-m", "chore(release): bump versions"],
31185
32155
  { cwd, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
31186
32156
  );
31187
32157
  if (commitResult.status !== 0 || commitResult.error) {
31188
- spawnSync9(
32158
+ spawnSync11(
31189
32159
  "git",
31190
32160
  ["restore", "--staged", "--worktree", "--", ...toStage],
31191
32161
  {
@@ -31230,7 +32200,7 @@ ${statusOut.trim()}`
31230
32200
  } else {
31231
32201
  createArgs.push("--body", defaultPrBody(feat, base));
31232
32202
  }
31233
- const createResult = spawnSync9("gh", createArgs, {
32203
+ const createResult = spawnSync11("gh", createArgs, {
31234
32204
  cwd,
31235
32205
  encoding: "utf-8",
31236
32206
  stdio: ["pipe", "pipe", "pipe"]
@@ -31261,7 +32231,7 @@ ${statusOut.trim()}`
31261
32231
  });
31262
32232
  let mergeCommit = null;
31263
32233
  try {
31264
- const prViewResult = spawnSync9(
32234
+ const prViewResult = spawnSync11(
31265
32235
  "gh",
31266
32236
  ["pr", "view", feat, "--json", "state,mergeCommit"],
31267
32237
  {
@@ -31419,14 +32389,14 @@ var init_ship2 = __esm({
31419
32389
 
31420
32390
  // src/lib/scaffold-publish-workflow.ts
31421
32391
  import * as fs6 from "node:fs";
31422
- import * as path8 from "node:path";
32392
+ import * as path9 from "node:path";
31423
32393
  async function runScaffoldPublishWorkflow(opts) {
31424
32394
  await Promise.resolve();
31425
32395
  const dryRun = opts?.dryRun ?? false;
31426
32396
  const force = opts?.force ?? false;
31427
- const projectDir = path8.resolve(opts?.projectDir ?? process.cwd());
32397
+ const projectDir = path9.resolve(opts?.projectDir ?? process.cwd());
31428
32398
  const templatesDir = opts?.templatesDir ?? resolveTemplatesDir();
31429
- const templatePath = path8.join(
32399
+ const templatePath = path9.join(
31430
32400
  templatesDir,
31431
32401
  "github-workflows",
31432
32402
  "publish.yml"
@@ -31437,7 +32407,7 @@ async function runScaffoldPublishWorkflow(opts) {
31437
32407
  );
31438
32408
  }
31439
32409
  const templateContent = fs6.readFileSync(templatePath, "utf-8");
31440
- const targetPath = path8.join(
32410
+ const targetPath = path9.join(
31441
32411
  projectDir,
31442
32412
  ".github",
31443
32413
  "workflows",
@@ -31461,7 +32431,7 @@ async function runScaffoldPublishWorkflow(opts) {
31461
32431
  );
31462
32432
  }
31463
32433
  }
31464
- const targetDir = path8.dirname(targetPath);
32434
+ const targetDir = path9.dirname(targetPath);
31465
32435
  fs6.mkdirSync(targetDir, { recursive: true });
31466
32436
  fs6.writeFileSync(targetPath, templateContent, "utf-8");
31467
32437
  return { status: "written", path: targetPath };
@@ -31558,7 +32528,7 @@ var init_atomic_write = __esm({
31558
32528
 
31559
32529
  // src/lib/ci-init.ts
31560
32530
  import * as fs8 from "node:fs";
31561
- import * as path9 from "node:path";
32531
+ import * as path10 from "node:path";
31562
32532
  function tryReadJson(filePath) {
31563
32533
  try {
31564
32534
  return JSON.parse(fs8.readFileSync(filePath, "utf-8"));
@@ -31580,27 +32550,27 @@ function hasDevDep(pkg, name) {
31580
32550
  function detectPlatforms(projectDir) {
31581
32551
  const detected = /* @__PURE__ */ new Set();
31582
32552
  const dirsToScan = [projectDir];
31583
- const appsDir = path9.join(projectDir, "apps");
32553
+ const appsDir = path10.join(projectDir, "apps");
31584
32554
  if (fs8.existsSync(appsDir)) {
31585
32555
  try {
31586
32556
  const appsEntries = fs8.readdirSync(appsDir, { withFileTypes: true });
31587
32557
  for (const entry of appsEntries) {
31588
32558
  if (entry.isDirectory()) {
31589
- dirsToScan.push(path9.join(appsDir, entry.name));
32559
+ dirsToScan.push(path10.join(appsDir, entry.name));
31590
32560
  }
31591
32561
  }
31592
32562
  } catch {
31593
32563
  }
31594
32564
  }
31595
32565
  for (const dir of dirsToScan) {
31596
- const pkg = tryReadJson(path9.join(dir, "package.json"));
31597
- if (fs8.existsSync(path9.join(dir, "next.config.ts")) || fs8.existsSync(path9.join(dir, "next.config.js")) || fs8.existsSync(path9.join(dir, "next.config.mjs"))) {
32566
+ const pkg = tryReadJson(path10.join(dir, "package.json"));
32567
+ 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"))) {
31598
32568
  detected.add("next_js");
31599
32569
  }
31600
32570
  if (hasDep(pkg, "@nestjs/core")) {
31601
32571
  detected.add("nestjs");
31602
32572
  }
31603
- if (fs8.existsSync(path9.join(dir, "tauri.conf.json")) || fs8.existsSync(path9.join(dir, "src-tauri"))) {
32573
+ if (fs8.existsSync(path10.join(dir, "tauri.conf.json")) || fs8.existsSync(path10.join(dir, "src-tauri"))) {
31604
32574
  detected.add("tauri");
31605
32575
  }
31606
32576
  if (hasDevDep(pkg, "@types/vscode")) {
@@ -31611,7 +32581,7 @@ function detectPlatforms(projectDir) {
31611
32581
  detected.add("expo");
31612
32582
  }
31613
32583
  }
31614
- const packagesDir = path9.join(projectDir, "packages");
32584
+ const packagesDir = path10.join(projectDir, "packages");
31615
32585
  if (fs8.existsSync(packagesDir)) {
31616
32586
  try {
31617
32587
  const pkgEntries = fs8.readdirSync(packagesDir, { withFileTypes: true });
@@ -31648,10 +32618,10 @@ function buildDefaultCiConfig(platforms) {
31648
32618
  }
31649
32619
  async function runCiInit(opts) {
31650
32620
  await Promise.resolve();
31651
- const projectDir = path9.resolve(opts?.projectDir ?? process.cwd());
32621
+ const projectDir = path10.resolve(opts?.projectDir ?? process.cwd());
31652
32622
  const dryRun = opts?.dryRun ?? false;
31653
32623
  const force = opts?.force ?? false;
31654
- const ciPath = path9.join(projectDir, ".codebyplan", "ci.json");
32624
+ const ciPath = path10.join(projectDir, ".codebyplan", "ci.json");
31655
32625
  const platforms = detectPlatforms(projectDir);
31656
32626
  if (dryRun) {
31657
32627
  return { status: "dry_run", path: ciPath, platforms };
@@ -31696,7 +32666,7 @@ async function runCiInit(opts) {
31696
32666
  platforms: newPlatforms.length > 0 ? newPlatforms : platforms
31697
32667
  };
31698
32668
  }
31699
- const codebyplanDir = path9.join(projectDir, ".codebyplan");
32669
+ const codebyplanDir = path10.join(projectDir, ".codebyplan");
31700
32670
  fs8.mkdirSync(codebyplanDir, { recursive: true });
31701
32671
  writeJsonAtomic(ciPath, newConfig);
31702
32672
  return { status: "written", path: ciPath, platforms };
@@ -31905,7 +32875,7 @@ var init_ci_init = __esm({
31905
32875
 
31906
32876
  // src/lib/scaffold-ci-workflow.ts
31907
32877
  import * as fs9 from "node:fs";
31908
- import * as path10 from "node:path";
32878
+ import * as path11 from "node:path";
31909
32879
  function substituteTokens(template, tokens) {
31910
32880
  let result = template;
31911
32881
  for (const [token, value] of Object.entries(tokens)) {
@@ -31915,7 +32885,7 @@ function substituteTokens(template, tokens) {
31915
32885
  }
31916
32886
  function detectPnpmVersionFromPackageJson(projectDir) {
31917
32887
  try {
31918
- const pkgPath = path10.join(projectDir, "package.json");
32888
+ const pkgPath = path11.join(projectDir, "package.json");
31919
32889
  const raw = fs9.readFileSync(pkgPath, "utf-8");
31920
32890
  const pkg = JSON.parse(raw);
31921
32891
  const pm = pkg.packageManager;
@@ -31932,7 +32902,7 @@ function detectPnpmVersionFromPackageJson(projectDir) {
31932
32902
  }
31933
32903
  function detectStrictEnforcedFromCiJson(projectDir) {
31934
32904
  try {
31935
- const ciJsonPath = path10.join(projectDir, ".codebyplan", "ci.json");
32905
+ const ciJsonPath = path11.join(projectDir, ".codebyplan", "ci.json");
31936
32906
  const raw = fs9.readFileSync(ciJsonPath, "utf-8");
31937
32907
  const parsed = JSON.parse(raw);
31938
32908
  return parsed.workflow?.strict_check_enforced === true;
@@ -31944,12 +32914,12 @@ async function runScaffoldCiWorkflow(opts) {
31944
32914
  await Promise.resolve();
31945
32915
  const dryRun = opts?.dryRun ?? false;
31946
32916
  const force = opts?.force ?? false;
31947
- const projectDir = path10.resolve(opts?.projectDir ?? process.cwd());
32917
+ const projectDir = path11.resolve(opts?.projectDir ?? process.cwd());
31948
32918
  const pnpmVersion = opts?.pnpmVersion ?? detectPnpmVersionFromPackageJson(projectDir);
31949
32919
  const nodeVersion = opts?.nodeVersion ?? "22";
31950
32920
  const strictEnforced = opts?.strictEnforced ?? detectStrictEnforcedFromCiJson(projectDir);
31951
32921
  const templatesDir = opts?.templatesDir ?? resolveTemplatesDir();
31952
- const templatePath = path10.join(templatesDir, "github-workflows", "ci.yml");
32922
+ const templatePath = path11.join(templatesDir, "github-workflows", "ci.yml");
31953
32923
  if (!fs9.existsSync(templatePath)) {
31954
32924
  throw new Error(
31955
32925
  `scaffold-ci-workflow: template not found at ${templatePath}`
@@ -31962,7 +32932,7 @@ async function runScaffoldCiWorkflow(opts) {
31962
32932
  STRICT_NAME_SUFFIX: strictEnforced ? "" : " (report-only)",
31963
32933
  STRICT_CONTINUE_ON_ERROR_LINE: strictEnforced ? "" : "\n continue-on-error: true"
31964
32934
  });
31965
- const targetPath = path10.join(projectDir, ".github", "workflows", "ci.yml");
32935
+ const targetPath = path11.join(projectDir, ".github", "workflows", "ci.yml");
31966
32936
  if (dryRun) {
31967
32937
  return { status: "dry_run", path: targetPath };
31968
32938
  }
@@ -31981,7 +32951,7 @@ async function runScaffoldCiWorkflow(opts) {
31981
32951
  );
31982
32952
  }
31983
32953
  }
31984
- const targetDir = path10.dirname(targetPath);
32954
+ const targetDir = path11.dirname(targetPath);
31985
32955
  fs9.mkdirSync(targetDir, { recursive: true });
31986
32956
  const tmpPath = targetPath + ".tmp";
31987
32957
  try {
@@ -32005,10 +32975,10 @@ var init_scaffold_ci_workflow = __esm({
32005
32975
 
32006
32976
  // src/lib/gh-required-checks.ts
32007
32977
  import * as fs10 from "node:fs";
32008
- import * as path11 from "node:path";
32978
+ import * as path12 from "node:path";
32009
32979
  import { execSync as execSync6 } from "node:child_process";
32010
32980
  function readCiJson(projectDir) {
32011
- const ciPath = path11.join(projectDir, ".codebyplan", "ci.json");
32981
+ const ciPath = path12.join(projectDir, ".codebyplan", "ci.json");
32012
32982
  if (!fs10.existsSync(ciPath)) {
32013
32983
  return {
32014
32984
  platforms: {},
@@ -32027,15 +32997,15 @@ function readCiJson(projectDir) {
32027
32997
  }
32028
32998
  }
32029
32999
  function writeCiJsonAtomic(projectDir, config) {
32030
- const ciPath = path11.join(projectDir, ".codebyplan", "ci.json");
33000
+ const ciPath = path12.join(projectDir, ".codebyplan", "ci.json");
32031
33001
  writeJsonAtomic(ciPath, config);
32032
33002
  }
32033
33003
  function enforceRequiredCheck(opts) {
32034
- const projectDir = path11.resolve(opts?.projectDir ?? process.cwd());
33004
+ const projectDir = path12.resolve(opts?.projectDir ?? process.cwd());
32035
33005
  const branch = opts?.branch ?? "main";
32036
33006
  const checkName = opts?.checkName ?? "Lint + typecheck + test + build";
32037
33007
  const dryRun = opts?.dryRun ?? false;
32038
- const ciPath = path11.join(projectDir, ".codebyplan", "ci.json");
33008
+ const ciPath = path12.join(projectDir, ".codebyplan", "ci.json");
32039
33009
  const config = readCiJson(projectDir);
32040
33010
  if (config.workflow?.required_check_enforced === true) {
32041
33011
  return { status: "already_enforced", path: ciPath };
@@ -32442,9 +33412,9 @@ var init_ci = __esm({
32442
33412
 
32443
33413
  // src/lib/cd-init.ts
32444
33414
  import * as fs11 from "node:fs";
32445
- import * as path12 from "node:path";
33415
+ import * as path13 from "node:path";
32446
33416
  function detectSurfaces(projectDir) {
32447
- const shipmentPath = path12.join(projectDir, ".codebyplan", "shipment.json");
33417
+ const shipmentPath = path13.join(projectDir, ".codebyplan", "shipment.json");
32448
33418
  let shipment;
32449
33419
  try {
32450
33420
  shipment = JSON.parse(fs11.readFileSync(shipmentPath, "utf-8"));
@@ -32497,10 +33467,10 @@ function buildDefaultCdConfig(rawSurfaceKeys) {
32497
33467
  }
32498
33468
  async function runCdInit(opts) {
32499
33469
  await Promise.resolve();
32500
- const projectDir = path12.resolve(opts?.projectDir ?? process.cwd());
33470
+ const projectDir = path13.resolve(opts?.projectDir ?? process.cwd());
32501
33471
  const dryRun = opts?.dryRun ?? false;
32502
33472
  const force = opts?.force ?? false;
32503
- const cdPath = path12.join(projectDir, ".codebyplan", "cd.json");
33473
+ const cdPath = path13.join(projectDir, ".codebyplan", "cd.json");
32504
33474
  const rawSurfaceKeys = detectSurfaces(projectDir);
32505
33475
  const seen = /* @__PURE__ */ new Set();
32506
33476
  const surfaces = [];
@@ -32541,7 +33511,7 @@ async function runCdInit(opts) {
32541
33511
  surfaces: newSurfaces
32542
33512
  };
32543
33513
  }
32544
- const codebyplanDir = path12.join(projectDir, ".codebyplan");
33514
+ const codebyplanDir = path13.join(projectDir, ".codebyplan");
32545
33515
  fs11.mkdirSync(codebyplanDir, { recursive: true });
32546
33516
  writeJsonAtomic(cdPath, newConfig);
32547
33517
  return { status: "written", path: cdPath, surfaces };
@@ -32631,14 +33601,14 @@ var init_cd_init = __esm({
32631
33601
 
32632
33602
  // src/lib/scaffold-cd-workflow.ts
32633
33603
  import * as fs12 from "node:fs";
32634
- import * as path13 from "node:path";
33604
+ import * as path14 from "node:path";
32635
33605
  async function scaffoldOneWorkflow(templateName, targetName, opts) {
32636
33606
  await Promise.resolve();
32637
33607
  const dryRun = opts.dryRun ?? false;
32638
33608
  const force = opts.force ?? false;
32639
- const projectDir = path13.resolve(opts.projectDir ?? process.cwd());
33609
+ const projectDir = path14.resolve(opts.projectDir ?? process.cwd());
32640
33610
  const templatesDir = opts.templatesDir ?? resolveTemplatesDir();
32641
- const templatePath = path13.join(
33611
+ const templatePath = path14.join(
32642
33612
  templatesDir,
32643
33613
  "github-workflows",
32644
33614
  templateName
@@ -32649,7 +33619,7 @@ async function scaffoldOneWorkflow(templateName, targetName, opts) {
32649
33619
  );
32650
33620
  }
32651
33621
  const templateContent = fs12.readFileSync(templatePath, "utf-8");
32652
- const targetPath = path13.join(projectDir, ".github", "workflows", targetName);
33622
+ const targetPath = path14.join(projectDir, ".github", "workflows", targetName);
32653
33623
  if (dryRun) {
32654
33624
  return { status: "dry_run", path: targetPath };
32655
33625
  }
@@ -32668,7 +33638,7 @@ async function scaffoldOneWorkflow(templateName, targetName, opts) {
32668
33638
  );
32669
33639
  }
32670
33640
  }
32671
- const targetDir = path13.dirname(targetPath);
33641
+ const targetDir = path14.dirname(targetPath);
32672
33642
  fs12.mkdirSync(targetDir, { recursive: true });
32673
33643
  const tmpPath = targetPath + ".tmp";
32674
33644
  try {
@@ -33344,7 +34314,7 @@ __export(version_status_exports, {
33344
34314
  });
33345
34315
  import { execFileSync, execSync as execSync7 } from "node:child_process";
33346
34316
  import { existsSync as existsSync10, readFileSync as readFileSync11 } from "node:fs";
33347
- import { dirname as dirname12, join as join31 } from "node:path";
34317
+ import { dirname as dirname13, join as join32 } from "node:path";
33348
34318
  function fetchLatestVersion() {
33349
34319
  try {
33350
34320
  return execFileSync("npm", ["view", "codebyplan", "version"], {
@@ -33368,11 +34338,11 @@ function detectPackageManager2(gitRoot) {
33368
34338
  let dir = process.cwd();
33369
34339
  const stopAt = gitRoot ?? null;
33370
34340
  while (true) {
33371
- if (existsSync10(join31(dir, "pnpm-lock.yaml"))) return "pnpm";
33372
- if (existsSync10(join31(dir, "yarn.lock"))) return "yarn";
33373
- if (existsSync10(join31(dir, "package-lock.json"))) return "npm";
34341
+ if (existsSync10(join32(dir, "pnpm-lock.yaml"))) return "pnpm";
34342
+ if (existsSync10(join32(dir, "yarn.lock"))) return "yarn";
34343
+ if (existsSync10(join32(dir, "package-lock.json"))) return "npm";
33374
34344
  if (stopAt !== null && dir === stopAt) break;
33375
- const parent = dirname12(dir);
34345
+ const parent = dirname13(dir);
33376
34346
  if (parent === dir) break;
33377
34347
  dir = parent;
33378
34348
  }
@@ -33390,7 +34360,7 @@ function buildInstallCommand2(pm) {
33390
34360
  }
33391
34361
  async function resolveGuard(gitRoot, currentBranch) {
33392
34362
  if (gitRoot !== null) {
33393
- const canonicalPkgPath = join31(
34363
+ const canonicalPkgPath = join32(
33394
34364
  gitRoot,
33395
34365
  "packages",
33396
34366
  "codebyplan-package",
@@ -33414,10 +34384,10 @@ async function resolveGuard(gitRoot, currentBranch) {
33414
34384
  let gitJsonPath;
33415
34385
  if (found.path.endsWith("/repo.json")) {
33416
34386
  const dir = found.path.slice(0, found.path.lastIndexOf("/"));
33417
- gitJsonPath = join31(dir, "git.json");
34387
+ gitJsonPath = join32(dir, "git.json");
33418
34388
  } else {
33419
34389
  const legacyDir = found.path.slice(0, found.path.lastIndexOf("/"));
33420
- gitJsonPath = join31(legacyDir, ".codebyplan", "git.json");
34390
+ gitJsonPath = join32(legacyDir, ".codebyplan", "git.json");
33421
34391
  }
33422
34392
  const raw = readFileSync11(gitJsonPath, "utf-8");
33423
34393
  const parsed = JSON.parse(raw);
@@ -33502,7 +34472,7 @@ __export(upload_e2e_images_exports, {
33502
34472
  runUploadE2eImagesCommand: () => runUploadE2eImagesCommand
33503
34473
  });
33504
34474
  import { readFile as readFile20 } from "node:fs/promises";
33505
- import { join as join32, basename, resolve as resolve10 } from "node:path";
34475
+ import { join as join33, basename as basename2, resolve as resolve10 } from "node:path";
33506
34476
  import { execSync as execSync8 } from "node:child_process";
33507
34477
  function baseUrl2() {
33508
34478
  return (process.env.CODEBYPLAN_API_URL ?? "https://www.codebyplan.com").replace(/\/$/, "");
@@ -33537,7 +34507,7 @@ function parseArgs(args) {
33537
34507
  async function readE2eConfig(projectPath) {
33538
34508
  try {
33539
34509
  const raw = await readFile20(
33540
- join32(projectPath, ".codebyplan", "e2e.json"),
34510
+ join33(projectPath, ".codebyplan", "e2e.json"),
33541
34511
  "utf-8"
33542
34512
  );
33543
34513
  return JSON.parse(raw);
@@ -33578,8 +34548,8 @@ function collectPngsFromGitDiff(projectPath, frameworkName, frameworkConfig, bas
33578
34548
  continue;
33579
34549
  const isNew = status === "A";
33580
34550
  results.push({
33581
- absolutePath: join32(projectPath, filePath),
33582
- filename: basename(filePath),
34551
+ absolutePath: join33(projectPath, filePath),
34552
+ filename: basename2(filePath),
33583
34553
  framework: frameworkName,
33584
34554
  is_new: isNew
33585
34555
  });
@@ -33594,11 +34564,11 @@ function deriveTestName(absolutePath) {
33594
34564
  return seg.replace(".spec.ts-snapshots", "");
33595
34565
  }
33596
34566
  }
33597
- return basename(absolutePath, ".png");
34567
+ return basename2(absolutePath, ".png");
33598
34568
  }
33599
34569
  function buildManifestItem(png) {
33600
34570
  const testName = deriveTestName(png.absolutePath);
33601
- const pageOrScreen = basename(png.absolutePath, ".png");
34571
+ const pageOrScreen = basename2(png.absolutePath, ".png");
33602
34572
  return {
33603
34573
  filename: png.filename,
33604
34574
  test_name: testName,
@@ -33754,8 +34724,8 @@ __export(arch_map_exports, {
33754
34724
  });
33755
34725
  import { readFile as readFile21, writeFile as writeFile17 } from "node:fs/promises";
33756
34726
  import { existsSync as existsSync11, readdirSync as readdirSync4 } from "node:fs";
33757
- import { join as join33 } from "node:path";
33758
- import { spawnSync as spawnSync10 } from "node:child_process";
34727
+ import { join as join34 } from "node:path";
34728
+ import { spawnSync as spawnSync12 } from "node:child_process";
33759
34729
  function normalizeModulePath(modulePath) {
33760
34730
  return modulePath.replace(/\/+$/, "");
33761
34731
  }
@@ -33779,7 +34749,7 @@ async function resolveCodebyplanDir(startDir) {
33779
34749
  }
33780
34750
  }
33781
34751
  async function readArchitectureConfig(codebyplanDir) {
33782
- const filePath = join33(codebyplanDir, "architecture.json");
34752
+ const filePath = join34(codebyplanDir, "architecture.json");
33783
34753
  try {
33784
34754
  const raw = await readFile21(filePath, "utf-8");
33785
34755
  const parsed = JSON.parse(raw);
@@ -33792,12 +34762,12 @@ async function readArchitectureConfig(codebyplanDir) {
33792
34762
  }
33793
34763
  }
33794
34764
  async function writeArchitectureConfig(codebyplanDir, config) {
33795
- const filePath = join33(codebyplanDir, "architecture.json");
34765
+ const filePath = join34(codebyplanDir, "architecture.json");
33796
34766
  await writeFile17(filePath, JSON.stringify(config, null, 2) + "\n", "utf-8");
33797
34767
  }
33798
34768
  function resolveGitSha(modulePath, cwd) {
33799
34769
  try {
33800
- const result = spawnSync10(
34770
+ const result = spawnSync12(
33801
34771
  "git",
33802
34772
  ["log", "--format=%H", "-1", "--", modulePath],
33803
34773
  { cwd, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
@@ -33811,7 +34781,7 @@ function resolveGitSha(modulePath, cwd) {
33811
34781
  }
33812
34782
  async function discoverModulePaths(projectRoot) {
33813
34783
  const paths = [];
33814
- const workspacePath = join33(projectRoot, "pnpm-workspace.yaml");
34784
+ const workspacePath = join34(projectRoot, "pnpm-workspace.yaml");
33815
34785
  let patterns = [];
33816
34786
  try {
33817
34787
  const raw = await readFile21(workspacePath, "utf-8");
@@ -33838,7 +34808,7 @@ async function discoverModulePaths(projectRoot) {
33838
34808
  for (const pattern of patterns) {
33839
34809
  if (pattern.endsWith("/*")) {
33840
34810
  const dir = pattern.slice(0, -2);
33841
- const absDir = join33(projectRoot, dir);
34811
+ const absDir = join34(projectRoot, dir);
33842
34812
  try {
33843
34813
  if (existsSync11(absDir)) {
33844
34814
  const entries = readdirSync4(absDir, { withFileTypes: true });
@@ -33851,7 +34821,7 @@ async function discoverModulePaths(projectRoot) {
33851
34821
  } catch {
33852
34822
  }
33853
34823
  } else if (!pattern.includes("*")) {
33854
- const absPath = join33(projectRoot, pattern);
34824
+ const absPath = join34(projectRoot, pattern);
33855
34825
  if (existsSync11(absPath)) {
33856
34826
  paths.push(pattern);
33857
34827
  }
@@ -33859,7 +34829,7 @@ async function discoverModulePaths(projectRoot) {
33859
34829
  }
33860
34830
  const crossCutting = ["supabase", ".github", "scripts"];
33861
34831
  for (const dir of crossCutting) {
33862
- const absPath = join33(projectRoot, dir);
34832
+ const absPath = join34(projectRoot, dir);
33863
34833
  try {
33864
34834
  if (existsSync11(absPath)) {
33865
34835
  paths.push(dir);
@@ -34045,7 +35015,7 @@ async function runStamp(modulePath, sha, depthArg, projectRoot) {
34045
35015
  }
34046
35016
  await writeArchitectureConfig(codebyplanDir, config);
34047
35017
  const stampedEntry = existingIndex >= 0 ? config.modules[existingIndex] : config.modules[config.modules.length - 1];
34048
- const mapAbsPath = join33(repoRoot, stampedEntry.map_file);
35018
+ const mapAbsPath = join34(repoRoot, stampedEntry.map_file);
34049
35019
  let mapContent = null;
34050
35020
  try {
34051
35021
  mapContent = await readFile21(mapAbsPath, "utf-8");
@@ -34251,18 +35221,18 @@ var init_worktree_port_resolver = __esm({
34251
35221
 
34252
35222
  // src/lib/migrate-local-config.ts
34253
35223
  import { mkdir as mkdir9, readFile as readFile22, unlink as unlink5, writeFile as writeFile18 } from "node:fs/promises";
34254
- import { join as join34 } from "node:path";
35224
+ import { join as join35 } from "node:path";
34255
35225
  function legacySharedPath(projectPath) {
34256
- return join34(projectPath, ".codebyplan.json");
35226
+ return join35(projectPath, ".codebyplan.json");
34257
35227
  }
34258
35228
  function legacyLocalPath(projectPath) {
34259
- return join34(projectPath, ".codebyplan.local.json");
35229
+ return join35(projectPath, ".codebyplan.local.json");
34260
35230
  }
34261
35231
  function newDirPath(projectPath) {
34262
- return join34(projectPath, ".codebyplan");
35232
+ return join35(projectPath, ".codebyplan");
34263
35233
  }
34264
35234
  function sentinelPath(projectPath) {
34265
- return join34(projectPath, ".codebyplan", "repo.json");
35235
+ return join35(projectPath, ".codebyplan", "repo.json");
34266
35236
  }
34267
35237
  async function statSafe(p) {
34268
35238
  const { stat: stat3 } = await import("node:fs/promises");
@@ -34356,7 +35326,7 @@ async function runLocalMigration(projectPath) {
34356
35326
  if ("organization_id" in cfg) repoJson.organization_id = cfg.organization_id;
34357
35327
  if ("project_id" in cfg) repoJson.project_id = cfg.project_id;
34358
35328
  await writeFile18(
34359
- join34(projectPath, ".codebyplan", "repo.json"),
35329
+ join35(projectPath, ".codebyplan", "repo.json"),
34360
35330
  JSON.stringify(repoJson, null, 2) + "\n",
34361
35331
  "utf-8"
34362
35332
  );
@@ -34369,7 +35339,7 @@ async function runLocalMigration(projectPath) {
34369
35339
  if ("port_allocations" in cfg)
34370
35340
  serverJson.port_allocations = cfg.port_allocations;
34371
35341
  await writeFile18(
34372
- join34(projectPath, ".codebyplan", "server.json"),
35342
+ join35(projectPath, ".codebyplan", "server.json"),
34373
35343
  JSON.stringify(serverJson, null, 2) + "\n",
34374
35344
  "utf-8"
34375
35345
  );
@@ -34378,7 +35348,7 @@ async function runLocalMigration(projectPath) {
34378
35348
  if ("git_branch" in cfg) gitJson.git_branch = cfg.git_branch;
34379
35349
  if ("branch_config" in cfg) gitJson.branch_config = cfg.branch_config;
34380
35350
  await writeFile18(
34381
- join34(projectPath, ".codebyplan", "git.json"),
35351
+ join35(projectPath, ".codebyplan", "git.json"),
34382
35352
  JSON.stringify(gitJson, null, 2) + "\n",
34383
35353
  "utf-8"
34384
35354
  );
@@ -34386,35 +35356,35 @@ async function runLocalMigration(projectPath) {
34386
35356
  const shipmentJson = {};
34387
35357
  if ("shipment" in cfg) shipmentJson.shipment = cfg.shipment;
34388
35358
  await writeFile18(
34389
- join34(projectPath, ".codebyplan", "shipment.json"),
35359
+ join35(projectPath, ".codebyplan", "shipment.json"),
34390
35360
  JSON.stringify(shipmentJson, null, 2) + "\n",
34391
35361
  "utf-8"
34392
35362
  );
34393
35363
  filesChanged.push(".codebyplan/shipment.json");
34394
35364
  const vendorJson = {};
34395
35365
  await writeFile18(
34396
- join34(projectPath, ".codebyplan", "vendor.json"),
35366
+ join35(projectPath, ".codebyplan", "vendor.json"),
34397
35367
  JSON.stringify(vendorJson, null, 2) + "\n",
34398
35368
  "utf-8"
34399
35369
  );
34400
35370
  filesChanged.push(".codebyplan/vendor.json");
34401
35371
  const e2eJson = {};
34402
35372
  await writeFile18(
34403
- join34(projectPath, ".codebyplan", "e2e.json"),
35373
+ join35(projectPath, ".codebyplan", "e2e.json"),
34404
35374
  JSON.stringify(e2eJson, null, 2) + "\n",
34405
35375
  "utf-8"
34406
35376
  );
34407
35377
  filesChanged.push(".codebyplan/e2e.json");
34408
35378
  const eslintJson = {};
34409
35379
  await writeFile18(
34410
- join34(projectPath, ".codebyplan", "eslint.json"),
35380
+ join35(projectPath, ".codebyplan", "eslint.json"),
34411
35381
  JSON.stringify(eslintJson, null, 2) + "\n",
34412
35382
  "utf-8"
34413
35383
  );
34414
35384
  filesChanged.push(".codebyplan/eslint.json");
34415
35385
  if (!deviceWrittenByHelper) {
34416
35386
  await writeFile18(
34417
- join34(projectPath, ".codebyplan", "device.local.json"),
35387
+ join35(projectPath, ".codebyplan", "device.local.json"),
34418
35388
  JSON.stringify({ device_id: deviceId }, null, 2) + "\n",
34419
35389
  "utf-8"
34420
35390
  );
@@ -34426,7 +35396,7 @@ async function runLocalMigration(projectPath) {
34426
35396
  "Migration write incomplete: .codebyplan/repo.json was not persisted. Re-run migration to retry from a clean state."
34427
35397
  );
34428
35398
  }
34429
- const gitignorePath = join34(projectPath, ".gitignore");
35399
+ const gitignorePath = join35(projectPath, ".gitignore");
34430
35400
  try {
34431
35401
  const gitignoreContent = await readFile22(gitignorePath, "utf-8");
34432
35402
  const legacyLine = ".codebyplan.local.json";
@@ -34490,7 +35460,7 @@ __export(config_exports, {
34490
35460
  runConfigMigrate: () => runConfigMigrate
34491
35461
  });
34492
35462
  import { mkdir as mkdir10, readFile as readFile23, writeFile as writeFile19 } from "node:fs/promises";
34493
- import { join as join35 } from "node:path";
35463
+ import { join as join36 } from "node:path";
34494
35464
  async function runConfig() {
34495
35465
  const flags = parseFlags(3);
34496
35466
  const dryRun = hasFlag("dry-run", 3);
@@ -34523,7 +35493,7 @@ async function runConfig() {
34523
35493
  console.log("\n Config complete.\n");
34524
35494
  }
34525
35495
  async function syncConfigToFile(repoId, projectPath, dryRun) {
34526
- const codebyplanDir = join35(projectPath, ".codebyplan");
35496
+ const codebyplanDir = join36(projectPath, ".codebyplan");
34527
35497
  const {
34528
35498
  resolvedWorktreeId,
34529
35499
  portAllocations,
@@ -34616,7 +35586,7 @@ async function syncConfigToFile(repoId, projectPath, dryRun) {
34616
35586
  ];
34617
35587
  let anyUpdated = false;
34618
35588
  for (const { name, payload, createOnly } of files) {
34619
- const filePath = join35(codebyplanDir, name);
35589
+ const filePath = join36(codebyplanDir, name);
34620
35590
  const newJson = JSON.stringify(payload, null, 2) + "\n";
34621
35591
  let currentJson = "";
34622
35592
  try {
@@ -34636,7 +35606,7 @@ async function syncConfigToFile(repoId, projectPath, dryRun) {
34636
35606
  async function readRepoConfig(projectPath) {
34637
35607
  try {
34638
35608
  const raw = await readFile23(
34639
- join35(projectPath, ".codebyplan", "repo.json"),
35609
+ join36(projectPath, ".codebyplan", "repo.json"),
34640
35610
  "utf-8"
34641
35611
  );
34642
35612
  return JSON.parse(raw);
@@ -34647,7 +35617,7 @@ async function readRepoConfig(projectPath) {
34647
35617
  async function readServerConfig(projectPath) {
34648
35618
  try {
34649
35619
  const raw = await readFile23(
34650
- join35(projectPath, ".codebyplan", "server.json"),
35620
+ join36(projectPath, ".codebyplan", "server.json"),
34651
35621
  "utf-8"
34652
35622
  );
34653
35623
  return JSON.parse(raw);
@@ -34658,7 +35628,7 @@ async function readServerConfig(projectPath) {
34658
35628
  async function readGitConfig2(projectPath) {
34659
35629
  try {
34660
35630
  const raw = await readFile23(
34661
- join35(projectPath, ".codebyplan", "git.json"),
35631
+ join36(projectPath, ".codebyplan", "git.json"),
34662
35632
  "utf-8"
34663
35633
  );
34664
35634
  return JSON.parse(raw);
@@ -34669,7 +35639,7 @@ async function readGitConfig2(projectPath) {
34669
35639
  async function readShipmentConfig2(projectPath) {
34670
35640
  try {
34671
35641
  const raw = await readFile23(
34672
- join35(projectPath, ".codebyplan", "shipment.json"),
35642
+ join36(projectPath, ".codebyplan", "shipment.json"),
34673
35643
  "utf-8"
34674
35644
  );
34675
35645
  return JSON.parse(raw);
@@ -34680,7 +35650,7 @@ async function readShipmentConfig2(projectPath) {
34680
35650
  async function readVendorConfig(projectPath) {
34681
35651
  try {
34682
35652
  const raw = await readFile23(
34683
- join35(projectPath, ".codebyplan", "vendor.json"),
35653
+ join36(projectPath, ".codebyplan", "vendor.json"),
34684
35654
  "utf-8"
34685
35655
  );
34686
35656
  return JSON.parse(raw);
@@ -34691,7 +35661,7 @@ async function readVendorConfig(projectPath) {
34691
35661
  async function readE2eConfig2(projectPath) {
34692
35662
  try {
34693
35663
  const raw = await readFile23(
34694
- join35(projectPath, ".codebyplan", "e2e.json"),
35664
+ join36(projectPath, ".codebyplan", "e2e.json"),
34695
35665
  "utf-8"
34696
35666
  );
34697
35667
  return JSON.parse(raw);
@@ -34702,7 +35672,7 @@ async function readE2eConfig2(projectPath) {
34702
35672
  async function readServerLocalConfig(projectPath) {
34703
35673
  try {
34704
35674
  const raw = await readFile23(
34705
- join35(projectPath, ".codebyplan", "server.local.json"),
35675
+ join36(projectPath, ".codebyplan", "server.local.json"),
34706
35676
  "utf-8"
34707
35677
  );
34708
35678
  return JSON.parse(raw);
@@ -34775,7 +35745,7 @@ var init_config = __esm({
34775
35745
 
34776
35746
  // src/lib/server-detect.ts
34777
35747
  import { readFile as readFile24, readdir as readdir5, access as access6 } from "node:fs/promises";
34778
- import { join as join36 } from "node:path";
35748
+ import { join as join37 } from "node:path";
34779
35749
  async function fileExists4(filePath) {
34780
35750
  try {
34781
35751
  await access6(filePath);
@@ -34786,8 +35756,8 @@ async function fileExists4(filePath) {
34786
35756
  }
34787
35757
  function detectPackageManager3(dir) {
34788
35758
  return (async () => {
34789
- if (await fileExists4(join36(dir, "pnpm-lock.yaml"))) return "pnpm";
34790
- if (await fileExists4(join36(dir, "yarn.lock"))) return "yarn";
35759
+ if (await fileExists4(join37(dir, "pnpm-lock.yaml"))) return "pnpm";
35760
+ if (await fileExists4(join37(dir, "yarn.lock"))) return "yarn";
34791
35761
  return "npm";
34792
35762
  })();
34793
35763
  }
@@ -34819,12 +35789,12 @@ function detectPortFromScripts(pkg) {
34819
35789
  return null;
34820
35790
  }
34821
35791
  async function isMonorepo(dir) {
34822
- return await fileExists4(join36(dir, "turbo.json")) || await fileExists4(join36(dir, "pnpm-workspace.yaml"));
35792
+ return await fileExists4(join37(dir, "turbo.json")) || await fileExists4(join37(dir, "pnpm-workspace.yaml"));
34823
35793
  }
34824
35794
  async function detectServers(projectPath) {
34825
35795
  let pkg;
34826
35796
  try {
34827
- const raw = await readFile24(join36(projectPath, "package.json"), "utf-8");
35797
+ const raw = await readFile24(join37(projectPath, "package.json"), "utf-8");
34828
35798
  pkg = JSON.parse(raw);
34829
35799
  } catch {
34830
35800
  return {
@@ -34840,13 +35810,13 @@ async function detectServers(projectPath) {
34840
35810
  const mono = await isMonorepo(projectPath);
34841
35811
  const servers = [];
34842
35812
  if (mono) {
34843
- const appsDir = join36(projectPath, "apps");
35813
+ const appsDir = join37(projectPath, "apps");
34844
35814
  try {
34845
35815
  const entries = await readdir5(appsDir, { withFileTypes: true });
34846
35816
  const sorted = [...entries].sort((a, b) => a.name.localeCompare(b.name));
34847
35817
  for (const entry of sorted) {
34848
35818
  if (!entry.isDirectory()) continue;
34849
- const appPkgPath = join36(appsDir, entry.name, "package.json");
35819
+ const appPkgPath = join37(appsDir, entry.name, "package.json");
34850
35820
  try {
34851
35821
  const appRaw = await readFile24(appPkgPath, "utf-8");
34852
35822
  const appPkg = JSON.parse(appRaw);
@@ -35012,7 +35982,7 @@ __export(ports_exports, {
35012
35982
  runPorts: () => runPorts
35013
35983
  });
35014
35984
  import { mkdir as mkdir11, readFile as readFile26, writeFile as writeFile20 } from "node:fs/promises";
35015
- import { join as join37 } from "node:path";
35985
+ import { join as join38 } from "node:path";
35016
35986
  function printDetectionResult(result, projectPath) {
35017
35987
  console.log(`
35018
35988
  CodeByPlan Ports - List`);
@@ -35168,8 +36138,8 @@ async function writeServerLocalConfig(repoId, projectPath, dryRun) {
35168
36138
  // and ServerLocalConfig.port_allocations is typed the same — honest end-to-end.
35169
36139
  port_allocations: portAllocations
35170
36140
  };
35171
- const codebyplanDir = join37(projectPath, ".codebyplan");
35172
- const filePath = join37(codebyplanDir, "server.local.json");
36141
+ const codebyplanDir = join38(projectPath, ".codebyplan");
36142
+ const filePath = join38(codebyplanDir, "server.local.json");
35173
36143
  const newJson = JSON.stringify(payload, null, 2) + "\n";
35174
36144
  let currentJson = "";
35175
36145
  try {
@@ -35191,8 +36161,8 @@ async function writeServerLocalConfig(repoId, projectPath, dryRun) {
35191
36161
  );
35192
36162
  }
35193
36163
  async function provisionE2eEnv(projectPath, dryRun) {
35194
- const relSource = join37("apps", "web", ".env.local");
35195
- const sourcePath = join37(projectPath, relSource);
36164
+ const relSource = join38("apps", "web", ".env.local");
36165
+ const sourcePath = join38(projectPath, relSource);
35196
36166
  let sourceRaw;
35197
36167
  try {
35198
36168
  sourceRaw = await readFile26(sourcePath, "utf-8");
@@ -35224,8 +36194,8 @@ async function provisionE2eEnv(projectPath, dryRun) {
35224
36194
  );
35225
36195
  return;
35226
36196
  }
35227
- const codebyplanDir = join37(projectPath, ".codebyplan");
35228
- const filePath = join37(codebyplanDir, "e2e.env");
36197
+ const codebyplanDir = join38(projectPath, ".codebyplan");
36198
+ const filePath = join38(codebyplanDir, "e2e.env");
35229
36199
  const newContent = lines.join("\n") + "\n";
35230
36200
  let currentContent = "";
35231
36201
  try {
@@ -35510,7 +36480,7 @@ __export(docs_exports, {
35510
36480
  });
35511
36481
  import { existsSync as existsSync13 } from "node:fs";
35512
36482
  import { mkdir as mkdir12, readFile as readFile27, readdir as readdir6, rm as rm2, writeFile as writeFile21 } from "node:fs/promises";
35513
- import { dirname as dirname13, isAbsolute as isAbsolute2, join as join38, relative as relative7, sep as sep2 } from "node:path";
36483
+ import { dirname as dirname14, isAbsolute as isAbsolute2, join as join39, relative as relative7, sep as sep2 } from "node:path";
35514
36484
  function selectDependencies(deps) {
35515
36485
  const byName = /* @__PURE__ */ new Map();
35516
36486
  for (const dep of deps) {
@@ -35564,12 +36534,12 @@ async function mapWithConcurrency(items, limit, fn) {
35564
36534
  }
35565
36535
  async function resolveExactVersion(projectPath, dep) {
35566
36536
  const candidateDirs = [projectPath];
35567
- const sourceDir = join38(projectPath, dirname13(dep.sourcePath));
36537
+ const sourceDir = join39(projectPath, dirname14(dep.sourcePath));
35568
36538
  if (sourceDir !== projectPath) candidateDirs.push(sourceDir);
35569
36539
  for (const base of candidateDirs) {
35570
36540
  try {
35571
36541
  const raw = await readFile27(
35572
- join38(base, "node_modules", dep.name, "package.json"),
36542
+ join39(base, "node_modules", dep.name, "package.json"),
35573
36543
  "utf-8"
35574
36544
  );
35575
36545
  const pkg = JSON.parse(raw);
@@ -35584,7 +36554,7 @@ async function resolveExactVersion(projectPath, dep) {
35584
36554
  async function readVendorDocsPath(projectPath) {
35585
36555
  try {
35586
36556
  const raw = await readFile27(
35587
- join38(projectPath, ".codebyplan", "vendor.json"),
36557
+ join39(projectPath, ".codebyplan", "vendor.json"),
35588
36558
  "utf-8"
35589
36559
  );
35590
36560
  const parsed = JSON.parse(raw);
@@ -35597,7 +36567,7 @@ async function readVendorDocsPath(projectPath) {
35597
36567
  }
35598
36568
  async function resolveDocsDir(projectPath, flags) {
35599
36569
  const configured = flags["dir"] ?? await readVendorDocsPath(projectPath) ?? DEFAULT_DOCS_DIR;
35600
- const absDir = isAbsolute2(configured) ? configured : join38(projectPath, configured);
36570
+ const absDir = isAbsolute2(configured) ? configured : join39(projectPath, configured);
35601
36571
  const rel = relative7(projectPath, absDir);
35602
36572
  const relDir = rel === "" || rel.startsWith("..") ? null : rel.split(sep2).join("/");
35603
36573
  return { absDir, relDir };
@@ -35606,7 +36576,7 @@ async function readDocsLock(absDir) {
35606
36576
  const empty = { generated_at: "", libraries: {} };
35607
36577
  let raw;
35608
36578
  try {
35609
- raw = await readFile27(join38(absDir, LOCK_FILE), "utf-8");
36579
+ raw = await readFile27(join39(absDir, LOCK_FILE), "utf-8");
35610
36580
  } catch {
35611
36581
  return empty;
35612
36582
  }
@@ -35702,7 +36672,7 @@ function buildTopIndex(outcomes) {
35702
36672
  }
35703
36673
  async function ensureDocsGitignoreEntry(projectPath, relDir, dryRun) {
35704
36674
  const entry = `/${relDir}/`;
35705
- const gitignorePath = join38(projectPath, ".gitignore");
36675
+ const gitignorePath = join39(projectPath, ".gitignore");
35706
36676
  let existing = "";
35707
36677
  try {
35708
36678
  existing = await readFile27(gitignorePath, "utf-8");
@@ -35725,7 +36695,7 @@ async function markUncovered(dep, exactVersion, ctx) {
35725
36695
  console.log(
35726
36696
  ` uncovered ${dep.name}@${exactVersion || "?"} \u2014 no docs in the library mirror`
35727
36697
  );
35728
- const libPath = join38(ctx.absDir, libDirName(dep.name));
36698
+ const libPath = join39(ctx.absDir, libDirName(dep.name));
35729
36699
  if (existsSync13(libPath)) {
35730
36700
  if (ctx.dryRun) {
35731
36701
  console.log(` would remove stale mirror dir ${libPath}`);
@@ -35778,14 +36748,14 @@ async function syncOneLibrary(dep, ctx) {
35778
36748
  }
35779
36749
  }
35780
36750
  const lockEntry = ctx.lock.libraries[dep.name];
35781
- const libPath = join38(ctx.absDir, libDirName(dep.name));
35782
- const versionPath = join38(libPath, manifest.resolved_version);
36751
+ const libPath = join39(ctx.absDir, libDirName(dep.name));
36752
+ const versionPath = join39(libPath, manifest.resolved_version);
35783
36753
  if (manifestMatchesLock(manifest, lockEntry)) {
35784
36754
  console.log(` unchanged ${dep.name}@${manifest.resolved_version}`);
35785
- if (!ctx.dryRun && !existsSync13(join38(libPath, "INDEX.md"))) {
36755
+ if (!ctx.dryRun && !existsSync13(join39(libPath, "INDEX.md"))) {
35786
36756
  await mkdir12(libPath, { recursive: true });
35787
36757
  await writeFile21(
35788
- join38(libPath, "INDEX.md"),
36758
+ join39(libPath, "INDEX.md"),
35789
36759
  buildLibIndex(dep.name, manifest),
35790
36760
  "utf-8"
35791
36761
  );
@@ -35807,13 +36777,13 @@ async function syncOneLibrary(dep, ctx) {
35807
36777
  );
35808
36778
  continue;
35809
36779
  }
35810
- const target = join38(versionPath, rel);
36780
+ const target = join39(versionPath, rel);
35811
36781
  if (sameVersionLockFiles[file.path] === file.content_hash && existsSync13(target)) {
35812
36782
  continue;
35813
36783
  }
35814
36784
  written++;
35815
36785
  if (!ctx.dryRun) {
35816
- await mkdir12(dirname13(target), { recursive: true });
36786
+ await mkdir12(dirname14(target), { recursive: true });
35817
36787
  await writeFile21(target, file.content, "utf-8");
35818
36788
  }
35819
36789
  }
@@ -35825,7 +36795,7 @@ async function syncOneLibrary(dep, ctx) {
35825
36795
  const rel = sanitizeDocPath(lockedPath);
35826
36796
  if (rel === null) continue;
35827
36797
  removedFiles++;
35828
- if (!ctx.dryRun) await rm2(join38(versionPath, rel), { force: true });
36798
+ if (!ctx.dryRun) await rm2(join39(versionPath, rel), { force: true });
35829
36799
  }
35830
36800
  }
35831
36801
  let removedVersionDirs = 0;
@@ -35840,13 +36810,13 @@ async function syncOneLibrary(dep, ctx) {
35840
36810
  }
35841
36811
  removedVersionDirs++;
35842
36812
  if (!ctx.dryRun) {
35843
- await rm2(join38(libPath, entry.name), { recursive: true, force: true });
36813
+ await rm2(join39(libPath, entry.name), { recursive: true, force: true });
35844
36814
  }
35845
36815
  }
35846
36816
  if (!ctx.dryRun) {
35847
36817
  await mkdir12(libPath, { recursive: true });
35848
36818
  await writeFile21(
35849
- join38(libPath, "INDEX.md"),
36819
+ join39(libPath, "INDEX.md"),
35850
36820
  buildLibIndex(dep.name, manifest),
35851
36821
  "utf-8"
35852
36822
  );
@@ -35900,7 +36870,7 @@ async function runDocsSync() {
35900
36870
  );
35901
36871
  if (!dryRun) {
35902
36872
  await mkdir12(absDir, { recursive: true });
35903
- await writeFile21(join38(absDir, "INDEX.md"), buildTopIndex(outcomes), "utf-8");
36873
+ await writeFile21(join39(absDir, "INDEX.md"), buildTopIndex(outcomes), "utf-8");
35904
36874
  const libraries = {};
35905
36875
  for (const o of outcomes) {
35906
36876
  if (o.kind === "synced" || o.kind === "unchanged") {
@@ -35926,7 +36896,7 @@ async function runDocsSync() {
35926
36896
  libraries: sortedLibraries
35927
36897
  };
35928
36898
  await writeFile21(
35929
- join38(absDir, LOCK_FILE),
36899
+ join39(absDir, LOCK_FILE),
35930
36900
  JSON.stringify(newLock, null, 2) + "\n",
35931
36901
  "utf-8"
35932
36902
  );
@@ -35968,7 +36938,7 @@ async function countFilesRecursively(dirPath) {
35968
36938
  let count = 0;
35969
36939
  for (const entry of entries) {
35970
36940
  if (entry.isDirectory()) {
35971
- count += await countFilesRecursively(join38(dirPath, entry.name));
36941
+ count += await countFilesRecursively(join39(dirPath, entry.name));
35972
36942
  } else if (entry.isFile()) {
35973
36943
  count++;
35974
36944
  }
@@ -35985,7 +36955,7 @@ async function runDocsStatus() {
35985
36955
  `);
35986
36956
  let raw;
35987
36957
  try {
35988
- raw = await readFile27(join38(absDir, LOCK_FILE), "utf-8");
36958
+ raw = await readFile27(join39(absDir, LOCK_FILE), "utf-8");
35989
36959
  } catch {
35990
36960
  console.log(
35991
36961
  ` No ${LOCK_FILE} found \u2014 run \`codebyplan docs sync\` first.
@@ -36014,7 +36984,7 @@ async function runDocsStatus() {
36014
36984
  let outOfSync = 0;
36015
36985
  for (const name of names) {
36016
36986
  const entry = lock.libraries[name];
36017
- const versionPath = join38(absDir, libDirName(name), entry.resolved_version);
36987
+ const versionPath = join39(absDir, libDirName(name), entry.resolved_version);
36018
36988
  const expected = Object.keys(entry.files).length;
36019
36989
  if (!existsSync13(versionPath)) {
36020
36990
  outOfSync++;
@@ -36102,7 +37072,7 @@ var init_docs = __esm({
36102
37072
 
36103
37073
  // src/lib/check-baseline.ts
36104
37074
  import { readFileSync as readFileSync12, writeFileSync as writeFileSync7 } from "node:fs";
36105
- import { join as join39 } from "node:path";
37075
+ import { join as join40 } from "node:path";
36106
37076
  function emptyBaseline() {
36107
37077
  return {
36108
37078
  lint: { known_failing: [] },
@@ -36112,7 +37082,7 @@ function emptyBaseline() {
36112
37082
  };
36113
37083
  }
36114
37084
  function loadBaseline(projectRoot) {
36115
- const filePath = join39(projectRoot, BASELINE_FILENAME);
37085
+ const filePath = join40(projectRoot, BASELINE_FILENAME);
36116
37086
  try {
36117
37087
  const raw = readFileSync12(filePath, "utf-8");
36118
37088
  const parsed = JSON.parse(raw);
@@ -36136,7 +37106,7 @@ function loadBaseline(projectRoot) {
36136
37106
  }
36137
37107
  }
36138
37108
  function saveBaseline(projectRoot, baseline) {
36139
- const filePath = join39(projectRoot, BASELINE_FILENAME);
37109
+ const filePath = join40(projectRoot, BASELINE_FILENAME);
36140
37110
  writeFileSync7(filePath, JSON.stringify(baseline, null, 2) + "\n", "utf-8");
36141
37111
  }
36142
37112
  function diffBaseline(check, currentFailingPackages, baseline) {
@@ -36186,8 +37156,8 @@ var init_check_baseline = __esm({
36186
37156
 
36187
37157
  // src/lib/check.ts
36188
37158
  import { readFileSync as readFileSync13, existsSync as existsSync14 } from "node:fs";
36189
- import { join as join40 } from "node:path";
36190
- import { spawnSync as spawnSync11 } from "node:child_process";
37159
+ import { join as join41 } from "node:path";
37160
+ import { spawnSync as spawnSync13 } from "node:child_process";
36191
37161
  function hasSentinelValue(arrays) {
36192
37162
  const SENTINELS = /* @__PURE__ */ new Set([
36193
37163
  SUMMARY_UNREADABLE,
@@ -36202,7 +37172,7 @@ function resolveNewFailures(check, failingPackages, baseline, updateBaseline, no
36202
37172
  return diffBaseline(check, failingPackages, baseline);
36203
37173
  }
36204
37174
  function defaultSpawnFn(command, opts) {
36205
- const result = spawnSync11(command, {
37175
+ const result = spawnSync13(command, {
36206
37176
  shell: true,
36207
37177
  cwd: opts.cwd,
36208
37178
  encoding: "utf-8",
@@ -36254,9 +37224,9 @@ function parseFailingPackagesFromSummary(summaryPath) {
36254
37224
  return Array.from(failing).sort();
36255
37225
  }
36256
37226
  function resolveTurboBin(projectRoot) {
36257
- const localBin = join40(projectRoot, "node_modules", ".bin", "turbo");
37227
+ const localBin = join41(projectRoot, "node_modules", ".bin", "turbo");
36258
37228
  if (existsSync14(localBin)) return localBin;
36259
- const workspaceRootBin = join40(
37229
+ const workspaceRootBin = join41(
36260
37230
  projectRoot,
36261
37231
  "..",
36262
37232
  "..",
@@ -36753,7 +37723,7 @@ var init_check2 = __esm({
36753
37723
 
36754
37724
  // src/lib/claude-plan.ts
36755
37725
  import * as fs13 from "node:fs";
36756
- import * as path14 from "node:path";
37726
+ import * as path15 from "node:path";
36757
37727
  function buildDriftPlan(projectDir, templatesDir, manifest) {
36758
37728
  const packaged = walkTemplates(templatesDir);
36759
37729
  const packagedBySrc = new Map(packaged.map((f) => [f.src, f]));
@@ -36767,8 +37737,8 @@ function buildDriftPlan(projectDir, templatesDir, manifest) {
36767
37737
  };
36768
37738
  for (const pkg of packaged) {
36769
37739
  const inManifest = manifestBySrc.get(pkg.src);
36770
- const absDest = path14.join(projectDir, ".claude", pkg.dest);
36771
- const absSrc = path14.join(templatesDir, pkg.src);
37740
+ const absDest = path15.join(projectDir, ".claude", pkg.dest);
37741
+ const absSrc = path15.join(templatesDir, pkg.src);
36772
37742
  if (!inManifest) {
36773
37743
  plan.newOptIn.push({
36774
37744
  packaged: { src: pkg.src, dest: pkg.dest, hash: pkg.hash },
@@ -36817,7 +37787,7 @@ __export(status_exports, {
36817
37787
  runStatus: () => runStatus2
36818
37788
  });
36819
37789
  import * as fs14 from "node:fs";
36820
- import * as path15 from "node:path";
37790
+ import * as path16 from "node:path";
36821
37791
  import { execSync as execSync9 } from "node:child_process";
36822
37792
  function makeFailSafe(checked_at) {
36823
37793
  return {
@@ -36926,12 +37896,12 @@ async function runStatus2(argv) {
36926
37896
  const latest = fetchLatestVersion();
36927
37897
  const newer = latest !== null && compareSemver(latest, installed) > 0;
36928
37898
  let settings_drift = false;
36929
- const settingsPath = path15.join(projectDir, ".claude", "settings.json");
36930
- const baseSettingsPath = path15.join(
37899
+ const settingsPath = path16.join(projectDir, ".claude", "settings.json");
37900
+ const baseSettingsPath = path16.join(
36931
37901
  templatesDir,
36932
37902
  "settings.project.base.json"
36933
37903
  );
36934
- const hooksJsonPath = path15.join(templatesDir, "hooks", "hooks.json");
37904
+ const hooksJsonPath = path16.join(templatesDir, "hooks", "hooks.json");
36935
37905
  if (fs14.existsSync(settingsPath)) {
36936
37906
  try {
36937
37907
  const settingsRaw = fs14.readFileSync(settingsPath, "utf8");
@@ -37001,10 +37971,10 @@ function emitResult(result, writeCache, quiet, projectDir) {
37001
37971
  const json = JSON.stringify(result, null, 2);
37002
37972
  if (writeCache) {
37003
37973
  try {
37004
- const cacheDir = path15.join(projectDir, ".codebyplan");
37974
+ const cacheDir = path16.join(projectDir, ".codebyplan");
37005
37975
  fs14.mkdirSync(cacheDir, { recursive: true });
37006
37976
  fs14.writeFileSync(
37007
- path15.join(cacheDir, "claude-status.local.json"),
37977
+ path16.join(cacheDir, "claude-status.local.json"),
37008
37978
  json + "\n",
37009
37979
  "utf8"
37010
37980
  );
@@ -37148,7 +38118,7 @@ __export(update_exports, {
37148
38118
  });
37149
38119
  import * as fs15 from "node:fs";
37150
38120
  import * as os3 from "node:os";
37151
- import * as path16 from "node:path";
38121
+ import * as path17 from "node:path";
37152
38122
  async function runUpdate(opts, deps = {}) {
37153
38123
  await Promise.resolve();
37154
38124
  const scope = opts.scope ?? "project";
@@ -37184,9 +38154,9 @@ async function runUpdate(opts, deps = {}) {
37184
38154
  finalManifestEntries.push(e);
37185
38155
  }
37186
38156
  for (const { packaged, absSrc } of plan.overwriteSafe) {
37187
- const absDest = path16.join(projectDir, ".claude", packaged.dest);
38157
+ const absDest = path17.join(projectDir, ".claude", packaged.dest);
37188
38158
  if (!opts.dryRun) {
37189
- fs15.mkdirSync(path16.dirname(absDest), { recursive: true });
38159
+ fs15.mkdirSync(path17.dirname(absDest), { recursive: true });
37190
38160
  fs15.copyFileSync(absSrc, absDest);
37191
38161
  if (opts.verbose) console.log(`updated ${packaged.dest}`);
37192
38162
  } else if (opts.verbose) {
@@ -37199,7 +38169,7 @@ async function runUpdate(opts, deps = {}) {
37199
38169
  absSrc,
37200
38170
  onDiskContent
37201
38171
  } of plan.overwriteHandEdited) {
37202
- const absDest = path16.join(projectDir, ".claude", packaged.dest);
38172
+ const absDest = path17.join(projectDir, ".claude", packaged.dest);
37203
38173
  const newContent = fs15.readFileSync(absSrc);
37204
38174
  const showDiff = () => {
37205
38175
  console.log(
@@ -37212,7 +38182,7 @@ async function runUpdate(opts, deps = {}) {
37212
38182
  const answer = await promptOverwrite(packaged.dest, opts, showDiff);
37213
38183
  if (answer === "overwrite") {
37214
38184
  if (!opts.dryRun) {
37215
- fs15.mkdirSync(path16.dirname(absDest), { recursive: true });
38185
+ fs15.mkdirSync(path17.dirname(absDest), { recursive: true });
37216
38186
  fs15.copyFileSync(absSrc, absDest);
37217
38187
  }
37218
38188
  finalManifestEntries.push(packaged);
@@ -37228,9 +38198,9 @@ async function runUpdate(opts, deps = {}) {
37228
38198
  for (const { packaged, absSrc } of plan.newOptIn) {
37229
38199
  const answer = await promptOptIn(packaged.dest, opts);
37230
38200
  if (answer === "opt-in") {
37231
- const absDest = path16.join(projectDir, ".claude", packaged.dest);
38201
+ const absDest = path17.join(projectDir, ".claude", packaged.dest);
37232
38202
  if (!opts.dryRun) {
37233
- fs15.mkdirSync(path16.dirname(absDest), { recursive: true });
38203
+ fs15.mkdirSync(path17.dirname(absDest), { recursive: true });
37234
38204
  fs15.copyFileSync(absSrc, absDest);
37235
38205
  }
37236
38206
  finalManifestEntries.push(packaged);
@@ -37242,25 +38212,25 @@ async function runUpdate(opts, deps = {}) {
37242
38212
  for (const e of plan.removedFromPackage) {
37243
38213
  const answer = await promptRemove(e.dest, opts);
37244
38214
  if (answer === "remove") {
37245
- const absDest = path16.join(projectDir, ".claude", e.dest);
38215
+ const absDest = path17.join(projectDir, ".claude", e.dest);
37246
38216
  if (!opts.dryRun && fs15.existsSync(absDest)) {
37247
38217
  fs15.rmSync(absDest);
37248
- const claudeDir = path16.join(projectDir, ".claude");
37249
- let cur = path16.dirname(absDest);
37250
- while (cur !== claudeDir && cur !== path16.dirname(cur)) {
37251
- if (path16.dirname(cur) === claudeDir) break;
38218
+ const claudeDir = path17.join(projectDir, ".claude");
38219
+ let cur = path17.dirname(absDest);
38220
+ while (cur !== claudeDir && cur !== path17.dirname(cur)) {
38221
+ if (path17.dirname(cur) === claudeDir) break;
37252
38222
  try {
37253
38223
  fs15.rmdirSync(cur);
37254
38224
  if (opts.verbose)
37255
38225
  console.log(
37256
- `pruned empty dir ${path16.relative(claudeDir, cur)}`
38226
+ `pruned empty dir ${path17.relative(claudeDir, cur)}`
37257
38227
  );
37258
- cur = path16.dirname(cur);
38228
+ cur = path17.dirname(cur);
37259
38229
  } catch (err) {
37260
38230
  const code = err.code;
37261
38231
  if (code !== "ENOTEMPTY" && code !== "ENOENT") {
37262
38232
  console.warn(
37263
- `codebyplan claude: could not prune empty dir ${path16.relative(claudeDir, cur)}: ${err.message}`
38233
+ `codebyplan claude: could not prune empty dir ${path17.relative(claudeDir, cur)}: ${err.message}`
37264
38234
  );
37265
38235
  }
37266
38236
  break;
@@ -37272,12 +38242,12 @@ async function runUpdate(opts, deps = {}) {
37272
38242
  if (opts.verbose) console.log(`kept (untracked) ${e.dest}`);
37273
38243
  }
37274
38244
  }
37275
- const hooksJsonPath = path16.join(templatesDir, "hooks", "hooks.json");
37276
- const baseSettingsPath = path16.join(
38245
+ const hooksJsonPath = path17.join(templatesDir, "hooks", "hooks.json");
38246
+ const baseSettingsPath = path17.join(
37277
38247
  templatesDir,
37278
38248
  "settings.project.base.json"
37279
38249
  );
37280
- const settingsPath = path16.join(projectDir, ".claude", "settings.json");
38250
+ const settingsPath = path17.join(projectDir, ".claude", "settings.json");
37281
38251
  const existingSettings = fs15.existsSync(settingsPath) ? JSON.parse(fs15.readFileSync(settingsPath, "utf8")) : {};
37282
38252
  if (fs15.existsSync(baseSettingsPath)) {
37283
38253
  const base = JSON.parse(
@@ -37304,7 +38274,7 @@ async function runUpdate(opts, deps = {}) {
37304
38274
  deps.detectHealDeps
37305
38275
  );
37306
38276
  if (!opts.dryRun) {
37307
- fs15.mkdirSync(path16.dirname(settingsPath), { recursive: true });
38277
+ fs15.mkdirSync(path17.dirname(settingsPath), { recursive: true });
37308
38278
  fs15.writeFileSync(
37309
38279
  settingsPath,
37310
38280
  JSON.stringify(existingSettings, null, 2) + "\n",
@@ -37320,7 +38290,7 @@ async function runUpdate(opts, deps = {}) {
37320
38290
  );
37321
38291
  if (opts.verbose && gitignoreAction !== "unchanged") {
37322
38292
  console.log(
37323
- `${opts.dryRun ? "[dry-run] would " : ""}${gitignoreAction} managed .gitignore block in ${path16.relative(projectDir, path16.join(projectDir, ".gitignore"))}`
38293
+ `${opts.dryRun ? "[dry-run] would " : ""}${gitignoreAction} managed .gitignore block in ${path17.relative(projectDir, path17.join(projectDir, ".gitignore"))}`
37324
38294
  );
37325
38295
  }
37326
38296
  if (!opts.dryRun) {
@@ -37360,9 +38330,9 @@ function runUpdateUser(opts, deps) {
37360
38330
  return;
37361
38331
  }
37362
38332
  try {
37363
- const userDir = deps.userDir ?? path16.join(os3.homedir(), ".claude");
37364
- const settingsPath = path16.join(userDir, "settings.json");
37365
- const userBaseSettingsPath = path16.join(
38333
+ const userDir = deps.userDir ?? path17.join(os3.homedir(), ".claude");
38334
+ const settingsPath = path17.join(userDir, "settings.json");
38335
+ const userBaseSettingsPath = path17.join(
37366
38336
  templatesDir,
37367
38337
  "settings.user.base.json"
37368
38338
  );
@@ -37434,7 +38404,7 @@ __export(uninstall_exports, {
37434
38404
  });
37435
38405
  import * as fs16 from "node:fs";
37436
38406
  import * as os4 from "node:os";
37437
- import * as path17 from "node:path";
38407
+ import * as path18 from "node:path";
37438
38408
  async function runUninstall(opts, deps = {}) {
37439
38409
  await Promise.resolve();
37440
38410
  const scope = opts.scope ?? "project";
@@ -37463,7 +38433,7 @@ async function runUninstall(opts, deps = {}) {
37463
38433
  let removed = 0;
37464
38434
  let warnings = 0;
37465
38435
  for (const entry of manifest.files) {
37466
- const abs = path17.join(projectDir, ".claude", entry.dest);
38436
+ const abs = path18.join(projectDir, ".claude", entry.dest);
37467
38437
  if (!fs16.existsSync(abs)) {
37468
38438
  console.warn(
37469
38439
  `codebyplan claude uninstall: ${entry.dest} already absent (skipping).`
@@ -37487,12 +38457,12 @@ async function runUninstall(opts, deps = {}) {
37487
38457
  if (!opts.dryRun) {
37488
38458
  pruneEmptyManagedDirs(projectDir);
37489
38459
  }
37490
- const settingsPath = path17.join(projectDir, ".claude", "settings.json");
38460
+ const settingsPath = path18.join(projectDir, ".claude", "settings.json");
37491
38461
  if (fs16.existsSync(settingsPath)) {
37492
38462
  const settings = JSON.parse(
37493
38463
  fs16.readFileSync(settingsPath, "utf8")
37494
38464
  );
37495
- const baseSettingsPath = templatesDir ? path17.join(templatesDir, "settings.project.base.json") : null;
38465
+ const baseSettingsPath = templatesDir ? path18.join(templatesDir, "settings.project.base.json") : null;
37496
38466
  if (baseSettingsPath && fs16.existsSync(baseSettingsPath)) {
37497
38467
  const base = JSON.parse(
37498
38468
  fs16.readFileSync(baseSettingsPath, "utf8")
@@ -37550,7 +38520,7 @@ function runUninstallUser(opts, deps) {
37550
38520
  }
37551
38521
  }
37552
38522
  try {
37553
- const userDir = deps.userDir ?? path17.join(os4.homedir(), ".claude");
38523
+ const userDir = deps.userDir ?? path18.join(os4.homedir(), ".claude");
37554
38524
  const existingManifest = readManifestForScope("user", userDir);
37555
38525
  if (!existingManifest) {
37556
38526
  console.error(
@@ -37559,12 +38529,12 @@ function runUninstallUser(opts, deps) {
37559
38529
  process.exitCode = 1;
37560
38530
  return;
37561
38531
  }
37562
- const settingsPath = path17.join(userDir, "settings.json");
38532
+ const settingsPath = path18.join(userDir, "settings.json");
37563
38533
  if (fs16.existsSync(settingsPath)) {
37564
38534
  const settings = JSON.parse(
37565
38535
  fs16.readFileSync(settingsPath, "utf8")
37566
38536
  );
37567
- const userBaseSettingsPath = templatesDir != null ? path17.join(templatesDir, "settings.user.base.json") : null;
38537
+ const userBaseSettingsPath = templatesDir != null ? path18.join(templatesDir, "settings.user.base.json") : null;
37568
38538
  if (userBaseSettingsPath && fs16.existsSync(userBaseSettingsPath)) {
37569
38539
  const userBase = JSON.parse(
37570
38540
  fs16.readFileSync(userBaseSettingsPath, "utf8")
@@ -37605,7 +38575,7 @@ function runUninstallUser(opts, deps) {
37605
38575
  function pruneEmptyManagedDirs(projectDir) {
37606
38576
  const managedRoots = ["skills", "agents", "hooks", "rules"];
37607
38577
  for (const root of managedRoots) {
37608
- const abs = path17.join(projectDir, ".claude", root);
38578
+ const abs = path18.join(projectDir, ".claude", root);
37609
38579
  if (!fs16.existsSync(abs)) continue;
37610
38580
  pruneLeafFirst(abs);
37611
38581
  }
@@ -37616,7 +38586,7 @@ function pruneLeafFirst(dir) {
37616
38586
  if (!stat3.isDirectory()) return;
37617
38587
  for (const entry of fs16.readdirSync(dir, { withFileTypes: true })) {
37618
38588
  if (entry.isDirectory()) {
37619
- pruneLeafFirst(path17.join(dir, entry.name));
38589
+ pruneLeafFirst(path18.join(dir, entry.name));
37620
38590
  }
37621
38591
  }
37622
38592
  const remaining = fs16.readdirSync(dir);
@@ -37637,7 +38607,7 @@ var init_uninstall = __esm({
37637
38607
 
37638
38608
  // src/lib/verify-parity.ts
37639
38609
  import * as fs17 from "node:fs";
37640
- import * as path18 from "node:path";
38610
+ import * as path19 from "node:path";
37641
38611
  function isValidScope(s) {
37642
38612
  return s === "org-shared" || s === "project-shared" || REPO_ONLY_RE.test(s);
37643
38613
  }
@@ -37654,25 +38624,25 @@ function checkSiblingParity(opts) {
37654
38624
  expectedOneSided = DEFAULT_EXPECTED_ONE_SIDED,
37655
38625
  ignoredSubtrees
37656
38626
  } = opts;
37657
- const defaultIgnored = [path18.join(claudeDir, "hooks", "__test-fixtures__")];
38627
+ const defaultIgnored = [path19.join(claudeDir, "hooks", "__test-fixtures__")];
37658
38628
  const ignored = ignoredSubtrees ?? defaultIgnored;
37659
38629
  const violations = [];
37660
38630
  const claudeSideRels = /* @__PURE__ */ new Set();
37661
38631
  for (const scanDir of SCAN_DIRS) {
37662
- const baseDir = path18.join(claudeDir, scanDir);
38632
+ const baseDir = path19.join(claudeDir, scanDir);
37663
38633
  if (!fs17.existsSync(baseDir)) continue;
37664
38634
  const entries = readdirRecursive(baseDir);
37665
38635
  for (const entry of entries) {
37666
- const absPath = path18.join(baseDir, entry);
38636
+ const absPath = path19.join(baseDir, entry);
37667
38637
  if (!fs17.lstatSync(absPath).isFile()) continue;
37668
38638
  if (ignored.some(
37669
- (ig) => absPath.startsWith(ig + path18.sep) || absPath === ig
38639
+ (ig) => absPath.startsWith(ig + path19.sep) || absPath === ig
37670
38640
  )) {
37671
38641
  continue;
37672
38642
  }
37673
- const relPath = path18.join(scanDir, entry).split(path18.sep).join("/");
38643
+ const relPath = path19.join(scanDir, entry).split(path19.sep).join("/");
37674
38644
  claudeSideRels.add(relPath);
37675
- const templatePath = path18.join(templatesDir, relPath);
38645
+ const templatePath = path19.join(templatesDir, relPath);
37676
38646
  if (!fs17.existsSync(templatePath)) {
37677
38647
  if (!expectedOneSided.has(relPath) && !isScaffoldFile(entry)) {
37678
38648
  violations.push({ type: "missing-twin", path: relPath });
@@ -37687,14 +38657,14 @@ function checkSiblingParity(opts) {
37687
38657
  }
37688
38658
  }
37689
38659
  for (const scanDir of SCAN_DIRS) {
37690
- const tplBase = path18.join(templatesDir, scanDir);
38660
+ const tplBase = path19.join(templatesDir, scanDir);
37691
38661
  if (!fs17.existsSync(tplBase)) continue;
37692
38662
  const entries = readdirRecursive(tplBase);
37693
38663
  for (const entry of entries) {
37694
- const absPath = path18.join(tplBase, entry);
38664
+ const absPath = path19.join(tplBase, entry);
37695
38665
  if (!fs17.lstatSync(absPath).isFile()) continue;
37696
38666
  if (isScaffoldFile(entry)) continue;
37697
- const relPath = path18.join(scanDir, entry).split(path18.sep).join("/");
38667
+ const relPath = path19.join(scanDir, entry).split(path19.sep).join("/");
37698
38668
  if (!claudeSideRels.has(relPath) && !expectedOneSided.has(relPath)) {
37699
38669
  violations.push({ type: "extra-twin", path: relPath });
37700
38670
  }
@@ -37730,18 +38700,18 @@ function checkScopeMarkers(opts) {
37730
38700
  const twinDetectionActive = templatesDir != null && fs17.existsSync(templatesDir);
37731
38701
  const violations = [];
37732
38702
  for (const scanDir of scanDirs) {
37733
- const baseDir = path18.join(claudeDir, scanDir);
38703
+ const baseDir = path19.join(claudeDir, scanDir);
37734
38704
  if (!fs17.existsSync(baseDir)) continue;
37735
38705
  const entries = readdirRecursive(baseDir);
37736
38706
  for (const entry of entries) {
37737
- const absPath = path18.join(baseDir, entry);
38707
+ const absPath = path19.join(baseDir, entry);
37738
38708
  if (!fs17.lstatSync(absPath).isFile()) continue;
37739
38709
  if (!isStructuralEntry(scanDir, entry)) continue;
37740
- const ext = path18.extname(entry).toLowerCase();
38710
+ const ext = path19.extname(entry).toLowerCase();
37741
38711
  const isMd = ext === ".md";
37742
38712
  const isSh = ext === ".sh";
37743
38713
  if (!isMd && !isSh) continue;
37744
- const relPath = path18.join(scanDir, entry).split(path18.sep).join("/");
38714
+ const relPath = path19.join(scanDir, entry).split(path19.sep).join("/");
37745
38715
  if (allowlist.has(relPath)) continue;
37746
38716
  let content;
37747
38717
  try {
@@ -37755,7 +38725,7 @@ function checkScopeMarkers(opts) {
37755
38725
  continue;
37756
38726
  }
37757
38727
  const scopeValue = isMd ? extractFrontmatterScope(content) : extractShScope(content);
37758
- const managed = twinDetectionActive && fs17.existsSync(path18.join(templatesDir, relPath));
38728
+ const managed = twinDetectionActive && fs17.existsSync(path19.join(templatesDir, relPath));
37759
38729
  if (managed) {
37760
38730
  if (scopeValue === null) {
37761
38731
  } else if (scopeValue === "org-shared") {
@@ -37809,7 +38779,7 @@ function readdirRecursive(dir, rel = "", visited = /* @__PURE__ */ new Set()) {
37809
38779
  visited.add(realDir);
37810
38780
  const results = [];
37811
38781
  for (const name of fs17.readdirSync(dir)) {
37812
- const full = path18.join(dir, name);
38782
+ const full = path19.join(dir, name);
37813
38783
  const relName = rel ? `${rel}/${name}` : name;
37814
38784
  if (fs17.lstatSync(full).isDirectory()) {
37815
38785
  results.push(...readdirRecursive(full, relName, visited));
@@ -37882,12 +38852,12 @@ __export(verify_parity_exports, {
37882
38852
  verifyParity: () => verifyParity
37883
38853
  });
37884
38854
  import * as fs18 from "node:fs";
37885
- import * as path19 from "node:path";
38855
+ import * as path20 from "node:path";
37886
38856
  function verifyParity(args, deps = {}) {
37887
38857
  const warnOnly = args.includes("--warn-only");
37888
38858
  const jsonMode = args.includes("--json");
37889
38859
  const projectDir = deps.cwd ?? process.cwd();
37890
- const claudeDir = path19.join(projectDir, ".claude");
38860
+ const claudeDir = path20.join(projectDir, ".claude");
37891
38861
  if (!fs18.existsSync(claudeDir)) {
37892
38862
  const msg = "codebyplan claude verify-parity: .claude/ not found in cwd \u2014 run from the project root.\n";
37893
38863
  process.stderr.write(msg);
@@ -38395,7 +39365,7 @@ __export(generate_exports, {
38395
39365
  runGenerate: () => runGenerate
38396
39366
  });
38397
39367
  import { readFile as readFile28, mkdir as mkdir13, writeFile as writeFile22 } from "node:fs/promises";
38398
- import { join as join47, resolve as resolve11 } from "node:path";
39368
+ import { join as join48, resolve as resolve11 } from "node:path";
38399
39369
  async function readJsonFile4(filePath) {
38400
39370
  try {
38401
39371
  const raw = await readFile28(filePath, "utf-8");
@@ -38406,7 +39376,7 @@ async function readJsonFile4(filePath) {
38406
39376
  }
38407
39377
  async function readPkgName(absPath) {
38408
39378
  try {
38409
- const raw = await readFile28(join47(absPath, "package.json"), "utf-8");
39379
+ const raw = await readFile28(join48(absPath, "package.json"), "utf-8");
38410
39380
  const pkg = JSON.parse(raw);
38411
39381
  return typeof pkg.name === "string" ? pkg.name : null;
38412
39382
  } catch {
@@ -38420,7 +39390,7 @@ async function runGenerate(opts) {
38420
39390
  const rootDir = resolve11(projectDir);
38421
39391
  let packageManager;
38422
39392
  try {
38423
- const raw = await readFile28(join47(rootDir, "package.json"), "utf-8");
39393
+ const raw = await readFile28(join48(rootDir, "package.json"), "utf-8");
38424
39394
  const pkg = JSON.parse(raw);
38425
39395
  if (typeof pkg.packageManager === "string") {
38426
39396
  packageManager = pkg.packageManager;
@@ -38428,7 +39398,7 @@ async function runGenerate(opts) {
38428
39398
  } catch {
38429
39399
  }
38430
39400
  const serverJson = await readJsonFile4(
38431
- join47(rootDir, ".codebyplan", "server.json")
39401
+ join48(rootDir, ".codebyplan", "server.json")
38432
39402
  );
38433
39403
  const ports = [];
38434
39404
  for (const alloc of serverJson?.port_allocations ?? []) {
@@ -38441,7 +39411,7 @@ async function runGenerate(opts) {
38441
39411
  }
38442
39412
  }
38443
39413
  const gitJson = await readJsonFile4(
38444
- join47(rootDir, ".codebyplan", "git.json")
39414
+ join48(rootDir, ".codebyplan", "git.json")
38445
39415
  );
38446
39416
  const branchModel = gitJson?.branch_config?.production ? {
38447
39417
  production: gitJson.branch_config.production,
@@ -38450,7 +39420,7 @@ async function runGenerate(opts) {
38450
39420
  )
38451
39421
  } : void 0;
38452
39422
  const shipmentJson = await readJsonFile4(
38453
- join47(rootDir, ".codebyplan", "shipment.json")
39423
+ join48(rootDir, ".codebyplan", "shipment.json")
38454
39424
  );
38455
39425
  const shipmentSurfaces = [];
38456
39426
  const rawSurfaces = shipmentJson?.shipment?.surfaces ?? shipmentJson?.surfaces ?? {};
@@ -38521,7 +39491,7 @@ async function runGenerate(opts) {
38521
39491
  const structureMdContent = generateStructureMd(config);
38522
39492
  const agentsContent = generateAgentsMd(structureMdContent);
38523
39493
  if (check) {
38524
- const agentsMdPath2 = join47(rootDir, "AGENTS.md");
39494
+ const agentsMdPath2 = join48(rootDir, "AGENTS.md");
38525
39495
  let existingAgents = null;
38526
39496
  try {
38527
39497
  existingAgents = await readFile28(agentsMdPath2, "utf-8");
@@ -38560,13 +39530,13 @@ async function runGenerate(opts) {
38560
39530
  process.stdout.write(agentsContent);
38561
39531
  return;
38562
39532
  }
38563
- const outputDir = join47(rootDir, ".claude", "generated");
39533
+ const outputDir = join48(rootDir, ".claude", "generated");
38564
39534
  await mkdir13(outputDir, { recursive: true });
38565
- const outputPath = join47(outputDir, "structure.md");
39535
+ const outputPath = join48(outputDir, "structure.md");
38566
39536
  await writeFile22(outputPath, structureMdContent, "utf-8");
38567
39537
  process.stdout.write(`Wrote: .claude/generated/structure.md
38568
39538
  `);
38569
- const agentsMdPath = join47(rootDir, "AGENTS.md");
39539
+ const agentsMdPath = join48(rootDir, "AGENTS.md");
38570
39540
  let existingAgentsContent = null;
38571
39541
  try {
38572
39542
  existingAgentsContent = await readFile28(agentsMdPath, "utf-8");
@@ -38598,7 +39568,7 @@ __export(readme_exports, {
38598
39568
  runReadmeCommand: () => runReadmeCommand
38599
39569
  });
38600
39570
  import { readFile as readFile29, writeFile as writeFile23 } from "node:fs/promises";
38601
- import { join as join48, resolve as resolve12, relative as relative9 } from "node:path";
39571
+ import { join as join49, resolve as resolve12, relative as relative9 } from "node:path";
38602
39572
  async function readJsonFile5(filePath) {
38603
39573
  try {
38604
39574
  const raw = await readFile29(filePath, "utf-8");
@@ -38670,7 +39640,7 @@ async function discoverUnits(rootDir, rootPkgJson) {
38670
39640
  const discovered = await discoverMonorepoApps(rootDir);
38671
39641
  for (const app of discovered) {
38672
39642
  const pkgJson = await readJsonFile5(
38673
- join48(app.absPath, "package.json")
39643
+ join49(app.absPath, "package.json")
38674
39644
  );
38675
39645
  pkgJsonByPath.set(app.absPath, pkgJson);
38676
39646
  allPackages.push({
@@ -38696,7 +39666,7 @@ async function runReadme(opts) {
38696
39666
  const init = opts.init ?? opts["init"] ?? false;
38697
39667
  const rootDir = resolve12(projectDir);
38698
39668
  const rootPkgJson = await readJsonFile5(
38699
- join48(rootDir, "package.json")
39669
+ join49(rootDir, "package.json")
38700
39670
  );
38701
39671
  const { units, allPackages, pkgJsonByPath } = await discoverUnits(
38702
39672
  rootDir,
@@ -38705,8 +39675,8 @@ async function runReadme(opts) {
38705
39675
  const driftUnits = [];
38706
39676
  const missingUnits = [];
38707
39677
  for (const unit of units) {
38708
- const readmePath = join48(unit.absPath, "README.md");
38709
- const relPath = unit.isRoot ? "README.md" : join48(relative9(rootDir, unit.absPath), "README.md");
39678
+ const readmePath = join49(unit.absPath, "README.md");
39679
+ const relPath = unit.isRoot ? "README.md" : join49(relative9(rootDir, unit.absPath), "README.md");
38710
39680
  let existingContent = null;
38711
39681
  try {
38712
39682
  existingContent = await readFile29(readmePath, "utf-8");
@@ -38897,7 +39867,7 @@ import {
38897
39867
  readdir as readdir7
38898
39868
  } from "node:fs/promises";
38899
39869
  import { existsSync as existsSync21 } from "node:fs";
38900
- import { join as join49, resolve as resolve13, dirname as dirname15, sep as sep4 } from "node:path";
39870
+ import { join as join50, resolve as resolve13, dirname as dirname16, sep as sep4 } from "node:path";
38901
39871
  import { homedir as homedir8 } from "node:os";
38902
39872
  function encodeProjectPath(absPath) {
38903
39873
  return resolve13(absPath).replace(/[/\\]/g, "-");
@@ -38908,7 +39878,7 @@ function resolveAutoMemoryDir(opts) {
38908
39878
  }
38909
39879
  const projectDir = opts.projectDir ?? process.cwd();
38910
39880
  const encoded = encodeProjectPath(projectDir);
38911
- return join49(homedir8(), ".claude", "projects", encoded, "memory");
39881
+ return join50(homedir8(), ".claude", "projects", encoded, "memory");
38912
39882
  }
38913
39883
  function parseFrontmatter(content) {
38914
39884
  content = content.replace(/\r\n/g, "\n");
@@ -38974,7 +39944,7 @@ async function inventoryFiles(dir) {
38974
39944
  }
38975
39945
  const results = [];
38976
39946
  for (const filename of filenames) {
38977
- const sourcePath = join49(dir, filename);
39947
+ const sourcePath = join50(dir, filename);
38978
39948
  let raw;
38979
39949
  try {
38980
39950
  raw = await readFile30(sourcePath, "utf-8");
@@ -39063,8 +40033,8 @@ async function applyPlan(plan, opts) {
39063
40033
  if (entry.suggested_action !== "keep") continue;
39064
40034
  if (!entry.suggested_target?.startsWith("nested:")) continue;
39065
40035
  const relPath = entry.suggested_target.slice("nested:".length);
39066
- const targetDir = resolve13(join49(projectDir, relPath));
39067
- const targetFile = join49(targetDir, "CLAUDE.md");
40036
+ const targetDir = resolve13(join50(projectDir, relPath));
40037
+ const targetFile = join50(targetDir, "CLAUDE.md");
39068
40038
  if (!targetDir.startsWith(resolve13(projectDir) + sep4)) {
39069
40039
  process.stderr.write(
39070
40040
  `migrate-memory: skipping unsafe suggested_target "${entry.suggested_target}" \u2014 resolves outside projectDir
@@ -39114,7 +40084,7 @@ ${anchor}
39114
40084
  );
39115
40085
  }
39116
40086
  }
39117
- const rootClaudeMd = join49(projectDir, ".claude", "CLAUDE.md");
40087
+ const rootClaudeMd = join50(projectDir, ".claude", "CLAUDE.md");
39118
40088
  if (dryRun) {
39119
40089
  process.stdout.write(
39120
40090
  `[dry-run] Would ensure ${rootClaudeMd} contains: ${IMPORT_LINE}
@@ -39125,7 +40095,7 @@ ${anchor}
39125
40095
  try {
39126
40096
  claudeMdContent = await readFile30(rootClaudeMd, "utf-8");
39127
40097
  } catch {
39128
- await mkdir14(dirname15(rootClaudeMd), { recursive: true });
40098
+ await mkdir14(dirname16(rootClaudeMd), { recursive: true });
39129
40099
  }
39130
40100
  if (!claudeMdContent.includes(IMPORT_LINE)) {
39131
40101
  await writeFile24(
@@ -39158,8 +40128,8 @@ ${IMPORT_LINE}
39158
40128
  } catch {
39159
40129
  }
39160
40130
  }
39161
- const memoryMd = join49(plan.auto_memory_dir, "MEMORY.md");
39162
- const safeRmdirBase = join49(homedir8(), ".claude", "projects");
40131
+ const memoryMd = join50(plan.auto_memory_dir, "MEMORY.md");
40132
+ const safeRmdirBase = join50(homedir8(), ".claude", "projects");
39163
40133
  if (dryRun) {
39164
40134
  process.stdout.write(`[dry-run] Would delete MEMORY.md: ${memoryMd}
39165
40135
  `);
@@ -39283,7 +40253,7 @@ var init_migrate_memory = __esm({
39283
40253
 
39284
40254
  // src/lib/claude-mode-audit.ts
39285
40255
  import { readdirSync as readdirSync7, readFileSync as readFileSync19, existsSync as existsSync22 } from "node:fs";
39286
- import { join as join50, basename as basename2 } from "node:path";
40256
+ import { join as join51, basename as basename3 } from "node:path";
39287
40257
  function parseFrontmatter2(content) {
39288
40258
  const match = /^---\r?\n([\s\S]*?)\r?\n---/.exec(content);
39289
40259
  if (!match) return {};
@@ -39303,7 +40273,7 @@ function parseFrontmatter2(content) {
39303
40273
  function auditAgent(filePath) {
39304
40274
  const content = readFileSync19(filePath, "utf-8");
39305
40275
  const fm = parseFrontmatter2(content);
39306
- const agentName = fm.name ?? basename2(filePath, ".md");
40276
+ const agentName = fm.name ?? basename3(filePath, ".md");
39307
40277
  const expected = AGENT_EXCEPTIONS[agentName] ?? AGENT_DEFAULT;
39308
40278
  const expectedStr = `model:${expected.model}/effort:${expected.effort}`;
39309
40279
  const model = fm.model ?? null;
@@ -39360,19 +40330,19 @@ function auditSkill(filePath) {
39360
40330
  }
39361
40331
  function auditMode(templatesDir) {
39362
40332
  const entries = [];
39363
- const agentsDir = join50(templatesDir, "agents");
40333
+ const agentsDir = join51(templatesDir, "agents");
39364
40334
  if (existsSync22(agentsDir)) {
39365
40335
  const agentFiles = readdirSync7(agentsDir).filter((f) => f.endsWith(".md")).sort();
39366
40336
  for (const f of agentFiles) {
39367
- entries.push(auditAgent(join50(agentsDir, f)));
40337
+ entries.push(auditAgent(join51(agentsDir, f)));
39368
40338
  }
39369
40339
  }
39370
- const skillsDir = join50(templatesDir, "skills");
40340
+ const skillsDir = join51(templatesDir, "skills");
39371
40341
  if (existsSync22(skillsDir)) {
39372
40342
  const skillDirs = readdirSync7(skillsDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name).sort();
39373
40343
  for (const dir of skillDirs) {
39374
- if (existsSync22(join50(skillsDir, dir, "PROVENANCE.md"))) continue;
39375
- const skillMd = join50(skillsDir, dir, "SKILL.md");
40344
+ if (existsSync22(join51(skillsDir, dir, "PROVENANCE.md"))) continue;
40345
+ const skillMd = join51(skillsDir, dir, "SKILL.md");
39376
40346
  if (existsSync22(skillMd)) {
39377
40347
  entries.push(auditSkill(skillMd));
39378
40348
  }
@@ -39477,9 +40447,9 @@ var resolve_preview_exports = {};
39477
40447
  __export(resolve_preview_exports, {
39478
40448
  resolvePreview: () => resolvePreview
39479
40449
  });
39480
- import { spawnSync as spawnSync12 } from "node:child_process";
40450
+ import { spawnSync as spawnSync14 } from "node:child_process";
39481
40451
  function defaultGetCurrentBranch(cwd) {
39482
- const result = spawnSync12("git", ["rev-parse", "--abbrev-ref", "HEAD"], {
40452
+ const result = spawnSync14("git", ["rev-parse", "--abbrev-ref", "HEAD"], {
39483
40453
  cwd,
39484
40454
  encoding: "utf-8",
39485
40455
  stdio: ["pipe", "pipe", "pipe"]
@@ -39631,7 +40601,7 @@ __export(new_migration_exports, {
39631
40601
  newMigration: () => newMigration
39632
40602
  });
39633
40603
  import * as fs19 from "node:fs";
39634
- import * as path20 from "node:path";
40604
+ import * as path21 from "node:path";
39635
40605
  function slugify(name) {
39636
40606
  return name.trim().toLowerCase().replace(/[^a-z0-9_-]+/g, "_").replace(/^_+|_+$/g, "").replace(/_+/g, "_");
39637
40607
  }
@@ -39652,9 +40622,9 @@ function newMigration(args, deps = {}) {
39652
40622
  }
39653
40623
  const slug = slugify(rawName);
39654
40624
  const stamp = genTimestamp({ cwd });
39655
- const migrationsDir = path20.join(cwd, "supabase", "migrations");
40625
+ const migrationsDir = path21.join(cwd, "supabase", "migrations");
39656
40626
  const filename = `${stamp}_${slug}.sql`;
39657
- const filePath = path20.join(migrationsDir, filename);
40627
+ const filePath = path21.join(migrationsDir, filename);
39658
40628
  mkdirSync11(migrationsDir, { recursive: true });
39659
40629
  writeFileSync12(filePath, "");
39660
40630
  process.stdout.write(JSON.stringify({ path: filePath }) + "\n");
@@ -39672,9 +40642,9 @@ var preview_check_exports = {};
39672
40642
  __export(preview_check_exports, {
39673
40643
  previewCheck: () => previewCheck
39674
40644
  });
39675
- import { spawnSync as spawnSync13 } from "node:child_process";
39676
- function defaultRun3(cmd, args) {
39677
- const result = spawnSync13(cmd, args, {
40645
+ import { spawnSync as spawnSync15 } from "node:child_process";
40646
+ function defaultRun4(cmd, args) {
40647
+ const result = spawnSync15(cmd, args, {
39678
40648
  encoding: "utf-8",
39679
40649
  stdio: ["pipe", "pipe", "pipe"]
39680
40650
  });
@@ -39699,7 +40669,7 @@ function defaultGetPrNumber(cwd, run) {
39699
40669
  }
39700
40670
  async function previewCheck(args, deps = {}) {
39701
40671
  const cwd = deps.cwd ?? process.cwd();
39702
- const run = deps.run ?? defaultRun3;
40672
+ const run = deps.run ?? defaultRun4;
39703
40673
  const sleep3 = deps.sleep ?? ((ms) => new Promise((resolve16) => setTimeout(resolve16, ms)));
39704
40674
  const getPrNumber = deps.getPrNumber ?? defaultGetPrNumber;
39705
40675
  const poll = deps.pollCheck ?? pollGhPreviewCheck;
@@ -39728,313 +40698,6 @@ var init_preview_check = __esm({
39728
40698
  }
39729
40699
  });
39730
40700
 
39731
- // src/lib/session.ts
39732
- import { spawnSync as spawnSync14 } from "node:child_process";
39733
- import * as path21 from "node:path";
39734
- function defaultRun4(cmd, args, cwd) {
39735
- const result = spawnSync14(cmd, args, {
39736
- cwd,
39737
- encoding: "utf-8",
39738
- stdio: ["pipe", "pipe", "pipe"]
39739
- });
39740
- if (result.error) throw result.error;
39741
- if (result.status !== 0) {
39742
- const stderr = (result.stderr ?? "").toString().trim();
39743
- throw new Error(
39744
- `${cmd} ${args.join(" ")} exited ${result.status ?? "null"}${stderr ? `: ${stderr}` : ""}`
39745
- );
39746
- }
39747
- return (result.stdout ?? "").toString();
39748
- }
39749
- function homeFf(opts = {}) {
39750
- const cwd = opts.cwd ?? process.cwd();
39751
- const run = opts.run ?? defaultRun4;
39752
- const gitCfg = readGitConfig(cwd);
39753
- const production = gitCfg.production;
39754
- let repoRoot;
39755
- try {
39756
- repoRoot = run("git", ["rev-parse", "--show-toplevel"], cwd).trim();
39757
- } catch {
39758
- return {
39759
- result: "skipped",
39760
- reason: "git rev-parse --show-toplevel failed"
39761
- };
39762
- }
39763
- const folder = path21.basename(repoRoot);
39764
- let current;
39765
- try {
39766
- current = run("git", ["rev-parse", "--abbrev-ref", "HEAD"], cwd).trim();
39767
- } catch {
39768
- return {
39769
- result: "skipped",
39770
- reason: "git rev-parse --abbrev-ref HEAD failed"
39771
- };
39772
- }
39773
- if (current !== folder) {
39774
- return { result: "skipped", reason: "not on home branch" };
39775
- }
39776
- try {
39777
- run("git", ["fetch", "origin", production], cwd);
39778
- } catch {
39779
- return {
39780
- result: "warn",
39781
- warn: `fetch failed \u2014 staying on local ${current}`
39782
- };
39783
- }
39784
- try {
39785
- run("git", ["merge", "--ff-only", `origin/${production}`], cwd);
39786
- } catch {
39787
- return {
39788
- result: "warn",
39789
- warn: `${current} not fast-forwardable (ahead/diverged) \u2014 left untouched`
39790
- };
39791
- }
39792
- return { result: "fast_forwarded" };
39793
- }
39794
- function spawnVersionStatus(cwd) {
39795
- try {
39796
- const result = spawnSync14("npx", ["codebyplan", "version-status"], {
39797
- cwd,
39798
- encoding: "utf-8",
39799
- stdio: ["pipe", "pipe", "pipe"]
39800
- });
39801
- if (result.error) return null;
39802
- const raw = (result.stdout ?? "").toString().trim();
39803
- if (!raw) return null;
39804
- const parsed = JSON.parse(raw);
39805
- if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
39806
- return null;
39807
- }
39808
- const obj = parsed;
39809
- if (typeof obj["installed"] !== "string" || typeof obj["newer"] !== "boolean" || typeof obj["guarded"] !== "boolean" || typeof obj["installCommand"] !== "string") {
39810
- return null;
39811
- }
39812
- return {
39813
- installed: obj["installed"],
39814
- latest: typeof obj["latest"] === "string" ? obj["latest"] : null,
39815
- newer: obj["newer"],
39816
- packageManager: typeof obj["packageManager"] === "string" ? obj["packageManager"] : "npm",
39817
- installCommand: obj["installCommand"],
39818
- guarded: obj["guarded"],
39819
- guardReason: typeof obj["guardReason"] === "string" ? obj["guardReason"] : null
39820
- };
39821
- } catch {
39822
- return null;
39823
- }
39824
- }
39825
- function defaultRunInstall(installCommand, cwd) {
39826
- const parts = installCommand.trim().split(/\s+/);
39827
- const cmd = parts[0];
39828
- const args = parts.slice(1);
39829
- if (!cmd) throw new Error("empty installCommand");
39830
- const result = spawnSync14(cmd, args, {
39831
- cwd,
39832
- encoding: "utf-8",
39833
- stdio: ["pipe", "pipe", "pipe"]
39834
- });
39835
- if (result.error) throw result.error;
39836
- if (result.status !== 0) {
39837
- const stderr = (result.stderr ?? "").toString().trim();
39838
- throw new Error(
39839
- `install exited ${result.status}${stderr ? `: ${stderr}` : ""}`
39840
- );
39841
- }
39842
- }
39843
- function defaultRunClaudeUpdate(cwd) {
39844
- const result = spawnSync14("npx", ["codebyplan", "claude", "update", "--yes"], {
39845
- cwd,
39846
- encoding: "utf-8",
39847
- stdio: ["pipe", "pipe", "pipe"]
39848
- });
39849
- if (result.error) throw result.error;
39850
- if (result.status !== 0) {
39851
- const stderr = (result.stderr ?? "").toString().trim();
39852
- throw new Error(
39853
- `claude update exited ${result.status}${stderr ? `: ${stderr}` : ""}`
39854
- );
39855
- }
39856
- }
39857
- function defaultRunGitStatus(cwd) {
39858
- const result = spawnSync14(
39859
- "git",
39860
- ["status", "--porcelain", "--", ".claude/", ".codebyplan/"],
39861
- {
39862
- cwd,
39863
- encoding: "utf-8",
39864
- stdio: ["pipe", "pipe", "pipe"]
39865
- }
39866
- );
39867
- if (result.error) throw result.error;
39868
- return (result.stdout ?? "").toString();
39869
- }
39870
- async function freshnessGate(opts = {}) {
39871
- const cwd = opts.cwd ?? process.cwd();
39872
- const probeVersionStatus = opts.probeVersionStatus ?? ((c) => spawnVersionStatus(c));
39873
- const runInstall2 = opts.runInstall ?? defaultRunInstall;
39874
- const runClaudeUpdate = opts.runClaudeUpdate ?? defaultRunClaudeUpdate;
39875
- const runGitStatus = opts.runGitStatus ?? defaultRunGitStatus;
39876
- const haltOnUpdate = opts.haltOnUpdate ?? false;
39877
- let probe;
39878
- try {
39879
- probe = probeVersionStatus(cwd);
39880
- } catch {
39881
- probe = null;
39882
- }
39883
- if (!probe) {
39884
- return { result: "skipped", reason: "probe failed (fail-safe)" };
39885
- }
39886
- if (probe.guarded) {
39887
- return { result: "guarded" };
39888
- }
39889
- if (!probe.newer) {
39890
- return { result: "up_to_date" };
39891
- }
39892
- try {
39893
- runInstall2(probe.installCommand, cwd);
39894
- } catch (err) {
39895
- const reason = err instanceof Error ? err.message : "install failed (unknown error)";
39896
- return { result: "error", reason };
39897
- }
39898
- try {
39899
- runClaudeUpdate(cwd);
39900
- } catch (err) {
39901
- const reason = err instanceof Error ? err.message : "claude update failed (unknown error)";
39902
- return { result: "error", reason };
39903
- }
39904
- let gitStatusOutput = "";
39905
- try {
39906
- gitStatusOutput = runGitStatus(cwd);
39907
- } catch {
39908
- gitStatusOutput = "";
39909
- }
39910
- const changedFiles = gitStatusOutput.split("\n").map((line) => line.trim()).filter(Boolean).map((line) => {
39911
- const parts = line.split(/\s+/);
39912
- return parts.slice(1).join(" ");
39913
- }).filter(Boolean);
39914
- return {
39915
- result: "updated",
39916
- latest: probe.latest ?? probe.installed,
39917
- changed_files: changedFiles,
39918
- halt: haltOnUpdate
39919
- };
39920
- }
39921
- async function infraFiles(opts = {}) {
39922
- const cwd = opts.cwd ?? process.cwd();
39923
- const run = opts.run ?? defaultRun4;
39924
- const getTaskFiles = opts.getTaskFiles ?? (() => Promise.resolve([]));
39925
- let firstOutput;
39926
- try {
39927
- firstOutput = run("git", ["status", "--porcelain"], cwd);
39928
- } catch {
39929
- firstOutput = "";
39930
- }
39931
- const firstChanged = parseGitStatus2(firstOutput);
39932
- if (firstChanged.length === 0) {
39933
- return { infra_files: [], task_files: [], note: "clean tree" };
39934
- }
39935
- const taskFiles = await getTaskFiles();
39936
- const taskSet = new Set(taskFiles);
39937
- let secondOutput;
39938
- try {
39939
- secondOutput = run("git", ["status", "--porcelain"], cwd);
39940
- } catch {
39941
- secondOutput = "";
39942
- }
39943
- const freshChanged = parseGitStatus2(secondOutput);
39944
- const infraFilesList = freshChanged.filter((f) => !taskSet.has(f));
39945
- return {
39946
- infra_files: infraFilesList,
39947
- task_files: taskFiles
39948
- };
39949
- }
39950
- function parseGitStatus2(output) {
39951
- return output.split("\n").filter(Boolean).map((line) => {
39952
- if (line.length > 3) {
39953
- const rest = line.slice(3);
39954
- const arrow = rest.indexOf(" -> ");
39955
- if (arrow !== -1) {
39956
- return rest.slice(arrow + 4).trim();
39957
- }
39958
- return rest.trim();
39959
- }
39960
- return "";
39961
- }).filter(Boolean);
39962
- }
39963
- var init_session2 = __esm({
39964
- "src/lib/session.ts"() {
39965
- "use strict";
39966
- init_supabase();
39967
- }
39968
- });
39969
-
39970
- // src/cli/session/home-ff.ts
39971
- var home_ff_exports = {};
39972
- __export(home_ff_exports, {
39973
- homeFfCli: () => homeFfCli
39974
- });
39975
- function homeFfCli(_args, deps = {}) {
39976
- const result = homeFf(deps);
39977
- process.stdout.write(JSON.stringify(result) + "\n");
39978
- return 0;
39979
- }
39980
- var init_home_ff = __esm({
39981
- "src/cli/session/home-ff.ts"() {
39982
- "use strict";
39983
- init_session2();
39984
- }
39985
- });
39986
-
39987
- // src/cli/session/freshness-gate.ts
39988
- var freshness_gate_exports = {};
39989
- __export(freshness_gate_exports, {
39990
- freshnessGateCli: () => freshnessGateCli
39991
- });
39992
- async function freshnessGateCli(args, deps = {}) {
39993
- const haltOnUpdate = args.includes("--halt-on-update");
39994
- const result = await freshnessGate({
39995
- ...deps,
39996
- haltOnUpdate: deps.haltOnUpdate ?? haltOnUpdate
39997
- });
39998
- process.stdout.write(JSON.stringify(result) + "\n");
39999
- return 0;
40000
- }
40001
- var init_freshness_gate = __esm({
40002
- "src/cli/session/freshness-gate.ts"() {
40003
- "use strict";
40004
- init_session2();
40005
- }
40006
- });
40007
-
40008
- // src/cli/session/infra-files.ts
40009
- var infra_files_exports = {};
40010
- __export(infra_files_exports, {
40011
- infraFilesCli: () => infraFilesCli
40012
- });
40013
- async function infraFilesCli(args, deps = {}) {
40014
- let taskFilesFromFlag = [];
40015
- const tfIdx = args.indexOf("--task-files");
40016
- if (tfIdx !== -1 && tfIdx + 1 < args.length) {
40017
- const raw = args[tfIdx + 1];
40018
- if (raw && !raw.startsWith("--")) {
40019
- taskFilesFromFlag = raw.split(",").map((f) => f.trim()).filter(Boolean);
40020
- }
40021
- }
40022
- const result = await infraFiles({
40023
- ...deps,
40024
- // When the caller passes --task-files, use those as the task file list.
40025
- // The deps injection wins when explicitly provided (test path).
40026
- getTaskFiles: deps.getTaskFiles ?? (taskFilesFromFlag.length > 0 ? () => Promise.resolve(taskFilesFromFlag) : () => Promise.resolve([]))
40027
- });
40028
- process.stdout.write(JSON.stringify(result) + "\n");
40029
- return 0;
40030
- }
40031
- var init_infra_files = __esm({
40032
- "src/cli/session/infra-files.ts"() {
40033
- "use strict";
40034
- init_session2();
40035
- }
40036
- });
40037
-
40038
40701
  // src/lib/slug.ts
40039
40702
  function slugify2(title) {
40040
40703
  if (!title) return "";
@@ -40108,9 +40771,9 @@ var commit_exports = {};
40108
40771
  __export(commit_exports, {
40109
40772
  runCommitCommand: () => runCommitCommand
40110
40773
  });
40111
- import { spawnSync as spawnSync15 } from "node:child_process";
40774
+ import { spawnSync as spawnSync16 } from "node:child_process";
40112
40775
  function defaultRun5(cmd, args) {
40113
- const result = spawnSync15(cmd, args, {
40776
+ const result = spawnSync16(cmd, args, {
40114
40777
  encoding: "utf-8",
40115
40778
  stdio: ["pipe", "pipe", "pipe"]
40116
40779
  });
@@ -40158,7 +40821,7 @@ var init_commit = __esm({
40158
40821
  });
40159
40822
 
40160
40823
  // src/lib/migration-collisions.ts
40161
- import { spawnSync as spawnSync16 } from "node:child_process";
40824
+ import { spawnSync as spawnSync17 } from "node:child_process";
40162
40825
  function extractPrefix(filename) {
40163
40826
  const base = filename.endsWith(".sql") ? filename.slice(0, -4) : filename;
40164
40827
  const underscoreIdx = base.indexOf("_");
@@ -40170,7 +40833,7 @@ function extractPrefix(filename) {
40170
40833
  }
40171
40834
  function makeDefaultRun(cwd) {
40172
40835
  return (cmd, args) => {
40173
- const result = spawnSync16(cmd, args, {
40836
+ const result = spawnSync17(cmd, args, {
40174
40837
  cwd,
40175
40838
  encoding: "utf-8",
40176
40839
  stdio: ["pipe", "pipe", "pipe"]
@@ -40526,12 +41189,12 @@ var init_validate_waves2 = __esm({
40526
41189
  });
40527
41190
 
40528
41191
  // src/cli/worktree/path.ts
40529
- import { dirname as dirname16, basename as basename4, join as join52 } from "node:path";
41192
+ import { dirname as dirname17, basename as basename4, join as join53 } from "node:path";
40530
41193
  function computeWorktreePath(cwd, checkpointNumber) {
40531
- const parent = dirname16(cwd);
41194
+ const parent = dirname17(cwd);
40532
41195
  const base = basename4(cwd);
40533
41196
  const nnn = String(checkpointNumber).padStart(3, "0");
40534
- return join52(parent, `${base}-CHK-${nnn}`);
41197
+ return join53(parent, `${base}-CHK-${nnn}`);
40535
41198
  }
40536
41199
  var init_path = __esm({
40537
41200
  "src/cli/worktree/path.ts"() {
@@ -40540,9 +41203,9 @@ var init_path = __esm({
40540
41203
  });
40541
41204
 
40542
41205
  // src/cli/worktree/add.ts
40543
- import { join as join53, basename as basename5 } from "node:path";
41206
+ import { join as join54, basename as basename5 } from "node:path";
40544
41207
  import { mkdir as mkdir15, readFile as readFile32, writeFile as writeFile25 } from "node:fs/promises";
40545
- import { spawnSync as spawnSync17 } from "node:child_process";
41208
+ import { spawnSync as spawnSync18 } from "node:child_process";
40546
41209
  async function defaultGetRepoId(cwd) {
40547
41210
  const found = await findCodebyplanConfig(cwd);
40548
41211
  return found?.contents.repo_id ?? null;
@@ -40571,7 +41234,7 @@ async function defaultLookupBranch(repoId, checkpointNumber) {
40571
41234
  return { found: true, branch_name: chk.branch_name };
40572
41235
  }
40573
41236
  function defaultGitRun(args, cwd) {
40574
- const result = spawnSync17("git", args, {
41237
+ const result = spawnSync18("git", args, {
40575
41238
  cwd,
40576
41239
  encoding: "utf-8",
40577
41240
  stdio: ["pipe", "pipe", "pipe"]
@@ -40590,11 +41253,11 @@ async function copyClaudeSettings(srcCwd, destPath, deps = {}) {
40590
41253
  (fsp) => fsp.access(p).then(() => true).catch(() => false)
40591
41254
  ));
40592
41255
  const mkdirFn = deps.mkdirFn ?? ((p, opts) => mkdir15(p, opts));
40593
- await mkdirFn(join53(destPath, ".claude"), { recursive: true });
41256
+ await mkdirFn(join54(destPath, ".claude"), { recursive: true });
40594
41257
  const claudeStubs = ["settings.json", "settings.local.json"];
40595
41258
  for (const stub of claudeStubs) {
40596
- const srcFile = join53(srcCwd, ".claude", stub);
40597
- const destFile = join53(destPath, ".claude", stub);
41259
+ const srcFile = join54(srcCwd, ".claude", stub);
41260
+ const destFile = join54(destPath, ".claude", stub);
40598
41261
  try {
40599
41262
  const destExists = await existsFn(destFile);
40600
41263
  if (destExists) continue;
@@ -40605,22 +41268,22 @@ async function copyClaudeSettings(srcCwd, destPath, deps = {}) {
40605
41268
  }
40606
41269
  }
40607
41270
  async function defaultCopyConfigStubs(srcCwd, destPath) {
40608
- await mkdir15(join53(destPath, ".codebyplan"), { recursive: true });
41271
+ await mkdir15(join54(destPath, ".codebyplan"), { recursive: true });
40609
41272
  const topLevelStubs = [".mcp.json", ".env.local"];
40610
41273
  for (const stub of topLevelStubs) {
40611
41274
  try {
40612
- const content = await readFile32(join53(srcCwd, stub), "utf-8");
40613
- await writeFile25(join53(destPath, stub), content, "utf-8");
41275
+ const content = await readFile32(join54(srcCwd, stub), "utf-8");
41276
+ await writeFile25(join54(destPath, stub), content, "utf-8");
40614
41277
  } catch {
40615
41278
  }
40616
41279
  }
40617
41280
  try {
40618
41281
  const content = await readFile32(
40619
- join53(srcCwd, ".codebyplan", "repo.json"),
41282
+ join54(srcCwd, ".codebyplan", "repo.json"),
40620
41283
  "utf-8"
40621
41284
  );
40622
41285
  await writeFile25(
40623
- join53(destPath, ".codebyplan", "repo.json"),
41286
+ join54(destPath, ".codebyplan", "repo.json"),
40624
41287
  content,
40625
41288
  "utf-8"
40626
41289
  );
@@ -40785,7 +41448,7 @@ var init_add = __esm({
40785
41448
  });
40786
41449
 
40787
41450
  // src/cli/worktree/create.ts
40788
- import { join as join54 } from "node:path";
41451
+ import { join as join55 } from "node:path";
40789
41452
  async function defaultGetRepoIdentity(cwd) {
40790
41453
  const found = await findCodebyplanConfig(cwd);
40791
41454
  const contents = found?.contents ?? null;
@@ -40841,7 +41504,7 @@ async function runWorktreeCreate(args, deps = {}) {
40841
41504
  );
40842
41505
  return 1;
40843
41506
  }
40844
- const worktreePath = explicitPath ?? join54(cwd, "..", name);
41507
+ const worktreePath = explicitPath ?? join55(cwd, "..", name);
40845
41508
  const deviceId = await getDeviceId(cwd);
40846
41509
  let filesWritten = false;
40847
41510
  try {
@@ -40906,7 +41569,7 @@ var init_create = __esm({
40906
41569
 
40907
41570
  // src/cli/worktree/remove.ts
40908
41571
  import { basename as basename6 } from "node:path";
40909
- import { spawnSync as spawnSync18 } from "node:child_process";
41572
+ import { spawnSync as spawnSync19 } from "node:child_process";
40910
41573
  async function defaultGetRepoId2(cwd) {
40911
41574
  const found = await findCodebyplanConfig(cwd);
40912
41575
  return found?.contents.repo_id ?? null;
@@ -40928,7 +41591,7 @@ async function defaultDeregisterWorktree(worktreeId) {
40928
41591
  await mcpCall("delete_worktree", { worktree_id: worktreeId });
40929
41592
  }
40930
41593
  function defaultGitRun2(args, cwd) {
40931
- const result = spawnSync18("git", args, {
41594
+ const result = spawnSync19("git", args, {
40932
41595
  cwd,
40933
41596
  encoding: "utf-8",
40934
41597
  stdio: ["pipe", "pipe", "pipe"]
@@ -40941,7 +41604,7 @@ function defaultGitRun2(args, cwd) {
40941
41604
  };
40942
41605
  }
40943
41606
  function defaultGetWorktreeBranchName(worktreePath) {
40944
- const result = spawnSync18("git", ["symbolic-ref", "--short", "HEAD"], {
41607
+ const result = spawnSync19("git", ["symbolic-ref", "--short", "HEAD"], {
40945
41608
  cwd: worktreePath,
40946
41609
  encoding: "utf-8",
40947
41610
  stdio: ["pipe", "pipe", "pipe"]
@@ -41486,7 +42149,7 @@ __export(doctor_exports, {
41486
42149
  runDoctor: () => runDoctor
41487
42150
  });
41488
42151
  import { existsSync as existsSync23 } from "node:fs";
41489
- import { join as join55 } from "node:path";
42152
+ import { join as join56 } from "node:path";
41490
42153
  import { execSync as execSync10 } from "node:child_process";
41491
42154
  async function checkAuth() {
41492
42155
  try {
@@ -41610,7 +42273,7 @@ function checkSettings() {
41610
42273
  detail: "codebyplan not installed (no .cbp.manifest.json)"
41611
42274
  };
41612
42275
  }
41613
- if (!existsSync23(join55(projectDir, ".claude", "settings.json"))) {
42276
+ if (!existsSync23(join56(projectDir, ".claude", "settings.json"))) {
41614
42277
  return {
41615
42278
  name: "settings",
41616
42279
  status: "warn",
@@ -41847,7 +42510,7 @@ void (async () => {
41847
42510
  process.exit(0);
41848
42511
  }
41849
42512
  if (arg === "session") {
41850
- const { runSessionCommand: runSessionCommand2 } = await Promise.resolve().then(() => (init_session(), session_exports));
42513
+ const { runSessionCommand: runSessionCommand2 } = await Promise.resolve().then(() => (init_session2(), session_exports));
41851
42514
  const rest = process.argv.slice(3);
41852
42515
  await runSessionCommand2(rest);
41853
42516
  process.exit(0);
@@ -42123,36 +42786,6 @@ void (async () => {
42123
42786
 
42124
42787
  The parent project ref is always read from .codebyplan/shipment.json
42125
42788
  (.shipment.surfaces.supabase.project_ref) \u2014 never hardcoded.
42126
- `);
42127
- process.exit(0);
42128
- }
42129
- if (arg === "session") {
42130
- const subcommand = process.argv[3];
42131
- const rest = process.argv.slice(4);
42132
- if (subcommand === "home-ff") {
42133
- const { homeFfCli: homeFfCli2 } = await Promise.resolve().then(() => (init_home_ff(), home_ff_exports));
42134
- process.exit(homeFfCli2(rest));
42135
- }
42136
- if (subcommand === "freshness-gate") {
42137
- const { freshnessGateCli: freshnessGateCli2 } = await Promise.resolve().then(() => (init_freshness_gate(), freshness_gate_exports));
42138
- process.exit(await freshnessGateCli2(rest));
42139
- }
42140
- if (subcommand === "infra-files") {
42141
- const { infraFilesCli: infraFilesCli2 } = await Promise.resolve().then(() => (init_infra_files(), infra_files_exports));
42142
- process.exit(await infraFilesCli2(rest));
42143
- }
42144
- console.log(`
42145
- CodeByPlan session helpers v${VERSION}
42146
-
42147
- Usage:
42148
- codebyplan session home-ff
42149
- Fast-forward the home branch to HEAD; outputs { result, reason?, warn? } JSON
42150
- codebyplan session freshness-gate [--halt-on-update]
42151
- Check package version freshness; outputs { result, ... } JSON
42152
- codebyplan session infra-files [--task-files <csv>] [--json]
42153
- Compute the infra-file set for the active session; outputs { infra_files, task_files } JSON
42154
-
42155
- Output is always JSON on stdout. Exit 0 always \u2014 callers branch on the result field.
42156
42789
  `);
42157
42790
  process.exit(0);
42158
42791
  }