@mod-computer/cli 0.2.3 → 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 (75) hide show
  1. package/dist/cli.bundle.js +216 -36371
  2. package/package.json +3 -3
  3. package/dist/app.js +0 -227
  4. package/dist/cli.bundle.js.map +0 -7
  5. package/dist/cli.js +0 -132
  6. package/dist/commands/add.js +0 -245
  7. package/dist/commands/agents-run.js +0 -71
  8. package/dist/commands/auth.js +0 -259
  9. package/dist/commands/branch.js +0 -1411
  10. package/dist/commands/claude-sync.js +0 -772
  11. package/dist/commands/comment.js +0 -568
  12. package/dist/commands/diff.js +0 -182
  13. package/dist/commands/index.js +0 -73
  14. package/dist/commands/init.js +0 -597
  15. package/dist/commands/ls.js +0 -135
  16. package/dist/commands/members.js +0 -687
  17. package/dist/commands/mv.js +0 -282
  18. package/dist/commands/recover.js +0 -207
  19. package/dist/commands/rm.js +0 -257
  20. package/dist/commands/spec.js +0 -386
  21. package/dist/commands/status.js +0 -296
  22. package/dist/commands/sync.js +0 -119
  23. package/dist/commands/trace.js +0 -1752
  24. package/dist/commands/workspace.js +0 -447
  25. package/dist/components/conflict-resolution-ui.js +0 -120
  26. package/dist/components/messages.js +0 -5
  27. package/dist/components/thread.js +0 -8
  28. package/dist/config/features.js +0 -83
  29. package/dist/containers/branches-container.js +0 -140
  30. package/dist/containers/directory-container.js +0 -92
  31. package/dist/containers/thread-container.js +0 -214
  32. package/dist/containers/threads-container.js +0 -27
  33. package/dist/containers/workspaces-container.js +0 -27
  34. package/dist/daemon/conflict-resolution.js +0 -172
  35. package/dist/daemon/content-hash.js +0 -31
  36. package/dist/daemon/file-sync.js +0 -985
  37. package/dist/daemon/index.js +0 -203
  38. package/dist/daemon/mime-types.js +0 -166
  39. package/dist/daemon/offline-queue.js +0 -211
  40. package/dist/daemon/path-utils.js +0 -64
  41. package/dist/daemon/share-policy.js +0 -83
  42. package/dist/daemon/wasm-errors.js +0 -189
  43. package/dist/daemon/worker.js +0 -557
  44. package/dist/daemon-worker.js +0 -258
  45. package/dist/errors/workspace-errors.js +0 -48
  46. package/dist/lib/auth-server.js +0 -216
  47. package/dist/lib/browser.js +0 -35
  48. package/dist/lib/diff.js +0 -284
  49. package/dist/lib/formatters.js +0 -204
  50. package/dist/lib/git.js +0 -137
  51. package/dist/lib/local-fs.js +0 -201
  52. package/dist/lib/prompts.js +0 -56
  53. package/dist/lib/storage.js +0 -213
  54. package/dist/lib/trace-formatters.js +0 -314
  55. package/dist/services/add-service.js +0 -554
  56. package/dist/services/add-validation.js +0 -124
  57. package/dist/services/automatic-file-tracker.js +0 -303
  58. package/dist/services/cli-orchestrator.js +0 -227
  59. package/dist/services/feature-flags.js +0 -187
  60. package/dist/services/file-import-service.js +0 -283
  61. package/dist/services/file-transformation-service.js +0 -218
  62. package/dist/services/logger.js +0 -44
  63. package/dist/services/mod-config.js +0 -67
  64. package/dist/services/modignore-service.js +0 -328
  65. package/dist/services/sync-daemon.js +0 -244
  66. package/dist/services/thread-notification-service.js +0 -50
  67. package/dist/services/thread-service.js +0 -147
  68. package/dist/stores/use-directory-store.js +0 -96
  69. package/dist/stores/use-threads-store.js +0 -46
  70. package/dist/stores/use-workspaces-store.js +0 -54
  71. package/dist/types/add-types.js +0 -99
  72. package/dist/types/config.js +0 -16
  73. package/dist/types/index.js +0 -2
  74. package/dist/types/workspace-connection.js +0 -53
  75. 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
- }