@sushanglewis/lincoln 1.8.0 → 1.8.2
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/dist/main.js +347 -107
- package/dist/main.js.map +1 -1
- package/dist/postinstall.js +306 -21
- package/dist/postinstall.js.map +1 -1
- package/framework/.claude/skills/dependencies.yaml +8 -8
- package/framework/.claude-plugin/marketplace.json +2 -2
- package/framework/.claude-plugin/plugin.json +1 -1
- package/framework/.version-bump.json +1 -1
- package/framework/README.en.md +2 -2
- package/framework/README.md +6 -4
- package/framework/RELEASE.md +20 -0
- package/framework/manifest.json +12 -12
- package/framework/tools/lincoln/package-lock.json +2 -2
- package/framework/tools/lincoln/package.json +1 -1
- package/framework/tools/lincoln-installer/package.json +1 -1
- package/package.json +1 -1
package/dist/postinstall.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/commands/install.ts
|
|
4
|
-
import
|
|
5
|
-
import
|
|
4
|
+
import fs6 from "fs";
|
|
5
|
+
import path7 from "path";
|
|
6
6
|
import { spawn as spawn2 } from "child_process";
|
|
7
7
|
|
|
8
8
|
// src/lib/paths.ts
|
|
@@ -327,9 +327,265 @@ async function syncHarness(harnessId, opts, syncClaude) {
|
|
|
327
327
|
return report;
|
|
328
328
|
}
|
|
329
329
|
|
|
330
|
-
// src/lib/
|
|
330
|
+
// src/lib/syncSkills.ts
|
|
331
331
|
import fs4 from "fs";
|
|
332
332
|
import path5 from "path";
|
|
333
|
+
import { execFile } from "child_process";
|
|
334
|
+
import yaml from "js-yaml";
|
|
335
|
+
|
|
336
|
+
// src/lib/semver.ts
|
|
337
|
+
var SEMVER_CORE = /^v?(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?(?:\+[0-9A-Za-z.-]+)?$/;
|
|
338
|
+
var NUMERIC_IDENTIFIER = /^\d+$/;
|
|
339
|
+
function compareVersions(a, b) {
|
|
340
|
+
const pa = parseVersion(a);
|
|
341
|
+
const pb = parseVersion(b);
|
|
342
|
+
if (!pa || !pb) {
|
|
343
|
+
return void 0;
|
|
344
|
+
}
|
|
345
|
+
if (pa.major !== pb.major) return pa.major - pb.major;
|
|
346
|
+
if (pa.minor !== pb.minor) return pa.minor - pb.minor;
|
|
347
|
+
if (pa.patch !== pb.patch) return pa.patch - pb.patch;
|
|
348
|
+
return comparePrerelease(pa.prerelease, pb.prerelease);
|
|
349
|
+
}
|
|
350
|
+
function parseVersion(version) {
|
|
351
|
+
const match = SEMVER_CORE.exec(version.trim());
|
|
352
|
+
if (!match) {
|
|
353
|
+
return void 0;
|
|
354
|
+
}
|
|
355
|
+
return {
|
|
356
|
+
major: Number(match[1]),
|
|
357
|
+
minor: Number(match[2]),
|
|
358
|
+
patch: Number(match[3]),
|
|
359
|
+
prerelease: match[4] ? match[4].split(".") : []
|
|
360
|
+
};
|
|
361
|
+
}
|
|
362
|
+
function comparePrerelease(a, b) {
|
|
363
|
+
if (a.length === 0 && b.length === 0) return 0;
|
|
364
|
+
if (a.length === 0) return 1;
|
|
365
|
+
if (b.length === 0) return -1;
|
|
366
|
+
const shared = Math.min(a.length, b.length);
|
|
367
|
+
for (let i = 0; i < shared; i++) {
|
|
368
|
+
const x = a[i];
|
|
369
|
+
const y = b[i];
|
|
370
|
+
if (x === y) continue;
|
|
371
|
+
const xNumeric = NUMERIC_IDENTIFIER.test(x);
|
|
372
|
+
const yNumeric = NUMERIC_IDENTIFIER.test(y);
|
|
373
|
+
if (xNumeric && yNumeric) return Number(x) - Number(y);
|
|
374
|
+
if (xNumeric) return -1;
|
|
375
|
+
if (yNumeric) return 1;
|
|
376
|
+
return x < y ? -1 : 1;
|
|
377
|
+
}
|
|
378
|
+
return a.length - b.length;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
// src/lib/syncSkills.ts
|
|
382
|
+
var GIT_SOURCE = /^(https?:\/\/|git@)/;
|
|
383
|
+
var FULL_SHA = /^[0-9a-f]{40}$/i;
|
|
384
|
+
var PINNED_SEMVER = /^v?(\d+\.\d+\.\d+)$/;
|
|
385
|
+
var NPM_GLOBAL_INSTALL = /^npm install -g (\S+)$/;
|
|
386
|
+
var MAX_BUFFER = 16 * 1024 * 1024;
|
|
387
|
+
var defaultRunner = (cmd, args) => new Promise((resolvePromise, rejectPromise) => {
|
|
388
|
+
execFile(cmd, args, { maxBuffer: MAX_BUFFER }, (err, stdout, stderr) => {
|
|
389
|
+
if (err && !("code" in err && typeof err.code === "number")) {
|
|
390
|
+
rejectPromise(err);
|
|
391
|
+
return;
|
|
392
|
+
}
|
|
393
|
+
const code = err && typeof err.code === "number" ? err.code : 0;
|
|
394
|
+
resolvePromise({ code, stdout: String(stdout), stderr: String(stderr) });
|
|
395
|
+
});
|
|
396
|
+
});
|
|
397
|
+
async function syncExternalSkills(options) {
|
|
398
|
+
const report = { entries: [], warnings: [] };
|
|
399
|
+
const manifestPath = path5.join(options.payloadRoot, ".claude", "skills", "dependencies.yaml");
|
|
400
|
+
if (!fs4.existsSync(manifestPath)) {
|
|
401
|
+
report.warnings.push(`skill dependency manifest not found at ${manifestPath}; skipping external skill sync`);
|
|
402
|
+
return report;
|
|
403
|
+
}
|
|
404
|
+
let manifest;
|
|
405
|
+
try {
|
|
406
|
+
manifest = yaml.load(fs4.readFileSync(manifestPath, "utf8")) ?? {};
|
|
407
|
+
} catch (err) {
|
|
408
|
+
report.warnings.push(
|
|
409
|
+
`failed to parse ${manifestPath}: ${err instanceof Error ? err.message : String(err)}`
|
|
410
|
+
);
|
|
411
|
+
return report;
|
|
412
|
+
}
|
|
413
|
+
const runCommand3 = options.runCommand ?? defaultRunner;
|
|
414
|
+
const platform = options.platform ?? (process.platform === "darwin" ? "macos" : process.platform === "linux" ? "linux" : process.platform);
|
|
415
|
+
for (const [name, cfg] of Object.entries(manifest.skills ?? {})) {
|
|
416
|
+
if (!cfg.source || cfg.source === "inline" || !GIT_SOURCE.test(cfg.source)) {
|
|
417
|
+
continue;
|
|
418
|
+
}
|
|
419
|
+
const enabled = cfg.default_install ?? cfg.required ?? true;
|
|
420
|
+
if (!enabled) {
|
|
421
|
+
report.entries.push({ name, status: "skipped-optional", detail: "default_install is false" });
|
|
422
|
+
continue;
|
|
423
|
+
}
|
|
424
|
+
if (cfg.type === "cli") {
|
|
425
|
+
await syncCli(name, cfg, options, platform, runCommand3, report);
|
|
426
|
+
} else {
|
|
427
|
+
await syncGitSkill(name, cfg, options, runCommand3, report);
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
return report;
|
|
431
|
+
}
|
|
432
|
+
async function syncGitSkill(name, cfg, options, runCommand3, report) {
|
|
433
|
+
const source = cfg.source;
|
|
434
|
+
const ref = cfg.ref ?? "";
|
|
435
|
+
const target = path5.join(options.skillsDir, name);
|
|
436
|
+
if (options.dryRun) {
|
|
437
|
+
const planned = fs4.existsSync(target) ? "verify pinned ref and update if behind" : `clone and pin to ${ref}`;
|
|
438
|
+
report.entries.push({ name, status: "dry-run", detail: `would ${planned}` });
|
|
439
|
+
return;
|
|
440
|
+
}
|
|
441
|
+
if (!fs4.existsSync(target)) {
|
|
442
|
+
const clone = await runCommand3("git", ["clone", source, target]);
|
|
443
|
+
if (clone.code !== 0) {
|
|
444
|
+
fail(report, name, `git clone failed: ${clone.stderr.trim() || `exit code ${clone.code}`}`);
|
|
445
|
+
return;
|
|
446
|
+
}
|
|
447
|
+
const checkout = await runCommand3("git", ["-C", target, "checkout", ref]);
|
|
448
|
+
if (checkout.code !== 0) {
|
|
449
|
+
fail(report, name, `git checkout ${ref} failed: ${checkout.stderr.trim() || `exit code ${checkout.code}`}`);
|
|
450
|
+
return;
|
|
451
|
+
}
|
|
452
|
+
report.entries.push({ name, status: "installed", detail: ref });
|
|
453
|
+
return;
|
|
454
|
+
}
|
|
455
|
+
const status = await runCommand3("git", ["-C", target, "status", "--porcelain"]);
|
|
456
|
+
if (status.code !== 0) {
|
|
457
|
+
fail(report, name, `git status failed (not a git repository?): ${status.stderr.trim() || `exit code ${status.code}`}`);
|
|
458
|
+
return;
|
|
459
|
+
}
|
|
460
|
+
if (status.stdout.trim() !== "") {
|
|
461
|
+
const detail = "working tree is dirty; skipping update (commit or stash local changes first)";
|
|
462
|
+
report.entries.push({ name, status: "skipped-dirty", detail });
|
|
463
|
+
report.warnings.push(`${name}: ${detail}`);
|
|
464
|
+
return;
|
|
465
|
+
}
|
|
466
|
+
const head = await runCommand3("git", ["-C", target, "rev-parse", "HEAD"]);
|
|
467
|
+
if (head.code !== 0) {
|
|
468
|
+
fail(report, name, `git rev-parse failed: ${head.stderr.trim() || `exit code ${head.code}`}`);
|
|
469
|
+
return;
|
|
470
|
+
}
|
|
471
|
+
if (head.stdout.trim() === ref) {
|
|
472
|
+
report.entries.push({ name, status: "current", detail: ref });
|
|
473
|
+
return;
|
|
474
|
+
}
|
|
475
|
+
const advertised = await isPinAdvertised(source, ref, runCommand3);
|
|
476
|
+
if (advertised) {
|
|
477
|
+
const fetch2 = await runCommand3("git", ["-C", target, "fetch", "origin", ref]);
|
|
478
|
+
if (fetch2.code === 0 && await checkoutFetchHead(name, target, runCommand3, report)) {
|
|
479
|
+
return;
|
|
480
|
+
}
|
|
481
|
+
if (fetch2.code !== 0) {
|
|
482
|
+
fail(report, name, `git fetch origin ${ref} failed: ${fetch2.stderr.trim() || `exit code ${fetch2.code}`}`);
|
|
483
|
+
return;
|
|
484
|
+
}
|
|
485
|
+
return;
|
|
486
|
+
}
|
|
487
|
+
const fetch = await runCommand3("git", ["-C", target, "fetch", "origin", ref]);
|
|
488
|
+
if (fetch.code === 0) {
|
|
489
|
+
await checkoutFetchHead(name, target, runCommand3, report);
|
|
490
|
+
return;
|
|
491
|
+
}
|
|
492
|
+
if (FULL_SHA.test(ref)) {
|
|
493
|
+
const fetchAll = await runCommand3("git", ["-C", target, "fetch", "origin"]);
|
|
494
|
+
if (fetchAll.code !== 0) {
|
|
495
|
+
fail(report, name, `git fetch origin failed: ${fetchAll.stderr.trim() || `exit code ${fetchAll.code}`}`);
|
|
496
|
+
return;
|
|
497
|
+
}
|
|
498
|
+
const checkout = await runCommand3("git", ["-C", target, "checkout", ref]);
|
|
499
|
+
if (checkout.code !== 0) {
|
|
500
|
+
fail(report, name, `git checkout ${ref} failed: ${checkout.stderr.trim() || `exit code ${checkout.code}`}`);
|
|
501
|
+
return;
|
|
502
|
+
}
|
|
503
|
+
report.entries.push({ name, status: "updated", detail: ref });
|
|
504
|
+
return;
|
|
505
|
+
}
|
|
506
|
+
fail(report, name, `git fetch origin ${ref} failed: ${fetch.stderr.trim() || `exit code ${fetch.code}`}`);
|
|
507
|
+
}
|
|
508
|
+
async function isPinAdvertised(source, ref, runCommand3) {
|
|
509
|
+
const remote = await runCommand3("git", ["ls-remote", source]);
|
|
510
|
+
if (remote.code !== 0) {
|
|
511
|
+
return false;
|
|
512
|
+
}
|
|
513
|
+
return remote.stdout.split("\n").some((line) => line.split(" ")[0]?.trim() === ref);
|
|
514
|
+
}
|
|
515
|
+
async function checkoutFetchHead(name, target, runCommand3, report) {
|
|
516
|
+
const checkout = await runCommand3("git", ["-C", target, "checkout", "FETCH_HEAD"]);
|
|
517
|
+
if (checkout.code !== 0) {
|
|
518
|
+
fail(report, name, `git checkout FETCH_HEAD failed: ${checkout.stderr.trim() || `exit code ${checkout.code}`}`);
|
|
519
|
+
return false;
|
|
520
|
+
}
|
|
521
|
+
report.entries.push({ name, status: "updated", detail: "checked out FETCH_HEAD" });
|
|
522
|
+
return true;
|
|
523
|
+
}
|
|
524
|
+
async function syncCli(name, cfg, options, platform, runCommand3, report) {
|
|
525
|
+
const binary = cfg.binary ?? name;
|
|
526
|
+
const installCommand = cfg.platforms?.[platform] ?? cfg.platforms?.linux;
|
|
527
|
+
const npmPackage = installCommand ? parseNpmGlobalInstall(installCommand) : void 0;
|
|
528
|
+
const pinned = cfg.ref ? pinnedSemver(cfg.ref) : void 0;
|
|
529
|
+
if (options.dryRun) {
|
|
530
|
+
const managed = npmPackage && pinned ? `install ${npmPackage}@${pinned} if missing or older` : "verify presence";
|
|
531
|
+
report.entries.push({ name, status: "dry-run", detail: `would ${managed}` });
|
|
532
|
+
return;
|
|
533
|
+
}
|
|
534
|
+
const whichCmd = process.platform === "win32" ? "where" : "which";
|
|
535
|
+
const found = await runCommand3(whichCmd, [binary]);
|
|
536
|
+
if (found.code !== 0) {
|
|
537
|
+
if (npmPackage && pinned) {
|
|
538
|
+
await npmInstall(name, npmPackage, pinned, runCommand3, report, "installed");
|
|
539
|
+
return;
|
|
540
|
+
}
|
|
541
|
+
fail(report, name, `CLI '${binary}' not found. Install manually (${platform}): ${installCommand ?? "see dependency manifest"}`);
|
|
542
|
+
return;
|
|
543
|
+
}
|
|
544
|
+
if (!npmPackage || !pinned) {
|
|
545
|
+
report.entries.push({ name, status: "current", detail: `${binary} present` });
|
|
546
|
+
return;
|
|
547
|
+
}
|
|
548
|
+
const version = await runCommand3(binary, ["--version"]);
|
|
549
|
+
const installed = version.code === 0 ? version.stdout.split("\n")[0]?.trim() ?? "" : "";
|
|
550
|
+
const comparison = installed ? compareVersions(installed, pinned) : void 0;
|
|
551
|
+
if (comparison === void 0) {
|
|
552
|
+
report.entries.push({
|
|
553
|
+
name,
|
|
554
|
+
status: "current",
|
|
555
|
+
detail: `could not parse installed version '${installed}'; leaving ${binary} as-is`
|
|
556
|
+
});
|
|
557
|
+
return;
|
|
558
|
+
}
|
|
559
|
+
if (comparison >= 0) {
|
|
560
|
+
report.entries.push({ name, status: "current", detail: `${binary} ${installed}` });
|
|
561
|
+
return;
|
|
562
|
+
}
|
|
563
|
+
await npmInstall(name, npmPackage, pinned, runCommand3, report, "updated");
|
|
564
|
+
}
|
|
565
|
+
async function npmInstall(name, npmPackage, version, runCommand3, report, status) {
|
|
566
|
+
const result = await runCommand3("npm", ["install", "-g", `${npmPackage}@${version}`]);
|
|
567
|
+
if (result.code !== 0) {
|
|
568
|
+
fail(report, name, `npm install -g ${npmPackage}@${version} failed: ${result.stderr.trim() || `exit code ${result.code}`}`);
|
|
569
|
+
return;
|
|
570
|
+
}
|
|
571
|
+
report.entries.push({ name, status, detail: `${npmPackage}@${version}` });
|
|
572
|
+
}
|
|
573
|
+
function parseNpmGlobalInstall(command) {
|
|
574
|
+
const match = NPM_GLOBAL_INSTALL.exec(command.trim());
|
|
575
|
+
return match?.[1];
|
|
576
|
+
}
|
|
577
|
+
function pinnedSemver(ref) {
|
|
578
|
+
const match = PINNED_SEMVER.exec(ref.trim());
|
|
579
|
+
return match?.[0].replace(/^v/, "");
|
|
580
|
+
}
|
|
581
|
+
function fail(report, name, detail) {
|
|
582
|
+
report.entries.push({ name, status: "failed", detail });
|
|
583
|
+
report.warnings.push(`${name}: ${detail}`);
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
// src/lib/harnessDetect.ts
|
|
587
|
+
import fs5 from "fs";
|
|
588
|
+
import path6 from "path";
|
|
333
589
|
import os2 from "os";
|
|
334
590
|
var HARNESS_SPECS = [
|
|
335
591
|
{
|
|
@@ -343,9 +599,9 @@ var HARNESS_SPECS = [
|
|
|
343
599
|
function detectGlobalHarnesses(overrideHomeDir) {
|
|
344
600
|
const homeDir = overrideHomeDir ?? os2.homedir();
|
|
345
601
|
return HARNESS_SPECS.map((spec) => {
|
|
346
|
-
const configDir =
|
|
347
|
-
const installed =
|
|
348
|
-
const pluginManaged = spec.pluginMarker ?
|
|
602
|
+
const configDir = path6.join(homeDir, spec.configDirName);
|
|
603
|
+
const installed = fs5.existsSync(configDir);
|
|
604
|
+
const pluginManaged = spec.pluginMarker ? fs5.existsSync(path6.join(configDir, spec.pluginMarker)) : false;
|
|
349
605
|
return {
|
|
350
606
|
id: spec.id,
|
|
351
607
|
installed,
|
|
@@ -537,6 +793,7 @@ function createDefaultDeps() {
|
|
|
537
793
|
paths: resolveLincolnPaths(),
|
|
538
794
|
payloadRoot: resolvePayloadRoot() || "",
|
|
539
795
|
syncHarnesses,
|
|
796
|
+
syncExternalSkills,
|
|
540
797
|
createPrompt,
|
|
541
798
|
resolvePythonForVenv,
|
|
542
799
|
isTTY: Boolean(process.stdin.isTTY && process.stdout.isTTY)
|
|
@@ -549,7 +806,7 @@ async function install(options, deps = createDefaultDeps()) {
|
|
|
549
806
|
return 1;
|
|
550
807
|
}
|
|
551
808
|
const payloadRoot = deps.payloadRoot;
|
|
552
|
-
if (!payloadRoot || !
|
|
809
|
+
if (!payloadRoot || !fs6.existsSync(payloadRoot)) {
|
|
553
810
|
console.error('Lincoln payload not found. Run "npm install -g @sushanglewis/lincoln" first.');
|
|
554
811
|
return 1;
|
|
555
812
|
}
|
|
@@ -568,15 +825,15 @@ async function install(options, deps = createDefaultDeps()) {
|
|
|
568
825
|
return 1;
|
|
569
826
|
}
|
|
570
827
|
if (!options.dryRun) {
|
|
571
|
-
const versionDir =
|
|
572
|
-
|
|
573
|
-
|
|
828
|
+
const versionDir = path7.join(deps.paths.versionsDir, version);
|
|
829
|
+
fs6.mkdirSync(versionDir, { recursive: true });
|
|
830
|
+
fs6.cpSync(payloadRoot, versionDir, { recursive: true, force: true });
|
|
574
831
|
try {
|
|
575
|
-
|
|
576
|
-
|
|
832
|
+
fs6.rmSync(deps.paths.currentDir, { recursive: true, force: true });
|
|
833
|
+
fs6.symlinkSync(versionDir, deps.paths.currentDir);
|
|
577
834
|
} catch {
|
|
578
|
-
|
|
579
|
-
|
|
835
|
+
fs6.rmSync(deps.paths.currentDir, { recursive: true, force: true });
|
|
836
|
+
fs6.cpSync(versionDir, deps.paths.currentDir, { recursive: true, force: true });
|
|
580
837
|
}
|
|
581
838
|
}
|
|
582
839
|
const reports = await deps.syncHarnesses({
|
|
@@ -596,9 +853,30 @@ async function install(options, deps = createDefaultDeps()) {
|
|
|
596
853
|
managedFiles: collectManagedFiles(reports)
|
|
597
854
|
});
|
|
598
855
|
}
|
|
599
|
-
|
|
856
|
+
const skillReport = await syncSkillLibraries(options, deps, harnesses);
|
|
857
|
+
printSummary(options, version, harnesses, reports, skillReport);
|
|
600
858
|
return 0;
|
|
601
859
|
}
|
|
860
|
+
async function syncSkillLibraries(options, deps, harnesses) {
|
|
861
|
+
if (!harnesses.includes("claude-code") || !deps.syncExternalSkills) {
|
|
862
|
+
return void 0;
|
|
863
|
+
}
|
|
864
|
+
const payloadRoot = deps.paths.currentDir;
|
|
865
|
+
const manifestPath = path7.join(payloadRoot, ".claude", "skills", "dependencies.yaml");
|
|
866
|
+
if (!fs6.existsSync(manifestPath)) {
|
|
867
|
+
return void 0;
|
|
868
|
+
}
|
|
869
|
+
try {
|
|
870
|
+
return await deps.syncExternalSkills({
|
|
871
|
+
payloadRoot,
|
|
872
|
+
skillsDir: path7.join(deps.paths.claudeDir, "skills"),
|
|
873
|
+
dryRun: options.dryRun
|
|
874
|
+
});
|
|
875
|
+
} catch (err) {
|
|
876
|
+
console.warn(` warning: external skill sync failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
877
|
+
return void 0;
|
|
878
|
+
}
|
|
879
|
+
}
|
|
602
880
|
async function resolvePythonIfNeeded(options, deps, harnesses) {
|
|
603
881
|
const needsPython = !options.dryRun && !options.noVenv && harnesses.some((id) => id === "codex" || id === "opencode");
|
|
604
882
|
if (!needsPython) {
|
|
@@ -659,7 +937,7 @@ function collectManagedFiles(reports) {
|
|
|
659
937
|
}
|
|
660
938
|
return files;
|
|
661
939
|
}
|
|
662
|
-
function printSummary(options, version, harnesses, reports) {
|
|
940
|
+
function printSummary(options, version, harnesses, reports, skillReport) {
|
|
663
941
|
const warnings = collectWarnings(reports);
|
|
664
942
|
if (options.dryRun) {
|
|
665
943
|
console.log(`Dry run: would install Lincoln ${version} for harnesses: ${harnesses.join(", ")}`);
|
|
@@ -670,6 +948,13 @@ function printSummary(options, version, harnesses, reports) {
|
|
|
670
948
|
const count = report.written.length + report.skipped.length + report.preserved.length;
|
|
671
949
|
console.log(` ${harnessId}: ${count} file(s)`);
|
|
672
950
|
}
|
|
951
|
+
if (skillReport) {
|
|
952
|
+
for (const entry of skillReport.entries) {
|
|
953
|
+
const detail = entry.detail ? ` (${entry.detail})` : "";
|
|
954
|
+
console.log(` skill ${entry.name}: ${entry.status}${detail}`);
|
|
955
|
+
}
|
|
956
|
+
warnings.push(...skillReport.warnings);
|
|
957
|
+
}
|
|
673
958
|
for (const warning of warnings) {
|
|
674
959
|
console.warn(` warning: ${warning}`);
|
|
675
960
|
}
|
|
@@ -730,7 +1015,7 @@ async function resolvePythonForVenv(envOverride = process.env.LINCOLN_PYTHON, ca
|
|
|
730
1015
|
return void 0;
|
|
731
1016
|
}
|
|
732
1017
|
function venvPythonPath(paths) {
|
|
733
|
-
return
|
|
1018
|
+
return path7.join(
|
|
734
1019
|
paths.venvDir,
|
|
735
1020
|
process.platform === "win32" ? "Scripts" : "bin",
|
|
736
1021
|
process.platform === "win32" ? "python.exe" : "python"
|
|
@@ -738,17 +1023,17 @@ function venvPythonPath(paths) {
|
|
|
738
1023
|
}
|
|
739
1024
|
async function setupVenv(paths, payloadRoot, pythonCommand) {
|
|
740
1025
|
const pythonExe = venvPythonPath(paths);
|
|
741
|
-
if (!
|
|
1026
|
+
if (!fs6.existsSync(pythonExe)) {
|
|
742
1027
|
console.log("Creating Lincoln virtual environment...");
|
|
743
1028
|
const venvCode = await runCommand2(pythonCommand, ["-m", "venv", paths.venvDir]);
|
|
744
1029
|
if (venvCode !== 0) {
|
|
745
1030
|
throw new Error(`Failed to create virtual environment (exit code ${venvCode})`);
|
|
746
1031
|
}
|
|
747
1032
|
}
|
|
748
|
-
const requirementsPath =
|
|
749
|
-
if (
|
|
1033
|
+
const requirementsPath = path7.join(payloadRoot, "requirements.txt");
|
|
1034
|
+
if (fs6.existsSync(requirementsPath)) {
|
|
750
1035
|
console.log("Installing Python dependencies...");
|
|
751
|
-
const pipExe =
|
|
1036
|
+
const pipExe = path7.join(
|
|
752
1037
|
paths.venvDir,
|
|
753
1038
|
process.platform === "win32" ? "Scripts" : "bin",
|
|
754
1039
|
process.platform === "win32" ? "pip.exe" : "pip"
|