@locusai/cli 0.17.3 → 0.17.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/bin/locus.js +378 -18
- 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
|
-
|
|
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",
|
|
@@ -8416,6 +8532,7 @@ import {
|
|
|
8416
8532
|
writeFileSync as writeFileSync8
|
|
8417
8533
|
} from "node:fs";
|
|
8418
8534
|
import { join as join16 } from "node:path";
|
|
8535
|
+
import { createInterface as createInterface2 } from "node:readline";
|
|
8419
8536
|
function printHelp4() {
|
|
8420
8537
|
process.stderr.write(`
|
|
8421
8538
|
${bold("locus discuss")} — AI-powered architectural discussions
|
|
@@ -8448,7 +8565,7 @@ function generateId() {
|
|
|
8448
8565
|
return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
|
|
8449
8566
|
}
|
|
8450
8567
|
async function discussCommand(projectRoot, args, flags = {}) {
|
|
8451
|
-
if (args[0] === "help"
|
|
8568
|
+
if (args[0] === "help") {
|
|
8452
8569
|
printHelp4();
|
|
8453
8570
|
return;
|
|
8454
8571
|
}
|
|
@@ -8462,6 +8579,14 @@ async function discussCommand(projectRoot, args, flags = {}) {
|
|
|
8462
8579
|
if (subcommand === "delete") {
|
|
8463
8580
|
return deleteDiscussion(projectRoot, args[1]);
|
|
8464
8581
|
}
|
|
8582
|
+
if (args.length === 0) {
|
|
8583
|
+
const topic2 = await promptForTopic();
|
|
8584
|
+
if (!topic2) {
|
|
8585
|
+
printHelp4();
|
|
8586
|
+
return;
|
|
8587
|
+
}
|
|
8588
|
+
return startDiscussion(projectRoot, topic2, flags);
|
|
8589
|
+
}
|
|
8465
8590
|
const topic = args.join(" ").trim();
|
|
8466
8591
|
return startDiscussion(projectRoot, topic, flags);
|
|
8467
8592
|
}
|
|
@@ -8541,6 +8666,21 @@ function deleteDiscussion(projectRoot, id) {
|
|
|
8541
8666
|
process.stderr.write(`${green("✓")} Deleted discussion: ${match.replace(".md", "")}
|
|
8542
8667
|
`);
|
|
8543
8668
|
}
|
|
8669
|
+
async function promptForTopic() {
|
|
8670
|
+
return new Promise((resolve2) => {
|
|
8671
|
+
const rl = createInterface2({
|
|
8672
|
+
input: process.stdin,
|
|
8673
|
+
output: process.stderr,
|
|
8674
|
+
terminal: true
|
|
8675
|
+
});
|
|
8676
|
+
process.stderr.write(`${bold("Discussion topic:")} `);
|
|
8677
|
+
rl.once("line", (line) => {
|
|
8678
|
+
rl.close();
|
|
8679
|
+
resolve2(line.trim());
|
|
8680
|
+
});
|
|
8681
|
+
rl.once("close", () => resolve2(""));
|
|
8682
|
+
});
|
|
8683
|
+
}
|
|
8544
8684
|
async function startDiscussion(projectRoot, topic, flags) {
|
|
8545
8685
|
const config = loadConfig(projectRoot);
|
|
8546
8686
|
const timer = createTimer();
|
|
@@ -8630,23 +8770,236 @@ var init_discuss = __esm(() => {
|
|
|
8630
8770
|
init_terminal();
|
|
8631
8771
|
});
|
|
8632
8772
|
|
|
8773
|
+
// src/commands/artifacts.ts
|
|
8774
|
+
var exports_artifacts = {};
|
|
8775
|
+
__export(exports_artifacts, {
|
|
8776
|
+
readArtifact: () => readArtifact,
|
|
8777
|
+
listArtifacts: () => listArtifacts,
|
|
8778
|
+
formatSize: () => formatSize,
|
|
8779
|
+
formatDate: () => formatDate2,
|
|
8780
|
+
artifactsCommand: () => artifactsCommand
|
|
8781
|
+
});
|
|
8782
|
+
import { existsSync as existsSync16, readdirSync as readdirSync8, readFileSync as readFileSync13, statSync as statSync4 } from "node:fs";
|
|
8783
|
+
import { join as join17 } from "node:path";
|
|
8784
|
+
function printHelp5() {
|
|
8785
|
+
process.stderr.write(`
|
|
8786
|
+
${bold("locus artifacts")} — View and manage AI-generated artifacts
|
|
8787
|
+
|
|
8788
|
+
${bold("Usage:")}
|
|
8789
|
+
locus artifacts ${dim("# List all artifacts")}
|
|
8790
|
+
locus artifacts show <name> ${dim("# Show artifact content")}
|
|
8791
|
+
locus artifacts plan <name> ${dim("# Convert artifact to a plan")}
|
|
8792
|
+
|
|
8793
|
+
${bold("Examples:")}
|
|
8794
|
+
locus artifacts
|
|
8795
|
+
locus artifacts show reduce-cli-terminal-output
|
|
8796
|
+
locus artifacts plan aws-instance-orchestration-prd
|
|
8797
|
+
|
|
8798
|
+
${dim("Artifact names support partial matching.")}
|
|
8799
|
+
|
|
8800
|
+
`);
|
|
8801
|
+
}
|
|
8802
|
+
function getArtifactsDir(projectRoot) {
|
|
8803
|
+
return join17(projectRoot, ".locus", "artifacts");
|
|
8804
|
+
}
|
|
8805
|
+
function listArtifacts(projectRoot) {
|
|
8806
|
+
const dir = getArtifactsDir(projectRoot);
|
|
8807
|
+
if (!existsSync16(dir))
|
|
8808
|
+
return [];
|
|
8809
|
+
return readdirSync8(dir).filter((f) => f.endsWith(".md")).map((fileName) => {
|
|
8810
|
+
const filePath = join17(dir, fileName);
|
|
8811
|
+
const stat = statSync4(filePath);
|
|
8812
|
+
return {
|
|
8813
|
+
name: fileName.replace(/\.md$/, ""),
|
|
8814
|
+
fileName,
|
|
8815
|
+
createdAt: stat.birthtime,
|
|
8816
|
+
size: stat.size
|
|
8817
|
+
};
|
|
8818
|
+
}).sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime());
|
|
8819
|
+
}
|
|
8820
|
+
function readArtifact(projectRoot, name) {
|
|
8821
|
+
const dir = getArtifactsDir(projectRoot);
|
|
8822
|
+
const fileName = name.endsWith(".md") ? name : `${name}.md`;
|
|
8823
|
+
const filePath = join17(dir, fileName);
|
|
8824
|
+
if (!existsSync16(filePath))
|
|
8825
|
+
return null;
|
|
8826
|
+
const stat = statSync4(filePath);
|
|
8827
|
+
return {
|
|
8828
|
+
content: readFileSync13(filePath, "utf-8"),
|
|
8829
|
+
info: {
|
|
8830
|
+
name: fileName.replace(/\.md$/, ""),
|
|
8831
|
+
fileName,
|
|
8832
|
+
createdAt: stat.birthtime,
|
|
8833
|
+
size: stat.size
|
|
8834
|
+
}
|
|
8835
|
+
};
|
|
8836
|
+
}
|
|
8837
|
+
function formatSize(bytes) {
|
|
8838
|
+
if (bytes < 1024)
|
|
8839
|
+
return `${bytes}B`;
|
|
8840
|
+
const kb = bytes / 1024;
|
|
8841
|
+
if (kb < 1024)
|
|
8842
|
+
return `${kb.toFixed(1)}KB`;
|
|
8843
|
+
return `${(kb / 1024).toFixed(1)}MB`;
|
|
8844
|
+
}
|
|
8845
|
+
function formatDate2(date) {
|
|
8846
|
+
return date.toLocaleDateString("en-US", {
|
|
8847
|
+
year: "numeric",
|
|
8848
|
+
month: "short",
|
|
8849
|
+
day: "numeric",
|
|
8850
|
+
hour: "2-digit",
|
|
8851
|
+
minute: "2-digit"
|
|
8852
|
+
});
|
|
8853
|
+
}
|
|
8854
|
+
async function artifactsCommand(projectRoot, args) {
|
|
8855
|
+
if (args[0] === "help") {
|
|
8856
|
+
printHelp5();
|
|
8857
|
+
return;
|
|
8858
|
+
}
|
|
8859
|
+
const subcommand = args[0];
|
|
8860
|
+
switch (subcommand) {
|
|
8861
|
+
case "show":
|
|
8862
|
+
case "view": {
|
|
8863
|
+
const name = args.slice(1).join(" ").trim();
|
|
8864
|
+
if (!name) {
|
|
8865
|
+
process.stderr.write(`${red("✗")} Please provide an artifact name.
|
|
8866
|
+
`);
|
|
8867
|
+
process.stderr.write(` Usage: ${bold("locus artifacts show <name>")}
|
|
8868
|
+
`);
|
|
8869
|
+
return;
|
|
8870
|
+
}
|
|
8871
|
+
showArtifact(projectRoot, name);
|
|
8872
|
+
break;
|
|
8873
|
+
}
|
|
8874
|
+
case "plan": {
|
|
8875
|
+
const name = args.slice(1).join(" ").trim();
|
|
8876
|
+
if (!name) {
|
|
8877
|
+
process.stderr.write(`${red("✗")} Please provide an artifact name.
|
|
8878
|
+
`);
|
|
8879
|
+
process.stderr.write(` Usage: ${bold("locus artifacts plan <name>")}
|
|
8880
|
+
`);
|
|
8881
|
+
return;
|
|
8882
|
+
}
|
|
8883
|
+
await convertToPlan(projectRoot, name);
|
|
8884
|
+
break;
|
|
8885
|
+
}
|
|
8886
|
+
default:
|
|
8887
|
+
listArtifactsCommand(projectRoot);
|
|
8888
|
+
break;
|
|
8889
|
+
}
|
|
8890
|
+
}
|
|
8891
|
+
function listArtifactsCommand(projectRoot) {
|
|
8892
|
+
const artifacts = listArtifacts(projectRoot);
|
|
8893
|
+
if (artifacts.length === 0) {
|
|
8894
|
+
process.stderr.write(`${dim("No artifacts found.")}
|
|
8895
|
+
`);
|
|
8896
|
+
return;
|
|
8897
|
+
}
|
|
8898
|
+
process.stderr.write(`
|
|
8899
|
+
${bold("Artifacts")} ${dim(`(${artifacts.length} total)`)}
|
|
8900
|
+
|
|
8901
|
+
`);
|
|
8902
|
+
for (let i = 0;i < artifacts.length; i++) {
|
|
8903
|
+
const a = artifacts[i];
|
|
8904
|
+
const idx = dim(`${String(i + 1).padStart(2)}.`);
|
|
8905
|
+
process.stderr.write(` ${idx} ${cyan(a.name)}
|
|
8906
|
+
`);
|
|
8907
|
+
process.stderr.write(` ${dim(`${formatDate2(a.createdAt)} • ${formatSize(a.size)}`)}
|
|
8908
|
+
`);
|
|
8909
|
+
}
|
|
8910
|
+
process.stderr.write(`
|
|
8911
|
+
${dim("Use")} ${bold("locus artifacts show <name>")} ${dim("to view content")}
|
|
8912
|
+
`);
|
|
8913
|
+
process.stderr.write(` ${dim("Use")} ${bold("locus artifacts plan <name>")} ${dim("to convert to a plan")}
|
|
8914
|
+
|
|
8915
|
+
`);
|
|
8916
|
+
}
|
|
8917
|
+
function showArtifact(projectRoot, name) {
|
|
8918
|
+
const result = readArtifact(projectRoot, name);
|
|
8919
|
+
if (!result) {
|
|
8920
|
+
const artifacts = listArtifacts(projectRoot);
|
|
8921
|
+
const matches = artifacts.filter((a) => a.name.toLowerCase().includes(name.toLowerCase()));
|
|
8922
|
+
if (matches.length === 1) {
|
|
8923
|
+
const match = readArtifact(projectRoot, matches[0].name);
|
|
8924
|
+
if (match) {
|
|
8925
|
+
printArtifact(match.info, match.content);
|
|
8926
|
+
return;
|
|
8927
|
+
}
|
|
8928
|
+
}
|
|
8929
|
+
if (matches.length > 1) {
|
|
8930
|
+
process.stderr.write(`${red("✗")} Multiple artifacts match "${name}":
|
|
8931
|
+
`);
|
|
8932
|
+
for (const m of matches) {
|
|
8933
|
+
process.stderr.write(` ${cyan(m.name)}
|
|
8934
|
+
`);
|
|
8935
|
+
}
|
|
8936
|
+
return;
|
|
8937
|
+
}
|
|
8938
|
+
process.stderr.write(`${red("✗")} Artifact "${name}" not found.
|
|
8939
|
+
`);
|
|
8940
|
+
process.stderr.write(` Run ${bold("locus artifacts")} to see available artifacts.
|
|
8941
|
+
`);
|
|
8942
|
+
return;
|
|
8943
|
+
}
|
|
8944
|
+
printArtifact(result.info, result.content);
|
|
8945
|
+
}
|
|
8946
|
+
function printArtifact(info, content) {
|
|
8947
|
+
const line = dim("─".repeat(50));
|
|
8948
|
+
process.stderr.write(`
|
|
8949
|
+
${bold(info.name)}
|
|
8950
|
+
${dim(`${formatDate2(info.createdAt)} • ${formatSize(info.size)}`)}
|
|
8951
|
+
${line}
|
|
8952
|
+
|
|
8953
|
+
`);
|
|
8954
|
+
process.stdout.write(`${content}
|
|
8955
|
+
`);
|
|
8956
|
+
}
|
|
8957
|
+
async function convertToPlan(projectRoot, name) {
|
|
8958
|
+
const result = readArtifact(projectRoot, name);
|
|
8959
|
+
if (!result) {
|
|
8960
|
+
const artifacts = listArtifacts(projectRoot);
|
|
8961
|
+
const matches = artifacts.filter((a) => a.name.toLowerCase().includes(name.toLowerCase()));
|
|
8962
|
+
if (matches.length === 1) {
|
|
8963
|
+
await runPlanConversion(projectRoot, matches[0].name);
|
|
8964
|
+
return;
|
|
8965
|
+
}
|
|
8966
|
+
process.stderr.write(`${red("✗")} Artifact "${name}" not found.
|
|
8967
|
+
`);
|
|
8968
|
+
process.stderr.write(` Run ${bold("locus artifacts")} to see available artifacts.
|
|
8969
|
+
`);
|
|
8970
|
+
return;
|
|
8971
|
+
}
|
|
8972
|
+
await runPlanConversion(projectRoot, result.info.name);
|
|
8973
|
+
}
|
|
8974
|
+
async function runPlanConversion(projectRoot, artifactName) {
|
|
8975
|
+
const { execCommand: execCommand2 } = await Promise.resolve().then(() => (init_exec(), exports_exec));
|
|
8976
|
+
process.stderr.write(`
|
|
8977
|
+
${bold("Converting artifact to plan:")} ${cyan(artifactName)}
|
|
8978
|
+
|
|
8979
|
+
`);
|
|
8980
|
+
await execCommand2(projectRoot, [`Create a plan according to ${artifactName}`], {});
|
|
8981
|
+
}
|
|
8982
|
+
var init_artifacts = __esm(() => {
|
|
8983
|
+
init_terminal();
|
|
8984
|
+
});
|
|
8985
|
+
|
|
8633
8986
|
// src/cli.ts
|
|
8634
8987
|
init_config();
|
|
8635
8988
|
init_context();
|
|
8636
8989
|
init_logger();
|
|
8637
8990
|
init_rate_limiter();
|
|
8638
8991
|
init_terminal();
|
|
8639
|
-
import {
|
|
8640
|
-
import {
|
|
8992
|
+
import { existsSync as existsSync17, readFileSync as readFileSync14 } from "node:fs";
|
|
8993
|
+
import { join as join18 } from "node:path";
|
|
8641
8994
|
import { fileURLToPath } from "node:url";
|
|
8642
8995
|
function getCliVersion() {
|
|
8643
8996
|
const fallbackVersion = "0.0.0";
|
|
8644
|
-
const packageJsonPath =
|
|
8645
|
-
if (!
|
|
8997
|
+
const packageJsonPath = join18(fileURLToPath(new URL(".", import.meta.url)), "..", "package.json");
|
|
8998
|
+
if (!existsSync17(packageJsonPath)) {
|
|
8646
8999
|
return fallbackVersion;
|
|
8647
9000
|
}
|
|
8648
9001
|
try {
|
|
8649
|
-
const parsed = JSON.parse(
|
|
9002
|
+
const parsed = JSON.parse(readFileSync14(packageJsonPath, "utf-8"));
|
|
8650
9003
|
return parsed.version ?? fallbackVersion;
|
|
8651
9004
|
} catch {
|
|
8652
9005
|
return fallbackVersion;
|
|
@@ -8733,7 +9086,7 @@ function parseArgs(argv) {
|
|
|
8733
9086
|
const args = positional.slice(1);
|
|
8734
9087
|
return { command, args, flags };
|
|
8735
9088
|
}
|
|
8736
|
-
function
|
|
9089
|
+
function printHelp6() {
|
|
8737
9090
|
process.stderr.write(`
|
|
8738
9091
|
${bold("Locus")} ${dim(`v${VERSION}`)} — GitHub-native AI engineering assistant
|
|
8739
9092
|
|
|
@@ -8750,6 +9103,7 @@ ${bold("Commands:")}
|
|
|
8750
9103
|
${cyan("review")} AI-powered code review on PRs
|
|
8751
9104
|
${cyan("iterate")} Re-execute tasks with PR feedback
|
|
8752
9105
|
${cyan("discuss")} AI-powered architectural discussions
|
|
9106
|
+
${cyan("artifacts")} View and manage AI-generated artifacts
|
|
8753
9107
|
${cyan("status")} Dashboard view of current state
|
|
8754
9108
|
${cyan("config")} View and manage settings
|
|
8755
9109
|
${cyan("logs")} View, tail, and manage execution logs
|
|
@@ -8786,7 +9140,7 @@ async function main() {
|
|
|
8786
9140
|
process.exit(0);
|
|
8787
9141
|
}
|
|
8788
9142
|
if (parsed.flags.help && !parsed.command) {
|
|
8789
|
-
|
|
9143
|
+
printHelp6();
|
|
8790
9144
|
process.exit(0);
|
|
8791
9145
|
}
|
|
8792
9146
|
const command = resolveAlias(parsed.command);
|
|
@@ -8797,7 +9151,7 @@ async function main() {
|
|
|
8797
9151
|
try {
|
|
8798
9152
|
const root = getGitRoot(cwd);
|
|
8799
9153
|
if (isInitialized(root)) {
|
|
8800
|
-
logDir =
|
|
9154
|
+
logDir = join18(root, ".locus", "logs");
|
|
8801
9155
|
getRateLimiter(root);
|
|
8802
9156
|
}
|
|
8803
9157
|
} catch {}
|
|
@@ -8818,7 +9172,7 @@ async function main() {
|
|
|
8818
9172
|
printVersionNotice = startVersionCheck2(VERSION);
|
|
8819
9173
|
}
|
|
8820
9174
|
if (!command) {
|
|
8821
|
-
|
|
9175
|
+
printHelp6();
|
|
8822
9176
|
process.exit(0);
|
|
8823
9177
|
}
|
|
8824
9178
|
if (command === "init") {
|
|
@@ -8931,6 +9285,12 @@ async function main() {
|
|
|
8931
9285
|
});
|
|
8932
9286
|
break;
|
|
8933
9287
|
}
|
|
9288
|
+
case "artifacts": {
|
|
9289
|
+
const { artifactsCommand: artifactsCommand2 } = await Promise.resolve().then(() => (init_artifacts(), exports_artifacts));
|
|
9290
|
+
const artifactsArgs = parsed.flags.help ? ["help"] : parsed.args;
|
|
9291
|
+
await artifactsCommand2(projectRoot, artifactsArgs);
|
|
9292
|
+
break;
|
|
9293
|
+
}
|
|
8934
9294
|
case "upgrade": {
|
|
8935
9295
|
const { upgradeCommand: upgradeCommand2 } = await Promise.resolve().then(() => (init_upgrade(), exports_upgrade));
|
|
8936
9296
|
await upgradeCommand2(projectRoot, parsed.args, {
|