@mod-computer/cli 0.2.4 → 0.2.5

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 (74) hide show
  1. package/package.json +3 -3
  2. package/dist/app.js +0 -227
  3. package/dist/cli.bundle.js.map +0 -7
  4. package/dist/cli.js +0 -132
  5. package/dist/commands/add.js +0 -245
  6. package/dist/commands/agents-run.js +0 -71
  7. package/dist/commands/auth.js +0 -259
  8. package/dist/commands/branch.js +0 -1411
  9. package/dist/commands/claude-sync.js +0 -772
  10. package/dist/commands/comment.js +0 -568
  11. package/dist/commands/diff.js +0 -182
  12. package/dist/commands/index.js +0 -73
  13. package/dist/commands/init.js +0 -597
  14. package/dist/commands/ls.js +0 -135
  15. package/dist/commands/members.js +0 -687
  16. package/dist/commands/mv.js +0 -282
  17. package/dist/commands/recover.js +0 -207
  18. package/dist/commands/rm.js +0 -257
  19. package/dist/commands/spec.js +0 -386
  20. package/dist/commands/status.js +0 -296
  21. package/dist/commands/sync.js +0 -119
  22. package/dist/commands/trace.js +0 -1752
  23. package/dist/commands/workspace.js +0 -447
  24. package/dist/components/conflict-resolution-ui.js +0 -120
  25. package/dist/components/messages.js +0 -5
  26. package/dist/components/thread.js +0 -8
  27. package/dist/config/features.js +0 -83
  28. package/dist/containers/branches-container.js +0 -140
  29. package/dist/containers/directory-container.js +0 -92
  30. package/dist/containers/thread-container.js +0 -214
  31. package/dist/containers/threads-container.js +0 -27
  32. package/dist/containers/workspaces-container.js +0 -27
  33. package/dist/daemon/conflict-resolution.js +0 -172
  34. package/dist/daemon/content-hash.js +0 -31
  35. package/dist/daemon/file-sync.js +0 -985
  36. package/dist/daemon/index.js +0 -203
  37. package/dist/daemon/mime-types.js +0 -166
  38. package/dist/daemon/offline-queue.js +0 -211
  39. package/dist/daemon/path-utils.js +0 -64
  40. package/dist/daemon/share-policy.js +0 -83
  41. package/dist/daemon/wasm-errors.js +0 -189
  42. package/dist/daemon/worker.js +0 -557
  43. package/dist/daemon-worker.js +0 -258
  44. package/dist/errors/workspace-errors.js +0 -48
  45. package/dist/lib/auth-server.js +0 -216
  46. package/dist/lib/browser.js +0 -35
  47. package/dist/lib/diff.js +0 -284
  48. package/dist/lib/formatters.js +0 -204
  49. package/dist/lib/git.js +0 -137
  50. package/dist/lib/local-fs.js +0 -201
  51. package/dist/lib/prompts.js +0 -56
  52. package/dist/lib/storage.js +0 -213
  53. package/dist/lib/trace-formatters.js +0 -314
  54. package/dist/services/add-service.js +0 -554
  55. package/dist/services/add-validation.js +0 -124
  56. package/dist/services/automatic-file-tracker.js +0 -303
  57. package/dist/services/cli-orchestrator.js +0 -227
  58. package/dist/services/feature-flags.js +0 -187
  59. package/dist/services/file-import-service.js +0 -283
  60. package/dist/services/file-transformation-service.js +0 -218
  61. package/dist/services/logger.js +0 -44
  62. package/dist/services/mod-config.js +0 -67
  63. package/dist/services/modignore-service.js +0 -328
  64. package/dist/services/sync-daemon.js +0 -244
  65. package/dist/services/thread-notification-service.js +0 -50
  66. package/dist/services/thread-service.js +0 -147
  67. package/dist/stores/use-directory-store.js +0 -96
  68. package/dist/stores/use-threads-store.js +0 -46
  69. package/dist/stores/use-workspaces-store.js +0 -54
  70. package/dist/types/add-types.js +0 -99
  71. package/dist/types/config.js +0 -16
  72. package/dist/types/index.js +0 -2
  73. package/dist/types/workspace-connection.js +0 -53
  74. package/dist/types.js +0 -1
