@locusai/cli 0.25.2 → 0.25.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/locus.js +220 -75
- package/package.json +2 -2
package/bin/locus.js
CHANGED
|
@@ -3352,46 +3352,155 @@ var init_lock = __esm(() => {
|
|
|
3352
3352
|
});
|
|
3353
3353
|
|
|
3354
3354
|
// src/skills/installer.ts
|
|
3355
|
-
import {
|
|
3355
|
+
import {
|
|
3356
|
+
existsSync as existsSync11,
|
|
3357
|
+
mkdirSync as mkdirSync8,
|
|
3358
|
+
readFileSync as readFileSync8,
|
|
3359
|
+
renameSync as renameSync2,
|
|
3360
|
+
rmSync,
|
|
3361
|
+
writeFileSync as writeFileSync8
|
|
3362
|
+
} from "node:fs";
|
|
3363
|
+
import { tmpdir } from "node:os";
|
|
3356
3364
|
import { join as join11 } from "node:path";
|
|
3357
3365
|
async function installSkill(projectRoot, name, content, source) {
|
|
3358
3366
|
const claudeDir = join11(projectRoot, CLAUDE_SKILLS_DIR, name);
|
|
3359
3367
|
const agentsDir = join11(projectRoot, AGENTS_SKILLS_DIR, name);
|
|
3360
|
-
|
|
3361
|
-
|
|
3362
|
-
|
|
3363
|
-
|
|
3364
|
-
|
|
3365
|
-
|
|
3366
|
-
|
|
3367
|
-
|
|
3368
|
-
|
|
3369
|
-
|
|
3370
|
-
|
|
3368
|
+
const stagingDir = join11(tmpdir(), `locus-skill-${name}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`);
|
|
3369
|
+
const stagingClaudeDir = join11(stagingDir, "claude");
|
|
3370
|
+
const stagingAgentsDir = join11(stagingDir, "agents");
|
|
3371
|
+
let wroteClaudeDir = false;
|
|
3372
|
+
let wroteAgentsDir = false;
|
|
3373
|
+
try {
|
|
3374
|
+
try {
|
|
3375
|
+
mkdirSync8(stagingClaudeDir, { recursive: true });
|
|
3376
|
+
mkdirSync8(stagingAgentsDir, { recursive: true });
|
|
3377
|
+
writeFileSync8(join11(stagingClaudeDir, "SKILL.md"), content, "utf-8");
|
|
3378
|
+
writeFileSync8(join11(stagingAgentsDir, "SKILL.md"), content, "utf-8");
|
|
3379
|
+
} catch (err) {
|
|
3380
|
+
throw new SkillInstallError(name, "stage", err);
|
|
3381
|
+
}
|
|
3382
|
+
try {
|
|
3383
|
+
if (!content || content.trim().length === 0) {
|
|
3384
|
+
throw new Error("Skill content is empty");
|
|
3385
|
+
}
|
|
3386
|
+
const expectedHash = computeSkillHash(content);
|
|
3387
|
+
const stagedContent = readFileSync8(join11(stagingClaudeDir, "SKILL.md"), "utf-8");
|
|
3388
|
+
const stagedHash = computeSkillHash(stagedContent);
|
|
3389
|
+
if (stagedHash !== expectedHash) {
|
|
3390
|
+
throw new Error("Staged file hash does not match expected content");
|
|
3391
|
+
}
|
|
3392
|
+
} catch (err) {
|
|
3393
|
+
if (err instanceof SkillInstallError)
|
|
3394
|
+
throw err;
|
|
3395
|
+
throw new SkillInstallError(name, "validate", err);
|
|
3396
|
+
}
|
|
3397
|
+
try {
|
|
3398
|
+
mkdirSync8(join11(projectRoot, CLAUDE_SKILLS_DIR), { recursive: true });
|
|
3399
|
+
mkdirSync8(join11(projectRoot, AGENTS_SKILLS_DIR), { recursive: true });
|
|
3400
|
+
if (existsSync11(claudeDir)) {
|
|
3401
|
+
rmSync(claudeDir, { recursive: true, force: true });
|
|
3402
|
+
}
|
|
3403
|
+
if (existsSync11(agentsDir)) {
|
|
3404
|
+
rmSync(agentsDir, { recursive: true, force: true });
|
|
3405
|
+
}
|
|
3406
|
+
try {
|
|
3407
|
+
renameSync2(stagingClaudeDir, claudeDir);
|
|
3408
|
+
wroteClaudeDir = true;
|
|
3409
|
+
} catch {
|
|
3410
|
+
mkdirSync8(claudeDir, { recursive: true });
|
|
3411
|
+
writeFileSync8(join11(claudeDir, "SKILL.md"), content, "utf-8");
|
|
3412
|
+
wroteClaudeDir = true;
|
|
3413
|
+
}
|
|
3414
|
+
try {
|
|
3415
|
+
renameSync2(stagingAgentsDir, agentsDir);
|
|
3416
|
+
wroteAgentsDir = true;
|
|
3417
|
+
} catch {
|
|
3418
|
+
mkdirSync8(agentsDir, { recursive: true });
|
|
3419
|
+
writeFileSync8(join11(agentsDir, "SKILL.md"), content, "utf-8");
|
|
3420
|
+
wroteAgentsDir = true;
|
|
3421
|
+
}
|
|
3422
|
+
} catch (err) {
|
|
3423
|
+
if (err instanceof SkillInstallError)
|
|
3424
|
+
throw err;
|
|
3425
|
+
throw new SkillInstallError(name, "write", err);
|
|
3426
|
+
}
|
|
3427
|
+
try {
|
|
3428
|
+
const lock = readLockFile(projectRoot);
|
|
3429
|
+
lock.skills[name] = {
|
|
3430
|
+
source,
|
|
3431
|
+
sourceType: "github",
|
|
3432
|
+
computedHash: computeSkillHash(content)
|
|
3433
|
+
};
|
|
3434
|
+
writeLockFile(projectRoot, lock);
|
|
3435
|
+
} catch (err) {
|
|
3436
|
+
throw new SkillInstallError(name, "register", err);
|
|
3437
|
+
}
|
|
3438
|
+
} catch (err) {
|
|
3439
|
+
if (wroteClaudeDir && existsSync11(claudeDir)) {
|
|
3440
|
+
rmSync(claudeDir, { recursive: true, force: true });
|
|
3441
|
+
}
|
|
3442
|
+
if (wroteAgentsDir && existsSync11(agentsDir)) {
|
|
3443
|
+
rmSync(agentsDir, { recursive: true, force: true });
|
|
3444
|
+
}
|
|
3445
|
+
throw err;
|
|
3446
|
+
} finally {
|
|
3447
|
+
if (existsSync11(stagingDir)) {
|
|
3448
|
+
rmSync(stagingDir, { recursive: true, force: true });
|
|
3449
|
+
}
|
|
3450
|
+
}
|
|
3371
3451
|
}
|
|
3372
3452
|
async function removeSkill(projectRoot, name) {
|
|
3373
|
-
|
|
3453
|
+
const claudeDir = join11(projectRoot, CLAUDE_SKILLS_DIR, name);
|
|
3454
|
+
const agentsDir = join11(projectRoot, AGENTS_SKILLS_DIR, name);
|
|
3455
|
+
const lock = readLockFile(projectRoot);
|
|
3456
|
+
const inLockFile = name in lock.skills;
|
|
3457
|
+
const hasClaude = existsSync11(claudeDir);
|
|
3458
|
+
const hasAgents = existsSync11(agentsDir);
|
|
3459
|
+
if (!inLockFile && !hasClaude && !hasAgents) {
|
|
3374
3460
|
console.warn(`Skill "${name}" is not installed.`);
|
|
3375
3461
|
return;
|
|
3376
3462
|
}
|
|
3377
|
-
|
|
3378
|
-
const agentsDir = join11(projectRoot, AGENTS_SKILLS_DIR, name);
|
|
3379
|
-
if (existsSync11(claudeDir)) {
|
|
3463
|
+
if (hasClaude) {
|
|
3380
3464
|
rmSync(claudeDir, { recursive: true, force: true });
|
|
3381
3465
|
}
|
|
3382
|
-
if (
|
|
3466
|
+
if (hasAgents) {
|
|
3383
3467
|
rmSync(agentsDir, { recursive: true, force: true });
|
|
3384
3468
|
}
|
|
3385
|
-
|
|
3386
|
-
|
|
3387
|
-
|
|
3469
|
+
if (inLockFile) {
|
|
3470
|
+
delete lock.skills[name];
|
|
3471
|
+
writeLockFile(projectRoot, lock);
|
|
3472
|
+
}
|
|
3388
3473
|
}
|
|
3389
3474
|
function isSkillInstalled(projectRoot, name) {
|
|
3390
3475
|
const lock = readLockFile(projectRoot);
|
|
3391
3476
|
return name in lock.skills;
|
|
3392
3477
|
}
|
|
3478
|
+
function hasOrphanedSkillFiles(projectRoot, name) {
|
|
3479
|
+
const claudeDir = join11(projectRoot, CLAUDE_SKILLS_DIR, name);
|
|
3480
|
+
const agentsDir = join11(projectRoot, AGENTS_SKILLS_DIR, name);
|
|
3481
|
+
const inLockFile = isSkillInstalled(projectRoot, name);
|
|
3482
|
+
return !inLockFile && (existsSync11(claudeDir) || existsSync11(agentsDir));
|
|
3483
|
+
}
|
|
3484
|
+
var SkillInstallError;
|
|
3393
3485
|
var init_installer = __esm(() => {
|
|
3394
3486
|
init_lock();
|
|
3487
|
+
SkillInstallError = class SkillInstallError extends Error {
|
|
3488
|
+
skillName;
|
|
3489
|
+
step;
|
|
3490
|
+
constructor(skillName, step, cause) {
|
|
3491
|
+
const stepLabel = {
|
|
3492
|
+
stage: "staging files to temp directory",
|
|
3493
|
+
validate: "validating skill content",
|
|
3494
|
+
write: "writing skill files to project",
|
|
3495
|
+
register: "updating skills-lock.json"
|
|
3496
|
+
};
|
|
3497
|
+
const reason = cause instanceof Error ? cause.message : String(cause ?? "");
|
|
3498
|
+
super(`Failed to install '${skillName}' during ${stepLabel[step]}${reason ? `: ${reason}` : ""}`);
|
|
3499
|
+
this.skillName = skillName;
|
|
3500
|
+
this.step = step;
|
|
3501
|
+
this.name = "SkillInstallError";
|
|
3502
|
+
}
|
|
3503
|
+
};
|
|
3395
3504
|
});
|
|
3396
3505
|
|
|
3397
3506
|
// src/skills/registry.ts
|
|
@@ -3565,7 +3674,22 @@ async function installRemoteSkill(name) {
|
|
|
3565
3674
|
}
|
|
3566
3675
|
const cwd = process.cwd();
|
|
3567
3676
|
const source = `${REGISTRY_REPO}/${entry.path}`;
|
|
3568
|
-
|
|
3677
|
+
try {
|
|
3678
|
+
await installSkill(cwd, name, content, source);
|
|
3679
|
+
} catch (err) {
|
|
3680
|
+
if (err instanceof SkillInstallError) {
|
|
3681
|
+
process.stderr.write(`${red2("✗")} ${err.message}
|
|
3682
|
+
`);
|
|
3683
|
+
process.stderr.write(` To clean up and retry: ${bold2(`locus skills remove ${name}`)} then ${bold2(`locus skills install ${name}`)}
|
|
3684
|
+
`);
|
|
3685
|
+
} else {
|
|
3686
|
+
process.stderr.write(`${red2("✗")} Unexpected error installing skill '${name}'.
|
|
3687
|
+
`);
|
|
3688
|
+
process.stderr.write(` ${dim2(err.message)}
|
|
3689
|
+
`);
|
|
3690
|
+
}
|
|
3691
|
+
process.exit(1);
|
|
3692
|
+
}
|
|
3569
3693
|
process.stderr.write(`
|
|
3570
3694
|
${green("✓")} Installed skill '${bold2(name)}' from ${REGISTRY_REPO}
|
|
3571
3695
|
`);
|
|
@@ -3584,7 +3708,9 @@ async function removeInstalledSkill(name) {
|
|
|
3584
3708
|
process.exit(1);
|
|
3585
3709
|
}
|
|
3586
3710
|
const cwd = process.cwd();
|
|
3587
|
-
|
|
3711
|
+
const installed = isSkillInstalled(cwd, name);
|
|
3712
|
+
const orphaned = hasOrphanedSkillFiles(cwd, name);
|
|
3713
|
+
if (!installed && !orphaned) {
|
|
3588
3714
|
process.stderr.write(`${red2("✗")} Skill '${bold2(name)}' is not installed.
|
|
3589
3715
|
`);
|
|
3590
3716
|
process.stderr.write(` Run ${bold2("locus skills list --installed")} to see installed skills.
|
|
@@ -3592,8 +3718,13 @@ async function removeInstalledSkill(name) {
|
|
|
3592
3718
|
process.exit(1);
|
|
3593
3719
|
}
|
|
3594
3720
|
await removeSkill(cwd, name);
|
|
3595
|
-
|
|
3721
|
+
if (orphaned) {
|
|
3722
|
+
process.stderr.write(`${green("✓")} Cleaned up orphaned skill files for '${bold2(name)}'
|
|
3723
|
+
`);
|
|
3724
|
+
} else {
|
|
3725
|
+
process.stderr.write(`${green("✓")} Removed skill '${bold2(name)}'
|
|
3596
3726
|
`);
|
|
3727
|
+
}
|
|
3597
3728
|
}
|
|
3598
3729
|
async function updateSkills(name) {
|
|
3599
3730
|
const cwd = process.cwd();
|
|
@@ -3649,7 +3780,20 @@ async function updateSkills(name) {
|
|
|
3649
3780
|
continue;
|
|
3650
3781
|
}
|
|
3651
3782
|
const source = `${REGISTRY_REPO}/${entry.path}`;
|
|
3652
|
-
|
|
3783
|
+
try {
|
|
3784
|
+
await installSkill(cwd, skillName, content, source);
|
|
3785
|
+
} catch (err) {
|
|
3786
|
+
if (err instanceof SkillInstallError) {
|
|
3787
|
+
process.stderr.write(`${red2("✗")} ${err.message}
|
|
3788
|
+
`);
|
|
3789
|
+
process.stderr.write(` To clean up: ${bold2(`locus skills remove ${skillName}`)}
|
|
3790
|
+
`);
|
|
3791
|
+
} else {
|
|
3792
|
+
process.stderr.write(`${red2("✗")} Failed to update '${skillName}': ${dim2(err.message)}
|
|
3793
|
+
`);
|
|
3794
|
+
}
|
|
3795
|
+
continue;
|
|
3796
|
+
}
|
|
3653
3797
|
updatedCount++;
|
|
3654
3798
|
process.stderr.write(`${green("✓")} Updated '${bold2(skillName)}' (hash changed)
|
|
3655
3799
|
`);
|
|
@@ -3743,7 +3887,7 @@ ${bold2("Subcommands:")}
|
|
|
3743
3887
|
${cyan2("list")} List available skills from the registry
|
|
3744
3888
|
${cyan2("list")} ${dim2("--installed")} List locally installed skills
|
|
3745
3889
|
${cyan2("install")} ${dim2("<name>")} Install a skill from the registry
|
|
3746
|
-
${cyan2("remove")} ${dim2("<name>")} Remove an installed skill
|
|
3890
|
+
${cyan2("remove")} ${dim2("<name>")} Remove an installed skill (alias: ${cyan2("uninstall")})
|
|
3747
3891
|
${cyan2("update")} ${dim2("[name]")} Update installed skill(s) from registry
|
|
3748
3892
|
${cyan2("info")} ${dim2("<name>")} Show skill metadata and install status
|
|
3749
3893
|
|
|
@@ -3778,7 +3922,8 @@ async function skillsCommand(args, flags) {
|
|
|
3778
3922
|
await installRemoteSkill(skillName);
|
|
3779
3923
|
break;
|
|
3780
3924
|
}
|
|
3781
|
-
case "remove":
|
|
3925
|
+
case "remove":
|
|
3926
|
+
case "uninstall": {
|
|
3782
3927
|
const skillName = args[1];
|
|
3783
3928
|
await removeInstalledSkill(skillName);
|
|
3784
3929
|
break;
|
|
@@ -3796,7 +3941,7 @@ async function skillsCommand(args, flags) {
|
|
|
3796
3941
|
default:
|
|
3797
3942
|
process.stderr.write(`${red2("✗")} Unknown subcommand: ${bold2(subcommand)}
|
|
3798
3943
|
`);
|
|
3799
|
-
process.stderr.write(` Available: ${bold2("list")}, ${bold2("install")}, ${bold2("remove")}, ${bold2("update")}, ${bold2("info")}
|
|
3944
|
+
process.stderr.write(` Available: ${bold2("list")}, ${bold2("install")}, ${bold2("remove")} (${bold2("uninstall")}), ${bold2("update")}, ${bold2("info")}
|
|
3800
3945
|
`);
|
|
3801
3946
|
process.exit(1);
|
|
3802
3947
|
}
|
|
@@ -3947,7 +4092,7 @@ __export(exports_logs, {
|
|
|
3947
4092
|
import {
|
|
3948
4093
|
existsSync as existsSync12,
|
|
3949
4094
|
readdirSync as readdirSync2,
|
|
3950
|
-
readFileSync as
|
|
4095
|
+
readFileSync as readFileSync9,
|
|
3951
4096
|
statSync as statSync2,
|
|
3952
4097
|
unlinkSync as unlinkSync2
|
|
3953
4098
|
} from "node:fs";
|
|
@@ -3974,7 +4119,7 @@ async function logsCommand(cwd, options) {
|
|
|
3974
4119
|
return viewLog(logFiles[0], options.level, options.lines ?? 50);
|
|
3975
4120
|
}
|
|
3976
4121
|
function viewLog(logFile, levelFilter, maxLines) {
|
|
3977
|
-
const content =
|
|
4122
|
+
const content = readFileSync9(logFile, "utf-8");
|
|
3978
4123
|
const lines = content.trim().split(`
|
|
3979
4124
|
`).filter(Boolean);
|
|
3980
4125
|
process.stderr.write(`
|
|
@@ -4011,7 +4156,7 @@ async function tailLog(logFile, levelFilter) {
|
|
|
4011
4156
|
`);
|
|
4012
4157
|
let lastSize = existsSync12(logFile) ? statSync2(logFile).size : 0;
|
|
4013
4158
|
if (existsSync12(logFile)) {
|
|
4014
|
-
const content =
|
|
4159
|
+
const content = readFileSync9(logFile, "utf-8");
|
|
4015
4160
|
const lines = content.trim().split(`
|
|
4016
4161
|
`).filter(Boolean);
|
|
4017
4162
|
const recent = lines.slice(-10);
|
|
@@ -4034,7 +4179,7 @@ async function tailLog(logFile, levelFilter) {
|
|
|
4034
4179
|
const currentSize = statSync2(logFile).size;
|
|
4035
4180
|
if (currentSize <= lastSize)
|
|
4036
4181
|
return;
|
|
4037
|
-
const content =
|
|
4182
|
+
const content = readFileSync9(logFile, "utf-8");
|
|
4038
4183
|
const allLines = content.trim().split(`
|
|
4039
4184
|
`).filter(Boolean);
|
|
4040
4185
|
const oldContent = content.slice(0, lastSize);
|
|
@@ -4400,7 +4545,7 @@ var init_stream_renderer = __esm(() => {
|
|
|
4400
4545
|
// src/repl/clipboard.ts
|
|
4401
4546
|
import { execSync as execSync6 } from "node:child_process";
|
|
4402
4547
|
import { existsSync as existsSync13, mkdirSync as mkdirSync9 } from "node:fs";
|
|
4403
|
-
import { tmpdir } from "node:os";
|
|
4548
|
+
import { tmpdir as tmpdir2 } from "node:os";
|
|
4404
4549
|
import { join as join13 } from "node:path";
|
|
4405
4550
|
function readClipboardImage() {
|
|
4406
4551
|
if (process.platform === "darwin") {
|
|
@@ -4466,12 +4611,12 @@ function readLinuxClipboardImage() {
|
|
|
4466
4611
|
}
|
|
4467
4612
|
var STABLE_DIR;
|
|
4468
4613
|
var init_clipboard = __esm(() => {
|
|
4469
|
-
STABLE_DIR = join13(
|
|
4614
|
+
STABLE_DIR = join13(tmpdir2(), "locus-images");
|
|
4470
4615
|
});
|
|
4471
4616
|
|
|
4472
4617
|
// src/repl/image-detect.ts
|
|
4473
4618
|
import { copyFileSync, existsSync as existsSync14, mkdirSync as mkdirSync10 } from "node:fs";
|
|
4474
|
-
import { homedir as homedir3, tmpdir as
|
|
4619
|
+
import { homedir as homedir3, tmpdir as tmpdir3 } from "node:os";
|
|
4475
4620
|
import { basename, extname, join as join14, resolve } from "node:path";
|
|
4476
4621
|
function detectImages(input) {
|
|
4477
4622
|
const detected = [];
|
|
@@ -4676,7 +4821,7 @@ var init_image_detect = __esm(() => {
|
|
|
4676
4821
|
".tif",
|
|
4677
4822
|
".tiff"
|
|
4678
4823
|
]);
|
|
4679
|
-
STABLE_DIR2 = join14(
|
|
4824
|
+
STABLE_DIR2 = join14(tmpdir3(), "locus-images");
|
|
4680
4825
|
PLACEHOLDER_ID_PATTERN = /\(locus:\/\/screenshot-(\d+)\)/g;
|
|
4681
4826
|
});
|
|
4682
4827
|
|
|
@@ -5689,17 +5834,17 @@ import {
|
|
|
5689
5834
|
mkdirSync as mkdirSync11,
|
|
5690
5835
|
mkdtempSync,
|
|
5691
5836
|
readdirSync as readdirSync3,
|
|
5692
|
-
readFileSync as
|
|
5837
|
+
readFileSync as readFileSync10,
|
|
5693
5838
|
rmSync as rmSync2,
|
|
5694
5839
|
statSync as statSync3
|
|
5695
5840
|
} from "node:fs";
|
|
5696
|
-
import { tmpdir as
|
|
5841
|
+
import { tmpdir as tmpdir4 } from "node:os";
|
|
5697
5842
|
import { dirname as dirname3, join as join15, relative } from "node:path";
|
|
5698
5843
|
import { promisify } from "node:util";
|
|
5699
5844
|
function parseIgnoreFile(filePath) {
|
|
5700
5845
|
if (!existsSync15(filePath))
|
|
5701
5846
|
return [];
|
|
5702
|
-
const content =
|
|
5847
|
+
const content = readFileSync10(filePath, "utf-8");
|
|
5703
5848
|
const rules = [];
|
|
5704
5849
|
for (const rawLine of content.split(`
|
|
5705
5850
|
`)) {
|
|
@@ -5810,7 +5955,7 @@ function backupIgnoredFiles(projectRoot) {
|
|
|
5810
5955
|
return NOOP_BACKUP;
|
|
5811
5956
|
let backupDir;
|
|
5812
5957
|
try {
|
|
5813
|
-
backupDir = mkdtempSync(join15(
|
|
5958
|
+
backupDir = mkdtempSync(join15(tmpdir4(), "locus-sandbox-backup-"));
|
|
5814
5959
|
} catch (err) {
|
|
5815
5960
|
log.debug("Failed to create sandbox backup dir", {
|
|
5816
5961
|
error: err instanceof Error ? err.message : String(err)
|
|
@@ -8028,7 +8173,7 @@ var init_sprint = __esm(() => {
|
|
|
8028
8173
|
|
|
8029
8174
|
// src/core/prompt-builder.ts
|
|
8030
8175
|
import { execSync as execSync9 } from "node:child_process";
|
|
8031
|
-
import { existsSync as existsSync16, readdirSync as readdirSync4, readFileSync as
|
|
8176
|
+
import { existsSync as existsSync16, readdirSync as readdirSync4, readFileSync as readFileSync11 } from "node:fs";
|
|
8032
8177
|
import { join as join16 } from "node:path";
|
|
8033
8178
|
function buildExecutionPrompt(ctx) {
|
|
8034
8179
|
const sections = [];
|
|
@@ -8256,7 +8401,7 @@ function readFileSafe(path) {
|
|
|
8256
8401
|
try {
|
|
8257
8402
|
if (!existsSync16(path))
|
|
8258
8403
|
return null;
|
|
8259
|
-
return
|
|
8404
|
+
return readFileSync11(path, "utf-8");
|
|
8260
8405
|
} catch {
|
|
8261
8406
|
return null;
|
|
8262
8407
|
}
|
|
@@ -8825,7 +8970,7 @@ class CombinedCompletion {
|
|
|
8825
8970
|
var init_completions = () => {};
|
|
8826
8971
|
|
|
8827
8972
|
// src/repl/input-history.ts
|
|
8828
|
-
import { existsSync as existsSync17, mkdirSync as mkdirSync12, readFileSync as
|
|
8973
|
+
import { existsSync as existsSync17, mkdirSync as mkdirSync12, readFileSync as readFileSync12, writeFileSync as writeFileSync9 } from "node:fs";
|
|
8829
8974
|
import { dirname as dirname5, join as join18 } from "node:path";
|
|
8830
8975
|
|
|
8831
8976
|
class InputHistory {
|
|
@@ -8873,7 +9018,7 @@ class InputHistory {
|
|
|
8873
9018
|
try {
|
|
8874
9019
|
if (!existsSync17(this.filePath))
|
|
8875
9020
|
return;
|
|
8876
|
-
const content =
|
|
9021
|
+
const content = readFileSync12(this.filePath, "utf-8");
|
|
8877
9022
|
this.entries = content.split(`
|
|
8878
9023
|
`).map((line) => this.unescape(line)).filter(Boolean);
|
|
8879
9024
|
} catch {}
|
|
@@ -8915,7 +9060,7 @@ import {
|
|
|
8915
9060
|
existsSync as existsSync18,
|
|
8916
9061
|
mkdirSync as mkdirSync13,
|
|
8917
9062
|
readdirSync as readdirSync6,
|
|
8918
|
-
readFileSync as
|
|
9063
|
+
readFileSync as readFileSync13,
|
|
8919
9064
|
unlinkSync as unlinkSync3,
|
|
8920
9065
|
writeFileSync as writeFileSync10
|
|
8921
9066
|
} from "node:fs";
|
|
@@ -8958,7 +9103,7 @@ class SessionManager {
|
|
|
8958
9103
|
const exactPath = this.getSessionPath(idOrPrefix);
|
|
8959
9104
|
if (existsSync18(exactPath)) {
|
|
8960
9105
|
try {
|
|
8961
|
-
return JSON.parse(
|
|
9106
|
+
return JSON.parse(readFileSync13(exactPath, "utf-8"));
|
|
8962
9107
|
} catch {
|
|
8963
9108
|
return null;
|
|
8964
9109
|
}
|
|
@@ -8966,7 +9111,7 @@ class SessionManager {
|
|
|
8966
9111
|
const matches = files.filter((f) => basename3(f, ".json").startsWith(idOrPrefix));
|
|
8967
9112
|
if (matches.length === 1) {
|
|
8968
9113
|
try {
|
|
8969
|
-
return JSON.parse(
|
|
9114
|
+
return JSON.parse(readFileSync13(matches[0], "utf-8"));
|
|
8970
9115
|
} catch {
|
|
8971
9116
|
return null;
|
|
8972
9117
|
}
|
|
@@ -8991,7 +9136,7 @@ class SessionManager {
|
|
|
8991
9136
|
const sessions = [];
|
|
8992
9137
|
for (const file of files) {
|
|
8993
9138
|
try {
|
|
8994
|
-
const session = JSON.parse(
|
|
9139
|
+
const session = JSON.parse(readFileSync13(file, "utf-8"));
|
|
8995
9140
|
sessions.push({
|
|
8996
9141
|
id: session.id,
|
|
8997
9142
|
created: session.created,
|
|
@@ -9018,7 +9163,7 @@ class SessionManager {
|
|
|
9018
9163
|
let pruned = 0;
|
|
9019
9164
|
const withStats = files.map((f) => {
|
|
9020
9165
|
try {
|
|
9021
|
-
const session = JSON.parse(
|
|
9166
|
+
const session = JSON.parse(readFileSync13(f, "utf-8"));
|
|
9022
9167
|
return { path: f, updated: new Date(session.updated).getTime() };
|
|
9023
9168
|
} catch {
|
|
9024
9169
|
return { path: f, updated: 0 };
|
|
@@ -9072,7 +9217,7 @@ var init_session_manager = __esm(() => {
|
|
|
9072
9217
|
// src/repl/voice.ts
|
|
9073
9218
|
import { execSync as execSync11, spawn as spawn6 } from "node:child_process";
|
|
9074
9219
|
import { existsSync as existsSync19, mkdirSync as mkdirSync14, unlinkSync as unlinkSync4 } from "node:fs";
|
|
9075
|
-
import { cpus, homedir as homedir4, platform, tmpdir as
|
|
9220
|
+
import { cpus, homedir as homedir4, platform, tmpdir as tmpdir5 } from "node:os";
|
|
9076
9221
|
import { join as join20 } from "node:path";
|
|
9077
9222
|
function getWhisperModelPath() {
|
|
9078
9223
|
return join20(WHISPER_MODELS_DIR, `ggml-${WHISPER_MODEL}.bin`);
|
|
@@ -9284,7 +9429,7 @@ function ensureBuildDeps(pm) {
|
|
|
9284
9429
|
}
|
|
9285
9430
|
function buildWhisperFromSource(pm) {
|
|
9286
9431
|
const out = process.stderr;
|
|
9287
|
-
const buildDir = join20(
|
|
9432
|
+
const buildDir = join20(tmpdir5(), `locus-whisper-build-${process.pid}`);
|
|
9288
9433
|
if (!ensureBuildDeps(pm)) {
|
|
9289
9434
|
out.write(` ${red2("✗")} Could not install build tools (cmake, g++, git).
|
|
9290
9435
|
`);
|
|
@@ -9442,7 +9587,7 @@ class VoiceController {
|
|
|
9442
9587
|
onStateChange;
|
|
9443
9588
|
constructor(options) {
|
|
9444
9589
|
this.onStateChange = options.onStateChange;
|
|
9445
|
-
this.tempFile = join20(
|
|
9590
|
+
this.tempFile = join20(tmpdir5(), `locus-voice-${process.pid}.wav`);
|
|
9446
9591
|
this.deps = checkDependencies();
|
|
9447
9592
|
}
|
|
9448
9593
|
getState() {
|
|
@@ -10693,7 +10838,7 @@ var init_conflict = __esm(() => {
|
|
|
10693
10838
|
import {
|
|
10694
10839
|
existsSync as existsSync21,
|
|
10695
10840
|
mkdirSync as mkdirSync15,
|
|
10696
|
-
readFileSync as
|
|
10841
|
+
readFileSync as readFileSync14,
|
|
10697
10842
|
unlinkSync as unlinkSync5,
|
|
10698
10843
|
writeFileSync as writeFileSync11
|
|
10699
10844
|
} from "node:fs";
|
|
@@ -10716,7 +10861,7 @@ function loadRunState(projectRoot, sprintName) {
|
|
|
10716
10861
|
if (!existsSync21(path))
|
|
10717
10862
|
return null;
|
|
10718
10863
|
try {
|
|
10719
|
-
return JSON.parse(
|
|
10864
|
+
return JSON.parse(readFileSync14(path, "utf-8"));
|
|
10720
10865
|
} catch {
|
|
10721
10866
|
getLogger().warn("Corrupted run state file, ignoring");
|
|
10722
10867
|
return null;
|
|
@@ -12302,7 +12447,7 @@ import {
|
|
|
12302
12447
|
existsSync as existsSync25,
|
|
12303
12448
|
mkdirSync as mkdirSync17,
|
|
12304
12449
|
readdirSync as readdirSync8,
|
|
12305
|
-
readFileSync as
|
|
12450
|
+
readFileSync as readFileSync15,
|
|
12306
12451
|
writeFileSync as writeFileSync12
|
|
12307
12452
|
} from "node:fs";
|
|
12308
12453
|
import { join as join26 } from "node:path";
|
|
@@ -12358,7 +12503,7 @@ function loadPlanFile(projectRoot, id) {
|
|
|
12358
12503
|
if (!match)
|
|
12359
12504
|
return null;
|
|
12360
12505
|
try {
|
|
12361
|
-
const content =
|
|
12506
|
+
const content = readFileSync15(join26(dir, match), "utf-8");
|
|
12362
12507
|
return JSON.parse(content);
|
|
12363
12508
|
} catch {
|
|
12364
12509
|
return null;
|
|
@@ -12443,7 +12588,7 @@ ${bold2("Saved Plans:")}
|
|
|
12443
12588
|
for (const file of files) {
|
|
12444
12589
|
const id = file.replace(".json", "");
|
|
12445
12590
|
try {
|
|
12446
|
-
const content =
|
|
12591
|
+
const content = readFileSync15(join26(dir, file), "utf-8");
|
|
12447
12592
|
const plan = JSON.parse(content);
|
|
12448
12593
|
const date = plan.createdAt ? plan.createdAt.slice(0, 10) : "";
|
|
12449
12594
|
const issueCount = Array.isArray(plan.issues) ? plan.issues.length : 0;
|
|
@@ -12558,7 +12703,7 @@ ${yellow2("⚠")} Plan file was not found at ${bold2(planPathRelative)}.
|
|
|
12558
12703
|
}
|
|
12559
12704
|
let updatedPlan;
|
|
12560
12705
|
try {
|
|
12561
|
-
const content =
|
|
12706
|
+
const content = readFileSync15(planPath, "utf-8");
|
|
12562
12707
|
updatedPlan = JSON.parse(content);
|
|
12563
12708
|
} catch {
|
|
12564
12709
|
process.stderr.write(`
|
|
@@ -12701,7 +12846,7 @@ ${yellow2("⚠")} Plan file was not created at ${bold2(planPathRelative)}.
|
|
|
12701
12846
|
}
|
|
12702
12847
|
let plan;
|
|
12703
12848
|
try {
|
|
12704
|
-
const content =
|
|
12849
|
+
const content = readFileSync15(planPath, "utf-8");
|
|
12705
12850
|
plan = JSON.parse(content);
|
|
12706
12851
|
} catch {
|
|
12707
12852
|
process.stderr.write(`
|
|
@@ -12875,14 +13020,14 @@ ${directive}${sprintName ? `
|
|
|
12875
13020
|
</directive>`);
|
|
12876
13021
|
const locusPath = join26(projectRoot, ".locus", "LOCUS.md");
|
|
12877
13022
|
if (existsSync25(locusPath)) {
|
|
12878
|
-
const content =
|
|
13023
|
+
const content = readFileSync15(locusPath, "utf-8");
|
|
12879
13024
|
parts.push(`<project-context>
|
|
12880
13025
|
${content.slice(0, 3000)}
|
|
12881
13026
|
</project-context>`);
|
|
12882
13027
|
}
|
|
12883
13028
|
const learningsPath = join26(projectRoot, ".locus", "LEARNINGS.md");
|
|
12884
13029
|
if (existsSync25(learningsPath)) {
|
|
12885
|
-
const content =
|
|
13030
|
+
const content = readFileSync15(learningsPath, "utf-8");
|
|
12886
13031
|
parts.push(`<past-learnings>
|
|
12887
13032
|
${content.slice(0, 2000)}
|
|
12888
13033
|
</past-learnings>`);
|
|
@@ -12936,7 +13081,7 @@ ${feedback}
|
|
|
12936
13081
|
</feedback>`);
|
|
12937
13082
|
const locusPath = join26(projectRoot, ".locus", "LOCUS.md");
|
|
12938
13083
|
if (existsSync25(locusPath)) {
|
|
12939
|
-
const content =
|
|
13084
|
+
const content = readFileSync15(locusPath, "utf-8");
|
|
12940
13085
|
parts.push(`<project-context>
|
|
12941
13086
|
${content.slice(0, 3000)}
|
|
12942
13087
|
</project-context>`);
|
|
@@ -13118,7 +13263,7 @@ __export(exports_review, {
|
|
|
13118
13263
|
reviewCommand: () => reviewCommand
|
|
13119
13264
|
});
|
|
13120
13265
|
import { execFileSync as execFileSync2, execSync as execSync19 } from "node:child_process";
|
|
13121
|
-
import { existsSync as existsSync26, readFileSync as
|
|
13266
|
+
import { existsSync as existsSync26, readFileSync as readFileSync16 } from "node:fs";
|
|
13122
13267
|
import { join as join27 } from "node:path";
|
|
13123
13268
|
function printHelp3() {
|
|
13124
13269
|
process.stderr.write(`
|
|
@@ -13290,7 +13435,7 @@ You are an expert code reviewer for the ${config.github.owner}/${config.github.r
|
|
|
13290
13435
|
</role>`);
|
|
13291
13436
|
const locusPath = join27(projectRoot, ".locus", "LOCUS.md");
|
|
13292
13437
|
if (existsSync26(locusPath)) {
|
|
13293
|
-
const content =
|
|
13438
|
+
const content = readFileSync16(locusPath, "utf-8");
|
|
13294
13439
|
parts.push(`<project-context>
|
|
13295
13440
|
${content.slice(0, 2000)}
|
|
13296
13441
|
</project-context>`);
|
|
@@ -13608,7 +13753,7 @@ import {
|
|
|
13608
13753
|
existsSync as existsSync27,
|
|
13609
13754
|
mkdirSync as mkdirSync18,
|
|
13610
13755
|
readdirSync as readdirSync9,
|
|
13611
|
-
readFileSync as
|
|
13756
|
+
readFileSync as readFileSync17,
|
|
13612
13757
|
unlinkSync as unlinkSync6,
|
|
13613
13758
|
writeFileSync as writeFileSync13
|
|
13614
13759
|
} from "node:fs";
|
|
@@ -13690,7 +13835,7 @@ ${bold2("Discussions:")}
|
|
|
13690
13835
|
`);
|
|
13691
13836
|
for (const file of files) {
|
|
13692
13837
|
const id = file.replace(".md", "");
|
|
13693
|
-
const content =
|
|
13838
|
+
const content = readFileSync17(join28(dir, file), "utf-8");
|
|
13694
13839
|
const titleMatch = content.match(/^#\s+(.+)/m);
|
|
13695
13840
|
const title = titleMatch ? titleMatch[1] : id;
|
|
13696
13841
|
const dateMatch = content.match(/\*\*Date:\*\*\s*(.+)/);
|
|
@@ -13720,7 +13865,7 @@ function showDiscussion(projectRoot, id) {
|
|
|
13720
13865
|
`);
|
|
13721
13866
|
return;
|
|
13722
13867
|
}
|
|
13723
|
-
const content =
|
|
13868
|
+
const content = readFileSync17(join28(dir, match), "utf-8");
|
|
13724
13869
|
process.stdout.write(`${content}
|
|
13725
13870
|
`);
|
|
13726
13871
|
}
|
|
@@ -13768,7 +13913,7 @@ async function convertDiscussionToPlan(projectRoot, id) {
|
|
|
13768
13913
|
`);
|
|
13769
13914
|
return;
|
|
13770
13915
|
}
|
|
13771
|
-
const content =
|
|
13916
|
+
const content = readFileSync17(join28(dir, match), "utf-8");
|
|
13772
13917
|
const titleMatch = content.match(/^#\s+(.+)/m);
|
|
13773
13918
|
const discussionTitle = titleMatch ? titleMatch[1].trim() : id;
|
|
13774
13919
|
await planCommand(projectRoot, [
|
|
@@ -13911,14 +14056,14 @@ You are a senior software architect and consultant for the ${config.github.owner
|
|
|
13911
14056
|
</role>`);
|
|
13912
14057
|
const locusPath = join28(projectRoot, ".locus", "LOCUS.md");
|
|
13913
14058
|
if (existsSync27(locusPath)) {
|
|
13914
|
-
const content =
|
|
14059
|
+
const content = readFileSync17(locusPath, "utf-8");
|
|
13915
14060
|
parts.push(`<project-context>
|
|
13916
14061
|
${content.slice(0, 3000)}
|
|
13917
14062
|
</project-context>`);
|
|
13918
14063
|
}
|
|
13919
14064
|
const learningsPath = join28(projectRoot, ".locus", "LEARNINGS.md");
|
|
13920
14065
|
if (existsSync27(learningsPath)) {
|
|
13921
|
-
const content =
|
|
14066
|
+
const content = readFileSync17(learningsPath, "utf-8");
|
|
13922
14067
|
parts.push(`<past-learnings>
|
|
13923
14068
|
${content.slice(0, 2000)}
|
|
13924
14069
|
</past-learnings>`);
|
|
@@ -13989,7 +14134,7 @@ __export(exports_artifacts, {
|
|
|
13989
14134
|
formatDate: () => formatDate2,
|
|
13990
14135
|
artifactsCommand: () => artifactsCommand
|
|
13991
14136
|
});
|
|
13992
|
-
import { existsSync as existsSync28, readdirSync as readdirSync10, readFileSync as
|
|
14137
|
+
import { existsSync as existsSync28, readdirSync as readdirSync10, readFileSync as readFileSync18, statSync as statSync5 } from "node:fs";
|
|
13993
14138
|
import { join as join29 } from "node:path";
|
|
13994
14139
|
function printHelp6() {
|
|
13995
14140
|
process.stderr.write(`
|
|
@@ -14035,7 +14180,7 @@ function readArtifact(projectRoot, name) {
|
|
|
14035
14180
|
return null;
|
|
14036
14181
|
const stat = statSync5(filePath);
|
|
14037
14182
|
return {
|
|
14038
|
-
content:
|
|
14183
|
+
content: readFileSync18(filePath, "utf-8"),
|
|
14039
14184
|
info: {
|
|
14040
14185
|
name: fileName.replace(/\.md$/, ""),
|
|
14041
14186
|
fileName,
|
|
@@ -14392,7 +14537,7 @@ __export(exports_sandbox2, {
|
|
|
14392
14537
|
});
|
|
14393
14538
|
import { execSync as execSync22, spawn as spawn7 } from "node:child_process";
|
|
14394
14539
|
import { createHash as createHash2 } from "node:crypto";
|
|
14395
|
-
import { existsSync as existsSync29, readFileSync as
|
|
14540
|
+
import { existsSync as existsSync29, readFileSync as readFileSync19 } from "node:fs";
|
|
14396
14541
|
import { basename as basename4, join as join30 } from "node:path";
|
|
14397
14542
|
import { createInterface as createInterface3 } from "node:readline";
|
|
14398
14543
|
function printSandboxHelp() {
|
|
@@ -14923,7 +15068,7 @@ async function handleLogs(projectRoot, args) {
|
|
|
14923
15068
|
}
|
|
14924
15069
|
function detectPackageManager2(projectRoot) {
|
|
14925
15070
|
try {
|
|
14926
|
-
const raw =
|
|
15071
|
+
const raw = readFileSync19(join30(projectRoot, "package.json"), "utf-8");
|
|
14927
15072
|
const pkgJson = JSON.parse(raw);
|
|
14928
15073
|
if (typeof pkgJson.packageManager === "string") {
|
|
14929
15074
|
const name = pkgJson.packageManager.split("@")[0];
|
|
@@ -15216,7 +15361,7 @@ init_context();
|
|
|
15216
15361
|
init_logger();
|
|
15217
15362
|
init_rate_limiter();
|
|
15218
15363
|
init_terminal();
|
|
15219
|
-
import { existsSync as existsSync30, readFileSync as
|
|
15364
|
+
import { existsSync as existsSync30, readFileSync as readFileSync20 } from "node:fs";
|
|
15220
15365
|
import { join as join31 } from "node:path";
|
|
15221
15366
|
import { fileURLToPath } from "node:url";
|
|
15222
15367
|
function getCliVersion() {
|
|
@@ -15226,7 +15371,7 @@ function getCliVersion() {
|
|
|
15226
15371
|
return fallbackVersion;
|
|
15227
15372
|
}
|
|
15228
15373
|
try {
|
|
15229
|
-
const parsed = JSON.parse(
|
|
15374
|
+
const parsed = JSON.parse(readFileSync20(packageJsonPath, "utf-8"));
|
|
15230
15375
|
return parsed.version ?? fallbackVersion;
|
|
15231
15376
|
} catch {
|
|
15232
15377
|
return fallbackVersion;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@locusai/cli",
|
|
3
|
-
"version": "0.25.
|
|
3
|
+
"version": "0.25.3",
|
|
4
4
|
"description": "GitHub-native AI engineering assistant",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"license": "MIT",
|
|
37
37
|
"dependencies": {},
|
|
38
38
|
"devDependencies": {
|
|
39
|
-
"@locusai/sdk": "^0.25.
|
|
39
|
+
"@locusai/sdk": "^0.25.3",
|
|
40
40
|
"@types/bun": "latest",
|
|
41
41
|
"typescript": "^5.8.3"
|
|
42
42
|
},
|