@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,568 +0,0 @@
1
- import * as Automerge from '@automerge/automerge';
2
- import path from 'path';
3
- import fs from 'fs/promises';
4
- import { createModWorkspace } from '@mod/mod-core';
5
- import { readConfig, readWorkspaceConnection } from '../lib/storage.js';
6
- import { listLocalFiles } from '../lib/local-fs.js';
7
- const INLINE_PREFIXES = ['// @comment:', '# @comment:'];
8
- // glassware[type="implementation", id="impl-comments-cli-command--f317679a", specifications="specification-spec-comments-cli-add--caae2295,specification-spec-comments-cli-list--823e8bef,specification-spec-comments-cli-reply--1943ca4d,specification-spec-comments-cli-resolve--04be66f3,specification-spec-comments-cli-show--07887a12"]
9
- export async function commentCommand(args, repo) {
10
- const subcommand = args[0];
11
- const remaining = args.slice(1);
12
- const showLogs = args.includes('--logs');
13
- const run = async () => {
14
- if (subcommand === 'add') {
15
- await commentAddCommand(remaining, repo);
16
- return;
17
- }
18
- if (subcommand === 'list') {
19
- await commentListCommand(remaining, repo);
20
- return;
21
- }
22
- if (subcommand === 'reply') {
23
- await commentReplyCommand(remaining, repo);
24
- return;
25
- }
26
- if (subcommand === 'resolve') {
27
- await commentResolveCommand(remaining, repo);
28
- return;
29
- }
30
- if (subcommand === 'show') {
31
- await commentShowCommand(remaining, repo);
32
- return;
33
- }
34
- console.error('Error: Unknown subcommand for comment');
35
- console.error('Usage:');
36
- console.error(' mod comment add <file> <text>');
37
- console.error(' mod comment add <path> [--dry-run] [--remove-inline] [--glob <pattern>]');
38
- console.error(' mod comment list [file]');
39
- console.error(' mod comment reply <thread> <text>');
40
- console.error(' mod comment resolve <thread>');
41
- console.error(' mod comment show <thread>');
42
- process.exit(1);
43
- };
44
- if (showLogs) {
45
- await run();
46
- return;
47
- }
48
- await withSuppressedLogs(run);
49
- }
50
- // glassware[type="implementation", id="impl-comments-cli-add-text--5cfa1217", specifications="specification-spec-comments-cli-add-text--a3b1431f,specification-spec-comments-cli-add--caae2295"]
51
- async function addTextComment(repo, workspaceId, workspacePath, targetPath, text) {
52
- const modWorkspace = createModWorkspace(repo);
53
- const workspaceHandle = await modWorkspace.openWorkspace(workspaceId);
54
- const resolved = resolveWorkspacePath(targetPath, workspacePath);
55
- if (!resolved) {
56
- console.error(`Error: ${targetPath} is not under the workspace root`);
57
- process.exit(1);
58
- }
59
- const fileDoc = await workspaceHandle.file.getByPath(resolved.relativePath);
60
- if (!fileDoc) {
61
- console.error(`Error: File not found in workspace: ${resolved.relativePath}`);
62
- process.exit(1);
63
- }
64
- const fileHandle = await workspaceHandle.file.getHandle(fileDoc.documentId);
65
- if (!fileHandle) {
66
- console.error(`Error: Failed to open file handle for ${resolved.relativePath}`);
67
- process.exit(1);
68
- }
69
- const content = await safeReadFile(resolved.absolutePath);
70
- const firstLine = content?.split(/\r?\n/)[0] ?? resolved.relativePath;
71
- const quotedText = firstLine && firstLine.trim().length > 0 ? firstLine : resolved.relativePath;
72
- const anchor = buildAnchorForLine(fileHandle.doc(), fileDoc.documentId, 0, quotedText.length, quotedText);
73
- const author = getAuthor();
74
- const threadId = await fileHandle.comments.create(anchor, {
75
- author,
76
- text,
77
- authorType: 'user'
78
- });
79
- await flushRepo(repo, [fileDoc.documentId, threadId]);
80
- console.log(`Added comment to ${resolved.relativePath}`);
81
- }
82
- // glassware[type="implementation", id="impl-comments-cli-list--7374ea5f", specifications="specification-spec-comments-cli-list--823e8bef,specification-spec-comments-cli-list-id--c37d4ff6,specification-spec-comments-cli-list-reply-count--84fc9ab3"]
83
- async function commentListCommand(args, repo) {
84
- const { targetPath } = parseCommentListArgs(args);
85
- const connection = requireWorkspaceConnection();
86
- const modWorkspace = createModWorkspace(repo);
87
- const workspaceHandle = await modWorkspace.openWorkspace(connection.workspaceId);
88
- if (targetPath) {
89
- const resolved = resolveWorkspacePath(targetPath, connection.workspacePath);
90
- if (!resolved) {
91
- console.error(`Error: ${targetPath} is not under the workspace root`);
92
- process.exit(1);
93
- }
94
- const fileDoc = await workspaceHandle.file.getByPath(resolved.relativePath);
95
- if (!fileDoc) {
96
- console.error(`Error: File not found in workspace: ${resolved.relativePath}`);
97
- process.exit(1);
98
- }
99
- const fileHandle = await workspaceHandle.file.getHandle(fileDoc.documentId);
100
- if (!fileHandle) {
101
- console.error(`Error: Failed to open file handle for ${resolved.relativePath}`);
102
- process.exit(1);
103
- }
104
- const threads = await fileHandle.comments.list();
105
- printThreads(resolved.relativePath, threads);
106
- return;
107
- }
108
- const files = await workspaceHandle.file.list();
109
- let totalThreads = 0;
110
- for (const file of files) {
111
- const filePath = file.metadata?.path || file.name;
112
- const fileHandle = await workspaceHandle.file.getHandle(file.id);
113
- if (!fileHandle)
114
- continue;
115
- const threads = await fileHandle.comments.list();
116
- if (threads.length === 0)
117
- continue;
118
- totalThreads += threads.length;
119
- printThreads(filePath, threads);
120
- }
121
- if (totalThreads === 0) {
122
- console.log('No comment threads found');
123
- }
124
- }
125
- // glassware[type="implementation", id="impl-comments-cli-reply--f9580150", specifications="specification-spec-comments-cli-reply--1943ca4d,specification-spec-comments-cli-reply-persist--b1e2328b"]
126
- async function commentReplyCommand(args, repo) {
127
- const { threadId, text } = parseCommentReplyArgs(args);
128
- if (!threadId || !text) {
129
- console.error('Error: Thread and text required');
130
- console.error('Usage: mod comment reply <thread> <text>');
131
- process.exit(1);
132
- }
133
- const connection = requireWorkspaceConnection();
134
- const modWorkspace = createModWorkspace(repo);
135
- const workspaceHandle = await modWorkspace.openWorkspace(connection.workspaceId);
136
- const author = getAuthor();
137
- await workspaceHandle.comment.reply(threadId, {
138
- author,
139
- text,
140
- authorType: 'user'
141
- });
142
- await flushRepo(repo, [threadId]);
143
- console.log(`Replied to thread ${threadId}`);
144
- }
145
- // glassware[type="implementation", id="impl-comments-cli-resolve--d4514340", specifications="specification-spec-comments-cli-resolve--04be66f3,specification-spec-comments-cli-resolve-persist--ca607aa7"]
146
- async function commentResolveCommand(args, repo) {
147
- const { threadId } = parseCommentResolveArgs(args);
148
- if (!threadId) {
149
- console.error('Error: Thread required');
150
- console.error('Usage: mod comment resolve <thread>');
151
- process.exit(1);
152
- }
153
- const connection = requireWorkspaceConnection();
154
- const modWorkspace = createModWorkspace(repo);
155
- const workspaceHandle = await modWorkspace.openWorkspace(connection.workspaceId);
156
- await workspaceHandle.comment.resolve(threadId);
157
- await flushRepo(repo, [threadId]);
158
- console.log(`Resolved thread ${threadId}`);
159
- }
160
- // glassware[type="implementation", id="impl-comments-cli-show--e8618786", specifications="specification-spec-comments-cli-show--07887a12,specification-spec-comments-cli-show-format--38abaa06"]
161
- async function commentShowCommand(args, repo) {
162
- const { threadId } = parseCommentShowArgs(args);
163
- if (!threadId) {
164
- console.error('Error: Thread required');
165
- console.error('Usage: mod comment show <thread>');
166
- process.exit(1);
167
- }
168
- const connection = requireWorkspaceConnection();
169
- const modWorkspace = createModWorkspace(repo);
170
- const workspaceHandle = await modWorkspace.openWorkspace(connection.workspaceId);
171
- let thread = null;
172
- try {
173
- thread = await workspaceHandle.comment.getThread(threadId);
174
- }
175
- catch {
176
- thread = null;
177
- }
178
- if (!thread) {
179
- console.error(`Error: Thread not found: ${threadId}`);
180
- process.exit(1);
181
- }
182
- printThreadDetails(thread);
183
- }
184
- // glassware[type="implementation", id="impl-comments-cli-inline-trigger--71f93e98", specifications="specification-spec-comments-cli-inline-trigger--c1da6532"]
185
- async function commentAddCommand(args, repo) {
186
- const parsed = parseCommentAddArgs(args);
187
- if (!parsed.targetPath) {
188
- console.error('Error: Path required');
189
- console.error('Usage: mod comment add <file> <text>');
190
- console.error(' mod comment add <path> [--dry-run] [--remove-inline] [--glob <pattern>]');
191
- process.exit(1);
192
- }
193
- const connection = requireWorkspaceConnection();
194
- if (parsed.mode === 'text' && parsed.text) {
195
- await addTextComment(repo, connection.workspaceId, connection.workspacePath, parsed.targetPath, parsed.text);
196
- return;
197
- }
198
- await convertInlineAnnotations(repo, connection.workspaceId, connection.workspacePath, parsed.targetPath, parsed.options);
199
- }
200
- // glassware[type="implementation", id="impl-comments-cli-inline-options--3a6ce99e", specifications="specification-spec-comments-cli-inline-options--92527951,specification-spec-comments-cli-inline-glob--63dce4ea"]
201
- export function parseInlineOptions(args) {
202
- const options = {
203
- dryRun: false,
204
- removeInline: false
205
- };
206
- const positional = [];
207
- for (let i = 0; i < args.length; i++) {
208
- const arg = args[i];
209
- if (arg === '--dry-run') {
210
- options.dryRun = true;
211
- }
212
- else if (arg === '--remove-inline') {
213
- options.removeInline = true;
214
- }
215
- else if (arg === '--glob') {
216
- const pattern = args[i + 1];
217
- if (!pattern || pattern.startsWith('-')) {
218
- console.error('Error: --glob requires a pattern');
219
- process.exit(1);
220
- }
221
- options.glob = pattern;
222
- i += 1;
223
- }
224
- else if (!arg.startsWith('-')) {
225
- positional.push(arg);
226
- }
227
- }
228
- return { options, positional };
229
- }
230
- export function parseCommentAddArgs(args) {
231
- const { options, positional } = parseInlineOptions(args);
232
- const targetPath = positional[0] ?? null;
233
- const text = positional.slice(1).join(' ').trim();
234
- return {
235
- targetPath,
236
- text: text.length > 0 ? text : null,
237
- mode: text.length > 0 ? 'text' : 'inline',
238
- options
239
- };
240
- }
241
- export function parseCommentListArgs(args) {
242
- for (const arg of args) {
243
- if (!arg.startsWith('-')) {
244
- return { targetPath: arg };
245
- }
246
- }
247
- return { targetPath: null };
248
- }
249
- export function parseCommentReplyArgs(args) {
250
- const positional = args.filter(arg => !arg.startsWith('-'));
251
- const threadId = positional[0] ?? null;
252
- const text = positional.slice(1).join(' ').trim();
253
- return {
254
- threadId,
255
- text: text.length > 0 ? text : null
256
- };
257
- }
258
- export function parseCommentResolveArgs(args) {
259
- for (const arg of args) {
260
- if (!arg.startsWith('-')) {
261
- return { threadId: arg };
262
- }
263
- }
264
- return { threadId: null };
265
- }
266
- export function parseCommentShowArgs(args) {
267
- for (const arg of args) {
268
- if (!arg.startsWith('-')) {
269
- return { threadId: arg };
270
- }
271
- }
272
- return { threadId: null };
273
- }
274
- // glassware[type="implementation", id="impl-comments-cli-inline-format--dfc82aeb", specifications="specification-spec-comments-cli-inline-format--0507e3c0"]
275
- export function findInlineAnnotations(content) {
276
- const newline = content.includes('\r\n') ? '\r\n' : '\n';
277
- const lines = content.split(/\r?\n/);
278
- const annotations = [];
279
- let offset = 0;
280
- for (let i = 0; i < lines.length; i++) {
281
- const line = lines[i];
282
- const match = findInlinePrefix(line);
283
- const lineStart = offset;
284
- const lineEnd = offset + line.length;
285
- if (match) {
286
- const commentText = line.slice(match.prefixIndex + match.prefix.length).trim();
287
- annotations.push({
288
- lineIndex: i,
289
- lineStart,
290
- lineEnd,
291
- line,
292
- prefixIndex: match.prefixIndex,
293
- prefix: match.prefix,
294
- commentText
295
- });
296
- }
297
- offset = lineEnd + (i < lines.length - 1 ? newline.length : 0);
298
- }
299
- return annotations;
300
- }
301
- // glassware[type="implementation", id="impl-comments-cli-inline-anchor--1abedfde", specifications="specification-spec-comments-cli-inline-anchor--9de12c54"]
302
- export function buildAnchorForLine(doc, docId, lineStart, lineEnd, quotedText) {
303
- const pathSegments = ['text'];
304
- let fromCursor = '';
305
- let toCursor = '';
306
- try {
307
- fromCursor = Automerge.getCursor(doc, pathSegments, lineStart).toString();
308
- toCursor = Automerge.getCursor(doc, pathSegments, lineEnd).toString();
309
- }
310
- catch { }
311
- return {
312
- docId,
313
- fromCursor,
314
- toCursor,
315
- path: pathSegments,
316
- quotedText
317
- };
318
- }
319
- // glassware[type="implementation", id="impl-comments-cli-inline-remove--90d16357", specifications="specification-spec-comments-cli-inline-remove--60995cac"]
320
- export function removeInlineAnnotations(content, annotations, convertedLineIndices) {
321
- const newline = content.includes('\r\n') ? '\r\n' : '\n';
322
- const lines = content.split(/\r?\n/);
323
- const updated = [];
324
- for (let i = 0; i < lines.length; i++) {
325
- const line = lines[i];
326
- if (!convertedLineIndices.has(i)) {
327
- updated.push(line);
328
- continue;
329
- }
330
- const annotation = annotations.find(item => item.lineIndex === i);
331
- if (!annotation) {
332
- updated.push(line);
333
- continue;
334
- }
335
- const beforePrefix = line.slice(0, annotation.prefixIndex);
336
- if (beforePrefix.trim().length > 0) {
337
- updated.push(beforePrefix.trimEnd());
338
- }
339
- }
340
- return updated.join(newline);
341
- }
342
- // glassware[type="implementation", id="impl-comments-cli-inline-dry-run--6126e52b", specifications="specification-spec-comments-cli-inline-dry-run--c8d04d14"]
343
- async function convertInlineAnnotations(repo, workspaceId, workspacePath, targetPath, options) {
344
- const resolvedTarget = resolveWorkspacePath(targetPath, workspacePath);
345
- if (!resolvedTarget) {
346
- console.error(`Error: ${targetPath} is not under the workspace root`);
347
- process.exit(1);
348
- }
349
- const stat = await fs.stat(resolvedTarget.absolutePath).catch(() => null);
350
- if (!stat) {
351
- console.error(`Error: Path not found: ${resolvedTarget.absolutePath}`);
352
- process.exit(1);
353
- }
354
- const modWorkspace = createModWorkspace(repo);
355
- const workspaceHandle = await modWorkspace.openWorkspace(workspaceId);
356
- const targets = stat.isDirectory()
357
- ? await listLocalFiles(resolvedTarget.absolutePath, options.glob)
358
- : [path.basename(resolvedTarget.absolutePath)];
359
- const baseDir = stat.isDirectory() ? resolvedTarget.absolutePath : path.dirname(resolvedTarget.absolutePath);
360
- let totalFound = 0;
361
- let totalConverted = 0;
362
- for (const relativeFile of targets) {
363
- const absoluteFile = stat.isDirectory()
364
- ? path.join(baseDir, relativeFile)
365
- : resolvedTarget.absolutePath;
366
- const relativeToWorkspace = resolveWorkspacePath(absoluteFile, workspacePath);
367
- if (!relativeToWorkspace)
368
- continue;
369
- const content = await safeReadFile(absoluteFile);
370
- if (content === null)
371
- continue;
372
- const annotations = findInlineAnnotations(content);
373
- if (annotations.length === 0)
374
- continue;
375
- totalFound += annotations.length;
376
- const fileDoc = await workspaceHandle.file.getByPath(relativeToWorkspace.relativePath);
377
- if (!fileDoc) {
378
- console.warn(`Warning: File not found in workspace: ${relativeToWorkspace.relativePath}`);
379
- continue;
380
- }
381
- const fileHandle = await workspaceHandle.file.getHandle(fileDoc.documentId);
382
- if (!fileHandle) {
383
- console.warn(`Warning: Failed to open file handle for ${relativeToWorkspace.relativePath}`);
384
- continue;
385
- }
386
- const convertedLineIndices = new Set();
387
- const createdThreadIds = [];
388
- for (const annotation of annotations) {
389
- if (!annotation.commentText) {
390
- console.warn(`Warning: Skipping empty inline comment in ${relativeToWorkspace.relativePath}:${annotation.lineIndex + 1}`);
391
- continue;
392
- }
393
- const anchor = buildAnchorForLine(fileHandle.doc(), fileDoc.documentId, annotation.lineStart, annotation.lineEnd, annotation.line);
394
- const author = getAuthor();
395
- if (!options.dryRun) {
396
- const threadId = await fileHandle.comments.create(anchor, {
397
- author,
398
- text: annotation.commentText,
399
- authorType: 'user'
400
- });
401
- createdThreadIds.push(threadId);
402
- convertedLineIndices.add(annotation.lineIndex);
403
- totalConverted += 1;
404
- }
405
- }
406
- if (!options.dryRun && options.removeInline && convertedLineIndices.size > 0) {
407
- const updatedContent = removeInlineAnnotations(content, annotations, convertedLineIndices);
408
- await fs.writeFile(absoluteFile, updatedContent, 'utf-8');
409
- }
410
- if (!options.dryRun && createdThreadIds.length > 0) {
411
- await flushRepo(repo, [fileDoc.documentId, ...createdThreadIds]);
412
- }
413
- }
414
- if (options.dryRun) {
415
- console.log(`Found ${totalFound} inline comments (dry run)`);
416
- }
417
- else {
418
- console.log(`Converted ${totalConverted} inline comments`);
419
- }
420
- }
421
- function findInlinePrefix(line) {
422
- let bestIndex = -1;
423
- let bestPrefix = null;
424
- for (const prefix of INLINE_PREFIXES) {
425
- const index = line.indexOf(prefix);
426
- if (index === -1)
427
- continue;
428
- if (bestIndex === -1 || index < bestIndex) {
429
- bestIndex = index;
430
- bestPrefix = prefix;
431
- }
432
- }
433
- if (bestIndex === -1 || !bestPrefix)
434
- return null;
435
- return { prefixIndex: bestIndex, prefix: bestPrefix };
436
- }
437
- function requireWorkspaceConnection() {
438
- const currentDir = process.cwd();
439
- const connection = readWorkspaceConnection(currentDir);
440
- if (!connection) {
441
- console.error('Error: Not connected to a workspace.');
442
- console.error('Run `mod init` to connect this directory first.');
443
- process.exit(1);
444
- }
445
- return {
446
- workspaceId: connection.workspaceId,
447
- workspaceName: connection.workspaceName,
448
- workspacePath: connection.path
449
- };
450
- }
451
- function resolveWorkspacePath(targetPath, workspacePath) {
452
- const absolutePath = path.isAbsolute(targetPath)
453
- ? targetPath
454
- : path.resolve(process.cwd(), targetPath);
455
- const relativePath = path.relative(workspacePath, absolutePath);
456
- if (relativePath.startsWith('..') || path.isAbsolute(relativePath)) {
457
- return null;
458
- }
459
- return {
460
- absolutePath,
461
- relativePath: relativePath.replace(/\\/g, '/')
462
- };
463
- }
464
- async function safeReadFile(filePath) {
465
- try {
466
- return await fs.readFile(filePath, 'utf-8');
467
- }
468
- catch {
469
- return null;
470
- }
471
- }
472
- function getAuthor() {
473
- const config = readConfig();
474
- return config.auth?.email || config.auth?.name || 'Anonymous';
475
- }
476
- // glassware[type="implementation", id="impl-comments-cli-persist--422d6a7b", specifications="specification-spec-comments-cli-add-persist--38f941f4,specification-spec-comments-cli-inline-persist--81bda0e1"]
477
- async function flushRepo(repo, documentIds) {
478
- const flush = repo.flush;
479
- if (!flush)
480
- return;
481
- try {
482
- await flush.call(repo, documentIds);
483
- }
484
- catch (error) {
485
- console.error('Error: Failed to persist comment changes');
486
- process.exit(1);
487
- }
488
- }
489
- // glassware[type="implementation", id="impl-comments-cli-logs--29a60b58", specifications="specification-spec-comments-cli-list-logs--0544ba41,specification-spec-comments-cli-inline-logs--b839d19b"]
490
- export async function withSuppressedLogs(fn) {
491
- const originalLog = console.log;
492
- const originalWarn = console.warn;
493
- const originalInfo = console.info;
494
- const originalDebug = console.debug;
495
- const shouldDrop = (args) => {
496
- if (args.length === 0)
497
- return false;
498
- const message = args
499
- .map((arg) => {
500
- if (typeof arg === 'string')
501
- return arg;
502
- if (arg && typeof arg === 'object' && 'message' in arg) {
503
- return String(arg.message);
504
- }
505
- return String(arg);
506
- })
507
- .join(' ');
508
- return message.startsWith('[');
509
- };
510
- console.log = (...args) => {
511
- if (shouldDrop(args))
512
- return;
513
- originalLog(...args);
514
- };
515
- console.warn = (...args) => {
516
- if (shouldDrop(args))
517
- return;
518
- originalWarn(...args);
519
- };
520
- console.info = (...args) => {
521
- if (shouldDrop(args))
522
- return;
523
- originalInfo(...args);
524
- };
525
- console.debug = (...args) => {
526
- if (shouldDrop(args))
527
- return;
528
- originalDebug(...args);
529
- };
530
- try {
531
- return await fn();
532
- }
533
- finally {
534
- console.log = originalLog;
535
- console.warn = originalWarn;
536
- console.info = originalInfo;
537
- console.debug = originalDebug;
538
- }
539
- }
540
- // glassware[type="implementation", id="impl-comments-cli-list-id--8fc0544c", specifications="specification-spec-comments-cli-list-id--c37d4ff6,specification-spec-comments-cli-list-reply-count--84fc9ab3"]
541
- function printThreads(filePath, threads) {
542
- console.log(filePath);
543
- for (const thread of threads) {
544
- const preview = thread.comments[0]?.text ?? '';
545
- const replyCount = Math.max(0, thread.comments.length - 1);
546
- console.log(` [${thread.status}] ${thread.id} (replies: ${replyCount}) ${preview}`);
547
- }
548
- }
549
- // glassware[type="implementation", id="impl-comments-cli-show-format--3d4a7569", specifications="specification-spec-comments-cli-show-format--38abaa06"]
550
- function printThreadDetails(thread) {
551
- console.log(`Thread ${thread.id}`);
552
- console.log(`Status: ${thread.status}`);
553
- console.log('Anchor:');
554
- console.log(` docId: ${thread.anchor.docId}`);
555
- console.log(` path: ${thread.anchor.path.join('.')}`);
556
- if (thread.anchor.quotedText) {
557
- console.log(` quotedText: ${thread.anchor.quotedText}`);
558
- }
559
- if (thread.comments.length === 0) {
560
- console.log('Comments: none');
561
- return;
562
- }
563
- console.log('Comments:');
564
- for (const comment of thread.comments) {
565
- console.log(` - ${comment.author} ${comment.createdAt}`);
566
- console.log(` ${comment.text}`);
567
- }
568
- }