recoder-code 2.5.2 → 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 (44) 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/workflowCommands.d.ts +16 -0
  38. package/dist/src/ui/commands/workflowCommands.js +291 -0
  39. package/dist/src/ui/commands/workspaceCommand.d.ts +11 -0
  40. package/dist/src/ui/commands/workspaceCommand.js +329 -0
  41. package/dist/src/zed-integration/schema.d.ts +30 -30
  42. package/package.json +29 -10
  43. package/src/postinstall.cjs +3 -2
  44. package/dist/tsconfig.tsbuildinfo +0 -1
@@ -0,0 +1,203 @@
1
+ /**
2
+ * 'recoder web pull' command
3
+ * Pull web project files to local directory
4
+ */
5
+ import path from 'node:path';
6
+ import fs from 'node:fs/promises';
7
+ import { RecoderWebService } from '../../services/RecoderWebService.js';
8
+ import { RecoderAuthService } from '../../services/RecoderAuthService.js';
9
+ const DOCKER_BACKEND_URL = process.env['RECODER_DOCKER_URL'] || 'https://docker.recoder.xyz';
10
+ export const pullCommand = {
11
+ command: 'pull [urlId]',
12
+ describe: 'Pull web project files to local directory',
13
+ builder: (yargs) => yargs
14
+ .positional('urlId', {
15
+ type: 'string',
16
+ description: 'Project URL ID (optional, will read from .recoder-web if present)',
17
+ })
18
+ .option('directory', {
19
+ type: 'string',
20
+ alias: 'd',
21
+ description: 'Directory to pull to (defaults to current directory)',
22
+ default: process.cwd(),
23
+ })
24
+ .option('dry-run', {
25
+ type: 'boolean',
26
+ description: 'Show what would be pulled without actually pulling',
27
+ default: false,
28
+ })
29
+ .option('force', {
30
+ type: 'boolean',
31
+ alias: 'f',
32
+ description: 'Overwrite local files without prompting',
33
+ default: false,
34
+ }),
35
+ handler: async (argv) => {
36
+ const webService = new RecoderWebService();
37
+ const authService = new RecoderAuthService();
38
+ try {
39
+ // Check authentication
40
+ const isAuth = await authService.isAuthenticated();
41
+ if (!isAuth) {
42
+ console.error('Not authenticated');
43
+ console.log('Run: recoder auth login');
44
+ process.exit(1);
45
+ }
46
+ const targetDir = path.resolve(argv.directory || process.cwd());
47
+ let urlId = argv.urlId;
48
+ // Try to read .recoder-web metadata if no urlId provided
49
+ if (!urlId) {
50
+ try {
51
+ const metadataPath = path.join(targetDir, '.recoder-web');
52
+ const metadata = JSON.parse(await fs.readFile(metadataPath, 'utf-8'));
53
+ urlId = metadata.urlId || metadata.projectId;
54
+ console.log(`Found project ID from .recoder-web: ${urlId}`);
55
+ }
56
+ catch {
57
+ console.error('No project ID provided and no .recoder-web file found');
58
+ console.log('Usage: recoder web pull <urlId>');
59
+ console.log(' Or run from a linked directory');
60
+ process.exit(1);
61
+ }
62
+ }
63
+ console.log(`Pulling project: ${urlId}`);
64
+ console.log(`Local directory: ${targetDir}\n`);
65
+ // Get token for backend request
66
+ const token = await authService.getAccessToken();
67
+ if (!token) {
68
+ console.error('Failed to get access token');
69
+ process.exit(1);
70
+ }
71
+ // Try to pull from docker backend first (for running containers)
72
+ let remoteFiles = {};
73
+ let pullSource = 'web';
74
+ try {
75
+ console.log('Checking docker backend for running container...');
76
+ const response = await fetch(`${DOCKER_BACKEND_URL}/api/sync/${urlId}/pull`, {
77
+ headers: {
78
+ 'Authorization': `Bearer ${token}`,
79
+ },
80
+ });
81
+ if (response.ok) {
82
+ const data = await response.json();
83
+ if (data.success && data.files) {
84
+ remoteFiles = data.files;
85
+ pullSource = 'docker';
86
+ console.log(`Found running container with ${data.fileCount} files`);
87
+ }
88
+ }
89
+ }
90
+ catch {
91
+ // Docker backend not available, fall back to web API
92
+ }
93
+ // Fall back to web API if docker backend didn't work
94
+ if (Object.keys(remoteFiles).length === 0) {
95
+ console.log('Fetching from web API...');
96
+ try {
97
+ const project = await webService.getProject(urlId);
98
+ remoteFiles = project.fileSnapshot || {};
99
+ console.log(`Found ${Object.keys(remoteFiles).length} files in web snapshot`);
100
+ }
101
+ catch (error) {
102
+ console.error(`Failed to fetch project: ${error.message}`);
103
+ process.exit(1);
104
+ }
105
+ }
106
+ if (Object.keys(remoteFiles).length === 0) {
107
+ console.log('\nNo files found in project');
108
+ return;
109
+ }
110
+ // Scan local files
111
+ console.log('\nScanning local directory...');
112
+ const localFiles = await webService.scanDirectory(targetDir);
113
+ // Detect changes (from remote perspective - what needs to come down)
114
+ const changes = await webService.detectChanges(localFiles, remoteFiles);
115
+ // Files to download: files in remote but not in local, or modified
116
+ const toDownload = [...changes.deleted, ...changes.modified];
117
+ // Files to add: files in local but not in remote - we don't touch these during pull
118
+ // Files to delete: none during pull unless --force
119
+ console.log('\nPull Analysis:');
120
+ console.log('-'.repeat(60));
121
+ if (changes.deleted.length > 0) {
122
+ console.log(`\nNew files to download (${changes.deleted.length}):`);
123
+ changes.deleted.slice(0, 15).forEach((file) => console.log(` + ${file}`));
124
+ if (changes.deleted.length > 15) {
125
+ console.log(` ... and ${changes.deleted.length - 15} more`);
126
+ }
127
+ }
128
+ if (changes.modified.length > 0) {
129
+ console.log(`\nFiles to update (${changes.modified.length}):`);
130
+ changes.modified.slice(0, 15).forEach((file) => console.log(` ~ ${file}`));
131
+ if (changes.modified.length > 15) {
132
+ console.log(` ... and ${changes.modified.length - 15} more`);
133
+ }
134
+ }
135
+ if (changes.added.length > 0) {
136
+ console.log(`\nLocal-only files (${changes.added.length}):`);
137
+ changes.added.slice(0, 10).forEach((file) => console.log(` * ${file} (kept)`));
138
+ if (changes.added.length > 10) {
139
+ console.log(` ... and ${changes.added.length - 10} more`);
140
+ }
141
+ }
142
+ const hasChanges = toDownload.length > 0;
143
+ if (!hasChanges) {
144
+ console.log('\nLocal directory is up to date with remote!');
145
+ return;
146
+ }
147
+ // Dry run mode
148
+ if (argv['dry-run']) {
149
+ console.log('\nDry run mode - no files were downloaded');
150
+ console.log('Remove --dry-run to actually pull');
151
+ return;
152
+ }
153
+ // Check for conflicts if not forcing
154
+ if (!argv.force && changes.modified.length > 0) {
155
+ console.log('\nModified files will be overwritten.');
156
+ console.log('Use --force to proceed or --dry-run to see what would change.');
157
+ // In a real CLI we'd prompt, but for simplicity we'll just warn
158
+ console.log('\nProceeding with pull...');
159
+ }
160
+ // Download files
161
+ console.log('\nDownloading files...');
162
+ let downloaded = 0;
163
+ for (const filePath of toDownload) {
164
+ const content = remoteFiles[filePath];
165
+ if (content === undefined)
166
+ continue;
167
+ const fullPath = path.join(targetDir, filePath);
168
+ const fileDir = path.dirname(fullPath);
169
+ try {
170
+ await fs.mkdir(fileDir, { recursive: true });
171
+ await fs.writeFile(fullPath, content, 'utf-8');
172
+ downloaded++;
173
+ console.log(` Downloaded: ${filePath}`);
174
+ }
175
+ catch (error) {
176
+ console.error(` Failed: ${filePath} - ${error.message}`);
177
+ }
178
+ }
179
+ // Update metadata
180
+ const metadataFile = path.join(targetDir, '.recoder-web');
181
+ try {
182
+ let metadata = {};
183
+ try {
184
+ metadata = JSON.parse(await fs.readFile(metadataFile, 'utf-8'));
185
+ }
186
+ catch { /* file doesn't exist */ }
187
+ metadata.urlId = urlId;
188
+ metadata.lastPull = new Date().toISOString();
189
+ metadata.pullSource = pullSource;
190
+ metadata.webUrl = webService.getProjectUrl(urlId);
191
+ await fs.writeFile(metadataFile, JSON.stringify(metadata, null, 2), 'utf-8');
192
+ }
193
+ catch { /* ignore metadata errors */ }
194
+ console.log(`\nPull complete!`);
195
+ console.log(`Downloaded ${downloaded} files from ${pullSource}`);
196
+ console.log(`View at: ${webService.getProjectUrl(urlId)}`);
197
+ }
198
+ catch (error) {
199
+ console.error(`${error.message}`);
200
+ process.exit(1);
201
+ }
202
+ },
203
+ };
@@ -0,0 +1,10 @@
1
+ /**
2
+ * 'recoder web status' command
3
+ * Show current project link and sync status
4
+ */
5
+ import type { CommandModule } from 'yargs';
6
+ interface StatusArgs {
7
+ directory?: string;
8
+ }
9
+ export declare const statusCommand: CommandModule<{}, StatusArgs>;
10
+ export {};
@@ -0,0 +1,104 @@
1
+ /**
2
+ * 'recoder web status' command
3
+ * Show current project link and sync status
4
+ */
5
+ import path from 'node:path';
6
+ import fs from 'node:fs/promises';
7
+ import { RecoderAuthService } from '../../services/RecoderAuthService.js';
8
+ import { RecoderWebService } from '../../services/RecoderWebService.js';
9
+ export const statusCommand = {
10
+ command: 'status',
11
+ describe: 'Show project link and sync status',
12
+ builder: (yargs) => yargs.option('directory', {
13
+ type: 'string',
14
+ alias: 'd',
15
+ description: 'Directory to check (defaults to current directory)',
16
+ default: process.cwd(),
17
+ }),
18
+ handler: async (argv) => {
19
+ const authService = new RecoderAuthService();
20
+ const webService = new RecoderWebService();
21
+ try {
22
+ const targetDir = path.resolve(argv.directory || process.cwd());
23
+ // Check authentication
24
+ const isAuth = await authService.isAuthenticated();
25
+ const user = isAuth ? await authService.getUser() : null;
26
+ // Check for project link
27
+ let metadata = null;
28
+ try {
29
+ const metadataPath = path.join(targetDir, '.recoder-web');
30
+ metadata = JSON.parse(await fs.readFile(metadataPath, 'utf-8'));
31
+ }
32
+ catch { }
33
+ console.log('\n┌────────────────────────────────────────────────┐');
34
+ console.log('│ 📊 Recoder Platform Status │');
35
+ console.log('├────────────────────────────────────────────────┤');
36
+ // Auth status
37
+ if (isAuth && user) {
38
+ console.log(`│ 👤 Account: ${user.email.slice(0, 32).padEnd(32)}│`);
39
+ console.log(`│ 📋 Plan: ${user.subscription_plan.toUpperCase().padEnd(35)}│`);
40
+ }
41
+ else {
42
+ console.log('│ 👤 Account: Not logged in │');
43
+ console.log('│ 💡 Run: recoder auth login │');
44
+ }
45
+ console.log('├────────────────────────────────────────────────┤');
46
+ // Project link status
47
+ if (metadata?.urlId || metadata?.projectId) {
48
+ const projectId = metadata.urlId || metadata.projectId;
49
+ console.log(`│ 🔗 Linked: Yes │`);
50
+ console.log(`│ 📁 Project: ${projectId.slice(0, 32).padEnd(32)}│`);
51
+ if (metadata.linkedAt) {
52
+ const linkedDate = new Date(metadata.linkedAt).toLocaleDateString();
53
+ console.log(`│ 📅 Linked: ${linkedDate.padEnd(33)}│`);
54
+ }
55
+ if (metadata.lastSync) {
56
+ const syncDate = new Date(metadata.lastSync).toLocaleString();
57
+ console.log(`│ 🔄 Last sync: ${syncDate.slice(0, 30).padEnd(30)}│`);
58
+ }
59
+ console.log('├────────────────────────────────────────────────┤');
60
+ console.log(`│ 🌐 Web: ${(metadata.webUrl || '').slice(0, 36).padEnd(36)}│`);
61
+ console.log(`│ 👁️ Preview: ${(metadata.previewUrl || '').slice(0, 31).padEnd(31)}│`);
62
+ // Check for local changes
63
+ if (isAuth) {
64
+ try {
65
+ const project = await webService.getProject(projectId);
66
+ const localFiles = await webService.scanDirectory(targetDir);
67
+ const remoteFiles = project.fileSnapshot || {};
68
+ const changes = await webService.detectChanges(localFiles, remoteFiles);
69
+ const totalChanges = changes.added.length + changes.modified.length + changes.deleted.length;
70
+ console.log('├────────────────────────────────────────────────┤');
71
+ if (totalChanges === 0) {
72
+ console.log('│ ✅ Status: In sync │');
73
+ }
74
+ else {
75
+ console.log(`│ ⚠️ Status: ${totalChanges} pending changes`.padEnd(47) + '│');
76
+ if (changes.added.length > 0) {
77
+ console.log(`│ + ${changes.added.length} new files`.padEnd(44) + '│');
78
+ }
79
+ if (changes.modified.length > 0) {
80
+ console.log(`│ ~ ${changes.modified.length} modified`.padEnd(44) + '│');
81
+ }
82
+ if (changes.deleted.length > 0) {
83
+ console.log(`│ - ${changes.deleted.length} deleted`.padEnd(44) + '│');
84
+ }
85
+ }
86
+ }
87
+ catch {
88
+ console.log('├────────────────────────────────────────────────┤');
89
+ console.log('│ ⚠️ Could not fetch remote status │');
90
+ }
91
+ }
92
+ }
93
+ else {
94
+ console.log('│ 🔗 Linked: No │');
95
+ console.log('│ 💡 Run: recoder web link <projectId> │');
96
+ }
97
+ console.log('└────────────────────────────────────────────────┘\n');
98
+ }
99
+ catch (error) {
100
+ console.error(`❌ ${error.message}`);
101
+ process.exit(1);
102
+ }
103
+ },
104
+ };
@@ -0,0 +1,10 @@
1
+ /**
2
+ * 'recoder web unlink' command
3
+ * Remove link between current directory and recoder.xyz project
4
+ */
5
+ import type { CommandModule } from 'yargs';
6
+ interface UnlinkArgs {
7
+ directory?: string;
8
+ }
9
+ export declare const unlinkCommand: CommandModule<{}, UnlinkArgs>;
10
+ export {};
@@ -0,0 +1,45 @@
1
+ /**
2
+ * 'recoder web unlink' command
3
+ * Remove link between current directory and recoder.xyz project
4
+ */
5
+ import path from 'node:path';
6
+ import fs from 'node:fs/promises';
7
+ export const unlinkCommand = {
8
+ command: 'unlink',
9
+ describe: 'Remove link to recoder.xyz project',
10
+ builder: (yargs) => yargs.option('directory', {
11
+ type: 'string',
12
+ alias: 'd',
13
+ description: 'Directory to unlink (defaults to current directory)',
14
+ default: process.cwd(),
15
+ }),
16
+ handler: async (argv) => {
17
+ try {
18
+ const targetDir = path.resolve(argv.directory || process.cwd());
19
+ const metadataFile = path.join(targetDir, '.recoder-web');
20
+ try {
21
+ await fs.access(metadataFile);
22
+ }
23
+ catch {
24
+ console.log('📂 No project link found in this directory');
25
+ return;
26
+ }
27
+ // Read metadata before deleting
28
+ let projectId = 'unknown';
29
+ try {
30
+ const metadata = JSON.parse(await fs.readFile(metadataFile, 'utf-8'));
31
+ projectId = metadata.urlId || metadata.projectId || 'unknown';
32
+ }
33
+ catch { }
34
+ await fs.unlink(metadataFile);
35
+ console.log('✅ Project unlinked successfully');
36
+ console.log(`📁 Directory: ${targetDir}`);
37
+ console.log(`🔗 Was linked to: ${projectId}`);
38
+ console.log('\n💡 Run "recoder web link <projectId>" to link again');
39
+ }
40
+ catch (error) {
41
+ console.error(`❌ ${error.message}`);
42
+ process.exit(1);
43
+ }
44
+ },
45
+ };
@@ -0,0 +1,14 @@
1
+ /**
2
+ * 'recoder web watch' command
3
+ * Live sync - watch for local changes and sync to web in real-time
4
+ */
5
+ import type { CommandModule } from 'yargs';
6
+ interface WatchArgs {
7
+ urlId?: string;
8
+ directory?: string;
9
+ 'push-only'?: boolean;
10
+ 'pull-only'?: boolean;
11
+ interval?: number;
12
+ }
13
+ export declare const watchCommand: CommandModule<{}, WatchArgs>;
14
+ export {};