recoder-code 2.5.1 โ†’ 2.5.3

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 (45) hide show
  1. package/dist/index.js +0 -0
  2. package/dist/src/commands/context/index.js +2 -2
  3. package/dist/src/commands/mcp/marketplace.d.ts +6 -0
  4. package/dist/src/commands/mcp/marketplace.js +448 -0
  5. package/dist/src/commands/mcp.js +2 -0
  6. package/dist/src/commands/parallel.d.ts +20 -0
  7. package/dist/src/commands/parallel.js +133 -0
  8. package/dist/src/commands/recoderWeb.js +184 -5
  9. package/dist/src/commands/web/diff.d.ts +13 -0
  10. package/dist/src/commands/web/diff.js +235 -0
  11. package/dist/src/commands/web/link.d.ts +11 -0
  12. package/dist/src/commands/web/link.js +96 -0
  13. package/dist/src/commands/web/pull.d.ts +13 -0
  14. package/dist/src/commands/web/pull.js +203 -0
  15. package/dist/src/commands/web/status.d.ts +10 -0
  16. package/dist/src/commands/web/status.js +104 -0
  17. package/dist/src/commands/web/unlink.d.ts +10 -0
  18. package/dist/src/commands/web/unlink.js +45 -0
  19. package/dist/src/commands/web/watch.d.ts +14 -0
  20. package/dist/src/commands/web/watch.js +360 -0
  21. package/dist/src/commands/web.js +12 -0
  22. package/dist/src/config/config.js +6 -2
  23. package/dist/src/config/defaultMcpServers.d.ts +1 -0
  24. package/dist/src/config/defaultMcpServers.js +46 -0
  25. package/dist/src/gemini.js +10 -0
  26. package/dist/src/parallel/git-utils.d.ts +42 -0
  27. package/dist/src/parallel/git-utils.js +161 -0
  28. package/dist/src/parallel/index.d.ts +14 -0
  29. package/dist/src/parallel/index.js +14 -0
  30. package/dist/src/parallel/parallel-mode.d.ts +48 -0
  31. package/dist/src/parallel/parallel-mode.js +224 -0
  32. package/dist/src/services/AgentBridgeService.d.ts +61 -0
  33. package/dist/src/services/AgentBridgeService.js +253 -0
  34. package/dist/src/services/BuiltinCommandLoader.js +7 -0
  35. package/dist/src/services/PlatformSyncService.d.ts +154 -0
  36. package/dist/src/services/PlatformSyncService.js +588 -0
  37. package/dist/src/ui/commands/docsCommand.js +1 -1
  38. package/dist/src/ui/commands/workflowCommands.d.ts +16 -0
  39. package/dist/src/ui/commands/workflowCommands.js +291 -0
  40. package/dist/src/ui/commands/workspaceCommand.d.ts +11 -0
  41. package/dist/src/ui/commands/workspaceCommand.js +329 -0
  42. package/dist/src/zed-integration/schema.d.ts +30 -30
  43. package/package.json +33 -10
  44. package/src/postinstall.cjs +3 -2
  45. package/dist/tsconfig.tsbuildinfo +0 -1
package/dist/index.js CHANGED
File without changes
@@ -3,8 +3,8 @@
3
3
  * Manage .recoder/ project context
4
4
  */
5
5
  import { Command } from 'commander';
