claude-code-session-manager 0.72.0 → 0.73.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/dist/assets/{AgentLibrary-CXw7Z5Iw.js → AgentLibrary-BowrgaXK.js} +1 -1
  2. package/dist/assets/{History-D64U_aDf.js → History-B8rJXcxk.js} +1 -1
  3. package/dist/assets/{Hooks-BFVkM6QH.js → Hooks-D-KzXjDk.js} +1 -1
  4. package/dist/assets/{HostBilko-BRERoCra.js → HostBilko-BSJhBE9I.js} +1 -1
  5. package/dist/assets/{Library-C6shVsjv.js → Library-CtqgqUc6.js} +1 -1
  6. package/dist/assets/{ListDetail-dXWSZuDV.js → ListDetail-D7k4TXvO.js} +1 -1
  7. package/dist/assets/{MarkdownEditor-D_akyPJ2.js → MarkdownEditor-DFm0I9B_.js} +1 -1
  8. package/dist/assets/{McpServers-DxROkYGa.js → McpServers-DDK04FMq.js} +1 -1
  9. package/dist/assets/{Memory-OqUyTRrr.js → Memory-B1p59Mas.js} +1 -1
  10. package/dist/assets/{Panel-Biw98xRO.js → Panel-BJpqcDzp.js} +1 -1
  11. package/dist/assets/{Permissions-CIdZOzK8.js → Permissions-CFC3RusZ.js} +1 -1
  12. package/dist/assets/{Plugins-Dt147wEE.js → Plugins-TeCQMr6X.js} +2 -2
  13. package/dist/assets/{ProvenanceBadge-BUikIHf4.js → ProvenanceBadge-BfIzSRrY.js} +1 -1
  14. package/dist/assets/{SaveBar-BoHRDHlp.js → SaveBar-7SmNcZB-.js} +1 -1
  15. package/dist/assets/{Scheduler-CipmAcy7.js → Scheduler-B9ovEniK.js} +1 -1
  16. package/dist/assets/{ScopeSwitcher-CkCwUYU5.js → ScopeSwitcher-KmemfTLa.js} +1 -1
  17. package/dist/assets/Settings-CxZijd66.js +3 -0
  18. package/dist/assets/{SkillReferenceGraph-BuSuA3B7.js → SkillReferenceGraph-BhACzgW7.js} +1 -1
  19. package/dist/assets/{Skills-BM8w5BGV.js → Skills-CFZU6ltE.js} +1 -1
  20. package/dist/assets/{SystemPrompt-BWOdtfze.js → SystemPrompt-3tHpyoge.js} +1 -1
  21. package/dist/assets/{TagLibrary-cn3JECC5.js → TagLibrary-BoJHe-aY.js} +1 -1
  22. package/dist/assets/{TiptapBody-BwoXKY8J.js → TiptapBody-DzlxVXaw.js} +1 -1
  23. package/dist/assets/{Toggle-BlNVxkq-.js → Toggle-DKmoif0X.js} +1 -1
  24. package/dist/assets/{index-BpzvONtX.js → index-Dtv0whpT.js} +672 -672
  25. package/dist/assets/{index-DDpA9yBe.css → index-N_v_4fqC.css} +1 -1
  26. package/dist/assets/{settingsSchema-DePBZnaw.js → settingsSchema-CW-0QfXi.js} +1 -1
  27. package/dist/index.html +2 -2
  28. package/package.json +1 -1
  29. package/scripts/lib/activeSessions.cjs +10 -1
  30. package/src/main/__tests__/chatRunner-epic-worktree-execcwd.test.cjs +125 -0
  31. package/src/main/__tests__/pty-epic-worktree-spawn-cwd.test.cjs +156 -0
  32. package/src/main/__tests__/queueOpsArchiveDestination.test.cjs +65 -0
  33. package/src/main/chatRunner.cjs +11 -1
  34. package/src/main/index.cjs +6 -0
  35. package/src/main/ipcSchemas.cjs +35 -0
  36. package/src/main/lib/__tests__/epicSpawnCwd.test.cjs +193 -0
  37. package/src/main/lib/__tests__/epicWorktreeBoot.test.cjs +136 -0
  38. package/src/main/lib/__tests__/epicWorktreeMerge.test.cjs +130 -0
  39. package/src/main/lib/__tests__/epicWorktreeMint.test.cjs +115 -0
  40. package/src/main/lib/__tests__/epicWorktreeProjectConfig.test.cjs +79 -0
  41. package/src/main/lib/__tests__/gitWorktree.test.cjs +400 -0
  42. package/src/main/lib/__tests__/opsRootAbsoluteCwd.test.cjs +126 -0
  43. package/src/main/lib/__tests__/terminalRunOutcome.test.cjs +82 -0
  44. package/src/main/lib/epicSpawnCwd.cjs +95 -0
  45. package/src/main/lib/epicWorktreeBoot.cjs +49 -0
  46. package/src/main/lib/epicWorktreeMerge.cjs +63 -0
  47. package/src/main/lib/epicWorktreeMint.cjs +54 -0
  48. package/src/main/lib/epicWorktreeProjectConfig.cjs +102 -0
  49. package/src/main/lib/gitWorktree.cjs +446 -0
  50. package/src/main/lib/jobWorktree.cjs +36 -293
  51. package/src/main/lib/promptSessionSchema.cjs +15 -0
  52. package/src/main/lib/queueStore.cjs +18 -0
  53. package/src/main/lib/terminalRunOutcome.cjs +14 -2
  54. package/src/main/pty.cjs +11 -1
  55. package/src/main/queueOps.cjs +40 -12
  56. package/src/main/scheduler.cjs +14 -0
  57. package/src/preload/api.d.ts +59 -0
  58. package/src/preload/index.cjs +22 -0
  59. package/dist/assets/Settings-CmU_7z2e.js +0 -3
