@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,296 @@
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.registerMigrateCommand = registerMigrateCommand;
37
+ const path = __importStar(require("path"));
38
+ const fs = __importStar(require("fs/promises"));
39
+ const child_process_1 = require("child_process");
40
+ const config_1 = require("../utils/config");
41
+ const workspace_meta_1 = require("../utils/workspace-meta");
42
+ const claude_integration_1 = require("../utils/claude-integration");
43
+ const logger_1 = require("../utils/logger");
44
+ const colors_1 = require("../utils/colors");
45
+ const agent_config_1 = require("../utils/agent-config");
46
+ function registerMigrateCommand(parent) {
47
+ parent
48
+ .command('migrate')
49
+ .description('Migrate all workspaces to latest format (regenerate context files, update metadata)')
50
+ .option('--dry-run', 'Show what would be changed without making changes')
51
+ .action(async (opts) => {
52
+ await handleMigrate(opts);
53
+ });
54
+ }
55
+ async function handleMigrate(opts) {
56
+ const dryRun = opts.dryRun ?? false;
57
+ if (dryRun) {
58
+ (0, logger_1.logInfo)('Dry run mode - no changes will be made\n');
59
+ }
60
+ const workspaces = await (0, workspace_meta_1.listWorkspaces)(false);
61
+ if (workspaces.length === 0) {
62
+ (0, logger_1.logInfo)('No workspaces found. Nothing to migrate.');
63
+ return;
64
+ }
65
+ (0, logger_1.logInfo)(`Found ${(0, colors_1.colorize)(String(workspaces.length), 'cyan')} workspaces to migrate\n`);
66
+ let migrated = 0;
67
+ let skipped = 0;
68
+ let errors = 0;
69
+ for (const ws of workspaces) {
70
+ const wsPath = ws.path;
71
+ const metadata = await (0, workspace_meta_1.loadMetadata)(wsPath);
72
+ if (!metadata) {
73
+ // No metadata file - reconstruct it by scanning git subdirectories
74
+ (0, logger_1.logWarning)(`${ws.name}: no metadata found - reconstructing from git repos`);
75
+ const reconstructed = await reconstructMetadata(ws.name, wsPath);
76
+ if (!reconstructed) {
77
+ (0, logger_1.logError)(` ${ws.name}: could not reconstruct metadata (no git repos found), skipping`);
78
+ skipped++;
79
+ continue;
80
+ }
81
+ if (!dryRun) {
82
+ await (0, workspace_meta_1.saveMetadata)(wsPath, reconstructed);
83
+ (0, logger_1.logSuccess)(` ${(0, colors_1.colorize)(ws.name, 'cyan')}: metadata created (${reconstructed.repositories.length} repos detected)`);
84
+ }
85
+ else {
86
+ (0, logger_1.logInfo)(` ${(0, colors_1.colorize)(ws.name, 'cyan')}: would create metadata (${reconstructed.repositories.length} repos detected)`);
87
+ }
88
+ // Regenerate context files using the reconstructed metadata.
89
+ const meta = reconstructed;
90
+ if (!dryRun) {
91
+ const repos = meta.repositories
92
+ .filter(r => r.status === 'success')
93
+ .map(r => ({ name: r.name, description: '', url: r.cloneUrl, owner: { login: r.owner }, sshUrl: r.cloneUrl }));
94
+ try {
95
+ await (0, claude_integration_1.generateClaudeContext)(wsPath, ws.name, repos, meta);
96
+ }
97
+ catch { /* context gen is best-effort */ }
98
+ }
99
+ migrated++;
100
+ continue;
101
+ }
102
+ try {
103
+ const dirNames = metadata.repositories
104
+ .filter(r => r.status === 'success')
105
+ .map(r => r.directoryName);
106
+ const contextFiles = (0, agent_config_1.getContextFileNames)();
107
+ // Read all existing context files first — before any writes.
108
+ // If any file is missing we must fall back to full regeneration;
109
+ // we determine this BEFORE touching anything so we never mix
110
+ // surgical patches with a subsequent full overwrite.
111
+ const existingContents = new Map();
112
+ let needsFullRegen = false;
113
+ for (const fileName of contextFiles) {
114
+ try {
115
+ existingContents.set(fileName, await fs.readFile(path.join(wsPath, fileName), 'utf-8'));
116
+ }
117
+ catch {
118
+ needsFullRegen = true;
119
+ break;
120
+ }
121
+ }
122
+ // Build the per-repo section (needs disk access; do once for both paths).
123
+ const perRepoSection = await (0, claude_integration_1.buildPerRepoContextSection)(wsPath, dirNames);
124
+ const repoCount = perRepoSection ? (perRepoSection.match(/^###/gm) || []).length : 0;
125
+ if (dryRun) {
126
+ if (needsFullRegen) {
127
+ (0, logger_1.logInfo)(` ${(0, colors_1.colorize)(ws.name, 'cyan')}: would regenerate context files from scratch (context file missing)`);
128
+ }
129
+ else if (repoCount > 0) {
130
+ (0, logger_1.logInfo)(` ${(0, colors_1.colorize)(ws.name, 'cyan')}: would embed per-repo context from ${repoCount} location(s) into ${contextFiles.join(', ')}`);
131
+ }
132
+ else {
133
+ (0, logger_1.logInfo)(` ${(0, colors_1.colorize)(ws.name, 'cyan')}: would update ${contextFiles.join(', ')} (no per-repo context files found — any existing section removed)`);
134
+ }
135
+ migrated++;
136
+ continue;
137
+ }
138
+ // Ensure lastModified is set
139
+ if (!metadata.lastModified) {
140
+ metadata.lastModified = new Date().toISOString();
141
+ await (0, workspace_meta_1.saveMetadata)(wsPath, metadata);
142
+ }
143
+ if (needsFullRegen) {
144
+ // One or more context files are missing — regenerate all from scratch.
145
+ const repos = metadata.repositories
146
+ .filter(r => r.status === 'success')
147
+ .map(r => ({
148
+ name: r.name, description: '', url: r.cloneUrl,
149
+ owner: { login: r.owner }, sshUrl: r.cloneUrl,
150
+ }));
151
+ await (0, claude_integration_1.generateClaudeContext)(wsPath, ws.name, repos, metadata);
152
+ }
153
+ else {
154
+ // All context files exist — patch only the per-repo section in each.
155
+ for (const [fileName, existing] of existingContents) {
156
+ const updated = upsertPerRepoSection(existing, perRepoSection);
157
+ if (updated !== existing) {
158
+ await fs.writeFile(path.join(wsPath, fileName), updated, 'utf-8');
159
+ }
160
+ }
161
+ }
162
+ const detail = needsFullRegen
163
+ ? ' (regenerated from scratch)'
164
+ : repoCount > 0
165
+ ? ` (embedded per-repo context from ${repoCount} location(s))`
166
+ : ' (no per-repo context files found)';
167
+ (0, logger_1.logSuccess)(` ${(0, colors_1.colorize)(ws.name, 'cyan')}: migrated${detail}`);
168
+ migrated++;
169
+ }
170
+ catch (err) {
171
+ const msg = err instanceof Error ? err.message : String(err);
172
+ (0, logger_1.logError)(` ${ws.name}: ${msg}`);
173
+ errors++;
174
+ }
175
+ }
176
+ console.log('');
177
+ (0, logger_1.logInfo)(dryRun ? 'Dry run complete:' : 'Migration complete:');
178
+ console.log(` ${(0, colors_1.colorize)(String(migrated), 'green')} ${dryRun ? 'would migrate' : 'migrated'}`);
179
+ if (skipped > 0)
180
+ console.log(` ${(0, colors_1.colorize)(String(skipped), 'yellow')} skipped`);
181
+ if (errors > 0)
182
+ console.log(` ${(0, colors_1.colorize)(String(errors), 'red')} errors`);
183
+ }
184
+ /**
185
+ * Reconstruct a WorkspaceMetadata object for a workspace that has no metadata
186
+ * file by scanning subdirectories for git repositories and reading their
187
+ * remote origin URLs.
188
+ *
189
+ * Returns null if no git repos are found in the workspace directory.
190
+ */
191
+ async function reconstructMetadata(workspaceName, workspacePath) {
192
+ let entries;
193
+ try {
194
+ entries = await fs.readdir(workspacePath);
195
+ }
196
+ catch {
197
+ return null;
198
+ }
199
+ const repositories = [];
200
+ for (const entry of entries) {
201
+ const repoPath = path.join(workspacePath, entry);
202
+ try {
203
+ const stat = await fs.stat(repoPath);
204
+ if (!stat.isDirectory())
205
+ continue;
206
+ // Check it's a git repo
207
+ await fs.access(path.join(repoPath, '.git'));
208
+ // Get the remote origin URL
209
+ let cloneUrl = '';
210
+ let owner = (0, config_1.getUserConfig)().githubOrg || 'your-org';
211
+ try {
212
+ cloneUrl = (0, child_process_1.execSync)('git remote get-url origin', {
213
+ cwd: repoPath, stdio: 'pipe', encoding: 'utf-8',
214
+ }).trim();
215
+ // Extract owner from SSH URL: git@github.com:owner/repo.git
216
+ const sshMatch = cloneUrl.match(/github\.com[:/]([^/]+)\//);
217
+ if (sshMatch)
218
+ owner = sshMatch[1];
219
+ }
220
+ catch { /* no remote - leave blank */ }
221
+ // Derive the canonical repo name from the remote URL, falling back
222
+ // to the directory name.
223
+ let repoName = entry;
224
+ try {
225
+ const urlMatch = cloneUrl.match(/\/([^/]+?)\.git$/) ||
226
+ cloneUrl.match(/\/([^/]+)$/);
227
+ if (urlMatch)
228
+ repoName = urlMatch[1];
229
+ }
230
+ catch { /* use directory name */ }
231
+ repositories.push({
232
+ name: repoName,
233
+ directoryName: entry,
234
+ owner,
235
+ clonedAt: new Date().toISOString(),
236
+ cloneUrl,
237
+ status: 'success',
238
+ });
239
+ }
240
+ catch { /* not accessible or not a git repo - skip */ }
241
+ }
242
+ if (repositories.length === 0)
243
+ return null;
244
+ return {
245
+ workspaceName,
246
+ createdAt: new Date().toISOString(),
247
+ lastModified: new Date().toISOString(),
248
+ repositories,
249
+ };
250
+ }
251
+ /**
252
+ * Insert or replace the '## Per-Repository Context' section in an existing
253
+ * workspace context file, leaving everything else (user notes, etc.) intact.
254
+ *
255
+ * Insertion order (preferred first — we want the section as early as
256
+ * possible so the LLM weights it heavily):
257
+ * 1. Before '## Common Workflows' — the new canonical position
258
+ * 2. Before '## Workspace Management' (older layouts)
259
+ * 3. Before '## AI Agent Rules' (older layouts)
260
+ * 4. Before '## Tips for Working' (older layouts)
261
+ * 5. Before '## Notes' (legacy fallback)
262
+ * 6. Before '## Saved Context' (legacy fallback)
263
+ * 7. Appended at the end (last resort)
264
+ *
265
+ * If `newSection` is null the existing section (if any) is removed so that
266
+ * a workspace that previously had per-repo context but no longer does gets
267
+ * cleaned up.
268
+ */
269
+ function upsertPerRepoSection(content, newSection) {
270
+ // Match the section *including* its leading blank line(s) so removal
271
+ // leaves a clean join with no leftover blank lines. No 'm' flag so '$'
272
+ // only matches the true end-of-string.
273
+ const sectionRegex = /\n{1,2}## Per-Repository Context\b[\s\S]*?(?=\n## |\n#{1,2} |$)/;
274
+ // Only trimEnd() the very end of the file — never touch the body.
275
+ const base = content.replace(sectionRegex, '').trimEnd();
276
+ if (!newSection)
277
+ return base + '\n'; // section removed, nothing to add back
278
+ const block = `\n\n${newSection.trim()}\n`;
279
+ // Try anchors in order of preference — earliest first so per-repo rules
280
+ // are read by the LLM before generic boilerplate.
281
+ const anchors = [
282
+ '\n## Common Workflows',
283
+ '\n## Workspace Management',
284
+ '\n## AI Agent Rules',
285
+ '\n## Tips for Working',
286
+ '\n## Notes',
287
+ '\n## Saved Context',
288
+ ];
289
+ for (const anchor of anchors) {
290
+ if (base.includes(anchor)) {
291
+ return base.replace(anchor, `${block}${anchor}`);
292
+ }
293
+ }
294
+ // Append (last resort)
295
+ return base + block;
296
+ }
@@ -0,0 +1,217 @@
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
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.registerRemoveRepoCommand = registerRemoveRepoCommand;
40
+ const fs = __importStar(require("fs/promises"));
41
+ const path = __importStar(require("path"));
42
+ const config_1 = require("../utils/config");
43
+ const workspace_meta_1 = require("../utils/workspace-meta");
44
+ const claude_integration_1 = require("../utils/claude-integration");
45
+ const logger_1 = require("../utils/logger");
46
+ const colors_1 = require("../utils/colors");
47
+ const inquirer_1 = __importDefault(require("inquirer"));
48
+ const inquirer_autocomplete_prompt_1 = __importDefault(require("inquirer-autocomplete-prompt"));
49
+ const fuzzy = __importStar(require("fuzzy"));
50
+ const command_helpers_1 = require("../utils/command-helpers");
51
+ inquirer_1.default.registerPrompt('autocomplete', inquirer_autocomplete_prompt_1.default);
52
+ function registerRemoveRepoCommand(parent) {
53
+ parent
54
+ .command('remove-repo')
55
+ .alias('rr')
56
+ .description('Remove a repo from a workspace')
57
+ .option('-w, --workspace <name>', 'Workspace name')
58
+ .option('-r, --repos <repos>', 'Comma-separated repository directory names')
59
+ .action(async (opts, cmd) => {
60
+ const globalOpts = (0, command_helpers_1.getGlobalOpts)(cmd);
61
+ await handleRemoveRepo({ ...opts, ...globalOpts });
62
+ });
63
+ }
64
+ async function handleRemoveRepo(opts) {
65
+ console.log('\n' + '='.repeat(60));
66
+ console.log((0, colors_1.colorize)('Remove Repository Instances', 'bright'));
67
+ console.log('='.repeat(60) + '\n');
68
+ try {
69
+ (0, logger_1.logStep)(1, 4, 'Select workspace...');
70
+ const workspaceName = await (0, command_helpers_1.resolveWorkspace)(opts.workspace);
71
+ const workspacePath = path.join(config_1.WORKSPACES_DIR, workspaceName);
72
+ (0, logger_1.logInfo)(`Selected workspace: ${(0, colors_1.colorize)(workspaceName, 'cyan')}`);
73
+ (0, logger_1.logStep)(2, 4, 'Loading repository instances...');
74
+ const metadata = await (0, workspace_meta_1.loadMetadata)(workspacePath);
75
+ const successRepos = metadata?.repositories.filter(r => r.status === 'success') ?? [];
76
+ const entries = await fs.readdir(workspacePath, { withFileTypes: true });
77
+ const diskDirs = entries
78
+ .filter(e => e.isDirectory() && !e.name.startsWith('.'))
79
+ .map(e => e.name);
80
+ const metaDirNames = new Set(successRepos.map(r => r.directoryName));
81
+ const repoEntries = [];
82
+ for (const repo of successRepos) {
83
+ repoEntries.push({
84
+ displayName: repo.directoryName !== repo.name
85
+ ? `${repo.directoryName} (${repo.name})`
86
+ : repo.directoryName,
87
+ dirName: repo.directoryName,
88
+ });
89
+ }
90
+ for (const dir of diskDirs) {
91
+ if (!metaDirNames.has(dir)) {
92
+ repoEntries.push({ displayName: `${dir} (untracked)`, dirName: dir });
93
+ }
94
+ }
95
+ if (repoEntries.length === 0) {
96
+ (0, logger_1.logInfo)('No repositories found in this workspace.');
97
+ if (opts.yes) {
98
+ await fs.rm(workspacePath, { recursive: true, force: true });
99
+ (0, logger_1.logSuccess)(`Workspace "${workspaceName}" deleted.`);
100
+ }
101
+ else {
102
+ const { deleteWorkspace } = await inquirer_1.default.prompt([{
103
+ type: 'confirm', name: 'deleteWorkspace',
104
+ message: `Delete the entire workspace folder "${workspaceName}"?`, default: false,
105
+ }]);
106
+ if (deleteWorkspace) {
107
+ await fs.rm(workspacePath, { recursive: true, force: true });
108
+ (0, logger_1.logSuccess)(`Workspace "${workspaceName}" deleted.`);
109
+ }
110
+ else {
111
+ (0, logger_1.logInfo)('No action taken.');
112
+ }
113
+ }
114
+ process.exit(0);
115
+ }
116
+ (0, logger_1.logStep)(3, 4, 'Select instances to remove...');
117
+ let selectedDirs;
118
+ if (opts.repos) {
119
+ selectedDirs = (0, command_helpers_1.parseList)(opts.repos);
120
+ const unknownDirs = selectedDirs.filter(d => !repoEntries.some(e => e.dirName === d));
121
+ if (unknownDirs.length > 0) {
122
+ (0, logger_1.logError)(`Directories not found in workspace: ${unknownDirs.join(', ')}`);
123
+ process.exit(1);
124
+ }
125
+ }
126
+ else {
127
+ console.log('\n' + (0, colors_1.colorize)('Repository Selection', 'bright'));
128
+ console.log('Type to search repositories. Use arrow keys to navigate, Enter to select.');
129
+ console.log('Type "done" when finished selecting.\n');
130
+ selectedDirs = [];
131
+ while (true) {
132
+ const available = repoEntries.filter(e => !selectedDirs.includes(e.dirName));
133
+ if (available.length === 0) {
134
+ console.log((0, colors_1.colorize)('All repositories selected.', 'yellow'));
135
+ break;
136
+ }
137
+ try {
138
+ const { repoDir } = await inquirer_1.default.prompt([{
139
+ type: 'autocomplete', name: 'repoDir',
140
+ message: `Search and select repository (${(0, colors_1.colorize)(String(selectedDirs.length), 'cyan')} selected):`,
141
+ source: async (_answersSoFar, input) => {
142
+ const searchInput = input || '';
143
+ const doneOption = { name: (0, colors_1.colorize)('done - Finish selection', 'green'), value: 'done' };
144
+ if (!searchInput || searchInput.toLowerCase().startsWith('done')) {
145
+ return [doneOption, ...available.map(e => ({ name: e.displayName, value: e.dirName }))];
146
+ }
147
+ const results = fuzzy.filter(searchInput, available, { extract: (e) => e.displayName });
148
+ return [doneOption, ...results.map(result => ({ name: result.original.displayName, value: result.original.dirName }))];
149
+ },
150
+ pageSize: 16,
151
+ }]);
152
+ if (repoDir === 'done') {
153
+ if (selectedDirs.length === 0) {
154
+ console.log((0, colors_1.colorize)('\nYou must select at least one repository\n', 'yellow'));
155
+ continue;
156
+ }
157
+ break;
158
+ }
159
+ selectedDirs.push(repoDir);
160
+ const entry = repoEntries.find(e => e.dirName === repoDir);
161
+ console.log((0, colors_1.colorize)(`Added: ${entry?.displayName || repoDir}`, 'green'));
162
+ }
163
+ catch {
164
+ console.log('\n');
165
+ process.exit(0);
166
+ }
167
+ }
168
+ }
169
+ console.log(`\n${(0, colors_1.colorize)(`Selected ${selectedDirs.length} repository instance${selectedDirs.length === 1 ? '' : 's'}:`, 'cyan')}`);
170
+ selectedDirs.forEach(dir => console.log(` - ${dir}`));
171
+ console.log('');
172
+ if (!opts.yes) {
173
+ const { confirm } = await inquirer_1.default.prompt([{
174
+ type: 'confirm', name: 'confirm',
175
+ message: `Remove ${selectedDirs.length} instance(s)? This will delete the directories.`, default: false,
176
+ }]);
177
+ if (!confirm) {
178
+ (0, logger_1.logInfo)('Removal cancelled');
179
+ process.exit(0);
180
+ }
181
+ }
182
+ (0, logger_1.logStep)(4, 4, 'Removing instances...');
183
+ for (const dirName of selectedDirs) {
184
+ const dirPath = path.join(workspacePath, dirName);
185
+ try {
186
+ await fs.rm(dirPath, { recursive: true, force: true });
187
+ (0, logger_1.logSuccess)(`Removed: ${dirName}`);
188
+ }
189
+ catch (error) {
190
+ (0, logger_1.logError)(`Failed to remove ${dirName}: ${error instanceof Error ? error.message : 'Unknown error'}`);
191
+ }
192
+ }
193
+ const removedSet = new Set(selectedDirs);
194
+ if (metadata) {
195
+ metadata.repositories = metadata.repositories.filter(r => !removedSet.has(r.directoryName));
196
+ await (0, workspace_meta_1.saveMetadata)(workspacePath, metadata);
197
+ const remainingRepos = metadata.repositories
198
+ .filter(r => r.status === 'success')
199
+ .map(r => ({
200
+ name: r.name, url: '', sshUrl: r.cloneUrl,
201
+ owner: { login: r.owner }, description: '', isPrivate: true,
202
+ }));
203
+ if (remainingRepos.length > 0) {
204
+ await (0, claude_integration_1.generateClaudeContext)(workspacePath, workspaceName, remainingRepos, metadata);
205
+ }
206
+ console.log(`\nWorkspace now has ${(0, colors_1.colorize)(String(metadata.repositories.length), 'cyan')} repositories\n`);
207
+ }
208
+ (0, logger_1.logSuccess)('Repository instances removed successfully!');
209
+ }
210
+ catch (error) {
211
+ (0, logger_1.logError)('Failed to remove repository instances');
212
+ if (error instanceof Error) {
213
+ (0, logger_1.logError)(error.message);
214
+ }
215
+ process.exit(1);
216
+ }
217
+ }
@@ -0,0 +1,112 @@
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.registerReportBugCommand = registerReportBugCommand;
37
+ const fs = __importStar(require("fs"));
38
+ const path = __importStar(require("path"));
39
+ const logger_1 = require("../utils/logger");
40
+ const colors_1 = require("../utils/colors");
41
+ const bug_report_1 = require("../utils/bug-report");
42
+ function getVersion() {
43
+ try {
44
+ const pkg = JSON.parse(fs.readFileSync(path.join(__dirname, '..', '..', 'package.json'), 'utf-8'));
45
+ return pkg.version ?? 'unknown';
46
+ }
47
+ catch {
48
+ return 'unknown';
49
+ }
50
+ }
51
+ function registerReportBugCommand(parent) {
52
+ parent
53
+ .command('report-bug')
54
+ .description('File the last error (or a custom message) as a GitHub issue')
55
+ .option('-m, --message <message>', 'Report a custom message instead of the last captured error')
56
+ .option('-f, --force', 'Report even if the error looks environmental (network/auth)')
57
+ .action(async (opts) => {
58
+ await handleReportBug(opts);
59
+ });
60
+ }
61
+ async function handleReportBug(opts) {
62
+ let captured;
63
+ if (opts.message) {
64
+ captured = {
65
+ command: 'w report-bug (manual)',
66
+ message: opts.message,
67
+ timestamp: new Date().toISOString(),
68
+ version: getVersion(),
69
+ };
70
+ }
71
+ else {
72
+ captured = (0, bug_report_1.readLastError)();
73
+ if (!captured) {
74
+ (0, logger_1.logError)('No recent error to report.');
75
+ (0, logger_1.logInfo)('Run a command that fails first, or use: w report-bug -m "describe the bug"');
76
+ process.exit(1);
77
+ return;
78
+ }
79
+ // Show which error we're about to report (with its age). Some failures
80
+ // — notably `nemus -- <prompt>` — exit without updating last-error.json, so
81
+ // the most recent capture could be an older crash. Surfacing the
82
+ // timestamp lets the user catch a stale report before filing.
83
+ const ageMs = Date.now() - new Date(captured.timestamp).getTime();
84
+ const ageMin = Math.floor(ageMs / 60000);
85
+ const when = Number.isFinite(ageMin)
86
+ ? (ageMin < 1 ? 'just now' : `${ageMin} min ago`)
87
+ : 'unknown time';
88
+ (0, logger_1.logInfo)(`Last captured error (${when}): ${(0, colors_1.colorize)(captured.command, 'cyan')}`);
89
+ (0, logger_1.logInfo)(` ${captured.message.split('\n')[0].slice(0, 100)}`);
90
+ if (ageMin >= 10) {
91
+ (0, logger_1.logWarning)(`This error is ${ageMin} min old — make sure it's the one you mean to report.`);
92
+ (0, logger_1.logInfo)('Tip: pass -m "..." to report a specific message instead.');
93
+ }
94
+ }
95
+ (0, logger_1.logInfo)(`Reporting to ${(0, colors_1.colorize)(bug_report_1.BUG_REPORT_REPO, 'cyan')}...`);
96
+ const result = (0, bug_report_1.reportBug)(captured, getVersion(), { force: opts.force });
97
+ switch (result.status) {
98
+ case 'created':
99
+ (0, logger_1.logSuccess)(`Bug issue created: ${(0, colors_1.colorize)(result.url, 'cyan')}`);
100
+ break;
101
+ case 'duplicate':
102
+ (0, logger_1.logInfo)(`This error was already reported: ${(0, colors_1.colorize)(result.url, 'cyan')}`);
103
+ (0, logger_1.logInfo)('Subscribe there for updates — no duplicate filed.');
104
+ break;
105
+ case 'skipped':
106
+ (0, logger_1.logWarning)(result.reason || 'Skipped.');
107
+ break;
108
+ case 'failed':
109
+ (0, logger_1.logError)(result.reason || 'Failed to file the bug report.');
110
+ process.exit(1);
111
+ }
112
+ }