@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,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
- }