@nemus-cli/nemus 0.2.1

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 (320) hide show
  1. package/CHANGELOG.md +86 -0
  2. package/LICENSE +21 -0
  3. package/README.md +275 -0
  4. package/assets/README.md +53 -0
  5. package/assets/banner.png +0 -0
  6. package/assets/banner.svg +66 -0
  7. package/assets/favicon-32.png +0 -0
  8. package/assets/favicon-64.png +0 -0
  9. package/assets/icon-256.png +0 -0
  10. package/assets/icon.svg +23 -0
  11. package/assets/logo-256.png +0 -0
  12. package/assets/logo-512.png +0 -0
  13. package/assets/logo-wordmark.svg +35 -0
  14. package/assets/logo.svg +32 -0
  15. package/bin/workspace.js +130 -0
  16. package/dist/cli/ai-prompt.js +421 -0
  17. package/dist/cli/dashboard/AgentList.js +61 -0
  18. package/dist/cli/dashboard/DashboardSidebar.js +280 -0
  19. package/dist/cli/dashboard/HelpFooter.js +73 -0
  20. package/dist/cli/dashboard/StatusBadge.js +50 -0
  21. package/dist/cli/dashboard/index.js +11 -0
  22. package/dist/cli/dashboard/types.js +2 -0
  23. package/dist/cli/tui.js +48 -0
  24. package/dist/commands/ai-prompt.js +22 -0
  25. package/dist/commands/analyze-deps.js +138 -0
  26. package/dist/commands/archive.js +113 -0
  27. package/dist/commands/branch/create.js +119 -0
  28. package/dist/commands/branch/index.js +104 -0
  29. package/dist/commands/branch/merge.js +90 -0
  30. package/dist/commands/branch/rebase.js +84 -0
  31. package/dist/commands/branch/switch.js +165 -0
  32. package/dist/commands/cache/index.js +80 -0
  33. package/dist/commands/cache/manager.js +198 -0
  34. package/dist/commands/cleanup.js +153 -0
  35. package/dist/commands/configure-claude.js +55 -0
  36. package/dist/commands/configure.js +231 -0
  37. package/dist/commands/create.js +204 -0
  38. package/dist/commands/dashboard/hook-handler.js +162 -0
  39. package/dist/commands/dashboard/index.js +258 -0
  40. package/dist/commands/dashboard/launcher.js +40 -0
  41. package/dist/commands/dashboard/session-picker.js +106 -0
  42. package/dist/commands/dashboard/sidebar.js +39 -0
  43. package/dist/commands/dashboard/workspace-picker.js +95 -0
  44. package/dist/commands/delete.js +194 -0
  45. package/dist/commands/deprecated-aliases.js +44 -0
  46. package/dist/commands/diff.js +129 -0
  47. package/dist/commands/doctor.js +141 -0
  48. package/dist/commands/generate-docs.js +77 -0
  49. package/dist/commands/ghq-status.js +72 -0
  50. package/dist/commands/go.js +154 -0
  51. package/dist/commands/history.js +124 -0
  52. package/dist/commands/list.js +191 -0
  53. package/dist/commands/mcp/index.js +69 -0
  54. package/dist/commands/migrate.js +296 -0
  55. package/dist/commands/remove-repo.js +217 -0
  56. package/dist/commands/report-bug.js +112 -0
  57. package/dist/commands/run.js +147 -0
  58. package/dist/commands/save-context.js +171 -0
  59. package/dist/commands/sessions.js +129 -0
  60. package/dist/commands/status.js +138 -0
  61. package/dist/commands/suite/create.js +212 -0
  62. package/dist/commands/suite/delete.js +64 -0
  63. package/dist/commands/suite/export.js +126 -0
  64. package/dist/commands/suite/import.js +128 -0
  65. package/dist/commands/suite/index.js +94 -0
  66. package/dist/commands/suite/list.js +49 -0
  67. package/dist/commands/suite/use.js +227 -0
  68. package/dist/commands/sync.js +117 -0
  69. package/dist/commands/update.js +203 -0
  70. package/dist/mcp/install.js +550 -0
  71. package/dist/mcp/server.js +398 -0
  72. package/dist/mcp/tools.js +922 -0
  73. package/dist/pi-extensions/permission-sync.ts.template +41 -0
  74. package/dist/pi-extensions/permissions-gate.ts.template +69 -0
  75. package/dist/pi-extensions/pr-fix-trigger.ts.template +124 -0
  76. package/dist/pi-extensions/review-reminder.ts.template +58 -0
  77. package/dist/pi-extensions/workspace-input-status.ts.template +919 -0
  78. package/dist/program.js +136 -0
  79. package/dist/scripts/workspace-table.py +394 -0
  80. package/dist/types/dashboard.js +11 -0
  81. package/dist/types/index.js +2 -0
  82. package/dist/utils/agent-config.js +263 -0
  83. package/dist/utils/agent-state.js +178 -0
  84. package/dist/utils/banner.js +24 -0
  85. package/dist/utils/branch-operations.js +232 -0
  86. package/dist/utils/bug-report.js +355 -0
  87. package/dist/utils/cache.js +168 -0
  88. package/dist/utils/claude-integration.js +617 -0
  89. package/dist/utils/claude-sessions.js +260 -0
  90. package/dist/utils/cleanup-operations.js +120 -0
  91. package/dist/utils/colors.js +26 -0
  92. package/dist/utils/command-helpers.js +44 -0
  93. package/dist/utils/config.js +150 -0
  94. package/dist/utils/context-file.js +33 -0
  95. package/dist/utils/dashboard-hooks.js +172 -0
  96. package/dist/utils/dependency-analyzer.js +234 -0
  97. package/dist/utils/diff-operations.js +80 -0
  98. package/dist/utils/doc-generator.js +184 -0
  99. package/dist/utils/ghq-integration.js +332 -0
  100. package/dist/utils/git-operations.js +237 -0
  101. package/dist/utils/git-status.js +187 -0
  102. package/dist/utils/github.js +68 -0
  103. package/dist/utils/health-checks.js +345 -0
  104. package/dist/utils/history.js +150 -0
  105. package/dist/utils/hooks.js +100 -0
  106. package/dist/utils/logger.js +40 -0
  107. package/dist/utils/permission-sync.js +681 -0
  108. package/dist/utils/pi-extensions.js +224 -0
  109. package/dist/utils/progress.js +92 -0
  110. package/dist/utils/prompts.js +279 -0
  111. package/dist/utils/repo-resolver.js +260 -0
  112. package/dist/utils/retry.js +65 -0
  113. package/dist/utils/run-operations.js +30 -0
  114. package/dist/utils/suite.js +159 -0
  115. package/dist/utils/sync-operations.js +107 -0
  116. package/dist/utils/tmux-dashboard.js +184 -0
  117. package/dist/utils/validation.js +153 -0
  118. package/dist/utils/version-check.js +121 -0
  119. package/dist/utils/workspace-meta.js +185 -0
  120. package/install-shell-integration.sh +532 -0
  121. package/install.sh +401 -0
  122. package/package.json +90 -0
  123. package/remove-shell-block.awk +44 -0
  124. package/scripts/postinstall.js +85 -0
  125. package/skills/analyze-deps.md +23 -0
  126. package/skills/archive-workspace.md +26 -0
  127. package/skills/branch-create.md +18 -0
  128. package/skills/create-workspace.md +39 -0
  129. package/skills/delete-workspace.md +37 -0
  130. package/skills/list-org-repos.md +26 -0
  131. package/skills/list-suites.md +24 -0
  132. package/skills/list-workspaces.md +27 -0
  133. package/skills/refresh-workspace-docs.md +89 -0
  134. package/skills/remove-repo.md +25 -0
  135. package/skills/run-command.md +23 -0
  136. package/skills/save-context.md +68 -0
  137. package/skills/search-repos.md +31 -0
  138. package/skills/snapshot-list.md +18 -0
  139. package/skills/snapshot-save.md +12 -0
  140. package/skills/switch-branch.md +18 -0
  141. package/skills/update-cache.md +21 -0
  142. package/skills/update-workspace.md +66 -0
  143. package/skills/workspace-cleanup.md +18 -0
  144. package/skills/workspace-diff.md +23 -0
  145. package/skills/workspace-doctor.md +23 -0
  146. package/skills/workspace-info.md +45 -0
  147. package/skills/workspace-manager/SKILL.md +201 -0
  148. package/skills/workspace-manager/references/ai-prompt.md +44 -0
  149. package/skills/workspace-manager/references/analyze-deps.md +45 -0
  150. package/skills/workspace-manager/references/archive-workspace.md +38 -0
  151. package/skills/workspace-manager/references/branch-create.md +31 -0
  152. package/skills/workspace-manager/references/branch-merge.md +22 -0
  153. package/skills/workspace-manager/references/branch-rebase.md +22 -0
  154. package/skills/workspace-manager/references/cache-clear.md +18 -0
  155. package/skills/workspace-manager/references/cache-info.md +22 -0
  156. package/skills/workspace-manager/references/configure-claude.md +31 -0
  157. package/skills/workspace-manager/references/configure.md +35 -0
  158. package/skills/workspace-manager/references/create-workspace.md +45 -0
  159. package/skills/workspace-manager/references/dashboard.md +61 -0
  160. package/skills/workspace-manager/references/delete-workspace.md +33 -0
  161. package/skills/workspace-manager/references/generate-docs.md +36 -0
  162. package/skills/workspace-manager/references/ghq-status.md +28 -0
  163. package/skills/workspace-manager/references/go.md +33 -0
  164. package/skills/workspace-manager/references/history.md +41 -0
  165. package/skills/workspace-manager/references/list-org-repos.md +26 -0
  166. package/skills/workspace-manager/references/list-suites.md +21 -0
  167. package/skills/workspace-manager/references/list-workspaces.md +27 -0
  168. package/skills/workspace-manager/references/mcp.md +49 -0
  169. package/skills/workspace-manager/references/remove-repo.md +26 -0
  170. package/skills/workspace-manager/references/run-command.md +44 -0
  171. package/skills/workspace-manager/references/search-repos.md +24 -0
  172. package/skills/workspace-manager/references/sessions.md +27 -0
  173. package/skills/workspace-manager/references/suite-create.md +22 -0
  174. package/skills/workspace-manager/references/suite-delete.md +21 -0
  175. package/skills/workspace-manager/references/suite-export.md +19 -0
  176. package/skills/workspace-manager/references/suite-import.md +19 -0
  177. package/skills/workspace-manager/references/suite-use.md +27 -0
  178. package/skills/workspace-manager/references/switch-branch.md +25 -0
  179. package/skills/workspace-manager/references/update-cache.md +22 -0
  180. package/skills/workspace-manager/references/update-workspace.md +50 -0
  181. package/skills/workspace-manager/references/workspace-cleanup.md +33 -0
  182. package/skills/workspace-manager/references/workspace-diff.md +27 -0
  183. package/skills/workspace-manager/references/workspace-doctor.md +27 -0
  184. package/skills/workspace-manager/references/workspace-info.md +33 -0
  185. package/skills/workspace-manager/references/workspace-status.md +43 -0
  186. package/skills/workspace-manager/references/workspace-sync.md +26 -0
  187. package/skills/workspace-status.md +26 -0
  188. package/skills/workspace-sync.md +23 -0
  189. package/src/cli/ai-prompt.test.ts +667 -0
  190. package/src/cli/ai-prompt.ts +421 -0
  191. package/src/cli/dashboard/AgentList.tsx +44 -0
  192. package/src/cli/dashboard/DashboardSidebar.tsx +291 -0
  193. package/src/cli/dashboard/HelpFooter.tsx +22 -0
  194. package/src/cli/dashboard/StatusBadge.tsx +23 -0
  195. package/src/cli/dashboard/index.ts +5 -0
  196. package/src/cli/dashboard/types.ts +16 -0
  197. package/src/cli/tui.tsx +51 -0
  198. package/src/cli/workspace-cli.test.ts +30 -0
  199. package/src/commands/ai-prompt.ts +21 -0
  200. package/src/commands/analyze-deps.ts +119 -0
  201. package/src/commands/archive.ts +114 -0
  202. package/src/commands/branch/create.ts +94 -0
  203. package/src/commands/branch/index.ts +74 -0
  204. package/src/commands/branch/merge.ts +61 -0
  205. package/src/commands/branch/rebase.ts +54 -0
  206. package/src/commands/branch/switch.ts +150 -0
  207. package/src/commands/cache/index.ts +51 -0
  208. package/src/commands/cache/manager.ts +168 -0
  209. package/src/commands/cleanup.ts +132 -0
  210. package/src/commands/configure-claude.ts +55 -0
  211. package/src/commands/configure.ts +204 -0
  212. package/src/commands/create.ts +196 -0
  213. package/src/commands/dashboard/hook-handler.ts +138 -0
  214. package/src/commands/dashboard/index.ts +248 -0
  215. package/src/commands/dashboard/launcher.ts +42 -0
  216. package/src/commands/dashboard/session-picker.ts +73 -0
  217. package/src/commands/dashboard/sidebar.js +39 -0
  218. package/src/commands/dashboard/workspace-picker.ts +62 -0
  219. package/src/commands/delete.test.ts +250 -0
  220. package/src/commands/delete.ts +171 -0
  221. package/src/commands/deprecated-aliases.ts +55 -0
  222. package/src/commands/diff.ts +106 -0
  223. package/src/commands/doctor.ts +110 -0
  224. package/src/commands/generate-docs.ts +45 -0
  225. package/src/commands/ghq-status.ts +70 -0
  226. package/src/commands/go.ts +125 -0
  227. package/src/commands/history.ts +136 -0
  228. package/src/commands/list.test.ts +219 -0
  229. package/src/commands/list.ts +176 -0
  230. package/src/commands/mcp/index.ts +39 -0
  231. package/src/commands/migrate.ts +277 -0
  232. package/src/commands/remove-repo.ts +194 -0
  233. package/src/commands/report-bug.ts +88 -0
  234. package/src/commands/run.ts +125 -0
  235. package/src/commands/save-context.test.ts +113 -0
  236. package/src/commands/save-context.ts +141 -0
  237. package/src/commands/sessions.ts +99 -0
  238. package/src/commands/status.ts +111 -0
  239. package/src/commands/suite/create.ts +240 -0
  240. package/src/commands/suite/delete.ts +65 -0
  241. package/src/commands/suite/export.ts +97 -0
  242. package/src/commands/suite/import.ts +100 -0
  243. package/src/commands/suite/index.ts +66 -0
  244. package/src/commands/suite/list.ts +54 -0
  245. package/src/commands/suite/use.ts +232 -0
  246. package/src/commands/sync.ts +97 -0
  247. package/src/commands/update.ts +197 -0
  248. package/src/mcp/install.ts +529 -0
  249. package/src/mcp/server.ts +579 -0
  250. package/src/mcp/tools.test.ts +545 -0
  251. package/src/mcp/tools.ts +1019 -0
  252. package/src/mcp/update-workspace.test.ts +220 -0
  253. package/src/pi-extensions/permission-sync.ts.template +41 -0
  254. package/src/pi-extensions/permissions-gate.ts.template +69 -0
  255. package/src/pi-extensions/pr-fix-trigger.ts.template +124 -0
  256. package/src/pi-extensions/review-reminder.ts.template +58 -0
  257. package/src/pi-extensions/workspace-input-status.ts.template +919 -0
  258. package/src/program.ts +112 -0
  259. package/src/scripts/workspace-table.py +394 -0
  260. package/src/types/dashboard.ts +29 -0
  261. package/src/types/index.ts +109 -0
  262. package/src/types/ink.d.ts +171 -0
  263. package/src/utils/agent-config.test.ts +303 -0
  264. package/src/utils/agent-config.ts +264 -0
  265. package/src/utils/agent-state.test.ts +166 -0
  266. package/src/utils/agent-state.ts +135 -0
  267. package/src/utils/banner.ts +24 -0
  268. package/src/utils/branch-operations.ts +237 -0
  269. package/src/utils/bug-report.test.ts +174 -0
  270. package/src/utils/bug-report.ts +355 -0
  271. package/src/utils/cache.ts +150 -0
  272. package/src/utils/claude-integration.test.ts +381 -0
  273. package/src/utils/claude-integration.ts +649 -0
  274. package/src/utils/claude-sessions.test.ts +262 -0
  275. package/src/utils/claude-sessions.ts +251 -0
  276. package/src/utils/cleanup-operations.ts +94 -0
  277. package/src/utils/colors.ts +25 -0
  278. package/src/utils/command-helpers.ts +46 -0
  279. package/src/utils/config.test.ts +203 -0
  280. package/src/utils/config.ts +133 -0
  281. package/src/utils/context-file.ts +36 -0
  282. package/src/utils/dashboard-hooks.test.ts +168 -0
  283. package/src/utils/dashboard-hooks.ts +163 -0
  284. package/src/utils/dependency-analyzer.ts +243 -0
  285. package/src/utils/diff-operations.ts +59 -0
  286. package/src/utils/doc-generator.ts +187 -0
  287. package/src/utils/ghq-integration.test.ts +195 -0
  288. package/src/utils/ghq-integration.ts +317 -0
  289. package/src/utils/git-operations.test.ts +265 -0
  290. package/src/utils/git-operations.ts +233 -0
  291. package/src/utils/git-status.ts +171 -0
  292. package/src/utils/github.ts +74 -0
  293. package/src/utils/health-checks.ts +359 -0
  294. package/src/utils/history.ts +140 -0
  295. package/src/utils/hooks.ts +92 -0
  296. package/src/utils/logger.ts +37 -0
  297. package/src/utils/permission-sync.test.ts +593 -0
  298. package/src/utils/permission-sync.ts +720 -0
  299. package/src/utils/pi-extensions.test.ts +182 -0
  300. package/src/utils/pi-extensions.ts +226 -0
  301. package/src/utils/progress.ts +73 -0
  302. package/src/utils/prompts.test.ts +169 -0
  303. package/src/utils/prompts.ts +296 -0
  304. package/src/utils/repo-resolver.test.ts +313 -0
  305. package/src/utils/repo-resolver.ts +294 -0
  306. package/src/utils/retry.test.ts +124 -0
  307. package/src/utils/retry.ts +85 -0
  308. package/src/utils/run-operations.ts +38 -0
  309. package/src/utils/suite.test.ts +256 -0
  310. package/src/utils/suite.ts +144 -0
  311. package/src/utils/sync-operations.ts +87 -0
  312. package/src/utils/tmux-dashboard.ts +193 -0
  313. package/src/utils/validation.test.ts +139 -0
  314. package/src/utils/validation.ts +128 -0
  315. package/src/utils/version-check.test.ts +108 -0
  316. package/src/utils/version-check.ts +96 -0
  317. package/src/utils/workspace-meta.ts +173 -0
  318. package/sync-permissions.sh +137 -0
  319. package/tsconfig.json +20 -0
  320. package/uninstall.sh +162 -0