6
- import { createContextInitCommand } from './init';
7
- import { createContextEditCommand } from './edit';
6
+ import { createContextInitCommand } from './init.js';
7
+ import { createContextEditCommand } from './edit.js';
8
8
  export function createContextCommand() {
9
9
  const command = new Command('context')
10
10
  .description('Manage .recoder/ project context directory')
@@ -0,0 +1,6 @@
1
+ /**
2
+ * MCP Marketplace Command
3
+ * Browse and install MCP servers from curated catalog
4
+ */
5
+ import type { CommandModule } from 'yargs';
6
+ export declare const marketplaceCommand: CommandModule;
@@ -0,0 +1,448 @@
1
+ /**
2
+ * MCP Marketplace Command
3
+ * Browse and install MCP servers from curated catalog
4
+ */
5
+ import { loadSettings, SettingScope } from '../../config/settings.js';
6
+ import * as readline from 'readline';
7
+ // Curated catalog of popular MCP servers
8
+ const MARKETPLACE_CATALOG = [
9
+ // Featured
10
+ {
11
+ id: 'filesystem',
12
+ name: 'Filesystem',
13
+ description: 'Read, write, and manage files and directories',
14
+ category: 'filesystem',
15
+ author: 'Anthropic',
16
+ verified: true,
17
+ featured: true,
18
+ toolCount: 14,
19
+ installCommand: {
20
+ type: 'npx',
21
+ command: '-y @modelcontextprotocol/server-filesystem',
22
+ args: ['/workspace'],
23
+ },
24
+ tags: ['files', 'read', 'write'],
25
+ },
26
+ {
27
+ id: 'github',
28
+ name: 'GitHub',
29
+ description: 'Interact with GitHub repos, issues, and PRs',
30
+ category: 'git',
31
+ author: 'Anthropic',
32
+ verified: true,
33
+ featured: true,
34
+ toolCount: 26,
35
+ installCommand: {
36
+ type: 'npx',
37
+ command: '-y @modelcontextprotocol/server-github',
38
+ envRequired: ['GITHUB_PERSONAL_ACCESS_TOKEN'],
39
+ },
40
+ tags: ['github', 'git', 'repos'],
41
+ },
42
+ {
43
+ id: 'puppeteer',
44
+ name: 'Puppeteer',
45
+ description: 'Browser automation with Chrome',
46
+ category: 'browser',
47
+ author: 'Anthropic',
48
+ verified: true,
49
+ featured: true,
50
+ toolCount: 7,
51
+ installCommand: {
52
+ type: 'npx',
53
+ command: '-y @modelcontextprotocol/server-puppeteer',
54
+ },
55
+ tags: ['browser', 'automation'],
56
+ },
57
+ {
58
+ id: 'brave-search',
59
+ name: 'Brave Search',
60
+ description: 'Web search using Brave Search API',
61
+ category: 'search',
62
+ author: 'Anthropic',
63
+ verified: true,
64
+ featured: true,
65
+ toolCount: 2,
66
+ installCommand: {
67
+ type: 'npx',
68
+ command: '-y @modelcontextprotocol/server-brave-search',
69
+ envRequired: ['BRAVE_API_KEY'],
70
+ },
71
+ tags: ['search', 'web'],
72
+ },
73
+ // Database
74
+ {
75
+ id: 'postgres',
76
+ name: 'PostgreSQL',
77
+ description: 'Query and manage PostgreSQL databases',
78
+ category: 'database',
79
+ author: 'Anthropic',
80
+ verified: true,
81
+ featured: false,
82
+ toolCount: 5,
83
+ installCommand: {
84
+ type: 'npx',
85
+ command: '-y @modelcontextprotocol/server-postgres',
86
+ envRequired: ['POSTGRES_CONNECTION_STRING'],
87
+ },
88
+ tags: ['database', 'postgres', 'sql'],
89
+ },
90
+ {
91
+ id: 'sqlite',
92
+ name: 'SQLite',
93
+ description: 'Local SQLite database operations',
94
+ category: 'database',
95
+ author: 'Anthropic',
96
+ verified: true,
97
+ featured: false,
98
+ toolCount: 4,
99
+ installCommand: {
100
+ type: 'npx',
101
+ command: '-y @modelcontextprotocol/server-sqlite',
102
+ args: ['--db-path', './database.db'],
103
+ },
104
+ tags: ['database', 'sqlite'],
105
+ },
106
+ {
107
+ id: 'supabase',
108
+ name: 'Supabase',
109
+ description: 'Supabase database, auth, and storage',
110
+ category: 'database',
111
+ author: 'supabase',
112
+ verified: true,
113
+ featured: false,
114
+ toolCount: 15,
115
+ installCommand: {
116
+ type: 'npx',
117
+ command: '-y supabase-mcp-server',
118
+ envRequired: ['SUPABASE_URL', 'SUPABASE_SERVICE_KEY'],
119
+ },
120
+ tags: ['database', 'supabase'],
121
+ },
122
+ // AI & Tools
123
+ {
124
+ id: 'sequential-thinking',
125
+ name: 'Sequential Thinking',
126
+ description: 'Dynamic problem-solving through thought sequences',
127
+ category: 'ai',
128
+ author: 'Anthropic',
129
+ verified: true,
130
+ featured: false,
131
+ toolCount: 1,
132
+ installCommand: {
133
+ type: 'npx',
134
+ command: '-y @modelcontextprotocol/server-sequential-thinking',
135
+ },
136
+ tags: ['thinking', 'reasoning'],
137
+ },
138
+ {
139
+ id: 'memory',
140
+ name: 'Memory',
141
+ description: 'Persistent memory using knowledge graph',
142
+ category: 'ai',
143
+ author: 'Anthropic',
144
+ verified: true,
145
+ featured: false,
146
+ toolCount: 9,
147
+ installCommand: {
148
+ type: 'npx',
149
+ command: '-y @modelcontextprotocol/server-memory',
150
+ },
151
+ tags: ['memory', 'knowledge-graph'],
152
+ },
153
+ // Git
154
+ {
155
+ id: 'git',
156
+ name: 'Git',
157
+ description: 'Local git repository operations',
158
+ category: 'git',
159
+ author: 'Anthropic',
160
+ verified: true,
161
+ featured: false,
162
+ toolCount: 8,
163
+ installCommand: {
164
+ type: 'uvx',
165
+ command: 'mcp-server-git',
166
+ args: ['--repository', '.'],
167
+ },
168
+ tags: ['git', 'version-control'],
169
+ },
170
+ // Productivity
171
+ {
172
+ id: 'slack',
173
+ name: 'Slack',
174
+ description: 'Read and send Slack messages',
175
+ category: 'communication',
176
+ author: 'Anthropic',
177
+ verified: true,
178
+ featured: false,
179
+ toolCount: 6,
180
+ installCommand: {
181
+ type: 'npx',
182
+ command: '-y @modelcontextprotocol/server-slack',
183
+ envRequired: ['SLACK_BOT_TOKEN', 'SLACK_TEAM_ID'],
184
+ },
185
+ tags: ['slack', 'messaging'],
186
+ },
187
+ {
188
+ id: 'notion',
189
+ name: 'Notion',
190
+ description: 'Read and write Notion pages and databases',
191
+ category: 'productivity',
192
+ author: 'notion',
193
+ verified: true,
194
+ featured: false,
195
+ toolCount: 8,
196
+ installCommand: {
197
+ type: 'npx',
198
+ command: '-y @notionhq/notion-mcp-server',
199
+ envRequired: ['NOTION_API_KEY'],
200
+ },
201
+ tags: ['notion', 'notes'],
202
+ },
203
+ // Other
204
+ {
205
+ id: 'fetch',
206
+ name: 'Fetch',
207
+ description: 'Make HTTP requests and fetch web content',
208
+ category: 'other',
209
+ author: 'Anthropic',
210
+ verified: true,
211
+ featured: false,
212
+ toolCount: 2,
213
+ installCommand: {
214
+ type: 'npx',
215
+ command: '-y @modelcontextprotocol/server-fetch',
216
+ },
217
+ tags: ['http', 'fetch', 'api'],
218
+ },
219
+ {
220
+ id: 'time',
221
+ name: 'Time',
222
+ description: 'Get current time in any timezone',
223
+ category: 'other',
224
+ author: 'Anthropic',
225
+ verified: true,
226
+ featured: false,
227
+ toolCount: 2,
228
+ installCommand: {
229
+ type: 'npx',
230
+ command: '-y @modelcontextprotocol/server-time',
231
+ },
232
+ tags: ['time', 'timezone'],
233
+ },
234
+ ];
235
+ const CATEGORY_LABELS = {
236
+ browser: 'Browser',
237
+ database: 'Database',
238
+ devtools: 'DevTools',
239
+ filesystem: 'Filesystem',
240
+ git: 'Git & VCS',
241
+ search: 'Search',
242
+ cloud: 'Cloud',
243
+ productivity: 'Productivity',
244
+ ai: 'AI & ML',
245
+ communication: 'Communication',
246
+ other: 'Other',
247
+ };
248
+ function prompt(question) {
249
+ const rl = readline.createInterface({
250
+ input: process.stdin,
251
+ output: process.stdout,
252
+ });
253
+ return new Promise((resolve) => {
254
+ rl.question(question, (answer) => {
255
+ rl.close();
256
+ resolve(answer);
257
+ });
258
+ });
259
+ }
260
+ async function listMarketplace(category, search) {
261
+ let servers = MARKETPLACE_CATALOG;
262
+ if (category) {
263
+ servers = servers.filter((s) => s.category === category);
264
+ }
265
+ if (search) {
266
+ const q = search.toLowerCase();
267
+ servers = servers.filter((s) => s.name.toLowerCase().includes(q) ||
268
+ s.description.toLowerCase().includes(q) ||
269
+ s.tags.some((t) => t.includes(q)));
270
+ }
271
+ if (servers.length === 0) {
272
+ console.log('No servers found matching your criteria.');
273
+ return;
274
+ }
275
+ console.log('\n๐Ÿ“ฆ MCP Server Marketplace\n');
276
+ console.log('โ”€'.repeat(60));
277
+ // Group by category
278
+ const grouped = new Map();
279
+ for (const server of servers) {
280
+ const list = grouped.get(server.category) || [];
281
+ list.push(server);
282
+ grouped.set(server.category, list);
283
+ }
284
+ for (const [cat, catServers] of grouped) {
285
+ console.log(`\n${CATEGORY_LABELS[cat]}:`);
286
+ for (const server of catServers) {
287
+ const verified = server.verified ? 'โœ“' : ' ';
288
+ const featured = server.featured ? 'โ˜…' : ' ';
289
+ console.log(` ${featured}${verified} ${server.id.padEnd(20)} ${server.name.padEnd(18)} (${server.toolCount} tools)`);
290
+ console.log(` ${server.description}`);
291
+ }
292
+ }
293
+ console.log('\nโ”€'.repeat(60));
294
+ console.log('โ˜… = Featured โœ“ = Verified\n');
295
+ console.log('Install with: recoder mcp marketplace install <id>');
296
+ console.log('Categories: ' + Object.keys(CATEGORY_LABELS).join(', '));
297
+ }
298
+ async function installFromMarketplace(serverId, scope, envValues) {
299
+ const server = MARKETPLACE_CATALOG.find((s) => s.id === serverId);
300
+ if (!server) {
301
+ console.error(`Server "${serverId}" not found in marketplace.`);
302
+ console.log('\nAvailable servers:');
303
+ MARKETPLACE_CATALOG.forEach((s) => console.log(` - ${s.id}: ${s.name}`));
304
+ return;
305
+ }
306
+ // Parse env values from command line
307
+ const envMap = {};
308
+ for (const env of envValues) {
309
+ const [key, ...valueParts] = env.split('=');
310
+ if (key && valueParts.length > 0) {
311
+ envMap[key] = valueParts.join('=');
312
+ }
313
+ }
314
+ // Check for required env vars
315
+ const missingEnv = server.installCommand.envRequired?.filter((key) => !envMap[key] && !process.env[key]);
316
+ if (missingEnv && missingEnv.length > 0) {
317
+ console.log(`\n${server.name} requires the following environment variables:\n`);
318
+ for (const key of missingEnv) {
319
+ const value = await prompt(` ${key}: `);
320
+ if (value) {
321
+ envMap[key] = value;
322
+ }
323
+ }
324
+ // Check again
325
+ const stillMissing = server.installCommand.envRequired?.filter((key) => !envMap[key]);
326
+ if (stillMissing && stillMissing.length > 0) {
327
+ console.error(`\nMissing required environment variables: ${stillMissing.join(', ')}`);
328
+ return;
329
+ }
330
+ }
331
+ // Build the server config
332
+ const { installCommand } = server;
333
+ let command;
334
+ let args;
335
+ switch (installCommand.type) {
336
+ case 'npx':
337
+ command = 'npx';
338
+ args = installCommand.command.split(' ').filter(Boolean);
339
+ if (installCommand.args) {
340
+ args.push(...installCommand.args);
341
+ }
342
+ break;
343
+ case 'uvx':
344
+ command = 'uvx';
345
+ args = [installCommand.command];
346
+ if (installCommand.args) {
347
+ args.push(...installCommand.args);
348
+ }
349
+ break;
350
+ default:
351
+ command = installCommand.command;
352
+ args = installCommand.args || [];
353
+ }
354
+ // Save to settings
355
+ const settingsScope = scope === 'user' ? SettingScope.User : SettingScope.Workspace;
356
+ const settings = loadSettings(process.cwd());
357
+ const newServer = {
358
+ command,
359
+ args,
360
+ env: Object.keys(envMap).length > 0 ? envMap : undefined,
361
+ description: server.description,
362
+ trust: server.verified,
363
+ };
364
+ const existingSettings = settings.forScope(settingsScope).settings;
365
+ const mcpServers = existingSettings.mcpServers || {};
366
+ if (mcpServers[serverId]) {
367
+ console.log(`Server "${serverId}" is already installed. Updating...`);
368
+ }
369
+ mcpServers[serverId] = newServer;
370
+ settings.setValue(settingsScope, 'mcpServers', mcpServers);
371
+ console.log(`\nโœ… ${server.name} installed successfully!`);
372
+ console.log(` ID: ${serverId}`);
373
+ console.log(` Command: ${command} ${args.join(' ')}`);
374
+ if (Object.keys(envMap).length > 0) {
375
+ console.log(` Environment: ${Object.keys(envMap).join(', ')}`);
376
+ }
377
+ console.log(` Scope: ${scope}`);
378
+ console.log(`\nThe server will be available on your next recoder session.`);
379
+ }
380
+ export const marketplaceCommand = {
381
+ command: 'marketplace [action]',
382
+ describe: 'Browse and install MCP servers from marketplace',
383
+ builder: (yargs) => yargs
384
+ .positional('action', {
385
+ describe: 'Action to perform',
386
+ type: 'string',
387
+ choices: ['list', 'install', 'search'],
388
+ default: 'list',
389
+ })
390
+ .option('category', {
391
+ alias: 'c',
392
+ describe: 'Filter by category',
393
+ type: 'string',
394
+ choices: Object.keys(CATEGORY_LABELS),
395
+ })
396
+ .option('search', {
397
+ alias: 'q',
398
+ describe: 'Search servers by name or tags',
399
+ type: 'string',
400
+ })
401
+ .option('id', {
402
+ describe: 'Server ID to install',
403
+ type: 'string',
404
+ })
405
+ .option('scope', {
406
+ alias: 's',
407
+ describe: 'Configuration scope',
408
+ type: 'string',
409
+ default: 'project',
410
+ choices: ['user', 'project'],
411
+ })
412
+ .option('env', {
413
+ alias: 'e',
414
+ describe: 'Environment variables (KEY=value)',
415
+ type: 'array',
416
+ string: true,
417
+ default: [],
418
+ })
419
+ .example('$0 mcp marketplace', 'List all available servers')
420
+ .example('$0 mcp marketplace --category database', 'List database servers')
421
+ .example('$0 mcp marketplace install --id github -e GITHUB_PERSONAL_ACCESS_TOKEN=ghp_xxx', 'Install GitHub server')
422
+ .example('$0 mcp marketplace search --query search', 'Search for servers'),
423
+ handler: async (argv) => {
424
+ const action = argv.action;
425
+ const category = argv.category;
426
+ const search = argv.search;
427
+ const id = argv.id;
428
+ const scope = argv.scope;
429
+ const env = argv.env;
430
+ switch (action) {
431
+ case 'install':
432
+ if (!id) {
433
+ console.error('Please specify a server ID with --id');
434
+ console.log('Example: recoder mcp marketplace install --id github');
435
+ return;
436
+ }
437
+ await installFromMarketplace(id, scope, env);
438
+ break;
439
+ case 'search':
440
+ await listMarketplace(category, search || argv._[2]?.toString());
441
+ break;
442
+ case 'list':
443
+ default:
444
+ await listMarketplace(category, search);
445
+ break;
446
+ }
447
+ },
448
+ };
@@ -7,6 +7,7 @@ import { addCommand } from './mcp/add.js';
7
7
  import { removeCommand } from './mcp/remove.js';
8
8
  import { listCommand } from './mcp/list.js';
9
9
  import { detectCommand } from './mcp/detect.js';
10
+ import { marketplaceCommand } from './mcp/marketplace.js';
10
11
  export const mcpCommand = {
11
12
  command: 'mcp',
12
13
  describe: 'Manage MCP servers',
@@ -15,6 +16,7 @@ export const mcpCommand = {
15
16
  .command(removeCommand)
16
17
  .command(listCommand)
17
18
  .command(detectCommand)
19
+ .command(marketplaceCommand)
18
20
  .demandCommand(1, 'You need at least one command before continuing.')
19
21
  .version(false),
20
22
  handler: () => {
@@ -0,0 +1,20 @@
1
+ /**
2
+ * 'recoder parallel' command
3
+ * Run tasks in parallel using git worktrees
4
+ *
5
+ * Based on Kilo Code (Apache-2.0 License)
6
+ */
7
+ import type { CommandModule } from 'yargs';
8
+ interface ParallelArgs {
9
+ prompt?: string;
10
+ 'existing-branch'?: string;
11
+ list?: boolean;
12
+ cleanup?: boolean;
13
+ }
14
+ export declare const parallelCommand: CommandModule<{}, ParallelArgs>;
15
+ interface ParallelFinishArgs {
16
+ worktree?: string;
17
+ branch?: string;
18
+ }
19
+ export declare const parallelFinishCommand: CommandModule<{}, ParallelFinishArgs>;
20
+ export {};
@@ -0,0 +1,133 @@
1
+ /**
2
+ * 'recoder parallel' command
3
+ * Run tasks in parallel using git worktrees
4
+ *
5
+ * Based on Kilo Code (Apache-2.0 License)
6
+ */
7
+ import { startParallelMode, finishParallelMode, listParallelWorktrees, cleanupStaleWorktrees, } from '../parallel/index.js';
8
+ export const parallelCommand = {
9
+ command: 'parallel [prompt]',
10
+ describe: 'Run tasks in parallel using git worktrees',
11
+ builder: (yargs) => yargs
12
+ .positional('prompt', {
13
+ type: 'string',
14
+ describe: 'Task prompt to execute in parallel mode',
15
+ })
16
+ .option('existing-branch', {
17
+ alias: 'b',
18
+ type: 'string',
19
+ describe: 'Resume work on an existing parallel branch',
20
+ })
21
+ .option('list', {
22
+ alias: 'l',
23
+ type: 'boolean',
24
+ describe: 'List active parallel mode worktrees',
25
+ })
26
+ .option('cleanup', {
27
+ alias: 'c',
28
+ type: 'boolean',
29
+ describe: 'Clean up stale parallel mode worktrees',
30
+ })
31
+ .example([
32
+ ['$0 parallel "implement user auth"', 'Start parallel task with new branch'],
33
+ ['$0 parallel -b recoder/user-auth-123 "continue work"', 'Resume existing branch'],
34
+ ['$0 parallel --list', 'List active parallel worktrees'],
35
+ ['$0 parallel --cleanup', 'Clean up stale worktrees'],
36
+ ]),
37
+ handler: async (argv) => {
38
+ const cwd = process.cwd();
39
+ // Handle list command
40
+ if (argv.list) {
41
+ console.log('\n๐Ÿ“‹ Active parallel mode worktrees:\n');
42
+ const worktrees = await listParallelWorktrees(cwd);
43
+ if (worktrees.length === 0) {
44
+ console.log(' No active parallel worktrees found.\n');
45
+ }
46
+ else {
47
+ for (const wt of worktrees) {
48
+ console.log(` ๐Ÿ“ ${wt}`);
49
+ }
50
+ console.log();
51
+ }
52
+ return;
53
+ }
54
+ // Handle cleanup command
55
+ if (argv.cleanup) {
56
+ console.log('\n๐Ÿงน Cleaning up stale parallel mode worktrees...\n');
57
+ const cleaned = await cleanupStaleWorktrees(cwd);
58
+ if (cleaned === 0) {
59
+ console.log(' No stale worktrees to clean up.\n');
60
+ }
61
+ else {
62
+ console.log(`\nโœ… Cleaned up ${cleaned} stale worktree(s).\n`);
63
+ }
64
+ return;
65
+ }
66
+ // Require prompt for starting parallel mode
67
+ if (!argv.prompt) {
68
+ console.log('\nโš ๏ธ Please provide a task prompt.\n');
69
+ console.log('Usage:');
70
+ console.log(' recoder parallel "your task description"');
71
+ console.log(' recoder parallel --existing-branch <branch> "continue task"');
72
+ console.log(' recoder parallel --list');
73
+ console.log(' recoder parallel --cleanup\n');
74
+ return;
75
+ }
76
+ try {
77
+ // Start parallel mode
78
+ const params = await startParallelMode(cwd, argv.prompt, argv['existing-branch']);
79
+ console.log('\n๐Ÿ“ You can now work in the worktree directory:');
80
+ console.log(` cd ${params.worktreePath}\n`);
81
+ console.log('๐Ÿ’ก When done, run your task and then call:');
82
+ console.log(' recoder parallel finish\n');
83
+ // Store the worktree info for later
84
+ console.log('Worktree info stored. Use "recoder parallel finish" when done.');
85
+ }
86
+ catch (error) {
87
+ const message = error instanceof Error ? error.message : String(error);
88
+ console.error(`\nโŒ Failed to start parallel mode: ${message}\n`);
89
+ process.exit(1);
90
+ }
91
+ },
92
+ };
93
+ export const parallelFinishCommand = {
94
+ command: 'parallel-finish',
95
+ describe: 'Finish parallel mode and commit changes',
96
+ builder: (yargs) => yargs
97
+ .option('worktree', {
98
+ alias: 'w',
99
+ type: 'string',
100
+ describe: 'Path to the worktree to finish',
101
+ })
102
+ .option('branch', {
103
+ alias: 'b',
104
+ type: 'string',
105
+ describe: 'Branch name of the worktree',
106
+ }),
107
+ handler: async (argv) => {
108
+ const cwd = process.cwd();
109
+ // If worktree and branch provided, use them
110
+ if (argv.worktree && argv.branch) {
111
+ try {
112
+ const result = await finishParallelMode(argv.worktree, argv.branch, cwd);
113
+ if (result.success) {
114
+ console.log(`\nโœ… ${result.message}\n`);
115
+ }
116
+ else {
117
+ console.error(`\nโŒ ${result.message}\n`);
118
+ process.exit(1);
119
+ }
120
+ }
121
+ catch (error) {
122
+ const message = error instanceof Error ? error.message : String(error);
123
+ console.error(`\nโŒ Failed to finish parallel mode: ${message}\n`);
124
+ process.exit(1);
125
+ }
126
+ return;
127
+ }
128
+ // Otherwise, try to detect from current directory
129
+ console.log('\nโš ๏ธ Please provide worktree and branch:');
130
+ console.log(' recoder parallel-finish --worktree <path> --branch <branch>\n');
131
+ console.log('Or use "recoder parallel --list" to see active worktrees.\n');
132
+ },
133
+ };