@locusai/cli 0.17.3 → 0.17.4

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 (2) hide show
  1. package/bin/locus.js +125 -9
  2. package/package.json +1 -1
package/bin/locus.js CHANGED
@@ -1598,7 +1598,8 @@ ${bold("Initializing Locus...")}
1598
1598
  const entriesToAdd = GITIGNORE_ENTRIES.filter((entry) => entry && !gitignoreContent.includes(entry.trim()));
1599
1599
  if (entriesToAdd.length > 0) {
1600
1600
  const newContent = `${gitignoreContent.trimEnd()}
1601
- ${GITIGNORE_ENTRIES.join(`
1601
+
1602
+ ${entriesToAdd.join(`
1602
1603
  `)}
1603
1604
  `;
1604
1605
  writeFileSync4(gitignorePath, newContent, "utf-8");
@@ -1672,8 +1673,8 @@ var init_init = __esm(() => {
1672
1673
  ".locus/sessions/",
1673
1674
  ".locus/logs/",
1674
1675
  ".locus/worktrees/",
1675
- ".locus/artifacts",
1676
- ".locus/discussions"
1676
+ ".locus/artifacts/",
1677
+ ".locus/discussions/"
1677
1678
  ];
1678
1679
  });
1679
1680
 
@@ -5117,7 +5118,7 @@ ${gitLog}
5117
5118
  function buildExecutionRules(config) {
5118
5119
  return `# Execution Rules
5119
5120
 
5120
- 1. **Commit format:** Use conventional commits: \`feat: <title> (#<issue>)\`, \`fix: ...\`, \`chore: ...\`
5121
+ 1. **Commit format:** Use conventional commits: \`feat: <title> (#<issue>)\`, \`fix: ...\`, \`chore: ...\`. Always include a blank line followed by \`Co-Authored-By: LocusAgent <agent@locusai.team>\` as a trailer in every commit message.
5121
5122
  2. **Code quality:** Follow existing code style. Run linters/formatters if available.
5122
5123
  3. **Testing:** If test files exist for modified code, update them accordingly.
5123
5124
  4. **Do NOT:**
@@ -5261,6 +5262,100 @@ class JsonStream {
5261
5262
  }
5262
5263
  }
5263
5264
 
5265
+ // src/display/diff-renderer.ts
5266
+ function renderDiff(diff, options = {}) {
5267
+ const { maxLines, lineNumbers = true } = options;
5268
+ const lines = diff.split(`
5269
+ `);
5270
+ const output = [];
5271
+ let lineCount = 0;
5272
+ let oldLine = 0;
5273
+ let newLine = 0;
5274
+ for (const line of lines) {
5275
+ if (maxLines && lineCount >= maxLines) {
5276
+ const remaining = lines.length - lineCount;
5277
+ if (remaining > 0) {
5278
+ output.push(dim(` ... +${remaining} more lines`));
5279
+ }
5280
+ break;
5281
+ }
5282
+ if (line.startsWith("diff --git")) {
5283
+ const filePath = extractFilePath(line);
5284
+ output.push("");
5285
+ output.push(bold(cyan(`── ${filePath} ──`)));
5286
+ lineCount += 2;
5287
+ continue;
5288
+ }
5289
+ if (line.startsWith("index ") || line.startsWith("---") || line.startsWith("+++")) {
5290
+ continue;
5291
+ }
5292
+ if (line.startsWith("@@")) {
5293
+ const match = line.match(/@@ -(\d+)(?:,\d+)? \+(\d+)(?:,\d+)? @@(.*)/);
5294
+ if (match) {
5295
+ oldLine = Number.parseInt(match[1], 10);
5296
+ newLine = Number.parseInt(match[2], 10);
5297
+ const context = match[3] ?? "";
5298
+ output.push(dim(` ${line.slice(0, 60)}${context ? ` ${context.trim()}` : ""}`));
5299
+ lineCount++;
5300
+ }
5301
+ continue;
5302
+ }
5303
+ if (line.startsWith("+")) {
5304
+ const gutter = lineNumbers ? `${dim(padNum(newLine))} ` : "";
5305
+ output.push(`${gutter}${green("+")} ${green(line.slice(1))}`);
5306
+ newLine++;
5307
+ lineCount++;
5308
+ continue;
5309
+ }
5310
+ if (line.startsWith("-")) {
5311
+ const gutter = lineNumbers ? `${dim(padNum(oldLine))} ` : "";
5312
+ output.push(`${gutter}${red("-")} ${red(line.slice(1))}`);
5313
+ oldLine++;
5314
+ lineCount++;
5315
+ continue;
5316
+ }
5317
+ if (line.startsWith(" ")) {
5318
+ const gutter = lineNumbers ? `${dim(padNum(newLine))} ` : "";
5319
+ output.push(`${gutter}${dim("|")} ${dim(line.slice(1))}`);
5320
+ oldLine++;
5321
+ newLine++;
5322
+ lineCount++;
5323
+ continue;
5324
+ }
5325
+ if (line.trim()) {
5326
+ output.push(dim(` ${line}`));
5327
+ lineCount++;
5328
+ }
5329
+ }
5330
+ return output;
5331
+ }
5332
+ function countDiffChanges(diff) {
5333
+ const lines = diff.split(`
5334
+ `);
5335
+ let additions = 0;
5336
+ let deletions = 0;
5337
+ let files = 0;
5338
+ for (const line of lines) {
5339
+ if (line.startsWith("diff --git"))
5340
+ files++;
5341
+ else if (line.startsWith("+") && !line.startsWith("+++"))
5342
+ additions++;
5343
+ else if (line.startsWith("-") && !line.startsWith("---"))
5344
+ deletions++;
5345
+ }
5346
+ return { additions, deletions, files };
5347
+ }
5348
+ function extractFilePath(diffLine) {
5349
+ const match = diffLine.match(/diff --git a\/(.+) b\//);
5350
+ return match?.[1] ?? diffLine;
5351
+ }
5352
+ function padNum(n) {
5353
+ return String(n).padStart(4);
5354
+ }
5355
+ var init_diff_renderer = __esm(() => {
5356
+ init_terminal();
5357
+ });
5358
+
5264
5359
  // src/repl/commands.ts
5265
5360
  import { execSync as execSync7 } from "node:child_process";
5266
5361
  function getSlashCommands() {
@@ -5431,12 +5526,30 @@ function cmdDiff(_args, ctx) {
5431
5526
  encoding: "utf-8",
5432
5527
  stdio: ["pipe", "pipe", "pipe"]
5433
5528
  });
5434
- if (diff.trim()) {
5435
- process.stdout.write(diff);
5436
- } else {
5529
+ if (!diff.trim()) {
5437
5530
  process.stderr.write(`${dim("No changes.")}
5531
+ `);
5532
+ return;
5533
+ }
5534
+ const { additions, deletions, files } = countDiffChanges(diff);
5535
+ const filesLabel = files === 1 ? "file" : "files";
5536
+ process.stderr.write(`
5537
+ `);
5538
+ process.stderr.write(`${bold("Changes:")} ${cyan(`${files} ${filesLabel}`)} ${green(`+${additions}`)} ${red(`-${deletions}`)}
5539
+ `);
5540
+ process.stderr.write(`${dim("─".repeat(60))}
5541
+ `);
5542
+ const lines = renderDiff(diff);
5543
+ for (const line of lines) {
5544
+ process.stderr.write(`${line}
5438
5545
  `);
5439
5546
  }
5547
+ process.stderr.write(`${dim("─".repeat(60))}
5548
+ `);
5549
+ process.stderr.write(dim(`${yellow("tip:")} use ${cyan("/undo")} to revert all unstaged changes
5550
+ `));
5551
+ process.stderr.write(`
5552
+ `);
5440
5553
  } catch {
5441
5554
  process.stderr.write(`${red("✗")} Could not get diff.
5442
5555
  `);
@@ -5476,6 +5589,7 @@ function cmdExit(_args, ctx) {
5476
5589
  }
5477
5590
  var init_commands = __esm(() => {
5478
5591
  init_ai_models();
5592
+ init_diff_renderer();
5479
5593
  init_terminal();
5480
5594
  });
5481
5595
 
@@ -7384,7 +7498,9 @@ function ensureTaskCommit(projectRoot, issueNumber, issueTitle) {
7384
7498
  encoding: "utf-8",
7385
7499
  stdio: ["pipe", "pipe", "pipe"]
7386
7500
  });
7387
- const message = `chore: complete #${issueNumber} - ${issueTitle}`;
7501
+ const message = `chore: complete #${issueNumber} - ${issueTitle}
7502
+
7503
+ Co-Authored-By: LocusAgent <agent@locusai.team>`;
7388
7504
  execSync12(`git commit -m ${JSON.stringify(message)}`, {
7389
7505
  cwd: projectRoot,
7390
7506
  encoding: "utf-8",
@@ -8636,8 +8752,8 @@ init_context();
8636
8752
  init_logger();
8637
8753
  init_rate_limiter();
8638
8754
  init_terminal();
8639
- import { join as join17 } from "node:path";
8640
8755
  import { existsSync as existsSync16, readFileSync as readFileSync13 } from "node:fs";
8756
+ import { join as join17 } from "node:path";
8641
8757
  import { fileURLToPath } from "node:url";
8642
8758
  function getCliVersion() {
8643
8759
  const fallbackVersion = "0.0.0";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@locusai/cli",
3
- "version": "0.17.3",
3
+ "version": "0.17.4",
4
4
  "description": "GitHub-native AI engineering assistant",
5
5
  "type": "module",
6
6
  "bin": {