@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.
- package/dist/cli.bundle.js +216 -36371
- package/package.json +3 -3
- package/dist/app.js +0 -227
- package/dist/cli.bundle.js.map +0 -7
- package/dist/cli.js +0 -132
- package/dist/commands/add.js +0 -245
- package/dist/commands/agents-run.js +0 -71
- package/dist/commands/auth.js +0 -259
- package/dist/commands/branch.js +0 -1411
- package/dist/commands/claude-sync.js +0 -772
- package/dist/commands/comment.js +0 -568
- package/dist/commands/diff.js +0 -182
- package/dist/commands/index.js +0 -73
- package/dist/commands/init.js +0 -597
- package/dist/commands/ls.js +0 -135
- package/dist/commands/members.js +0 -687
- package/dist/commands/mv.js +0 -282
- package/dist/commands/recover.js +0 -207
- package/dist/commands/rm.js +0 -257
- package/dist/commands/spec.js +0 -386
- package/dist/commands/status.js +0 -296
- package/dist/commands/sync.js +0 -119
- package/dist/commands/trace.js +0 -1752
- package/dist/commands/workspace.js +0 -447
- package/dist/components/conflict-resolution-ui.js +0 -120
- package/dist/components/messages.js +0 -5
- package/dist/components/thread.js +0 -8
- package/dist/config/features.js +0 -83
- package/dist/containers/branches-container.js +0 -140
- package/dist/containers/directory-container.js +0 -92
- package/dist/containers/thread-container.js +0 -214
- package/dist/containers/threads-container.js +0 -27
- package/dist/containers/workspaces-container.js +0 -27
- package/dist/daemon/conflict-resolution.js +0 -172
- package/dist/daemon/content-hash.js +0 -31
- package/dist/daemon/file-sync.js +0 -985
- package/dist/daemon/index.js +0 -203
- package/dist/daemon/mime-types.js +0 -166
- package/dist/daemon/offline-queue.js +0 -211
- package/dist/daemon/path-utils.js +0 -64
- package/dist/daemon/share-policy.js +0 -83
- package/dist/daemon/wasm-errors.js +0 -189
- package/dist/daemon/worker.js +0 -557
- package/dist/daemon-worker.js +0 -258
- package/dist/errors/workspace-errors.js +0 -48
- package/dist/lib/auth-server.js +0 -216
- package/dist/lib/browser.js +0 -35
- package/dist/lib/diff.js +0 -284
- package/dist/lib/formatters.js +0 -204
- package/dist/lib/git.js +0 -137
- package/dist/lib/local-fs.js +0 -201
- package/dist/lib/prompts.js +0 -56
- package/dist/lib/storage.js +0 -213
- package/dist/lib/trace-formatters.js +0 -314
- package/dist/services/add-service.js +0 -554
- package/dist/services/add-validation.js +0 -124
- package/dist/services/automatic-file-tracker.js +0 -303
- package/dist/services/cli-orchestrator.js +0 -227
- package/dist/services/feature-flags.js +0 -187
- package/dist/services/file-import-service.js +0 -283
- package/dist/services/file-transformation-service.js +0 -218
- package/dist/services/logger.js +0 -44
- package/dist/services/mod-config.js +0 -67
- package/dist/services/modignore-service.js +0 -328
- package/dist/services/sync-daemon.js +0 -244
- package/dist/services/thread-notification-service.js +0 -50
- package/dist/services/thread-service.js +0 -147
- package/dist/stores/use-directory-store.js +0 -96
- package/dist/stores/use-threads-store.js +0 -46
- package/dist/stores/use-workspaces-store.js +0 -54
- package/dist/types/add-types.js +0 -99
- package/dist/types/config.js +0 -16
- package/dist/types/index.js +0 -2
- package/dist/types/workspace-connection.js +0 -53
- package/dist/types.js +0 -1
package/dist/commands/comment.js
DELETED
|
@@ -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
|
-
}
|