@mrsf/cli 0.7.0 → 0.8.0

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.
@@ -7,7 +7,7 @@ import { discoverSidecar, findWorkspaceRoot } from "../lib/discovery.js";
7
7
  import { parseSidecar, readDocumentLines } from "../lib/parser.js";
8
8
  import { writeSidecar } from "../lib/writer.js";
9
9
  import { addComment, populateSelectedText } from "../lib/comments.js";
10
- import { findRepoRoot } from "../lib/git.js";
10
+ import { findRepoRoot, getGitUserName } from "../lib/git.js";
11
11
  function collectOptionValues(value, previous) {
12
12
  previous.push(value);
13
13
  return previous;
@@ -52,12 +52,12 @@ export function registerAdd(program) {
52
52
  program
53
53
  .command("add <document>")
54
54
  .description("Add a review comment to a document's sidecar")
55
- .requiredOption("-a, --author <name>", "Comment author")
55
+ .option("-a, --author <name>", "Comment author (defaults to repository-local Git user.name)")
56
56
  .requiredOption("-t, --text <text>", "Comment text")
57
57
  .option("-l, --line <n>", "Line number (1-based)")
58
58
  .option("--end-line <n>", "End line (inclusive)")
59
- .option("--start-column <n>", "Start column (0-based)")
60
- .option("--end-column <n>", "End column (0-based)")
59
+ .option("--start-column <n>", "Inclusive UTF-16 column (0-based)")
60
+ .option("--end-column <n>", "Exclusive UTF-16 column (0-based)")
61
61
  .option("--type <type>", "Comment type (e.g. suggestion, issue)")
62
62
  .option("--severity <level>", "Severity: low | medium | high")
63
63
  .option("--reply-to <id>", "Reply to an existing comment")
@@ -84,9 +84,17 @@ export function registerAdd(program) {
84
84
  comments: [],
85
85
  };
86
86
  }
87
- const repoRoot = await findRepoRoot(cwd);
87
+ const repoRoot = await findRepoRoot(path.dirname(docPath));
88
+ const author = opts.author?.trim()
89
+ || (repoRoot ? await getGitUserName(repoRoot) : null);
90
+ if (!author) {
91
+ console.error(chalk.red("Comment author is required. Pass --author or configure "
92
+ + "repository-local Git identity with: "
93
+ + "git config --local user.name \"Your Name\""));
94
+ process.exit(1);
95
+ }
88
96
  const comment = await addComment(doc, {
89
- author: opts.author,
97
+ author,
90
98
  text: opts.text,
91
99
  line: opts.line ? parseInt(opts.line, 10) : undefined,
92
100
  end_line: opts.endLine ? parseInt(opts.endLine, 10) : undefined,
@@ -108,7 +116,7 @@ export function registerAdd(program) {
108
116
  else if (comment.line != null) {
109
117
  try {
110
118
  const lines = await readDocumentLines(docPath);
111
- populateSelectedText(comment, lines);
119
+ populateSelectedText(comment, lines.slice(1));
112
120
  }
113
121
  catch {
114
122
  // Document file may not exist yet, skip
package/dist/index.cjs CHANGED
@@ -221,6 +221,7 @@ __export(index_exports, {
221
221
  getCurrentCommit: () => getCurrentCommit2,
222
222
  getDiff: () => getDiff2,
223
223
  getFileAtCommit: () => getFileAtCommit2,
224
+ getGitUserName: () => getGitUserName2,
224
225
  getLineShift: () => getLineShift4,
225
226
  getStagedFiles: () => getStagedFiles2,
226
227
  getThreads: () => getThreads2,
@@ -380,6 +381,7 @@ init_parser();
380
381
  var import_promises3 = require("node:fs/promises");
381
382
  var import_node_fs2 = require("node:fs");
382
383
  var import_node_crypto = require("node:crypto");
384
+ var import_promises4 = require("node:timers/promises");
383
385
  var import_node_path4 = __toESM(require("node:path"), 1);
384
386
  var import_yaml2 = require("yaml");
385
387
  init_serialize();
@@ -400,7 +402,17 @@ async function atomicWriteFile(filePath, content) {
400
402
  const tmp = filePath + "." + (0, import_node_crypto.randomBytes)(6).toString("hex") + ".tmp";
401
403
  try {
402
404
  await (0, import_promises3.writeFile)(tmp, content, "utf-8");
403
- await (0, import_promises3.rename)(tmp, filePath);
405
+ for (let attempt = 0; ; attempt++) {
406
+ try {
407
+ await (0, import_promises3.rename)(tmp, filePath);
408
+ break;
409
+ } catch (error) {
410
+ if (attempt >= 5 || !(error instanceof Error) || !("code" in error) || !["EPERM", "EACCES", "EBUSY"].some((code) => code === error.code)) {
411
+ throw error;
412
+ }
413
+ await (0, import_promises4.setTimeout)(50 * (attempt + 1));
414
+ }
415
+ }
404
416
  } catch (err) {
405
417
  try {
406
418
  await (0, import_promises3.unlink)(tmp);
@@ -710,7 +722,7 @@ async function writeSidecarInternal(abs, doc) {
710
722
  }
711
723
 
712
724
  // src/lib/validator.ts
713
- var import_promises4 = require("node:fs/promises");
725
+ var import_promises5 = require("node:fs/promises");
714
726
  var import_node_path5 = __toESM(require("node:path"), 1);
715
727
  var import_node_url = require("node:url");
716
728
 
@@ -804,12 +816,12 @@ var mrsf_schema_default = {
804
816
  start_column: {
805
817
  type: "integer",
806
818
  minimum: 0,
807
- description: "Starting column index (0-based) within the starting line."
819
+ description: "Inclusive starting UTF-16 code-unit offset (0-based) within the starting line."
808
820
  },
809
821
  end_column: {
810
822
  type: "integer",
811
823
  minimum: 0,
812
- description: "Ending column index. MUST be >= start_column when on the same line."
824
+ description: "Exclusive ending UTF-16 code-unit offset (0-based) within the ending line. MUST be >= start_column when on the same line."
813
825
  },
814
826
  selected_text: {
815
827
  type: "string",
@@ -974,7 +986,7 @@ async function loadSchema() {
974
986
  ];
975
987
  for (const candidate of candidates) {
976
988
  try {
977
- const raw = await (0, import_promises4.readFile)(candidate, "utf-8");
989
+ const raw = await (0, import_promises5.readFile)(candidate, "utf-8");
978
990
  _schemaCache = JSON.parse(raw);
979
991
  return _schemaCache;
980
992
  } catch {
@@ -1352,6 +1364,20 @@ async function findRepoRoot(cwd) {
1352
1364
  return null;
1353
1365
  }
1354
1366
  }
1367
+ async function getGitUserName(repoRoot) {
1368
+ if (!await isGitAvailable()) return null;
1369
+ try {
1370
+ const { stdout } = await execFile(
1371
+ "git",
1372
+ ["config", "--local", "--get", "user.name"],
1373
+ { cwd: repoRoot, timeout: GIT_TIMEOUT }
1374
+ );
1375
+ const name = stdout.trim();
1376
+ return name || null;
1377
+ } catch {
1378
+ return null;
1379
+ }
1380
+ }
1355
1381
  async function getCurrentCommit(repoRoot) {
1356
1382
  if (!await isGitAvailable()) return null;
1357
1383
  try {
@@ -2849,7 +2875,7 @@ async function reanchorDocument(doc, documentLines, opts = {}) {
2849
2875
  if (!opts.noGit && await isGitAvailable()) {
2850
2876
  const repoRoot = opts.repoRoot ?? await findRepoRoot(opts.cwd);
2851
2877
  if (repoRoot && opts.documentPath) {
2852
- const relPath = import_node_path6.default.relative(repoRoot, opts.documentPath);
2878
+ const relPath = import_node_path6.default.relative(repoRoot, opts.documentPath).split(import_node_path6.default.sep).join("/");
2853
2879
  const head = await getCurrentCommit(repoRoot);
2854
2880
  const globalFrom = opts.fromCommit;
2855
2881
  const diffCache = /* @__PURE__ */ new Map();
@@ -3255,6 +3281,7 @@ var fuzzySearch2 = fuzzySearch;
3255
3281
  var combinedScore2 = combinedScore;
3256
3282
  var isGitAvailable2 = isGitAvailable;
3257
3283
  var findRepoRoot3 = findRepoRoot;
3284
+ var getGitUserName2 = getGitUserName;
3258
3285
  var getCurrentCommit2 = getCurrentCommit;
3259
3286
  var resolveCommit2 = resolveCommit;
3260
3287
  var isStale2 = isStale;
@@ -3315,6 +3342,7 @@ var newCommentId2 = newCommentId;
3315
3342
  getCurrentCommit,
3316
3343
  getDiff,
3317
3344
  getFileAtCommit,
3345
+ getGitUserName,
3318
3346
  getLineShift,
3319
3347
  getStagedFiles,
3320
3348
  getThreads,