@@ -1,282 +0,0 @@
1
- // glassware[type="implementation", id="impl-cli-mv-cmd--7526e170", requirements="requirement-cli-mv-cmd--01f3db90,requirement-cli-mv-requires-workspace--e8eff602,requirement-cli-mv-workspace--ed3f7751,requirement-cli-mv-create-folders--62adc040,requirement-cli-mv-local--7bdf0396,requirement-cli-mv-no-overwrite--3c71bcba,requirement-cli-mv-folder--af5ef6eb"]
2
- // spec: packages/mod-cli/specs/file-directory.md
3
- import { createModWorkspace } from '@mod/mod-core';
4
- import { readWorkspaceConnection } from '../lib/storage.js';
5
- import { moveLocalFile } from '../lib/local-fs.js';
6
- import path from 'path';
7
- // glassware[type="implementation", id="impl-cli-mv-requires-workspace--35f86c8f", requirements="requirement-cli-mv-requires-workspace--e8eff602,requirement-cli-fd-error-no-workspace--1919b4fb"]
8
- function requireWorkspaceConnection() {
9
- const currentDir = process.cwd();
10
- const connection = readWorkspaceConnection(currentDir);
11
- if (!connection) {
12
- console.error('Error: Not connected to a workspace.');
13
- console.error('Run `mod init` to connect this directory first.');
14
- process.exit(1);
15
- }
16
- return {
17
- workspaceId: connection.workspaceId,
18
- workspaceName: connection.workspaceName,
19
- workspacePath: connection.path,
20
- };
21
- }
22
- function parseArgs(args) {
23
- const options = {
24
- force: false,
25
- local: false,
26
- dryRun: false,
27
- quiet: false,
28
- };
29
- const paths = [];
30
- for (let i = 0; i < args.length; i++) {
31
- const arg = args[i];
32
- if (arg === '--force' || arg === '-f') {
33
- options.force = true;
34
- }
35
- else if (arg === '--local') {
36
- options.local = true;
37
- }
38
- else if (arg === '--dry-run') {
39
- options.dryRun = true;
40
- }
41
- else if (arg === '--quiet' || arg === '-q') {
42
- options.quiet = true;
43
- }
44
- else if (!arg.startsWith('-')) {
45
- paths.push(arg);
46
- }
47
- }
48
- // Last path is destination, rest are sources
49
- const dest = paths.pop();
50
- return { sources: paths, dest, options };
51
- }
52
- export async function mvCommand(args, repo) {
53
- const { workspaceId, workspacePath } = requireWorkspaceConnection();
54
- const { sources, dest, options } = parseArgs(args);
55
- if (sources.length === 0 || !dest) {
56
- console.error('Usage: mod mv <source...> <dest>');
57
- console.error('');
58
- console.error('Options:');
59
- console.error(' --force, -f Overwrite existing files');
60
- console.error(' --local Also move local files');
61
- console.error(' --dry-run Show what would be moved');
62
- console.error(' --quiet, -q Only show errors');
63
- process.exit(1);
64
- }
65
- try {
66
- const modWorkspace = createModWorkspace(repo);
67
- const workspaceHandle = await modWorkspace.openWorkspace(workspaceId);
68
- // Get all files and folders
69
- const fileRefs = await workspaceHandle.file.list();
70
- const folderRefs = await workspaceHandle.folder.list();
71
- // Determine if destination is a folder
72
- const destIsFolder = dest.endsWith('/') ||
73
- folderRefs.some(f => f.path === dest) ||
74
- sources.length > 1;
75
- const moveOps = [];
76
- const foldersToCreate = new Set();
77
- for (const source of sources) {
78
- const normalizedSource = source.replace(/\/$/, '');
79
- // Find matching file
80
- const matchingFile = fileRefs.find(f => {
81
- const filePath = f.metadata?.path || f.name;
82
- return filePath === normalizedSource;
83
- });
84
- if (matchingFile) {
85
- // Single file move/rename
86
- const filePath = matchingFile.metadata?.path || matchingFile.name;
87
- const fileName = path.basename(filePath);
88
- let toPath;
89
- let toFolderId = null;
90
- let newName;
91
- if (destIsFolder) {
92
- // Move to folder, keep name
93
- toPath = path.join(dest.replace(/\/$/, ''), fileName);
94
- // Find or mark folder for creation
95
- const destFolder = folderRefs.find(f => f.path === dest.replace(/\/$/, ''));
96
- if (destFolder) {
97
- toFolderId = destFolder.id;
98
- }
99
- else {
100
- foldersToCreate.add(dest.replace(/\/$/, ''));
101
- }
102
- }
103
- else {
104
- // Rename
105
- toPath = dest;
106
- newName = path.basename(dest);
107
- // Determine target folder
108
- const targetDir = path.dirname(dest);
109
- if (targetDir && targetDir !== '.') {
110
- const targetFolder = folderRefs.find(f => f.path === targetDir);
111
- if (targetFolder) {
112
- toFolderId = targetFolder.id;
113
- }
114
- else {
115
- foldersToCreate.add(targetDir);
116
- }
117
- }
118
- }
119
- // Check for existing file at destination (no-overwrite check)
120
- const existingFile = fileRefs.find(f => {
121
- const fp = f.metadata?.path || f.name;
122
- return fp === toPath && f.id !== matchingFile.id;
123
- });
124
- if (existingFile && !options.force) {
125
- console.error(`Error: ${toPath} already exists. Use --force to overwrite.`);
126
- process.exit(1);
127
- }
128
- moveOps.push({
129
- fileId: matchingFile.id,
130
- fromPath: filePath,
131
- toPath,
132
- toFolderId,
133
- newName,
134
- });
135
- }
136
- else {
137
- // Check if it's a folder - move all contents
138
- const filesInFolder = fileRefs.filter(f => {
139
- const filePath = f.metadata?.path || f.name;
140
- return filePath.startsWith(normalizedSource + '/') || filePath === normalizedSource;
141
- });
142
- if (filesInFolder.length > 0) {
143
- for (const file of filesInFolder) {
144
- const filePath = file.metadata?.path || file.name;
145
- const relativePath = filePath.startsWith(normalizedSource + '/')
146
- ? filePath.slice(normalizedSource.length + 1)
147
- : path.basename(filePath);
148
- const toPath = path.join(dest.replace(/\/$/, ''), relativePath);
149
- const targetDir = path.dirname(toPath);
150
- let toFolderId = null;
151
- if (targetDir && targetDir !== '.') {
152
- const targetFolder = folderRefs.find(f => f.path === targetDir);
153
- if (targetFolder) {
154
- toFolderId = targetFolder.id;
155
- }
156
- else {
157
- foldersToCreate.add(targetDir);
158
- }
159
- }
160
- moveOps.push({
161
- fileId: file.id,
162
- fromPath: filePath,
163
- toPath,
164
- toFolderId,
165
- });
166
- }
167
- }
168
- else {
169
- console.error(`Error: File not found in workspace: ${source}`);
170
- console.error("Run `mod ls` to see workspace files.");
171
- process.exit(1);
172
- }
173
- }
174
- }
175
- if (moveOps.length === 0) {
176
- console.log('No files to move.');
177
- return;
178
- }
179
- // Dry run
180
- if (options.dryRun) {
181
- if (foldersToCreate.size > 0) {
182
- console.log('Would create folders:');
183
- for (const folder of foldersToCreate) {
184
- console.log(` ${folder}/`);
185
- }
186
- console.log('');
187
- }
188
- console.log(`Would move ${moveOps.length} file${moveOps.length === 1 ? '' : 's'}:`);
189
- for (const op of moveOps) {
190
- console.log(` ${op.fromPath} -> ${op.toPath}`);
191
- }
192
- return;
193
- }
194
- // Create folders if needed
195
- const folderIdMap = new Map();
196
- for (const folderPath of Array.from(foldersToCreate).sort()) {
197
- try {
198
- const newFolder = await workspaceHandle.folder.create(folderPath);
199
- folderIdMap.set(folderPath, newFolder.id);
200
- if (!options.quiet) {
201
- console.log(`Created folder: ${folderPath}/`);
202
- }
203
- }
204
- catch (error) {
205
- // Folder might already exist, try to find it
206
- const existing = (await workspaceHandle.folder.list()).find(f => f.path === folderPath);
207
- if (existing) {
208
- folderIdMap.set(folderPath, existing.id);
209
- }
210
- }
211
- }
212
- // Execute moves
213
- let moved = 0;
214
- let localMoved = 0;
215
- const errors = [];
216
- for (const op of moveOps) {
217
- try {
218
- // Update folder ID from created folders
219
- let targetFolderId = op.toFolderId;
220
- const targetDir = path.dirname(op.toPath);
221
- if (targetDir && targetDir !== '.' && folderIdMap.has(targetDir)) {
222
- targetFolderId = folderIdMap.get(targetDir);
223
- }
224
- // Move in workspace
225
- if (op.newName) {
226
- await workspaceHandle.file.rename(op.fileId, op.newName);
227
- }
228
- if (targetFolderId !== undefined) {
229
- await workspaceHandle.file.move(op.fileId, targetFolderId);
230
- }
231
- moved++;
232
- if (!options.quiet) {
233
- console.log(`Moved in workspace: ${op.fromPath} -> ${op.toPath}`);
234
- }
235
- // Move local file if --local flag is set
236
- if (options.local) {
237
- const localFrom = path.join(workspacePath, op.fromPath);
238
- const localTo = path.join(workspacePath, op.toPath);
239
- const result = await moveLocalFile(localFrom, localTo);
240
- if (result.success) {
241
- localMoved++;
242
- if (!options.quiet) {
243
- console.log(`Moved local file: ${op.fromPath} -> ${op.toPath}`);
244
- }
245
- }
246
- else if (result.error) {
247
- // Permission error handling
248
- console.warn(`Warning: ${result.error}`);
249
- console.warn('Workspace updated, but local file not moved.');
250
- }
251
- }
252
- }
253
- catch (error) {
254
- errors.push(`Failed to move ${op.fromPath}: ${error.message}`);
255
- }
256
- }
257
- // Summary
258
- if (!options.quiet) {
259
- console.log('');
260
- if (moveOps.length === 1) {
261
- console.log(`Moved: ${moveOps[0].fromPath} -> ${moveOps[0].toPath}`);
262
- }
263
- else {
264
- console.log(`Moved ${moved} file${moved === 1 ? '' : 's'}.`);
265
- }
266
- if (!options.local && moved > 0) {
267
- console.log('Note: Local files unchanged. Use --local to also move locally.');
268
- }
269
- }
270
- if (errors.length > 0) {
271
- console.error('');
272
- for (const error of errors) {
273
- console.error(error);
274
- }
275
- process.exit(1);
276
- }
277
- }
278
- catch (error) {
279
- console.error('Error moving files:', error.message);
280
- process.exit(1);
281
- }
282
- }
@@ -1,207 +0,0 @@
1
- import * as fs from 'fs';
2
- import * as path from 'path';
3
- import { readModConfig, writeModConfig } from '../services/mod-config.js';
4
- export async function recoverCommand(args, repo) {
5
- const [action] = args;
6
- if (!action || !['automerge', 'workspace', 'branches'].includes(action)) {
7
- console.error('Usage: mod recover <automerge|workspace|branches>');
8
- console.error(' automerge - Attempt to recover corrupted Automerge storage');
9
- console.error(' workspace - Reset workspace configuration');
10
- console.error(' branches - Recreate corrupted branch documents');
11
- process.exit(1);
12
- }
13
- switch (action) {
14
- case 'automerge':
15
- await handleAutomergeRecovery(repo);
16
- break;
17
- case 'workspace':
18
- await handleWorkspaceRecovery();
19
- break;
20
- case 'branches':
21
- await handleBranchRecovery(repo);
22
- break;
23
- }
24
- }
25
- async function handleAutomergeRecovery(repo) {
26
- console.log('šŸ”§ Attempting Automerge storage recovery...');
27
- const storageDir = process.env.MOD_AUTOMERGE_STORAGE_DIR
28
- ? path.resolve(process.env.MOD_AUTOMERGE_STORAGE_DIR)
29
- : path.resolve('./.automerge-data');
30
- if (!fs.existsSync(storageDir)) {
31
- console.log('No Automerge storage directory found. Nothing to recover.');
32
- return;
33
- }
34
- console.log(`Scanning storage directory: ${storageDir}`);
35
- // Create backup of corrupted storage
36
- const backupDir = `${storageDir}.backup.${Date.now()}`;
37
- try {
38
- console.log(`Creating backup at: ${backupDir}`);
39
- fs.cpSync(storageDir, backupDir, { recursive: true });
40
- }
41
- catch (error) {
42
- console.warn('Could not create backup:', error);
43
- }
44
- // Test document loading to identify corrupted documents
45
- const corruptedDocs = [];
46
- const validDocs = [];
47
- const allDocIds = [];
48
- const scanDirectory = (dir) => {
49
- try {
50
- const items = fs.readdirSync(dir);
51
- for (const item of items) {
52
- const itemPath = path.join(dir, item);
53
- const stat = fs.statSync(itemPath);
54
- if (stat.isDirectory()) {
55
- scanDirectory(itemPath);
56
- }
57
- else if (itemPath.includes('/incremental/')) {
58
- // This is an Automerge incremental storage file
59
- // Extract document ID from path like: 3K/9QuxnF8NM8g71nvphZYzgxsxxJ/incremental/...
60
- const pathParts = path.relative(storageDir, itemPath).split(path.sep);
61
- if (pathParts.length >= 3 && pathParts[2] === 'incremental') {
62
- const docId = `${pathParts[0]}${pathParts[1]}`;
63
- if (!allDocIds.includes(docId)) {
64
- allDocIds.push(docId);
65
- }
66
- }
67
- }
68
- }
69
- }
70
- catch (error) {
71
- console.warn(`Error scanning directory ${dir}:`, error);
72
- }
73
- };
74
- scanDirectory(storageDir);
75
- console.log(`Found ${allDocIds.length} document files to test...`);
76
- // Test each document by actually trying to load it
77
- for (const docId of allDocIds) {
78
- try {
79
- const handle = await repo.find(docId);
80
- const doc = await handle.doc();
81
- if (doc) {
82
- validDocs.push(docId);
83
- }
84
- }
85
- catch (error) {
86
- const errorMessage = String(error?.message || error || '');
87
- if (errorMessage.includes('corrupt') || errorMessage.includes('deflate') || errorMessage.includes('unable to parse chunk')) {
88
- corruptedDocs.push(docId);
89
- console.log(` šŸ’„ Corrupted: ${docId}`);
90
- }
91
- else {
92
- // Other errors might not be corruption
93
- console.warn(` āš ļø Error loading ${docId}: ${errorMessage.substring(0, 100)}`);
94
- }
95
- }
96
- }
97
- console.log(`Found ${validDocs.length} valid documents and ${corruptedDocs.length} potentially corrupted documents`);
98
- if (corruptedDocs.length > 0) {
99
- console.log('\nCorrupted documents detected:');
100
- corruptedDocs.slice(0, 5).forEach(docId => {
101
- console.log(` ${docId}`);
102
- });
103
- if (corruptedDocs.length > 5) {
104
- console.log(` ... and ${corruptedDocs.length - 5} more`);
105
- }
106
- // Offer to remove corrupted documents
107
- console.log('\nāš ļø This will remove corrupted documents and may cause data loss.');
108
- console.log('šŸ’” Backup created at:', backupDir);
109
- // Auto-proceed with recovery
110
- console.log('Proceeding with corruption cleanup...');
111
- let removedCount = 0;
112
- for (const docId of corruptedDocs) {
113
- try {
114
- // Find and remove the corrupted document files
115
- // DocId format: 3K9QuxnF8NM8g71nvphZYzgxsxxJ -> 3K/9QuxnF8NM8g71nvphZYzgxsxxJ
116
- const prefix = docId.substring(0, 2);
117
- const suffix = docId.substring(2);
118
- const docDir = path.join(storageDir, prefix, suffix);
119
- if (fs.existsSync(docDir)) {
120
- // Remove the entire document directory
121
- fs.rmSync(docDir, { recursive: true, force: true });
122
- removedCount++;
123
- console.log(` šŸ—‘ļø Removed document directory: ${prefix}/${suffix}`);
124
- }
125
- // Check if parent directory is empty
126
- const parentDir = path.join(storageDir, prefix);
127
- try {
128
- const remainingFiles = fs.readdirSync(parentDir);
129
- if (remainingFiles.length === 0) {
130
- fs.rmdirSync(parentDir);
131
- console.log(` šŸ—‘ļø Removed empty prefix directory: ${prefix}`);
132
- }
133
- }
134
- catch { }
135
- }
136
- catch (error) {
137
- console.warn(`Could not remove corrupted document ${docId}:`, error);
138
- }
139
- }
140
- console.log(`āœ… Removed ${removedCount} corrupted document files`);
141
- console.log('šŸ”„ Please restart the application and try your command again');
142
- }
143
- else {
144
- console.log('āœ… No corrupted documents detected in Automerge storage');
145
- }
146
- }
147
- async function handleWorkspaceRecovery() {
148
- console.log('šŸ”§ Resetting workspace configuration...');
149
- const configPath = '.mod/config.json';
150
- if (fs.existsSync(configPath)) {
151
- console.log(`Backing up current config to ${configPath}.backup`);
152
- fs.copyFileSync(configPath, `${configPath}.backup`);
153
- }
154
- // Reset to minimal config
155
- const minimalConfig = {};
156
- writeModConfig(minimalConfig);
157
- console.log('āœ… Workspace configuration reset');
158
- console.log('šŸ’” Run "mod workspace list" to see available workspaces');
159
- console.log('šŸ’” Run "mod workspace switch <workspace-name>" to select a workspace');
160
- }
161
- async function handleBranchRecovery(repo) {
162
- console.log('šŸ”§ Attempting branch recovery...');
163
- const cfg = readModConfig();
164
- if (!cfg?.workspaceId) {
165
- console.error('No workspace configured. Run "mod recover workspace" first.');
166
- process.exit(1);
167
- }
168
- try {
169
- // Try to access the workspace
170
- const wsHandle = await repo.find(cfg.workspaceId);
171
- const workspace = await wsHandle.doc();
172
- if (!workspace) {
173
- console.error('Workspace document is corrupted or missing');
174
- console.log('šŸ’” Run "mod recover automerge" to fix storage corruption');
175
- process.exit(1);
176
- }
177
- const workspaceData = workspace;
178
- console.log(`āœ… Workspace "${workspaceData.title || 'Untitled'}" is accessible`);
179
- // Try to access branches document
180
- if (workspaceData.branchesDocId) {
181
- try {
182
- const branchesHandle = await repo.find(workspaceData.branchesDocId);
183
- const branchesDoc = await branchesHandle.doc();
184
- const branchesData = branchesDoc;
185
- if (branchesData && branchesData.branches) {
186
- console.log(`āœ… Found ${Object.keys(branchesData.branches).length} branches`);
187
- console.log('Branches appear to be intact');
188
- }
189
- else {
190
- console.log('āš ļø Branches document exists but appears empty');
191
- }
192
- }
193
- catch (error) {
194
- console.error('Branches document is corrupted:', error);
195
- console.log('šŸ’” Run "mod recover automerge" to fix storage corruption');
196
- }
197
- }
198
- else {
199
- console.log('āš ļø Workspace has no branches document ID');
200
- }
201
- }
202
- catch (error) {
203
- console.error('Failed to access workspace:', error);
204
- console.log('šŸ’” Run "mod recover automerge" to fix storage corruption');
205
- process.exit(1);
206
- }
207
- }