@locusai/cli 0.15.1 → 0.15.3
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/agent/worker.js +1 -0
- package/bin/locus.js +171 -51
- package/package.json +4 -4
package/bin/agent/worker.js
CHANGED
|
@@ -15621,6 +15621,7 @@ var init_resolve_bin = __esm(() => {
|
|
|
15621
15621
|
join2(homedir(), ".local", "bin"),
|
|
15622
15622
|
join2(homedir(), ".npm", "bin"),
|
|
15623
15623
|
join2(homedir(), ".npm-global", "bin"),
|
|
15624
|
+
join2(homedir(), ".npm-packages", "bin"),
|
|
15624
15625
|
join2(homedir(), ".yarn", "bin"),
|
|
15625
15626
|
join2(homedir(), ".bun", "bin"),
|
|
15626
15627
|
join2(homedir(), "Library", "pnpm"),
|
package/bin/locus.js
CHANGED
|
@@ -7055,6 +7055,7 @@ var init_resolve_bin = __esm(() => {
|
|
|
7055
7055
|
join4(homedir(), ".local", "bin"),
|
|
7056
7056
|
join4(homedir(), ".npm", "bin"),
|
|
7057
7057
|
join4(homedir(), ".npm-global", "bin"),
|
|
7058
|
+
join4(homedir(), ".npm-packages", "bin"),
|
|
7058
7059
|
join4(homedir(), ".yarn", "bin"),
|
|
7059
7060
|
join4(homedir(), ".bun", "bin"),
|
|
7060
7061
|
join4(homedir(), "Library", "pnpm"),
|
|
@@ -43125,31 +43126,19 @@ class ProgressRenderer {
|
|
|
43125
43126
|
toolDisplay = new ToolDisplay;
|
|
43126
43127
|
toolDisplayShown = false;
|
|
43127
43128
|
thinkingShown = false;
|
|
43128
|
-
animated;
|
|
43129
43129
|
spinnerInterval = null;
|
|
43130
43130
|
spinnerFrameIndex = 0;
|
|
43131
43131
|
thinkingStartTime = null;
|
|
43132
43132
|
isInTextBlock = false;
|
|
43133
43133
|
textBuffer = "";
|
|
43134
|
-
constructor(options = {}) {
|
|
43135
|
-
this.animated = options.animated ?? false;
|
|
43136
|
-
}
|
|
43137
43134
|
showThinkingStarted() {
|
|
43138
43135
|
if (this.isThinking)
|
|
43139
43136
|
return;
|
|
43140
43137
|
this.isThinking = true;
|
|
43141
43138
|
this.thinkingStartTime = Date.now();
|
|
43142
|
-
if (this.
|
|
43143
|
-
|
|
43144
|
-
|
|
43145
|
-
this.startThinkingAnimation();
|
|
43146
|
-
}
|
|
43147
|
-
} else {
|
|
43148
|
-
if (!this.thinkingShown) {
|
|
43149
|
-
console.log(c.dim(`\uD83E\uDD14 Thinking...
|
|
43150
|
-
`));
|
|
43151
|
-
this.thinkingShown = true;
|
|
43152
|
-
}
|
|
43139
|
+
if (!this.thinkingShown) {
|
|
43140
|
+
this.thinkingShown = true;
|
|
43141
|
+
this.startThinkingAnimation();
|
|
43153
43142
|
}
|
|
43154
43143
|
}
|
|
43155
43144
|
showThinkingStopped() {
|
|
@@ -43180,7 +43169,7 @@ class ProgressRenderer {
|
|
|
43180
43169
|
clearInterval(this.spinnerInterval);
|
|
43181
43170
|
this.spinnerInterval = null;
|
|
43182
43171
|
}
|
|
43183
|
-
if (this.
|
|
43172
|
+
if (this.thinkingShown && this.isThinking) {
|
|
43184
43173
|
process.stdout.write(`${ANSI.MOVE_TO_START}${ANSI.CLEAR_LINE}
|
|
43185
43174
|
`);
|
|
43186
43175
|
}
|
|
@@ -44123,7 +44112,7 @@ class InteractiveSession {
|
|
|
44123
44112
|
model: options.model
|
|
44124
44113
|
});
|
|
44125
44114
|
this.promptBuilder = new PromptBuilder(options.projectPath);
|
|
44126
|
-
this.renderer = new ProgressRenderer
|
|
44115
|
+
this.renderer = new ProgressRenderer;
|
|
44127
44116
|
this.historyManager = new HistoryManager(options.projectPath);
|
|
44128
44117
|
this.projectPath = options.projectPath;
|
|
44129
44118
|
this.model = options.model;
|
|
@@ -44865,7 +44854,7 @@ async function discussCommand(args) {
|
|
|
44865
44854
|
console.log(` ${c.dim("Topic:")} ${c.bold(topic)}`);
|
|
44866
44855
|
console.log(` ${c.dim("Model:")} ${c.dim(`${model} (${provider})`)}
|
|
44867
44856
|
`);
|
|
44868
|
-
const renderer = new ProgressRenderer
|
|
44857
|
+
const renderer = new ProgressRenderer;
|
|
44869
44858
|
let discussionId;
|
|
44870
44859
|
try {
|
|
44871
44860
|
renderer.showThinkingStarted();
|
|
@@ -44929,7 +44918,7 @@ async function discussCommand(args) {
|
|
|
44929
44918
|
}
|
|
44930
44919
|
if (lowerInput === "summary") {
|
|
44931
44920
|
isProcessing = true;
|
|
44932
|
-
const summaryRenderer = new ProgressRenderer
|
|
44921
|
+
const summaryRenderer = new ProgressRenderer;
|
|
44933
44922
|
try {
|
|
44934
44923
|
summaryRenderer.showThinkingStarted();
|
|
44935
44924
|
const summary = await facilitator.summarizeDiscussion(discussionId);
|
|
@@ -44973,7 +44962,7 @@ async function discussCommand(args) {
|
|
|
44973
44962
|
const cleanedInput = stripImagePaths(trimmed, images);
|
|
44974
44963
|
const effectiveInput = cleanedInput + buildImageContext(images);
|
|
44975
44964
|
isProcessing = true;
|
|
44976
|
-
const chunkRenderer = new ProgressRenderer
|
|
44965
|
+
const chunkRenderer = new ProgressRenderer;
|
|
44977
44966
|
try {
|
|
44978
44967
|
chunkRenderer.showThinkingStarted();
|
|
44979
44968
|
const stream4 = facilitator.continueDiscussionStream(discussionId, effectiveInput);
|
|
@@ -46274,9 +46263,93 @@ init_index_node();
|
|
|
46274
46263
|
init_settings_manager();
|
|
46275
46264
|
init_utils3();
|
|
46276
46265
|
import { spawn as spawn4 } from "node:child_process";
|
|
46277
|
-
import { existsSync as existsSync20, writeFileSync as writeFileSync9 } from "node:fs";
|
|
46266
|
+
import { existsSync as existsSync20, readdirSync as readdirSync6, readFileSync as readFileSync15, writeFileSync as writeFileSync9 } from "node:fs";
|
|
46278
46267
|
import { homedir as homedir3 } from "node:os";
|
|
46279
|
-
import { join as join20 } from "node:path";
|
|
46268
|
+
import { dirname as dirname4, join as join20 } from "node:path";
|
|
46269
|
+
async function findBinary() {
|
|
46270
|
+
const result = await runShell("which", ["locus-telegram"]);
|
|
46271
|
+
const p = result.stdout.trim();
|
|
46272
|
+
return p?.startsWith?.("/") ? p : null;
|
|
46273
|
+
}
|
|
46274
|
+
async function findBinDir(binary) {
|
|
46275
|
+
const result = await runShell("which", [binary]);
|
|
46276
|
+
const p = result.stdout.trim();
|
|
46277
|
+
if (p?.startsWith?.("/"))
|
|
46278
|
+
return dirname4(p);
|
|
46279
|
+
return null;
|
|
46280
|
+
}
|
|
46281
|
+
function resolveNvmBinDir() {
|
|
46282
|
+
const nvmDir = process.env.NVM_DIR || join20(homedir3(), ".nvm");
|
|
46283
|
+
const versionsDir = join20(nvmDir, "versions", "node");
|
|
46284
|
+
if (!existsSync20(versionsDir))
|
|
46285
|
+
return null;
|
|
46286
|
+
let versions2;
|
|
46287
|
+
try {
|
|
46288
|
+
versions2 = readdirSync6(versionsDir).filter((d) => d.startsWith("v"));
|
|
46289
|
+
} catch {
|
|
46290
|
+
return null;
|
|
46291
|
+
}
|
|
46292
|
+
if (versions2.length === 0)
|
|
46293
|
+
return null;
|
|
46294
|
+
const currentNodeVersion = `v${process.versions.node}`;
|
|
46295
|
+
const currentBin = join20(versionsDir, currentNodeVersion, "bin");
|
|
46296
|
+
if (versions2.includes(currentNodeVersion) && existsSync20(currentBin)) {
|
|
46297
|
+
return currentBin;
|
|
46298
|
+
}
|
|
46299
|
+
const aliasPath = join20(nvmDir, "alias", "default");
|
|
46300
|
+
if (existsSync20(aliasPath)) {
|
|
46301
|
+
try {
|
|
46302
|
+
const alias = readFileSync15(aliasPath, "utf-8").trim();
|
|
46303
|
+
const match = versions2.find((v) => v === `v${alias}` || v.startsWith(`v${alias}.`));
|
|
46304
|
+
if (match) {
|
|
46305
|
+
const bin2 = join20(versionsDir, match, "bin");
|
|
46306
|
+
if (existsSync20(bin2))
|
|
46307
|
+
return bin2;
|
|
46308
|
+
}
|
|
46309
|
+
} catch {}
|
|
46310
|
+
}
|
|
46311
|
+
const sorted = versions2.sort((a, b) => {
|
|
46312
|
+
const pa = a.slice(1).split(".").map(Number);
|
|
46313
|
+
const pb = b.slice(1).split(".").map(Number);
|
|
46314
|
+
for (let i = 0;i < 3; i++) {
|
|
46315
|
+
if ((pa[i] || 0) !== (pb[i] || 0))
|
|
46316
|
+
return (pb[i] || 0) - (pa[i] || 0);
|
|
46317
|
+
}
|
|
46318
|
+
return 0;
|
|
46319
|
+
});
|
|
46320
|
+
const bin = join20(versionsDir, sorted[0], "bin");
|
|
46321
|
+
return existsSync20(bin) ? bin : null;
|
|
46322
|
+
}
|
|
46323
|
+
async function buildServicePath() {
|
|
46324
|
+
const home = homedir3();
|
|
46325
|
+
const dirs = new Set;
|
|
46326
|
+
dirs.add("/usr/local/bin");
|
|
46327
|
+
dirs.add("/usr/bin");
|
|
46328
|
+
dirs.add("/bin");
|
|
46329
|
+
const candidates = [
|
|
46330
|
+
join20(home, ".bun", "bin"),
|
|
46331
|
+
join20(home, ".local", "bin"),
|
|
46332
|
+
join20(home, ".npm", "bin"),
|
|
46333
|
+
join20(home, ".npm-global", "bin"),
|
|
46334
|
+
join20(home, ".yarn", "bin")
|
|
46335
|
+
];
|
|
46336
|
+
for (const d of candidates) {
|
|
46337
|
+
if (existsSync20(d))
|
|
46338
|
+
dirs.add(d);
|
|
46339
|
+
}
|
|
46340
|
+
const nvmBin = resolveNvmBinDir();
|
|
46341
|
+
if (nvmBin)
|
|
46342
|
+
dirs.add(nvmBin);
|
|
46343
|
+
const fnmCurrent = join20(home, ".fnm", "current", "bin");
|
|
46344
|
+
if (existsSync20(fnmCurrent))
|
|
46345
|
+
dirs.add(fnmCurrent);
|
|
46346
|
+
for (const bin of ["claude", "codex"]) {
|
|
46347
|
+
const dir = await findBinDir(bin);
|
|
46348
|
+
if (dir)
|
|
46349
|
+
dirs.add(dir);
|
|
46350
|
+
}
|
|
46351
|
+
return Array.from(dirs).join(":");
|
|
46352
|
+
}
|
|
46280
46353
|
var SERVICE_NAME = "locus";
|
|
46281
46354
|
var SYSTEMD_UNIT_PATH = `/etc/systemd/system/${SERVICE_NAME}.service`;
|
|
46282
46355
|
var PLIST_LABEL = "com.locus.agent";
|
|
@@ -46316,7 +46389,7 @@ function runShell(cmd, args) {
|
|
|
46316
46389
|
proc.on("error", (err) => resolve2({ exitCode: 1, stdout, stderr: err.message }));
|
|
46317
46390
|
});
|
|
46318
46391
|
}
|
|
46319
|
-
function generateSystemdUnit(projectPath, user2, binaryPath) {
|
|
46392
|
+
function generateSystemdUnit(projectPath, user2, binaryPath, servicePath) {
|
|
46320
46393
|
return `[Unit]
|
|
46321
46394
|
Description=Locus AI Agent (Telegram bot + proposal scheduler)
|
|
46322
46395
|
After=network-online.target
|
|
@@ -46329,7 +46402,7 @@ WorkingDirectory=${projectPath}
|
|
|
46329
46402
|
ExecStart=${binaryPath}
|
|
46330
46403
|
Restart=on-failure
|
|
46331
46404
|
RestartSec=10
|
|
46332
|
-
Environment=PATH
|
|
46405
|
+
Environment=PATH=${servicePath}
|
|
46333
46406
|
Environment=HOME=${homedir3()}
|
|
46334
46407
|
|
|
46335
46408
|
[Install]
|
|
@@ -46338,18 +46411,30 @@ WantedBy=multi-user.target
|
|
|
46338
46411
|
}
|
|
46339
46412
|
async function installSystemd(projectPath) {
|
|
46340
46413
|
const user2 = process.env.USER || "root";
|
|
46341
|
-
const
|
|
46342
|
-
|
|
46343
|
-
|
|
46344
|
-
|
|
46345
|
-
|
|
46346
|
-
|
|
46347
|
-
|
|
46348
|
-
|
|
46349
|
-
|
|
46350
|
-
|
|
46414
|
+
const binaryPath = await findBinary();
|
|
46415
|
+
if (!binaryPath) {
|
|
46416
|
+
console.error(`
|
|
46417
|
+
${c.error("✖")} ${c.bold("Could not find locus-telegram binary.")}
|
|
46418
|
+
` + ` Install with: ${c.primary("npm install -g @locusai/telegram")}
|
|
46419
|
+
`);
|
|
46420
|
+
process.exit(1);
|
|
46421
|
+
}
|
|
46422
|
+
if (!await findBinDir("claude")) {
|
|
46423
|
+
console.warn(`
|
|
46424
|
+
${c.secondary("⚠")} ${c.bold("Could not find 'claude' CLI in PATH.")}
|
|
46425
|
+
` + ` The service needs the Claude Code CLI to execute tasks.
|
|
46426
|
+
` + ` Install with: ${c.primary("npm install -g @anthropic-ai/claude-code")}
|
|
46427
|
+
`);
|
|
46351
46428
|
}
|
|
46352
|
-
|
|
46429
|
+
if (!await findBinDir("codex")) {
|
|
46430
|
+
console.warn(`
|
|
46431
|
+
${c.secondary("⚠")} ${c.bold("Could not find 'codex' CLI in PATH.")}
|
|
46432
|
+
` + ` The service needs the Codex CLI if using the Codex provider.
|
|
46433
|
+
` + ` Install with: ${c.primary("npm install -g @openai/codex")}
|
|
46434
|
+
`);
|
|
46435
|
+
}
|
|
46436
|
+
const servicePath = await buildServicePath();
|
|
46437
|
+
const unit = generateSystemdUnit(projectPath, user2, binaryPath, servicePath);
|
|
46353
46438
|
console.log(`
|
|
46354
46439
|
${c.info("▶")} Writing systemd unit to ${c.dim(SYSTEMD_UNIT_PATH)}`);
|
|
46355
46440
|
writeFileSync9(SYSTEMD_UNIT_PATH, unit, "utf-8");
|
|
@@ -46414,7 +46499,7 @@ async function statusSystemd() {
|
|
|
46414
46499
|
`);
|
|
46415
46500
|
}
|
|
46416
46501
|
}
|
|
46417
|
-
function generatePlist(projectPath, binaryPath, binaryArgs) {
|
|
46502
|
+
function generatePlist(projectPath, binaryPath, binaryArgs, servicePath) {
|
|
46418
46503
|
const argsXml = [binaryPath, ...binaryArgs].map((a) => ` <string>${a}</string>`).join(`
|
|
46419
46504
|
`);
|
|
46420
46505
|
const logDir = join20(homedir3(), "Library/Logs/Locus");
|
|
@@ -46441,7 +46526,7 @@ ${argsXml}
|
|
|
46441
46526
|
<key>EnvironmentVariables</key>
|
|
46442
46527
|
<dict>
|
|
46443
46528
|
<key>PATH</key>
|
|
46444
|
-
<string
|
|
46529
|
+
<string>${servicePath}</string>
|
|
46445
46530
|
</dict>
|
|
46446
46531
|
</dict>
|
|
46447
46532
|
</plist>
|
|
@@ -46452,26 +46537,36 @@ async function installLaunchd(projectPath) {
|
|
|
46452
46537
|
if (existsSync20(plistPath)) {
|
|
46453
46538
|
await runShell("launchctl", ["unload", plistPath]);
|
|
46454
46539
|
}
|
|
46455
|
-
const
|
|
46456
|
-
|
|
46457
|
-
|
|
46458
|
-
|
|
46459
|
-
|
|
46460
|
-
|
|
46461
|
-
|
|
46462
|
-
|
|
46463
|
-
|
|
46464
|
-
|
|
46465
|
-
|
|
46466
|
-
|
|
46467
|
-
|
|
46540
|
+
const binaryPath = await findBinary();
|
|
46541
|
+
if (!binaryPath) {
|
|
46542
|
+
console.error(`
|
|
46543
|
+
${c.error("✖")} ${c.bold("Could not find locus-telegram binary.")}
|
|
46544
|
+
Install with: ${c.primary("npm install -g @locusai/telegram")}
|
|
46545
|
+
`);
|
|
46546
|
+
process.exit(1);
|
|
46547
|
+
}
|
|
46548
|
+
const binaryArgs = [];
|
|
46549
|
+
if (!await findBinDir("claude")) {
|
|
46550
|
+
console.warn(`
|
|
46551
|
+
${c.secondary("⚠")} ${c.bold("Could not find 'claude' CLI in PATH.")}
|
|
46552
|
+
The service needs the Claude Code CLI to execute tasks.
|
|
46553
|
+
Install with: ${c.primary("npm install -g @anthropic-ai/claude-code")}
|
|
46554
|
+
`);
|
|
46555
|
+
}
|
|
46556
|
+
if (!await findBinDir("codex")) {
|
|
46557
|
+
console.warn(`
|
|
46558
|
+
${c.secondary("⚠")} ${c.bold("Could not find 'codex' CLI in PATH.")}
|
|
46559
|
+
The service needs the Codex CLI if using the Codex provider.
|
|
46560
|
+
Install with: ${c.primary("npm install -g @openai/codex")}
|
|
46561
|
+
`);
|
|
46468
46562
|
}
|
|
46469
46563
|
const logDir = join20(homedir3(), "Library/Logs/Locus");
|
|
46470
46564
|
const { mkdirSync: mkdirSync10 } = await import("node:fs");
|
|
46471
46565
|
mkdirSync10(logDir, { recursive: true });
|
|
46472
46566
|
const launchAgentsDir = join20(homedir3(), "Library/LaunchAgents");
|
|
46473
46567
|
mkdirSync10(launchAgentsDir, { recursive: true });
|
|
46474
|
-
const
|
|
46568
|
+
const servicePath = await buildServicePath();
|
|
46569
|
+
const plist = generatePlist(projectPath, binaryPath, binaryArgs, servicePath);
|
|
46475
46570
|
console.log(`
|
|
46476
46571
|
${c.info("▶")} Writing plist to ${c.dim(plistPath)}`);
|
|
46477
46572
|
writeFileSync9(plistPath, plist, "utf-8");
|
|
@@ -46930,7 +47025,10 @@ async function telegramCommand(args) {
|
|
|
46930
47025
|
// src/commands/upgrade.ts
|
|
46931
47026
|
init_index_node();
|
|
46932
47027
|
import { execSync as execSync3 } from "node:child_process";
|
|
47028
|
+
import { existsSync as existsSync22 } from "node:fs";
|
|
46933
47029
|
var PACKAGES = ["@locusai/cli", "@locusai/telegram"];
|
|
47030
|
+
var SYSTEMD_UNIT_PATH2 = "/etc/systemd/system/locus.service";
|
|
47031
|
+
var SYSTEMD_TELEGRAM_UNIT_PATH = "/etc/systemd/system/locus-telegram.service";
|
|
46934
47032
|
function getInstalledVersion(pkg) {
|
|
46935
47033
|
try {
|
|
46936
47034
|
const output = execSync3(`npm list -g ${pkg} --depth=0 --json`, {
|
|
@@ -46996,6 +47094,28 @@ async function upgradeCommand() {
|
|
|
46996
47094
|
`);
|
|
46997
47095
|
}
|
|
46998
47096
|
}
|
|
47097
|
+
if (process.platform === "linux") {
|
|
47098
|
+
for (const unit of [SYSTEMD_UNIT_PATH2, SYSTEMD_TELEGRAM_UNIT_PATH]) {
|
|
47099
|
+
if (!existsSync22(unit))
|
|
47100
|
+
continue;
|
|
47101
|
+
const split = unit.split("/").pop();
|
|
47102
|
+
if (!split) {
|
|
47103
|
+
throw "PATH NOTH FOUND";
|
|
47104
|
+
}
|
|
47105
|
+
const name = split.replace(".service", "");
|
|
47106
|
+
try {
|
|
47107
|
+
console.log(` ${c.info("▶")} Restarting ${name} service...`);
|
|
47108
|
+
execSync3(`systemctl restart ${name}`, {
|
|
47109
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
47110
|
+
});
|
|
47111
|
+
console.log(` ${c.success("✔")} ${name} service restarted
|
|
47112
|
+
`);
|
|
47113
|
+
} catch {
|
|
47114
|
+
console.log(` ${c.dim("⚠")} Could not restart ${name} service (may need sudo)
|
|
47115
|
+
`);
|
|
47116
|
+
}
|
|
47117
|
+
}
|
|
47118
|
+
}
|
|
46999
47119
|
console.log("");
|
|
47000
47120
|
}
|
|
47001
47121
|
// src/commands/version.ts
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@locusai/cli",
|
|
3
|
-
"version": "0.15.
|
|
3
|
+
"version": "0.15.3",
|
|
4
4
|
"description": "CLI for Locus - AI-native project management platform",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -32,9 +32,9 @@
|
|
|
32
32
|
"author": "",
|
|
33
33
|
"license": "MIT",
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@locusai/sdk": "^0.15.
|
|
36
|
-
"@locusai/shared": "^0.15.
|
|
37
|
-
"@locusai/telegram": "^0.15.
|
|
35
|
+
"@locusai/sdk": "^0.15.3",
|
|
36
|
+
"@locusai/shared": "^0.15.3",
|
|
37
|
+
"@locusai/telegram": "^0.15.3"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {}
|
|
40
40
|
}
|