@locusai/cli 0.17.4 → 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 +254 -10
- package/package.json +1 -1
package/bin/locus.js
CHANGED
|
@@ -8532,6 +8532,7 @@ import {
|
|
|
8532
8532
|
writeFileSync as writeFileSync8
|
|
8533
8533
|
} from "node:fs";
|
|
8534
8534
|
import { join as join16 } from "node:path";
|
|
8535
|
+
import { createInterface as createInterface2 } from "node:readline";
|
|
8535
8536
|
function printHelp4() {
|
|
8536
8537
|
process.stderr.write(`
|
|
8537
8538
|
${bold("locus discuss")} — AI-powered architectural discussions
|
|
@@ -8564,7 +8565,7 @@ function generateId() {
|
|
|
8564
8565
|
return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
|
|
8565
8566
|
}
|
|
8566
8567
|
async function discussCommand(projectRoot, args, flags = {}) {
|
|
8567
|
-
if (args[0] === "help"
|
|
8568
|
+
if (args[0] === "help") {
|
|
8568
8569
|
printHelp4();
|
|
8569
8570
|
return;
|
|
8570
8571
|
}
|
|
@@ -8578,6 +8579,14 @@ async function discussCommand(projectRoot, args, flags = {}) {
|
|
|
8578
8579
|
if (subcommand === "delete") {
|
|
8579
8580
|
return deleteDiscussion(projectRoot, args[1]);
|
|
8580
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
|
+
}
|
|
8581
8590
|
const topic = args.join(" ").trim();
|
|
8582
8591
|
return startDiscussion(projectRoot, topic, flags);
|
|
8583
8592
|
}
|
|
@@ -8657,6 +8666,21 @@ function deleteDiscussion(projectRoot, id) {
|
|
|
8657
8666
|
process.stderr.write(`${green("✓")} Deleted discussion: ${match.replace(".md", "")}
|
|
8658
8667
|
`);
|
|
8659
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
|
+
}
|
|
8660
8684
|
async function startDiscussion(projectRoot, topic, flags) {
|
|
8661
8685
|
const config = loadConfig(projectRoot);
|
|
8662
8686
|
const timer = createTimer();
|
|
@@ -8746,23 +8770,236 @@ var init_discuss = __esm(() => {
|
|
|
8746
8770
|
init_terminal();
|
|
8747
8771
|
});
|
|
8748
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
|
+
|
|
8749
8986
|
// src/cli.ts
|
|
8750
8987
|
init_config();
|
|
8751
8988
|
init_context();
|
|
8752
8989
|
init_logger();
|
|
8753
8990
|
init_rate_limiter();
|
|
8754
8991
|
init_terminal();
|
|
8755
|
-
import { existsSync as
|
|
8756
|
-
import { join as
|
|
8992
|
+
import { existsSync as existsSync17, readFileSync as readFileSync14 } from "node:fs";
|
|
8993
|
+
import { join as join18 } from "node:path";
|
|
8757
8994
|
import { fileURLToPath } from "node:url";
|
|
8758
8995
|
function getCliVersion() {
|
|
8759
8996
|
const fallbackVersion = "0.0.0";
|
|
8760
|
-
const packageJsonPath =
|
|
8761
|
-
if (!
|
|
8997
|
+
const packageJsonPath = join18(fileURLToPath(new URL(".", import.meta.url)), "..", "package.json");
|
|
8998
|
+
if (!existsSync17(packageJsonPath)) {
|
|
8762
8999
|
return fallbackVersion;
|
|
8763
9000
|
}
|
|
8764
9001
|
try {
|
|
8765
|
-
const parsed = JSON.parse(
|
|
9002
|
+
const parsed = JSON.parse(readFileSync14(packageJsonPath, "utf-8"));
|
|
8766
9003
|
return parsed.version ?? fallbackVersion;
|
|
8767
9004
|
} catch {
|
|
8768
9005
|
return fallbackVersion;
|
|
@@ -8849,7 +9086,7 @@ function parseArgs(argv) {
|
|
|
8849
9086
|
const args = positional.slice(1);
|
|
8850
9087
|
return { command, args, flags };
|
|
8851
9088
|
}
|
|
8852
|
-
function
|
|
9089
|
+
function printHelp6() {
|
|
8853
9090
|
process.stderr.write(`
|
|
8854
9091
|
${bold("Locus")} ${dim(`v${VERSION}`)} — GitHub-native AI engineering assistant
|
|
8855
9092
|
|
|
@@ -8866,6 +9103,7 @@ ${bold("Commands:")}
|
|
|
8866
9103
|
${cyan("review")} AI-powered code review on PRs
|
|
8867
9104
|
${cyan("iterate")} Re-execute tasks with PR feedback
|
|
8868
9105
|
${cyan("discuss")} AI-powered architectural discussions
|
|
9106
|
+
${cyan("artifacts")} View and manage AI-generated artifacts
|
|
8869
9107
|
${cyan("status")} Dashboard view of current state
|
|
8870
9108
|
${cyan("config")} View and manage settings
|
|
8871
9109
|
${cyan("logs")} View, tail, and manage execution logs
|
|
@@ -8902,7 +9140,7 @@ async function main() {
|
|
|
8902
9140
|
process.exit(0);
|
|
8903
9141
|
}
|
|
8904
9142
|
if (parsed.flags.help && !parsed.command) {
|
|
8905
|
-
|
|
9143
|
+
printHelp6();
|
|
8906
9144
|
process.exit(0);
|
|
8907
9145
|
}
|
|
8908
9146
|
const command = resolveAlias(parsed.command);
|
|
@@ -8913,7 +9151,7 @@ async function main() {
|
|
|
8913
9151
|
try {
|
|
8914
9152
|
const root = getGitRoot(cwd);
|
|
8915
9153
|
if (isInitialized(root)) {
|
|
8916
|
-
logDir =
|
|
9154
|
+
logDir = join18(root, ".locus", "logs");
|
|
8917
9155
|
getRateLimiter(root);
|
|
8918
9156
|
}
|
|
8919
9157
|
} catch {}
|
|
@@ -8934,7 +9172,7 @@ async function main() {
|
|
|
8934
9172
|
printVersionNotice = startVersionCheck2(VERSION);
|
|
8935
9173
|
}
|
|
8936
9174
|
if (!command) {
|
|
8937
|
-
|
|
9175
|
+
printHelp6();
|
|
8938
9176
|
process.exit(0);
|
|
8939
9177
|
}
|
|
8940
9178
|
if (command === "init") {
|
|
@@ -9047,6 +9285,12 @@ async function main() {
|
|
|
9047
9285
|
});
|
|
9048
9286
|
break;
|
|
9049
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
|
+
}
|
|
9050
9294
|
case "upgrade": {
|
|
9051
9295
|
const { upgradeCommand: upgradeCommand2 } = await Promise.resolve().then(() => (init_upgrade(), exports_upgrade));
|
|
9052
9296
|
await upgradeCommand2(projectRoot, parsed.args, {
|