@@ -0,0 +1,263 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.AGENT_ORDER = void 0;
37
+ exports.getAgentPaths = getAgentPaths;
38
+ exports.getActiveAgents = getActiveAgents;
39
+ exports.getPrimaryAgent = getPrimaryAgent;
40
+ exports.isAgentCliAvailable = isAgentCliAvailable;
41
+ exports.resetAgentConfigCache = resetAgentConfigCache;
42
+ exports.getSkillsTargetDirs = getSkillsTargetDirs;
43
+ exports.getContextFileNames = getContextFileNames;
44
+ exports.getHookTargetFiles = getHookTargetFiles;
45
+ exports.getMcpAgents = getMcpAgents;
46
+ exports.getAllKnownContextFileNames = getAllKnownContextFileNames;
47
+ const os = __importStar(require("os"));
48
+ const path = __importStar(require("path"));
49
+ const child_process_1 = require("child_process");
50
+ const config_1 = require("./config");
51
+ const HOME = os.homedir();
52
+ /**
53
+ * Detection order for `auto` / `both` / `getPrimaryAgent`. Also the order agents
54
+ * appear in `getActiveAgents()`. Add a new agent's config below and to this list.
55
+ */
56
+ exports.AGENT_ORDER = ['claude', 'pi', 'opencode', 'codex', 'gemini'];
57
+ const CLAUDE_PATHS = {
58
+ type: 'claude',
59
+ skillsDir: path.join(HOME, '.claude', 'skills'),
60
+ settingsFile: path.join(HOME, '.claude', 'settings.json'),
61
+ // Must be exactly 'CLAUDE.md': Claude Code only auto-discovers CLAUDE.md /
62
+ // AGENTS.md up the cwd/ancestor chain. A hidden lowercase '.claude.md' is
63
+ // invisible to its project-memory loader, so the workspace context (and its
64
+ // 'Saved Context' pointer) would never surface automatically (issue #186).
65
+ contextFileName: 'CLAUDE.md',
66
+ launchCommand: 'claude',
67
+ resumeCommand: (id) => `claude --resume ${id} --fork-session`,
68
+ supportsMcp: true,
69
+ supportsHooks: true,
70
+ sessionProjectsDir: path.join(HOME, '.claude', 'projects'),
71
+ };
72
+ const PI_PATHS = {
73
+ type: 'pi',
74
+ skillsDir: path.join(HOME, '.pi', 'agent', 'skills'),
75
+ settingsFile: path.join(HOME, '.pi', 'agent', 'settings.json'),
76
+ contextFileName: 'AGENTS.md',
77
+ launchCommand: 'pi',
78
+ resumeCommand: (id) => `pi --session ${id} --fork`,
79
+ supportsMcp: false,
80
+ supportsHooks: false,
81
+ sessionProjectsDir: path.join(HOME, '.pi', 'agent', 'sessions'),
82
+ };
83
+ // OpenCode uses XDG paths: ~/.local/share/opencode for data, ~/.config/opencode for config
84
+ // It reads skills from ~/.claude/skills/ automatically (Claude-compatible)
85
+ // Project config lives in .opencode/ within the project directory
86
+ const OPENCODE_DATA_DIR = path.join(process.env.XDG_DATA_HOME || path.join(HOME, '.local', 'share'), 'opencode');
87
+ const OPENCODE_CONFIG_DIR = path.join(process.env.XDG_CONFIG_HOME || path.join(HOME, '.config'), 'opencode');
88
+ const OPENCODE_PATHS = {
89
+ type: 'opencode',
90
+ // OpenCode reads skills from ~/.claude/skills/ natively — no separate install needed
91
+ skillsDir: path.join(HOME, '.claude', 'skills'),
92
+ settingsFile: path.join(OPENCODE_CONFIG_DIR, 'opencode.jsonc'),
93
+ contextFileName: 'AGENTS.md',
94
+ launchCommand: 'opencode',
95
+ resumeCommand: (_id) => `opencode --continue`,
96
+ supportsMcp: true,
97
+ supportsHooks: false,
98
+ sessionProjectsDir: OPENCODE_DATA_DIR,
99
+ };
100
+ // Codex (OpenAI Codex CLI) — config under ~/.codex, reads AGENTS.md for context,
101
+ // supports MCP servers via ~/.codex/config.toml. No native skills or hooks.
102
+ const CODEX_HOME = process.env.CODEX_HOME || path.join(HOME, '.codex');
103
+ const CODEX_PATHS = {
104
+ type: 'codex',
105
+ skillsDir: path.join(CODEX_HOME, 'skills'),
106
+ settingsFile: path.join(CODEX_HOME, 'config.toml'),
107
+ contextFileName: 'AGENTS.md',
108
+ launchCommand: 'codex',
109
+ resumeCommand: (id) => `codex resume ${id}`,
110
+ supportsMcp: true,
111
+ supportsHooks: false,
112
+ sessionProjectsDir: path.join(CODEX_HOME, 'sessions'),
113
+ };
114
+ // Gemini (Google Gemini CLI) — config under ~/.gemini, reads GEMINI.md for
115
+ // context, supports MCP servers via ~/.gemini/settings.json. No hooks.
116
+ const GEMINI_HOME = path.join(HOME, '.gemini');
117
+ const GEMINI_PATHS = {
118
+ type: 'gemini',
119
+ skillsDir: path.join(GEMINI_HOME, 'skills'),
120
+ settingsFile: path.join(GEMINI_HOME, 'settings.json'),
121
+ contextFileName: 'GEMINI.md',
122
+ launchCommand: 'gemini',
123
+ resumeCommand: (_id) => `gemini`,
124
+ supportsMcp: true,
125
+ supportsHooks: false,
126
+ sessionProjectsDir: path.join(GEMINI_HOME, 'tmp'),
127
+ };
128
+ const AGENT_REGISTRY = {
129
+ claude: CLAUDE_PATHS,
130
+ pi: PI_PATHS,
131
+ opencode: OPENCODE_PATHS,
132
+ codex: CODEX_PATHS,
133
+ gemini: GEMINI_PATHS,
134
+ };
135
+ /**
136
+ * Get AgentPaths for a specific agent type.
137
+ */
138
+ function getAgentPaths(agent) {
139
+ return { ...AGENT_REGISTRY[agent] };
140
+ }
141
+ /**
142
+ * Resolve 'auto' to a concrete agent type by detecting installed CLIs.
143
+ * Cached after first call to avoid repeated shell exec.
144
+ */
145
+ let resolvedAutoAgent = null;
146
+ function resolveAutoAgent() {
147
+ if (resolvedAutoAgent)
148
+ return resolvedAutoAgent;
149
+ const available = exports.AGENT_ORDER.filter(a => isAgentCliAvailable(a));
150
+ // If multiple agents detected, use 'both' (meaning: all available agents).
151
+ if (available.length > 1)
152
+ resolvedAutoAgent = 'both';
153
+ else if (available.length === 1)
154
+ resolvedAutoAgent = available[0];
155
+ else
156
+ resolvedAutoAgent = 'claude'; // default to claude even if not installed
157
+ return resolvedAutoAgent;
158
+ }
159
+ /**
160
+ * Get all active agent configurations based on user config.
161
+ * Resolves 'auto' by detecting installed CLIs. 'both' means every available agent.
162
+ */
163
+ function getActiveAgents() {
164
+ let { aiAgent } = (0, config_1.getUserConfig)();
165
+ if (aiAgent === 'auto')
166
+ aiAgent = resolveAutoAgent();
167
+ if (aiAgent === 'both') {
168
+ const agents = exports.AGENT_ORDER.filter(a => isAgentCliAvailable(a)).map(a => ({ ...AGENT_REGISTRY[a] }));
169
+ // Fallback to Claude if nothing detected (shouldn't happen in 'both' mode)
170
+ return agents.length > 0 ? agents : [{ ...CLAUDE_PATHS }];
171
+ }
172
+ return [{ ...AGENT_REGISTRY[aiAgent] }];
173
+ }
174
+ /**
175
+ * Get the preferred (primary) agent — the one used for launching, dashboards, etc.
176
+ * Uses the `primaryAgent` config. When 'auto', picks the first available CLI.
177
+ */
178
+ function getPrimaryAgent() {
179
+ const { primaryAgent } = (0, config_1.getUserConfig)();
180
+ if (primaryAgent !== 'auto')
181
+ return { ...AGENT_REGISTRY[primaryAgent] };
182
+ // 'auto' — pick first available in detection order
183
+ const first = exports.AGENT_ORDER.find(a => isAgentCliAvailable(a));
184
+ return { ...AGENT_REGISTRY[first ?? 'claude'] };
185
+ }
186
+ /**
187
+ * Check if a specific agent CLI is available on the system.
188
+ * Result is cached per agent to avoid repeated execSync overhead.
189
+ */
190
+ const cliAvailabilityCache = new Map();
191
+ function isAgentCliAvailable(agent) {
192
+ if (cliAvailabilityCache.has(agent))
193
+ return cliAvailabilityCache.get(agent);
194
+ const command = `${AGENT_REGISTRY[agent].launchCommand} --version`;
195
+ let available;
196
+ try {
197
+ (0, child_process_1.execSync)(command, { stdio: 'pipe' });
198
+ available = true;
199
+ }
200
+ catch {
201
+ available = false;
202
+ }
203
+ cliAvailabilityCache.set(agent, available);
204
+ return available;
205
+ }
206
+ /**
207
+ * Reset all cached values. For use in tests to ensure clean state.
208
+ * @internal
209
+ */
210
+ function resetAgentConfigCache() {
211
+ resolvedAutoAgent = null;
212
+ cliAvailabilityCache.clear();
213
+ }
214
+ /**
215
+ * Get all skills directories that should be written to.
216
+ */
217
+ function getSkillsTargetDirs() {
218
+ const dirs = getActiveAgents().map(a => a.skillsDir);
219
+ return [...new Set(dirs)];
220
+ }
221
+ /**
222
+ * Get all context file names that should be generated in workspaces.
223
+ * Deduplicates if multiple agents use the same file.
224
+ */
225
+ function getContextFileNames() {
226
+ const names = getActiveAgents().map(a => a.contextFileName);
227
+ return [...new Set(names)];
228
+ }
229
+ /**
230
+ * Get all settings files where hooks should be installed.
231
+ * Only returns agents that support hooks.
232
+ */
233
+ function getHookTargetFiles() {
234
+ return getActiveAgents()
235
+ .filter(a => a.supportsHooks)
236
+ .map(a => a.settingsFile);
237
+ }
238
+ /**
239
+ * Get all agents that support MCP.
240
+ */
241
+ function getMcpAgents() {
242
+ return getActiveAgents().filter(a => a.supportsMcp);
243
+ }
244
+ /**
245
+ * Get every context file name that any known agent can produce, regardless
246
+ * of which agents are currently configured. Used when scanning repos for
247
+ * existing context files (e.g. a Pi workspace may contain repos that were
248
+ * previously set up for Claude Code, and vice-versa).
249
+ *
250
+ * Also includes legacy '.claude.md' — the filename generated for Claude before
251
+ * issue #186 — so repos/workspaces that still contain one are still recognized.
252
+ */
253
+ function getAllKnownContextFileNames() {
254
+ // Order matters: this is the per-repo scan PRIORITY (findContextFilesInDir
255
+ // embeds the first existing candidate per directory). AGENTS.md must come
256
+ // before CLAUDE.md — in dual-agent repos CLAUDE.md is commonly a thin
257
+ // "@AGENTS.md" shim, so AGENTS.md holds the real content. '.claude.md' is the
258
+ // legacy output (pre-#186), kept last so any lingering files are still
259
+ // recognized.
260
+ const priority = ['AGENTS.md', 'CLAUDE.md', 'GEMINI.md', '.claude.md'];
261
+ const fromAgents = exports.AGENT_ORDER.map(a => AGENT_REGISTRY[a].contextFileName);
262
+ return [...new Set([...priority, ...fromAgents])];
263
+ }
@@ -0,0 +1,178 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.AGENTS_STATE_DIR = void 0;
37
+ exports.ensureStateDir = ensureStateDir;
38
+ exports.writeAgentState = writeAgentState;
39
+ exports.readAgentState = readAgentState;
40
+ exports.readAllAgentStates = readAllAgentStates;
41
+ exports.removeAgentState = removeAgentState;
42
+ const fs = __importStar(require("fs"));
43
+ const path = __importStar(require("path"));
44
+ const os = __importStar(require("os"));
45
+ const dashboard_1 = require("../types/dashboard");
46
+ exports.AGENTS_STATE_DIR = path.join(os.homedir(), '.workspace-manager', 'agents');
47
+ function ensureStateDir() {
48
+ fs.mkdirSync(exports.AGENTS_STATE_DIR, { recursive: true });
49
+ }
50
+ /**
51
+ * Validate that a session ID is safe to use as a filename.
52
+ * Allows only alphanumeric characters and hyphens, max 100 chars.
53
+ */
54
+ function isValidSessionId(id) {
55
+ return typeof id === 'string' && /^[a-zA-Z0-9\-]{1,100}$/.test(id);
56
+ }
57
+ /**
58
+ * Write agent state atomically (write tmp + rename).
59
+ */
60
+ function writeAgentState(state) {
61
+ if (!isValidSessionId(state.sessionId))
62
+ return; // reject invalid IDs silently
63
+ ensureStateDir();
64
+ const filePath = path.join(exports.AGENTS_STATE_DIR, `${state.sessionId}.json`);
65
+ const tmpPath = filePath + '.tmp';
66
+ try {
67
+ fs.writeFileSync(tmpPath, JSON.stringify(state, null, 2), 'utf-8');
68
+ fs.renameSync(tmpPath, filePath);
69
+ }
70
+ catch {
71
+ // Clean up tmp on failure
72
+ try {
73
+ fs.unlinkSync(tmpPath);
74
+ }
75
+ catch { /* ignore */ }
76
+ }
77
+ }
78
+ /**
79
+ * Read a single agent state by session ID.
80
+ */
81
+ function readAgentState(sessionId) {
82
+ if (!isValidSessionId(sessionId))
83
+ return null;
84
+ try {
85
+ const filePath = path.join(exports.AGENTS_STATE_DIR, `${sessionId}.json`);
86
+ const content = fs.readFileSync(filePath, 'utf-8');
87
+ return JSON.parse(content);
88
+ }
89
+ catch {
90
+ return null;
91
+ }
92
+ }
93
+ /**
94
+ * Check if a process is alive by sending signal 0.
95
+ */
96
+ function isProcessAlive(pid) {
97
+ try {
98
+ process.kill(pid, 0);
99
+ return true;
100
+ }
101
+ catch {
102
+ return false;
103
+ }
104
+ }
105
+ /**
106
+ * Read all agent states, check PID liveness, and clean stale entries.
107
+ * Returns active states sorted by workspace, then startedAt.
108
+ */
109
+ function readAllAgentStates() {
110
+ ensureStateDir();
111
+ let entries;
112
+ try {
113
+ entries = fs.readdirSync(exports.AGENTS_STATE_DIR);
114
+ }
115
+ catch {
116
+ return [];
117
+ }
118
+ const now = Date.now();
119
+ const states = [];
120
+ for (const entry of entries) {
121
+ if (!entry.endsWith('.json') || entry.startsWith('.'))
122
+ continue;
123
+ const sessionId = entry.replace('.json', '');
124
+ const state = readAgentState(sessionId);
125
+ if (!state) {
126
+ // Malformed file — remove it
127
+ try {
128
+ fs.unlinkSync(path.join(exports.AGENTS_STATE_DIR, entry));
129
+ }
130
+ catch { /* ignore */ }
131
+ continue;
132
+ }
133
+ // PID liveness check for non-stopped states
134
+ // Skip the check if the state was updated very recently (within 10s)
135
+ // to allow hooks time to update the PID on session resume
136
+ if (state.status !== 'stopped' && state.pid > 0) {
137
+ const age = now - new Date(state.lastUpdatedAt).getTime();
138
+ if (age > 10000 && !isProcessAlive(state.pid)) {
139
+ state.status = 'stopped';
140
+ state.lastUpdatedAt = new Date().toISOString();
141
+ writeAgentState(state);
142
+ }
143
+ }
144
+ // Filter out stale stopped states
145
+ if (state.status === 'stopped') {
146
+ const age = now - new Date(state.lastUpdatedAt).getTime();
147
+ if (age > dashboard_1.DASHBOARD_DEFAULTS.staleTtlMs) {
148
+ try {
149
+ fs.unlinkSync(path.join(exports.AGENTS_STATE_DIR, entry));
150
+ }
151
+ catch { /* ignore */ }
152
+ continue;
153
+ }
154
+ }
155
+ states.push(state);
156
+ }
157
+ // Sort by workspace ascending, then startedAt ascending
158
+ states.sort((a, b) => {
159
+ const wsCmp = a.workspace.localeCompare(b.workspace);
160
+ if (wsCmp !== 0)
161
+ return wsCmp;
162
+ return new Date(a.startedAt).getTime() - new Date(b.startedAt).getTime();
163
+ });
164
+ return states;
165
+ }
166
+ /**
167
+ * Remove a single agent state file.
168
+ */
169
+ function removeAgentState(sessionId) {
170
+ if (!isValidSessionId(sessionId))
171
+ return;
172
+ try {
173
+ fs.unlinkSync(path.join(exports.AGENTS_STATE_DIR, `${sessionId}.json`));
174
+ }
175
+ catch {
176
+ // File doesn't exist — fine
177
+ }
178
+ }
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.printBanner = exports.BANNER_PLAIN = exports.BANNER = void 0;
4
+ const colors_1 = require("./colors");
5
+ const g = colors_1.colors.green;
6
+ const d = colors_1.colors.dim;
7
+ const b = colors_1.colors.bright;
8
+ const r = colors_1.colors.reset;
9
+ exports.BANNER = `
10
+ ${d} ╭──────────────────────────────────────╮${r}
11
+ ${d} │${r} ${g}>_${r} ${b}Nemus${r} ${d}│${r}
12
+ ${d} │${r} ${d}multi-repo workspaces${r} ${d}│${r}
13
+ ${d} ╰──────────────────────────────────────╯${r}
14
+ `;
15
+ exports.BANNER_PLAIN = `
16
+ ╭──────────────────────────────────────╮
17
+ │ >_ Nemus │
18
+ │ multi-repo workspaces │
19
+ ╰──────────────────────────────────────╯
20
+ `;
21
+ const printBanner = () => {
22
+ console.log(exports.BANNER);
23
+ };
24
+ exports.printBanner = printBanner;
@@ -0,0 +1,232 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.rebaseBranch = exports.mergeBranch = exports.createBranch = exports.switchBranch = void 0;
37
+ const child_process_1 = require("child_process");
38
+ const util_1 = require("util");
39
+ const fs = __importStar(require("fs/promises"));
40
+ const git_status_1 = require("./git-status");
41
+ const execAsync = (0, util_1.promisify)(child_process_1.exec);
42
+ const GIT_TIMEOUT = 30000;
43
+ const switchBranch = async (repoPath, repoName, targetBranch) => {
44
+ try {
45
+ // Check if directory exists
46
+ try {
47
+ await fs.access(repoPath);
48
+ }
49
+ catch {
50
+ return {
51
+ repo: repoName,
52
+ status: 'skipped',
53
+ message: 'Directory not found',
54
+ };
55
+ }
56
+ // Check if it's a git repository
57
+ try {
58
+ await execAsync('git rev-parse --git-dir', { cwd: repoPath });
59
+ }
60
+ catch {
61
+ return {
62
+ repo: repoName,
63
+ status: 'skipped',
64
+ message: 'Not a git repository',
65
+ };
66
+ }
67
+ // Get current branch
68
+ const { stdout: currentBranchOutput } = await execAsync('git branch --show-current', { cwd: repoPath });
69
+ const currentBranch = currentBranchOutput.trim();
70
+ if (currentBranch === targetBranch) {
71
+ return {
72
+ repo: repoName,
73
+ status: 'skipped',
74
+ message: 'Already on target branch',
75
+ previousBranch: currentBranch,
76
+ };
77
+ }
78
+ // Check for uncommitted changes
79
+ const { stdout: statusOutput } = await execAsync('git status --porcelain', { cwd: repoPath });
80
+ if (statusOutput.trim().length > 0) {
81
+ return {
82
+ repo: repoName,
83
+ status: 'skipped',
84
+ message: 'Uncommitted changes',
85
+ previousBranch: currentBranch,
86
+ };
87
+ }
88
+ // Fetch to ensure we have latest branches
89
+ await execAsync('git fetch', { cwd: repoPath, timeout: GIT_TIMEOUT });
90
+ // Check if branch exists locally
91
+ try {
92
+ await execAsync(`git rev-parse --verify ${targetBranch}`, { cwd: repoPath });
93
+ }
94
+ catch {
95
+ // Branch doesn't exist locally, check remote
96
+ try {
97
+ await execAsync(`git rev-parse --verify origin/${targetBranch}`, { cwd: repoPath });
98
+ // Branch exists on remote, create local tracking branch
99
+ await execAsync(`git checkout -b ${targetBranch} origin/${targetBranch}`, { cwd: repoPath });
100
+ return {
101
+ repo: repoName,
102
+ status: 'success',
103
+ previousBranch: currentBranch,
104
+ newBranch: targetBranch,
105
+ };
106
+ }
107
+ catch {
108
+ return {
109
+ repo: repoName,
110
+ status: 'failed',
111
+ message: `Branch ${targetBranch} not found`,
112
+ previousBranch: currentBranch,
113
+ };
114
+ }
115
+ }
116
+ // Switch to existing local branch
117
+ await execAsync(`git checkout ${targetBranch}`, { cwd: repoPath });
118
+ return {
119
+ repo: repoName,
120
+ status: 'success',
121
+ previousBranch: currentBranch,
122
+ newBranch: targetBranch,
123
+ };
124
+ }
125
+ catch (error) {
126
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error';
127
+ return {
128
+ repo: repoName,
129
+ status: 'failed',
130
+ message: errorMessage,
131
+ };
132
+ }
133
+ };
134
+ exports.switchBranch = switchBranch;
135
+ const createBranch = async (repoPath, repoName, branchName, baseBranch, force) => {
136
+ try {
137
+ // Check for uncommitted changes
138
+ if (!force) {
139
+ const hasChanges = await (0, git_status_1.hasUncommittedChanges)(repoPath);
140
+ if (hasChanges) {
141
+ return {
142
+ repo: repoName,
143
+ success: false,
144
+ message: 'Skipped (uncommitted changes)',
145
+ };
146
+ }
147
+ }
148
+ // Checkout base branch if specified
149
+ if (baseBranch) {
150
+ await execAsync(`git checkout ${baseBranch}`, {
151
+ cwd: repoPath,
152
+ timeout: GIT_TIMEOUT,
153
+ });
154
+ }
155
+ // Create and checkout new branch
156
+ await execAsync(`git checkout -b ${branchName}`, {
157
+ cwd: repoPath,
158
+ timeout: GIT_TIMEOUT,
159
+ });
160
+ return {
161
+ repo: repoName,
162
+ success: true,
163
+ message: `Created branch ${branchName}`,
164
+ };
165
+ }
166
+ catch (error) {
167
+ return {
168
+ repo: repoName,
169
+ success: false,
170
+ message: 'Failed',
171
+ error: error instanceof Error ? error.message : 'Unknown error',
172
+ };
173
+ }
174
+ };
175
+ exports.createBranch = createBranch;
176
+ const mergeBranch = async (repoPath, repoName, sourceBranch, targetBranch, options) => {
177
+ try {
178
+ // Checkout target branch
179
+ await execAsync(`git checkout ${targetBranch}`, {
180
+ cwd: repoPath,
181
+ timeout: GIT_TIMEOUT,
182
+ });
183
+ // Build merge command
184
+ let mergeCmd = `git merge ${sourceBranch}`;
185
+ if (options?.noFf)
186
+ mergeCmd += ' --no-ff';
187
+ if (options?.ffOnly)
188
+ mergeCmd += ' --ff-only';
189
+ if (options?.squash)
190
+ mergeCmd += ' --squash';
191
+ await execAsync(mergeCmd, {
192
+ cwd: repoPath,
193
+ timeout: GIT_TIMEOUT,
194
+ });
195
+ return {
196
+ repo: repoName,
197
+ success: true,
198
+ message: `Merged ${sourceBranch} into ${targetBranch}`,
199
+ };
200
+ }
201
+ catch (error) {
202
+ return {
203
+ repo: repoName,
204
+ success: false,
205
+ message: 'Merge failed',
206
+ error: error instanceof Error ? error.message : 'Unknown error',
207
+ };
208
+ }
209
+ };
210
+ exports.mergeBranch = mergeBranch;
211
+ const rebaseBranch = async (repoPath, repoName, targetBranch) => {
212
+ try {
213
+ await execAsync(`git rebase ${targetBranch}`, {
214
+ cwd: repoPath,
215
+ timeout: GIT_TIMEOUT,
216
+ });
217
+ return {
218
+ repo: repoName,
219
+ success: true,
220
+ message: `Rebased onto ${targetBranch}`,
221
+ };
222
+ }
223
+ catch (error) {
224
+ return {
225
+ repo: repoName,
226
+ success: false,
227
+ message: 'Rebase failed',
228
+ error: error instanceof Error ? error.message : 'Unknown error',
229
+ };
230
+ }
231
+ };
232
+ exports.rebaseBranch = rebaseBranch;