@@ -0,0 +1,95 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * epicSpawnCwd.cjs — resolves the cwd a child process spawned FOR an Epic's
5
+ * session should actually launch in: the Epic's isolated `git worktree`
6
+ * checkout (`worktree.dir`) when one was created for it, else the Epic's
7
+ * real project cwd unchanged (PRD 1033, wiring the primitives PRD 1032
8
+ * built).
9
+ *
10
+ * Mirrors agentModelResolve.cjs's `findAgentTypeByClaudeSessionId` shape and
11
+ * reuses the same join: an Epic-backed pty.cjs tab / chatRunner.cjs run is
12
+ * keyed by `claudeSessionId` (Tab ID = claudeSessionId, CLAUDE.md), so the
13
+ * matching PromptSession record — and its `worktree` field, when present —
14
+ * is found by scanning `cwd`'s own active-index.json for that id. Plain sync
15
+ * fs (via epicMint.cjs's readActiveIndex), no Electron deps, so callers can
16
+ * use it from a synchronous spawn path without restructuring into async.
17
+ *
18
+ * ---------- the ops-root hazard (read before touching cwd plumbing) --------
19
+ *
20
+ * This resolves ONLY the value a caller hands to a child process's own `cwd`
21
+ * spawn option. `cwd` itself — used for every ops-root read/write
22
+ * (active-index.json, prompt-sessions, scheduler state, opsErrorLog, model
23
+ * resolution) — must keep flowing unchanged everywhere else; see
24
+ * gitWorktree.cjs's own header comment for the full incident history this
25
+ * invariant guards against. Never substitute this function's return value
26
+ * for `cwd` outside a literal spawn-cwd argument.
27
+ */
28
+
29
+ const fs = require('node:fs');
30
+ const { readActiveIndex } = require('./epicMint.cjs');
31
+
32
+ /**
33
+ * True when `dir` is a directory that exists RIGHT NOW.
34
+ *
35
+ * `worktree.dir` is an absolute path under os.tmpdir() that gets PERSISTED
36
+ * onto the Epic record in active-index.json — a file this project tracks in
37
+ * git. It therefore outlives the checkout it names, in three ordinary ways:
38
+ *
39
+ * 1. Reboot / tmp sweep. Most Linux distros and macOS clear /tmp on boot
40
+ * (this host: `D /tmp 1777 root root 30d` in tmpfiles.d — `D` clears at
41
+ * boot AND ages entries out at 30d). Epics are deliberately long-lived
42
+ * (that is exactly why the epic kind has no short-lived cap and why boot
43
+ * reconciliation spares still-active Epics), so an active Epic routinely
44
+ * outlives its own checkout.
45
+ * 2. Another machine. active-index.json is committed, so a clone carries a
46
+ * worktree.dir naming a path built from the ORIGINAL machine's tmpdir and
47
+ * a sha1 of the ORIGINAL machine's project cwd. It cannot exist here.
48
+ * 3. Manual cleanup — `git worktree prune`, an rm -rf, a disk-space sweep.
49
+ *
50
+ * Without this check the spawn path handed a vanished directory straight to
51
+ * node-pty / child_process as its cwd, which fails the spawn outright: the
52
+ * Epic's Terminal and Chat both break with an opaque ENOENT instead of simply
53
+ * falling back to the project's shared tree the way every other failure mode
54
+ * in this chain does.
55
+ */
56
+ function isUsableDir(dir, statImpl) {
57
+ try {
58
+ return statImpl(dir).isDirectory();
59
+ } catch {
60
+ return false;
61
+ }
62
+ }
63
+
64
+ /**
65
+ * @param {{ cwd: string, claudeSessionId: string, deps?: object }} opts
66
+ * @returns {string} `worktree.dir` when the matching Epic has one AND it still
67
+ * exists on disk, else `cwd` unchanged.
68
+ */
69
+ function resolveEpicSpawnCwd({ cwd, claudeSessionId, deps = {} } = {}) {
70
+ if (!cwd || !claudeSessionId) return cwd;
71
+ try {
72
+ const load = deps.readActiveIndex || readActiveIndex;
73
+ const statSync = deps.statSync || fs.statSync;
74
+ const { sessions } = load(cwd);
75
+ for (const session of Object.values(sessions)) {
76
+ if (session && session.claudeSessionId === claudeSessionId) {
77
+ const dir = session.worktree?.dir;
78
+ if (!dir) return cwd;
79
+ if (!isUsableDir(dir, statSync)) {
80
+ // Falling back is strictly better than failing the spawn: the
81
+ // session still runs, just un-isolated, which is the same degraded
82
+ // mode a project that never had a worktree runs in.
83
+ console.log(`[epicSpawnCwd] worktree dir gone (${dir}) — falling back to ${cwd}`);
84
+ return cwd;
85
+ }
86
+ return dir;
87
+ }
88
+ }
89
+ } catch {
90
+ return cwd;
91
+ }
92
+ return cwd;
93
+ }
94
+
95
+ module.exports = { resolveEpicSpawnCwd };
@@ -0,0 +1,49 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * epicWorktreeBoot.cjs — boot reconciliation for Epic git worktrees (PRD
5
+ * 1033, wiring gitWorktree.cjs's `reconcileWorktreesOnBoot` isLive predicate
6
+ * that PRD 1032 built but left unwired).
7
+ *
8
+ * A worktree that survives an app crash/host reboot must not leak disk or a
9
+ * dangling branch forever — but unlike a scheduler job worktree (always safe
10
+ * to reap at boot; a job worktree found at boot is by definition from a run
11
+ * that didn't finish), an Epic worktree backs a session a human may still be
12
+ * mid-way through. Reaping it out from under a still-`active` Epic would
13
+ * silently drop that Epic's isolation (and, worse, any uncommitted work sat
14
+ * in the checkout) the moment the app restarts.
15
+ *
16
+ * Per project cwd, reads that project's own active-index.json (the same file
17
+ * gitWorktree.cjs's own header comment calls the "ops-root" — resolved here
18
+ * via epicMint.cjs's readActiveIndex, never a worktree path) and only reaps
19
+ * a worktree whose owning Epic is NOT `active` in it. At boot there is by
20
+ * definition no live attached PTY/chat process yet (the app process is
21
+ * fresh), so the AC's "no live attached process" half of the gate holds
22
+ * automatically — this predicate covers the other half.
23
+ */
24
+
25
+ const gitWorktree = require('./gitWorktree.cjs');
26
+ const { readActiveIndex } = require('./epicMint.cjs');
27
+
28
+ /**
29
+ * @param {string[]} cwds - known project cwds to sweep.
30
+ * @param {{ readActiveIndex?: Function, reconcileWorktreesOnBoot?: Function }} [deps]
31
+ * @returns {Promise<void>}
32
+ */
33
+ async function reconcileEpicWorktreesOnBoot(cwds, deps = {}) {
34
+ const load = deps.readActiveIndex || readActiveIndex;
35
+ const reconcile = deps.reconcileWorktreesOnBoot || gitWorktree.reconcileWorktreesOnBoot;
36
+ const list = Array.isArray(cwds) ? cwds.filter(Boolean) : [];
37
+ for (const cwd of list) {
38
+ let sessions = {};
39
+ try {
40
+ sessions = load(cwd).sessions || {};
41
+ } catch {
42
+ sessions = {}; // no active-index.json yet, or unreadable — nothing is "live"
43
+ }
44
+ const isLive = (epicId) => !!sessions[epicId] && sessions[epicId].status === 'active';
45
+ await reconcile([cwd], { kind: 'epic', isLive });
46
+ }
47
+ }
48
+
49
+ module.exports = { reconcileEpicWorktreesOnBoot };
@@ -0,0 +1,63 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * epicWorktreeMerge.cjs — IPC entry point that folds an Epic's isolated git
5
+ * worktree branch (gitWorktree.cjs's `integrateEpicBranch`, kind: 'epic')
6
+ * back into its owning project's main tree (PRD 1034, third link of the
7
+ * epic-worktree-isolation chain started by PRD 1032/1033).
8
+ *
9
+ * This is the ONLY point where that per-Epic isolation resolves back into
10
+ * the shared tree — never mid-session (see gitWorktree.cjs's own header
11
+ * comment for the ff-only -> merge-commit -> abort-and-flag algorithm this
12
+ * reuses verbatim). Callers reach it two ways: an explicit "merge to main"
13
+ * action (renderer state's `mergeEpicToMain`), and `markCompleted`'s
14
+ * merge-before-archive checkpoint — both funnel through this one handler so
15
+ * the integration strategy is never duplicated.
16
+ *
17
+ * On success the worktree checkout is torn down (cleanupEpicWorktree) since
18
+ * its content now safely lives on the main tree. On a real conflict, the
19
+ * branch and worktree directory are left intact — never silently discarded
20
+ * — so a human can still open a Terminal into `worktree.dir` (PRD 1033's
21
+ * existing epicSpawnCwd.cjs wiring — it keys off `worktree.dir` alone, not
22
+ * `worktree.status`, so a conflicted Epic's Terminal spawn keeps landing
23
+ * there with no new code path needed) and resolve it manually before
24
+ * re-running this same action.
25
+ */
26
+
27
+ const { integrateEpicBranch, cleanupEpicWorktree } = require('./gitWorktree.cjs');
28
+ const { validatePath } = require('../config.cjs');
29
+
30
+ /**
31
+ * mergeEpicToMainViaIpc(cwd, epicId, branch, dir) → Promise<MergeOutcome>
32
+ *
33
+ * `MergeOutcome` is `{ ok: true, status: 'merged', integrated: boolean }` on
34
+ * a clean merge (or a legitimate no-new-commits no-op — either way nothing
35
+ * is left to resolve, so the worktree is cleaned up), or
36
+ * `{ ok: false, status: 'needs_merge_resolution', reason: string }` on a
37
+ * real conflict — never throws (integrateEpicBranch/cleanupEpicWorktree
38
+ * never do either).
39
+ */
40
+ async function mergeEpicToMainViaIpc(cwd, epicId, branch, dir) {
41
+ validatePath(cwd);
42
+ const outcome = await integrateEpicBranch({ cwd, branch, epicId });
43
+ if (!outcome.ok) {
44
+ console.log(`[epicWorktreeMerge] ${epicId}: needs manual resolution (${outcome.reason})`);
45
+ return { ok: false, status: 'needs_merge_resolution', reason: outcome.reason };
46
+ }
47
+ // Clean ff-only/merge-commit landing, or a legitimate no-new-commits
48
+ // no-op — either way the branch's content is safely reflected (or was
49
+ // never ahead), so the checkout has nothing left to guard.
50
+ await cleanupEpicWorktree({ cwd, dir, branch, keepBranch: false });
51
+ return { ok: true, status: 'merged', integrated: outcome.integrated };
52
+ }
53
+
54
+ function registerEpicWorktreeMergeHandlers() {
55
+ const { ipcMain } = require('electron');
56
+ const { schemas: s, validated: v } = require('../ipcSchemas.cjs');
57
+ ipcMain.handle(
58
+ 'promptSessions:merge-to-main',
59
+ v(s.promptSessionsMergeToMain, ({ cwd, epicId, branch, dir }) => mergeEpicToMainViaIpc(cwd, epicId, branch, dir)),
60
+ );
61
+ }
62
+
63
+ module.exports = { mergeEpicToMainViaIpc, registerEpicWorktreeMergeHandlers };
@@ -0,0 +1,54 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * epicWorktreeMint.cjs — IPC entry point that creates an Epic's isolated git
5
+ * worktree (gitWorktree.cjs's createEpicWorktree, kind: 'epic') at the
6
+ * `proposed -> active` transition (PRD 1033, second link of the
7
+ * epic-worktree-isolation chain started by PRD 1032).
8
+ *
9
+ * That transition itself lives in the renderer (state/promptSessions.ts's
10
+ * approveProposed) and is synchronous — every caller relies on getting the
11
+ * approved session back immediately to start its chat send in the same tick
12
+ * (see that function's own comment). Worktree creation is real git/fs work
13
+ * that can only run main-process side, so approveProposed fires this IPC
14
+ * call fire-and-forget and patches `worktree` onto the session once it
15
+ * resolves — the transition itself is never blocked or delayed by it, and a
16
+ * failure (not a repo / dirty base tree / disabled / cap reached) simply
17
+ * leaves `worktree` unset, exactly as if this call had never been made.
18
+ *
19
+ * Mirrors promptSessionsCreateEpic.cjs's shape: `validatePath(cwd)` closes
20
+ * the same "arbitrary renderer-supplied cwd" gap that handler documents,
21
+ * since this is likewise reachable from the renderer over IPC.
22
+ */
23
+
24
+ const { createEpicWorktree } = require('./gitWorktree.cjs');
25
+ const { validatePath } = require('../config.cjs');
26
+
27
+ /**
28
+ * createEpicWorktreeViaIpc(cwd, epicId) → Promise<EpicWorktree | null>
29
+ *
30
+ * Returns the `worktree` field shape (`{ dir, branch, baseCwd, status }`)
31
+ * ready to persist onto the Epic record on success, or `null` on any
32
+ * failure — createEpicWorktree/createWorktree never throw, so this never
33
+ * does either.
34
+ */
35
+ async function createEpicWorktreeViaIpc(cwd, epicId) {
36
+ validatePath(cwd);
37
+ const result = await createEpicWorktree({ cwd, epicId });
38
+ if (!result.ok) {
39
+ console.log(`[epicWorktreeMint] ${epicId}: not isolated (${result.reason})`);
40
+ return null;
41
+ }
42
+ return { dir: result.dir, branch: result.branch, baseCwd: result.baseCwd, status: 'active' };
43
+ }
44
+
45
+ function registerEpicWorktreeMintHandlers() {
46
+ const { ipcMain } = require('electron');
47
+ const { schemas: s, validated: v } = require('../ipcSchemas.cjs');
48
+ ipcMain.handle(
49
+ 'promptSessions:create-worktree',
50
+ v(s.promptSessionsCreateWorktree, ({ cwd, epicId }) => createEpicWorktreeViaIpc(cwd, epicId)),
51
+ );
52
+ }
53
+
54
+ module.exports = { createEpicWorktreeViaIpc, registerEpicWorktreeMintHandlers };
@@ -0,0 +1,102 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * epicWorktreeProjectConfig.cjs — per-project UI toggle for Epic worktree
5
+ * isolation (PRD 1035, final link of the epic-worktree-isolation chain).
6
+ *
7
+ * `SM_EPIC_WORKTREE_DISABLE` (gitWorktree.cjs) is an env var, checked once at
8
+ * process start — there was previously no way to turn the feature off for
9
+ * one project from the app itself. This module is that per-project knob:
10
+ * a single JSON file mapping project cwd -> disabled, read by
11
+ * gitWorktree.cjs's `isWorktreeDisabled('epic', cwd)` on every worktree
12
+ * creation attempt, and read/written by Settings.tsx's per-project toggle
13
+ * over the two IPC handlers registered below.
14
+ *
15
+ * Lives under `~/.claude/session-manager/` — machine-runtime bookkeeping,
16
+ * the same tier as scheduler-machine.json (see queueStore.cjs's header
17
+ * comment) — NOT under any project's `session-manager-operations/`, so the
18
+ * single-writer OWNERS law (opsOwnership.cjs) doesn't apply here; this file
19
+ * only ever has one writer (this module) by construction.
20
+ *
21
+ * Plain Node (no Electron deps in the read/write helpers) so gitWorktree.cjs
22
+ * — itself Electron-free — can require this lazily without pulling Electron
23
+ * into contexts (tests, watchdog scripts) that don't have it.
24
+ */
25
+
26
+ const fs = require('node:fs');
27
+ const path = require('node:path');
28
+ const os = require('node:os');
29
+
30
+ const DEFAULT_CONFIG_PATH = path.join(os.homedir(), '.claude', 'session-manager', 'epic-worktree-project-config.json');
31
+
32
+ // Resolved per-call (not a frozen const) so tests can point this at a
33
+ // throwaway tmpdir file via SM_EPIC_WORKTREE_PROJECT_CONFIG_PATH instead of
34
+ // mutating the real machine-level file at DEFAULT_CONFIG_PATH.
35
+ function configPath() {
36
+ return process.env.SM_EPIC_WORKTREE_PROJECT_CONFIG_PATH || DEFAULT_CONFIG_PATH;
37
+ }
38
+
39
+ function readConfig() {
40
+ try {
41
+ const raw = fs.readFileSync(configPath(), 'utf8');
42
+ const parsed = JSON.parse(raw);
43
+ return parsed && typeof parsed === 'object' && !Array.isArray(parsed) ? parsed : {};
44
+ } catch {
45
+ return {};
46
+ }
47
+ }
48
+
49
+ function writeConfig(config) {
50
+ const file = configPath();
51
+ fs.mkdirSync(path.dirname(file), { recursive: true });
52
+ const tmp = `${file}.tmp-${process.pid}`;
53
+ fs.writeFileSync(tmp, JSON.stringify(config, null, 2));
54
+ fs.renameSync(tmp, file);
55
+ }
56
+
57
+ /** True when the project at `cwd` has explicitly turned Epic worktree isolation off. */
58
+ function isEpicWorktreeDisabledForProject(cwd) {
59
+ if (!cwd || typeof cwd !== 'string') return false;
60
+ return readConfig()[cwd] === true;
61
+ }
62
+
63
+ /** Persists (or clears, when `disabled` is false) the per-project toggle. */
64
+ function setEpicWorktreeDisabledForProject(cwd, disabled) {
65
+ if (!cwd || typeof cwd !== 'string') throw new Error('setEpicWorktreeDisabledForProject: cwd is required');
66
+ const config = readConfig();
67
+ if (disabled) {
68
+ config[cwd] = true;
69
+ } else {
70
+ delete config[cwd];
71
+ }
72
+ writeConfig(config);
73
+ return disabled;
74
+ }
75
+
76
+ function registerEpicWorktreeProjectConfigHandlers() {
77
+ const { ipcMain } = require('electron');
78
+ const { schemas: s, validated: v } = require('../ipcSchemas.cjs');
79
+ const { validatePath } = require('../config.cjs');
80
+ ipcMain.handle(
81
+ 'promptSessions:get-worktree-disabled',
82
+ v(s.promptSessionsGetWorktreeDisabled, ({ cwd }) => {
83
+ validatePath(cwd);
84
+ return { disabled: isEpicWorktreeDisabledForProject(cwd) };
85
+ }),
86
+ );
87
+ ipcMain.handle(
88
+ 'promptSessions:set-worktree-disabled',
89
+ v(s.promptSessionsSetWorktreeDisabled, ({ cwd, disabled }) => {
90
+ validatePath(cwd);
91
+ return { disabled: setEpicWorktreeDisabledForProject(cwd, disabled) };
92
+ }),
93
+ );
94
+ }
95
+
96
+ module.exports = {
97
+ DEFAULT_CONFIG_PATH,
98
+ configPath,
99
+ isEpicWorktreeDisabledForProject,
100
+ setEpicWorktreeDisabledForProject,
101
+ registerEpicWorktreeProjectConfigHandlers,
102
+ };