@zabaca/lattice 1.2.0 → 1.3.0
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
CHANGED
|
@@ -437,7 +437,8 @@ var SITE_TEMPLATE_FILES = [
|
|
|
437
437
|
"src/content.config.ts",
|
|
438
438
|
"src/collections/authors.ts",
|
|
439
439
|
"src/collections/documents.ts",
|
|
440
|
-
"src/collections/tags.ts"
|
|
440
|
+
"src/collections/tags.ts",
|
|
441
|
+
"src/plugins/rehype-strip-md-extension.ts"
|
|
441
442
|
];
|
|
442
443
|
|
|
443
444
|
class InitCommand extends CommandRunner2 {
|
|
@@ -522,6 +523,9 @@ OBSIDIAN_VAULT_DIR=docs
|
|
|
522
523
|
await fs.mkdir(path.join(latticeHome, "src", "collections"), {
|
|
523
524
|
recursive: true
|
|
524
525
|
});
|
|
526
|
+
await fs.mkdir(path.join(latticeHome, "src", "plugins"), {
|
|
527
|
+
recursive: true
|
|
528
|
+
});
|
|
525
529
|
let copied = 0;
|
|
526
530
|
let skipped = 0;
|
|
527
531
|
for (const file of SITE_TEMPLATE_FILES) {
|
|
@@ -3456,15 +3460,328 @@ QuestionUnansweredCommand = __legacyDecorateClassTS([
|
|
|
3456
3460
|
typeof GraphService === "undefined" ? Object : GraphService
|
|
3457
3461
|
])
|
|
3458
3462
|
], QuestionUnansweredCommand);
|
|
3459
|
-
// src/commands/
|
|
3463
|
+
// src/commands/receive.command.ts
|
|
3460
3464
|
import { spawn } from "child_process";
|
|
3461
|
-
import { existsSync as existsSync6, readFileSync as readFileSync2, unlinkSync, writeFileSync as writeFileSync2 } from "fs";
|
|
3462
|
-
import * as path2 from "path";
|
|
3463
3465
|
import { Injectable as Injectable17 } from "@nestjs/common";
|
|
3464
3466
|
import { Command as Command7, CommandRunner as CommandRunner7, Option as Option5 } from "nest-commander";
|
|
3465
|
-
|
|
3467
|
+
|
|
3468
|
+
// src/utils/croc-binary.ts
|
|
3469
|
+
import { execSync } from "child_process";
|
|
3470
|
+
import {
|
|
3471
|
+
chmodSync,
|
|
3472
|
+
createWriteStream,
|
|
3473
|
+
existsSync as existsSync6,
|
|
3474
|
+
mkdirSync as mkdirSync2,
|
|
3475
|
+
unlinkSync
|
|
3476
|
+
} from "fs";
|
|
3477
|
+
import { join as join3 } from "path";
|
|
3478
|
+
var CROC_VERSION = "10.3.1";
|
|
3479
|
+
function getBinPath() {
|
|
3480
|
+
return join3(getLatticeHome(), "bin");
|
|
3481
|
+
}
|
|
3482
|
+
function getCrocPath() {
|
|
3483
|
+
const binName = process.platform === "win32" ? "croc.exe" : "croc";
|
|
3484
|
+
return join3(getBinPath(), binName);
|
|
3485
|
+
}
|
|
3486
|
+
function getAssetName() {
|
|
3487
|
+
const platform = process.platform;
|
|
3488
|
+
const arch = process.arch;
|
|
3489
|
+
const assetMap = {
|
|
3490
|
+
"darwin-arm64": "macOS-ARM64",
|
|
3491
|
+
"darwin-x64": "macOS-64bit",
|
|
3492
|
+
"linux-x64": "Linux-64bit",
|
|
3493
|
+
"linux-arm64": "Linux-ARM64",
|
|
3494
|
+
"win32-x64": "Windows-64bit"
|
|
3495
|
+
};
|
|
3496
|
+
const key = `${platform}-${arch}`;
|
|
3497
|
+
return assetMap[key] || null;
|
|
3498
|
+
}
|
|
3499
|
+
async function downloadCroc() {
|
|
3500
|
+
const asset = getAssetName();
|
|
3501
|
+
if (!asset) {
|
|
3502
|
+
const key = `${process.platform}-${process.arch}`;
|
|
3503
|
+
console.error(`
|
|
3504
|
+
\u274C Unsupported platform: ${key}`);
|
|
3505
|
+
console.error(`
|
|
3506
|
+
Install croc manually: https://github.com/schollz/croc#install`);
|
|
3507
|
+
console.error(`Then place the binary at: ~/.lattice/bin/croc
|
|
3508
|
+
`);
|
|
3509
|
+
process.exit(1);
|
|
3510
|
+
}
|
|
3511
|
+
const binDir = getBinPath();
|
|
3512
|
+
if (!existsSync6(binDir)) {
|
|
3513
|
+
mkdirSync2(binDir, { recursive: true });
|
|
3514
|
+
}
|
|
3515
|
+
const ext = process.platform === "win32" ? "zip" : "tar.gz";
|
|
3516
|
+
const url = `https://github.com/schollz/croc/releases/download/v${CROC_VERSION}/croc_v${CROC_VERSION}_${asset}.${ext}`;
|
|
3517
|
+
console.log(`\uD83D\uDCE5 Downloading croc v${CROC_VERSION}...`);
|
|
3518
|
+
try {
|
|
3519
|
+
const response = await fetch(url);
|
|
3520
|
+
if (!response.ok) {
|
|
3521
|
+
throw new Error(`Failed to download: ${response.status} ${response.statusText}`);
|
|
3522
|
+
}
|
|
3523
|
+
const crocPath = getCrocPath();
|
|
3524
|
+
if (ext === "tar.gz") {
|
|
3525
|
+
const tempTarGz = join3(binDir, "croc.tar.gz");
|
|
3526
|
+
const fileStream = createWriteStream(tempTarGz);
|
|
3527
|
+
const arrayBuffer = await response.arrayBuffer();
|
|
3528
|
+
const buffer = Buffer.from(arrayBuffer);
|
|
3529
|
+
fileStream.write(buffer);
|
|
3530
|
+
fileStream.end();
|
|
3531
|
+
await new Promise((resolve4, reject) => {
|
|
3532
|
+
fileStream.on("finish", resolve4);
|
|
3533
|
+
fileStream.on("error", reject);
|
|
3534
|
+
});
|
|
3535
|
+
execSync(`tar -xzf croc.tar.gz`, { cwd: binDir, stdio: "pipe" });
|
|
3536
|
+
unlinkSync(tempTarGz);
|
|
3537
|
+
chmodSync(crocPath, 493);
|
|
3538
|
+
} else {
|
|
3539
|
+
console.error(`
|
|
3540
|
+
\u274C Windows auto-download not yet implemented.`);
|
|
3541
|
+
console.error(`
|
|
3542
|
+
Install croc manually: https://github.com/schollz/croc#install`);
|
|
3543
|
+
console.error(`Then place the binary at: ~/.lattice/bin/croc.exe
|
|
3544
|
+
`);
|
|
3545
|
+
process.exit(1);
|
|
3546
|
+
}
|
|
3547
|
+
console.log(`\u2705 Installed croc to ${crocPath}
|
|
3548
|
+
`);
|
|
3549
|
+
} catch (error) {
|
|
3550
|
+
console.error(`
|
|
3551
|
+
\u274C Failed to download croc: ${error instanceof Error ? error.message : String(error)}`);
|
|
3552
|
+
console.error(`
|
|
3553
|
+
Install croc manually: https://github.com/schollz/croc#install`);
|
|
3554
|
+
console.error(`Then place the binary at: ${getCrocPath()}
|
|
3555
|
+
`);
|
|
3556
|
+
process.exit(1);
|
|
3557
|
+
}
|
|
3558
|
+
}
|
|
3559
|
+
async function ensureCroc() {
|
|
3560
|
+
const crocPath = getCrocPath();
|
|
3561
|
+
if (existsSync6(crocPath)) {
|
|
3562
|
+
return crocPath;
|
|
3563
|
+
}
|
|
3564
|
+
await downloadCroc();
|
|
3565
|
+
return crocPath;
|
|
3566
|
+
}
|
|
3567
|
+
|
|
3568
|
+
// src/commands/receive.command.ts
|
|
3569
|
+
class ReceiveCommand extends CommandRunner7 {
|
|
3570
|
+
syncService;
|
|
3571
|
+
constructor(syncService) {
|
|
3572
|
+
super();
|
|
3573
|
+
this.syncService = syncService;
|
|
3574
|
+
}
|
|
3575
|
+
async run([code], options) {
|
|
3576
|
+
if (!code) {
|
|
3577
|
+
console.error(`
|
|
3578
|
+
\u274C Please specify a share code
|
|
3579
|
+
`);
|
|
3580
|
+
console.error(`Usage: lattice receive <code>
|
|
3581
|
+
`);
|
|
3582
|
+
console.error("Example:");
|
|
3583
|
+
console.error(` lattice receive 7-actress-plural-pilgrim
|
|
3584
|
+
`);
|
|
3585
|
+
process.exit(1);
|
|
3586
|
+
}
|
|
3587
|
+
const docsDir = getDocsPath();
|
|
3588
|
+
console.log(`
|
|
3589
|
+
\uD83D\uDCE5 Receiving files to: ${docsDir}
|
|
3590
|
+
`);
|
|
3591
|
+
const crocPath = await ensureCroc();
|
|
3592
|
+
const receiveCode = await new Promise((resolve4, reject) => {
|
|
3593
|
+
const child = spawn(crocPath, ["--yes", "--out", docsDir, code], {
|
|
3594
|
+
stdio: "inherit"
|
|
3595
|
+
});
|
|
3596
|
+
child.on("close", (code2) => {
|
|
3597
|
+
resolve4(code2 ?? 0);
|
|
3598
|
+
});
|
|
3599
|
+
child.on("error", (err) => {
|
|
3600
|
+
reject(err);
|
|
3601
|
+
});
|
|
3602
|
+
});
|
|
3603
|
+
if (receiveCode !== 0) {
|
|
3604
|
+
console.error(`
|
|
3605
|
+
\u274C Transfer failed
|
|
3606
|
+
`);
|
|
3607
|
+
process.exit(receiveCode);
|
|
3608
|
+
}
|
|
3609
|
+
if (!options.noSync) {
|
|
3610
|
+
console.log(`
|
|
3611
|
+
\uD83D\uDD04 Syncing received documents to knowledge graph...
|
|
3612
|
+
`);
|
|
3613
|
+
try {
|
|
3614
|
+
const result = await this.syncService.sync({
|
|
3615
|
+
verbose: false
|
|
3616
|
+
});
|
|
3617
|
+
console.log(`\uD83D\uDCCA Sync Results:
|
|
3618
|
+
`);
|
|
3619
|
+
console.log(` \u2705 Added: ${result.added}`);
|
|
3620
|
+
console.log(` \uD83D\uDD04 Updated: ${result.updated}`);
|
|
3621
|
+
console.log(` \u23ED\uFE0F Unchanged: ${result.unchanged}`);
|
|
3622
|
+
if (result.embeddingsGenerated > 0) {
|
|
3623
|
+
console.log(` \uD83E\uDDE0 Embeddings: ${result.embeddingsGenerated}`);
|
|
3624
|
+
}
|
|
3625
|
+
if (result.errors.length > 0) {
|
|
3626
|
+
console.log(`
|
|
3627
|
+
\u274C Errors (${result.errors.length}):
|
|
3628
|
+
`);
|
|
3629
|
+
result.errors.forEach((e) => {
|
|
3630
|
+
console.log(` ${e.path}: ${e.error}`);
|
|
3631
|
+
});
|
|
3632
|
+
}
|
|
3633
|
+
} catch (error) {
|
|
3634
|
+
console.error(`
|
|
3635
|
+
\u26A0\uFE0F Sync failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
3636
|
+
console.error("Files were received but not synced to the knowledge graph.");
|
|
3637
|
+
console.error(`Run 'lattice sync' manually to complete sync.
|
|
3638
|
+
`);
|
|
3639
|
+
}
|
|
3640
|
+
} else {
|
|
3641
|
+
console.log(`
|
|
3642
|
+
\u23ED\uFE0F Skipping sync (--no-sync specified)`);
|
|
3643
|
+
console.log(`Run 'lattice sync' to add documents to the knowledge graph.
|
|
3644
|
+
`);
|
|
3645
|
+
}
|
|
3646
|
+
console.log(`\u2705 Done!
|
|
3647
|
+
`);
|
|
3648
|
+
}
|
|
3649
|
+
parseNoSync() {
|
|
3650
|
+
return true;
|
|
3651
|
+
}
|
|
3652
|
+
}
|
|
3653
|
+
__legacyDecorateClassTS([
|
|
3654
|
+
Option5({
|
|
3655
|
+
flags: "--no-sync",
|
|
3656
|
+
description: "Skip running lattice sync after receiving"
|
|
3657
|
+
}),
|
|
3658
|
+
__legacyMetadataTS("design:type", Function),
|
|
3659
|
+
__legacyMetadataTS("design:paramtypes", []),
|
|
3660
|
+
__legacyMetadataTS("design:returntype", Boolean)
|
|
3661
|
+
], ReceiveCommand.prototype, "parseNoSync", null);
|
|
3662
|
+
ReceiveCommand = __legacyDecorateClassTS([
|
|
3663
|
+
Injectable17(),
|
|
3664
|
+
Command7({
|
|
3665
|
+
name: "receive",
|
|
3666
|
+
arguments: "<code>",
|
|
3667
|
+
description: "Receive shared documents via P2P transfer"
|
|
3668
|
+
}),
|
|
3669
|
+
__legacyMetadataTS("design:paramtypes", [
|
|
3670
|
+
typeof SyncService === "undefined" ? Object : SyncService
|
|
3671
|
+
])
|
|
3672
|
+
], ReceiveCommand);
|
|
3673
|
+
// src/commands/share.command.ts
|
|
3674
|
+
import { spawn as spawn2 } from "child_process";
|
|
3675
|
+
import { existsSync as existsSync7, statSync } from "fs";
|
|
3676
|
+
import * as path2 from "path";
|
|
3677
|
+
import { Injectable as Injectable18 } from "@nestjs/common";
|
|
3678
|
+
import { Command as Command8, CommandRunner as CommandRunner8 } from "nest-commander";
|
|
3679
|
+
class ShareCommand extends CommandRunner8 {
|
|
3680
|
+
async run([docPath]) {
|
|
3681
|
+
if (!docPath) {
|
|
3682
|
+
console.error(`
|
|
3683
|
+
\u274C Please specify a path to share
|
|
3684
|
+
`);
|
|
3685
|
+
console.error(`Usage: lattice share <path>
|
|
3686
|
+
`);
|
|
3687
|
+
console.error("Examples:");
|
|
3688
|
+
console.error(" lattice share duckdb # Share ~/.lattice/docs/duckdb/");
|
|
3689
|
+
console.error(` lattice share duckdb/README.md # Share single file
|
|
3690
|
+
`);
|
|
3691
|
+
process.exit(1);
|
|
3692
|
+
}
|
|
3693
|
+
const fullPath = this.resolvePath(docPath);
|
|
3694
|
+
if (!existsSync7(fullPath)) {
|
|
3695
|
+
console.error(`
|
|
3696
|
+
\u274C Path not found: ${fullPath}
|
|
3697
|
+
`);
|
|
3698
|
+
process.exit(1);
|
|
3699
|
+
}
|
|
3700
|
+
const stat = statSync(fullPath);
|
|
3701
|
+
const isDir = stat.isDirectory();
|
|
3702
|
+
console.log(`
|
|
3703
|
+
\uD83D\uDCE4 Sharing ${isDir ? "directory" : "file"}: ${fullPath}
|
|
3704
|
+
`);
|
|
3705
|
+
const crocPath = await ensureCroc();
|
|
3706
|
+
const child = spawn2(crocPath, ["--disable-clipboard", "send", fullPath], {
|
|
3707
|
+
stdio: ["inherit", "pipe", "pipe"]
|
|
3708
|
+
});
|
|
3709
|
+
let codeExtracted = false;
|
|
3710
|
+
let outputBuffer = "";
|
|
3711
|
+
const handleOutput = (data) => {
|
|
3712
|
+
const text = data.toString();
|
|
3713
|
+
outputBuffer += text;
|
|
3714
|
+
if (!codeExtracted) {
|
|
3715
|
+
const codeMatch = outputBuffer.match(/Code is:\s*(\S+)/);
|
|
3716
|
+
if (codeMatch) {
|
|
3717
|
+
codeExtracted = true;
|
|
3718
|
+
const code = codeMatch[1];
|
|
3719
|
+
const sendingMatches = outputBuffer.match(/Sending \d+ files? (?:and \d+ folders? )?\([^)]+\)/g);
|
|
3720
|
+
if (sendingMatches && sendingMatches.length > 0) {
|
|
3721
|
+
const lastMatch = sendingMatches[sendingMatches.length - 1];
|
|
3722
|
+
if (!lastMatch.includes("0 files")) {
|
|
3723
|
+
console.log(lastMatch);
|
|
3724
|
+
}
|
|
3725
|
+
}
|
|
3726
|
+
console.log(`
|
|
3727
|
+
\uD83D\uDD17 Share code: ${code}
|
|
3728
|
+
`);
|
|
3729
|
+
console.log("On the receiving machine, run:");
|
|
3730
|
+
console.log(` lattice receive ${code}
|
|
3731
|
+
`);
|
|
3732
|
+
console.log(`Waiting for recipient...
|
|
3733
|
+
`);
|
|
3734
|
+
outputBuffer = "";
|
|
3735
|
+
}
|
|
3736
|
+
return;
|
|
3737
|
+
}
|
|
3738
|
+
if (text.includes("On the other computer") || text.includes("(For Windows)") || text.includes("(For Linux/macOS)") || text.includes("CROC_SECRET=") || text.includes("Code copied to clipboard") || text.includes("croc ")) {
|
|
3739
|
+
return;
|
|
3740
|
+
}
|
|
3741
|
+
process.stdout.write(text);
|
|
3742
|
+
};
|
|
3743
|
+
child.stdout?.on("data", handleOutput);
|
|
3744
|
+
child.stderr?.on("data", handleOutput);
|
|
3745
|
+
child.on("close", (code) => {
|
|
3746
|
+
if (code === 0) {
|
|
3747
|
+
console.log(`
|
|
3748
|
+
\u2705 Transfer complete!
|
|
3749
|
+
`);
|
|
3750
|
+
}
|
|
3751
|
+
process.exit(code ?? 0);
|
|
3752
|
+
});
|
|
3753
|
+
child.on("error", (err) => {
|
|
3754
|
+
console.error(`
|
|
3755
|
+
\u274C Failed to run croc: ${err.message}
|
|
3756
|
+
`);
|
|
3757
|
+
process.exit(1);
|
|
3758
|
+
});
|
|
3759
|
+
}
|
|
3760
|
+
resolvePath(input) {
|
|
3761
|
+
if (path2.isAbsolute(input)) {
|
|
3762
|
+
return input;
|
|
3763
|
+
}
|
|
3764
|
+
const docsDir = getDocsPath();
|
|
3765
|
+
return path2.join(docsDir, input);
|
|
3766
|
+
}
|
|
3767
|
+
}
|
|
3768
|
+
ShareCommand = __legacyDecorateClassTS([
|
|
3769
|
+
Injectable18(),
|
|
3770
|
+
Command8({
|
|
3771
|
+
name: "share",
|
|
3772
|
+
arguments: "<path>",
|
|
3773
|
+
description: "Share a document or topic directory via P2P transfer"
|
|
3774
|
+
})
|
|
3775
|
+
], ShareCommand);
|
|
3776
|
+
// src/commands/site.command.ts
|
|
3777
|
+
import { spawn as spawn3 } from "child_process";
|
|
3778
|
+
import { existsSync as existsSync8, readFileSync as readFileSync2, unlinkSync as unlinkSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
3779
|
+
import * as path3 from "path";
|
|
3780
|
+
import { Injectable as Injectable19 } from "@nestjs/common";
|
|
3781
|
+
import { Command as Command9, CommandRunner as CommandRunner9, Option as Option6 } from "nest-commander";
|
|
3782
|
+
class SiteCommand extends CommandRunner9 {
|
|
3466
3783
|
getPidFile() {
|
|
3467
|
-
return
|
|
3784
|
+
return path3.join(getLatticeHome(), "site.pid");
|
|
3468
3785
|
}
|
|
3469
3786
|
async run(_inputs, options) {
|
|
3470
3787
|
if (options.kill) {
|
|
@@ -3472,9 +3789,9 @@ class SiteCommand extends CommandRunner7 {
|
|
|
3472
3789
|
process.exit(0);
|
|
3473
3790
|
}
|
|
3474
3791
|
const latticeHome = getLatticeHome();
|
|
3475
|
-
const packageJsonPath =
|
|
3476
|
-
const nodeModulesPath =
|
|
3477
|
-
if (!
|
|
3792
|
+
const packageJsonPath = path3.join(latticeHome, "package.json");
|
|
3793
|
+
const nodeModulesPath = path3.join(latticeHome, "node_modules");
|
|
3794
|
+
if (!existsSync8(packageJsonPath)) {
|
|
3478
3795
|
console.error("Error: Site not initialized. Run 'lattice init' first.");
|
|
3479
3796
|
process.exit(1);
|
|
3480
3797
|
}
|
|
@@ -3483,7 +3800,7 @@ class SiteCommand extends CommandRunner7 {
|
|
|
3483
3800
|
console.error("Use 'lattice site --kill' to stop it first.");
|
|
3484
3801
|
process.exit(1);
|
|
3485
3802
|
}
|
|
3486
|
-
if (!
|
|
3803
|
+
if (!existsSync8(nodeModulesPath)) {
|
|
3487
3804
|
console.log("\uD83D\uDCE6 Installing dependencies...");
|
|
3488
3805
|
await this.runCommand("bun", ["install"], latticeHome);
|
|
3489
3806
|
console.log();
|
|
@@ -3510,7 +3827,7 @@ class SiteCommand extends CommandRunner7 {
|
|
|
3510
3827
|
}
|
|
3511
3828
|
runCommand(cmd, args, cwd) {
|
|
3512
3829
|
return new Promise((resolve4, reject) => {
|
|
3513
|
-
const child =
|
|
3830
|
+
const child = spawn3(cmd, args, {
|
|
3514
3831
|
cwd,
|
|
3515
3832
|
stdio: "pipe",
|
|
3516
3833
|
env: { ...process.env, FORCE_COLOR: "1" }
|
|
@@ -3535,7 +3852,7 @@ class SiteCommand extends CommandRunner7 {
|
|
|
3535
3852
|
}
|
|
3536
3853
|
runServerCommand(cmd, args, cwd) {
|
|
3537
3854
|
return new Promise((resolve4, reject) => {
|
|
3538
|
-
const child =
|
|
3855
|
+
const child = spawn3(cmd, args, {
|
|
3539
3856
|
cwd,
|
|
3540
3857
|
stdio: "inherit",
|
|
3541
3858
|
env: { ...process.env, FORCE_COLOR: "1" }
|
|
@@ -3545,7 +3862,7 @@ class SiteCommand extends CommandRunner7 {
|
|
|
3545
3862
|
}
|
|
3546
3863
|
const cleanup = () => {
|
|
3547
3864
|
try {
|
|
3548
|
-
|
|
3865
|
+
unlinkSync2(this.getPidFile());
|
|
3549
3866
|
} catch {}
|
|
3550
3867
|
};
|
|
3551
3868
|
child.on("close", (code) => {
|
|
@@ -3566,7 +3883,7 @@ class SiteCommand extends CommandRunner7 {
|
|
|
3566
3883
|
}
|
|
3567
3884
|
isRunning() {
|
|
3568
3885
|
const pidFile = this.getPidFile();
|
|
3569
|
-
if (!
|
|
3886
|
+
if (!existsSync8(pidFile)) {
|
|
3570
3887
|
return false;
|
|
3571
3888
|
}
|
|
3572
3889
|
try {
|
|
@@ -3575,14 +3892,14 @@ class SiteCommand extends CommandRunner7 {
|
|
|
3575
3892
|
return true;
|
|
3576
3893
|
} catch {
|
|
3577
3894
|
try {
|
|
3578
|
-
|
|
3895
|
+
unlinkSync2(pidFile);
|
|
3579
3896
|
} catch {}
|
|
3580
3897
|
return false;
|
|
3581
3898
|
}
|
|
3582
3899
|
}
|
|
3583
3900
|
killSiteProcess() {
|
|
3584
3901
|
const pidFile = this.getPidFile();
|
|
3585
|
-
if (!
|
|
3902
|
+
if (!existsSync8(pidFile)) {
|
|
3586
3903
|
console.log("No Lattice site process running");
|
|
3587
3904
|
return;
|
|
3588
3905
|
}
|
|
@@ -3593,11 +3910,11 @@ class SiteCommand extends CommandRunner7 {
|
|
|
3593
3910
|
} catch {
|
|
3594
3911
|
process.kill(pid, "SIGTERM");
|
|
3595
3912
|
}
|
|
3596
|
-
|
|
3913
|
+
unlinkSync2(pidFile);
|
|
3597
3914
|
console.log(`\u2705 Killed Lattice site process (PID: ${pid})`);
|
|
3598
3915
|
} catch (_err) {
|
|
3599
3916
|
try {
|
|
3600
|
-
|
|
3917
|
+
unlinkSync2(pidFile);
|
|
3601
3918
|
} catch {}
|
|
3602
3919
|
console.log("No Lattice site process running");
|
|
3603
3920
|
}
|
|
@@ -3616,7 +3933,7 @@ class SiteCommand extends CommandRunner7 {
|
|
|
3616
3933
|
}
|
|
3617
3934
|
}
|
|
3618
3935
|
__legacyDecorateClassTS([
|
|
3619
|
-
|
|
3936
|
+
Option6({
|
|
3620
3937
|
flags: "-b, --build",
|
|
3621
3938
|
description: "Build the site without starting the server"
|
|
3622
3939
|
}),
|
|
@@ -3625,7 +3942,7 @@ __legacyDecorateClassTS([
|
|
|
3625
3942
|
__legacyMetadataTS("design:returntype", Boolean)
|
|
3626
3943
|
], SiteCommand.prototype, "parseBuild", null);
|
|
3627
3944
|
__legacyDecorateClassTS([
|
|
3628
|
-
|
|
3945
|
+
Option6({
|
|
3629
3946
|
flags: "-d, --dev",
|
|
3630
3947
|
description: "Run in development mode (hot reload, no search)"
|
|
3631
3948
|
}),
|
|
@@ -3634,7 +3951,7 @@ __legacyDecorateClassTS([
|
|
|
3634
3951
|
__legacyMetadataTS("design:returntype", Boolean)
|
|
3635
3952
|
], SiteCommand.prototype, "parseDev", null);
|
|
3636
3953
|
__legacyDecorateClassTS([
|
|
3637
|
-
|
|
3954
|
+
Option6({
|
|
3638
3955
|
flags: "-p, --port <port>",
|
|
3639
3956
|
description: "Port to run the server on (default: 4321)"
|
|
3640
3957
|
}),
|
|
@@ -3645,7 +3962,7 @@ __legacyDecorateClassTS([
|
|
|
3645
3962
|
__legacyMetadataTS("design:returntype", String)
|
|
3646
3963
|
], SiteCommand.prototype, "parsePort", null);
|
|
3647
3964
|
__legacyDecorateClassTS([
|
|
3648
|
-
|
|
3965
|
+
Option6({
|
|
3649
3966
|
flags: "-k, --kill",
|
|
3650
3967
|
description: "Kill the running Lattice site process"
|
|
3651
3968
|
}),
|
|
@@ -3654,16 +3971,16 @@ __legacyDecorateClassTS([
|
|
|
3654
3971
|
__legacyMetadataTS("design:returntype", Boolean)
|
|
3655
3972
|
], SiteCommand.prototype, "parseKill", null);
|
|
3656
3973
|
SiteCommand = __legacyDecorateClassTS([
|
|
3657
|
-
|
|
3658
|
-
|
|
3974
|
+
Injectable19(),
|
|
3975
|
+
Command9({
|
|
3659
3976
|
name: "site",
|
|
3660
3977
|
description: "Build and run the Lattice documentation site"
|
|
3661
3978
|
})
|
|
3662
3979
|
], SiteCommand);
|
|
3663
3980
|
// src/commands/status.command.ts
|
|
3664
|
-
import { Injectable as
|
|
3665
|
-
import { Command as
|
|
3666
|
-
class StatusCommand extends
|
|
3981
|
+
import { Injectable as Injectable20 } from "@nestjs/common";
|
|
3982
|
+
import { Command as Command10, CommandRunner as CommandRunner10, Option as Option7 } from "nest-commander";
|
|
3983
|
+
class StatusCommand extends CommandRunner10 {
|
|
3667
3984
|
syncService;
|
|
3668
3985
|
dbChangeDetector;
|
|
3669
3986
|
constructor(syncService, dbChangeDetector) {
|
|
@@ -3729,7 +4046,7 @@ class StatusCommand extends CommandRunner8 {
|
|
|
3729
4046
|
}
|
|
3730
4047
|
}
|
|
3731
4048
|
__legacyDecorateClassTS([
|
|
3732
|
-
|
|
4049
|
+
Option7({
|
|
3733
4050
|
flags: "-v, --verbose",
|
|
3734
4051
|
description: "Show all documents including unchanged"
|
|
3735
4052
|
}),
|
|
@@ -3738,8 +4055,8 @@ __legacyDecorateClassTS([
|
|
|
3738
4055
|
__legacyMetadataTS("design:returntype", Boolean)
|
|
3739
4056
|
], StatusCommand.prototype, "parseVerbose", null);
|
|
3740
4057
|
StatusCommand = __legacyDecorateClassTS([
|
|
3741
|
-
|
|
3742
|
-
|
|
4058
|
+
Injectable20(),
|
|
4059
|
+
Command10({
|
|
3743
4060
|
name: "status",
|
|
3744
4061
|
description: "Show documents that need syncing (new or updated)"
|
|
3745
4062
|
}),
|
|
@@ -3750,12 +4067,12 @@ StatusCommand = __legacyDecorateClassTS([
|
|
|
3750
4067
|
], StatusCommand);
|
|
3751
4068
|
// src/commands/sync.command.ts
|
|
3752
4069
|
import { watch } from "fs";
|
|
3753
|
-
import { join as
|
|
3754
|
-
import { Injectable as
|
|
3755
|
-
import { Command as
|
|
4070
|
+
import { join as join6 } from "path";
|
|
4071
|
+
import { Injectable as Injectable22 } from "@nestjs/common";
|
|
4072
|
+
import { Command as Command11, CommandRunner as CommandRunner11, Option as Option8 } from "nest-commander";
|
|
3756
4073
|
|
|
3757
4074
|
// src/sync/graph-validator.service.ts
|
|
3758
|
-
import { Injectable as
|
|
4075
|
+
import { Injectable as Injectable21, Logger as Logger9 } from "@nestjs/common";
|
|
3759
4076
|
class GraphValidatorService {
|
|
3760
4077
|
graph;
|
|
3761
4078
|
logger = new Logger9(GraphValidatorService.name);
|
|
@@ -3874,15 +4191,15 @@ class GraphValidatorService {
|
|
|
3874
4191
|
});
|
|
3875
4192
|
}
|
|
3876
4193
|
}
|
|
3877
|
-
async validateDocument(
|
|
4194
|
+
async validateDocument(path4) {
|
|
3878
4195
|
const issues = [];
|
|
3879
4196
|
try {
|
|
3880
|
-
const result = await this.graph.query(`SELECT label, name, properties FROM nodes WHERE label = 'Document' AND name = '${this.escape(
|
|
4197
|
+
const result = await this.graph.query(`SELECT label, name, properties FROM nodes WHERE label = 'Document' AND name = '${this.escape(path4)}'`);
|
|
3881
4198
|
if (result.resultSet.length === 0) {
|
|
3882
4199
|
issues.push({
|
|
3883
4200
|
type: "error",
|
|
3884
4201
|
nodeLabel: "Document",
|
|
3885
|
-
nodeName:
|
|
4202
|
+
nodeName: path4,
|
|
3886
4203
|
field: "node",
|
|
3887
4204
|
message: "Document not found in graph",
|
|
3888
4205
|
suggestion: "Run 'lattice sync' to add this document"
|
|
@@ -3892,9 +4209,9 @@ class GraphValidatorService {
|
|
|
3892
4209
|
const row = result.resultSet[0];
|
|
3893
4210
|
const propertiesJson = row[2];
|
|
3894
4211
|
const properties = typeof propertiesJson === "string" ? JSON.parse(propertiesJson) : propertiesJson;
|
|
3895
|
-
this.validateDocumentNode(
|
|
4212
|
+
this.validateDocumentNode(path4, properties, issues);
|
|
3896
4213
|
} catch (error) {
|
|
3897
|
-
this.logger.error(`Failed to validate document ${
|
|
4214
|
+
this.logger.error(`Failed to validate document ${path4}: ${error instanceof Error ? error.message : String(error)}`);
|
|
3898
4215
|
throw error;
|
|
3899
4216
|
}
|
|
3900
4217
|
return issues;
|
|
@@ -3904,14 +4221,14 @@ class GraphValidatorService {
|
|
|
3904
4221
|
}
|
|
3905
4222
|
}
|
|
3906
4223
|
GraphValidatorService = __legacyDecorateClassTS([
|
|
3907
|
-
|
|
4224
|
+
Injectable21(),
|
|
3908
4225
|
__legacyMetadataTS("design:paramtypes", [
|
|
3909
4226
|
typeof GraphService === "undefined" ? Object : GraphService
|
|
3910
4227
|
])
|
|
3911
4228
|
], GraphValidatorService);
|
|
3912
4229
|
|
|
3913
4230
|
// src/commands/sync.command.ts
|
|
3914
|
-
class SyncCommand extends
|
|
4231
|
+
class SyncCommand extends CommandRunner11 {
|
|
3915
4232
|
syncService;
|
|
3916
4233
|
graphService;
|
|
3917
4234
|
_graphValidator;
|
|
@@ -4054,7 +4371,7 @@ class SyncCommand extends CommandRunner9 {
|
|
|
4054
4371
|
`);
|
|
4055
4372
|
this.watcher = watch(docsPath, { recursive: true }, (event, filename) => {
|
|
4056
4373
|
if (filename?.endsWith(".md")) {
|
|
4057
|
-
const fullPath =
|
|
4374
|
+
const fullPath = join6(docsPath, filename);
|
|
4058
4375
|
trackedFiles.add(fullPath);
|
|
4059
4376
|
debouncedSync();
|
|
4060
4377
|
}
|
|
@@ -4184,7 +4501,7 @@ class SyncCommand extends CommandRunner9 {
|
|
|
4184
4501
|
}
|
|
4185
4502
|
}
|
|
4186
4503
|
__legacyDecorateClassTS([
|
|
4187
|
-
|
|
4504
|
+
Option8({
|
|
4188
4505
|
flags: "-f, --force",
|
|
4189
4506
|
description: "Force re-sync specified documents (requires paths to be specified)"
|
|
4190
4507
|
}),
|
|
@@ -4193,7 +4510,7 @@ __legacyDecorateClassTS([
|
|
|
4193
4510
|
__legacyMetadataTS("design:returntype", Boolean)
|
|
4194
4511
|
], SyncCommand.prototype, "parseForce", null);
|
|
4195
4512
|
__legacyDecorateClassTS([
|
|
4196
|
-
|
|
4513
|
+
Option8({
|
|
4197
4514
|
flags: "-d, --dry-run",
|
|
4198
4515
|
description: "Show what would change without applying"
|
|
4199
4516
|
}),
|
|
@@ -4202,7 +4519,7 @@ __legacyDecorateClassTS([
|
|
|
4202
4519
|
__legacyMetadataTS("design:returntype", Boolean)
|
|
4203
4520
|
], SyncCommand.prototype, "parseDryRun", null);
|
|
4204
4521
|
__legacyDecorateClassTS([
|
|
4205
|
-
|
|
4522
|
+
Option8({
|
|
4206
4523
|
flags: "-v, --verbose",
|
|
4207
4524
|
description: "Show detailed output"
|
|
4208
4525
|
}),
|
|
@@ -4211,7 +4528,7 @@ __legacyDecorateClassTS([
|
|
|
4211
4528
|
__legacyMetadataTS("design:returntype", Boolean)
|
|
4212
4529
|
], SyncCommand.prototype, "parseVerbose", null);
|
|
4213
4530
|
__legacyDecorateClassTS([
|
|
4214
|
-
|
|
4531
|
+
Option8({
|
|
4215
4532
|
flags: "-w, --watch",
|
|
4216
4533
|
description: "Watch for file changes and sync automatically"
|
|
4217
4534
|
}),
|
|
@@ -4220,7 +4537,7 @@ __legacyDecorateClassTS([
|
|
|
4220
4537
|
__legacyMetadataTS("design:returntype", Boolean)
|
|
4221
4538
|
], SyncCommand.prototype, "parseWatch", null);
|
|
4222
4539
|
__legacyDecorateClassTS([
|
|
4223
|
-
|
|
4540
|
+
Option8({
|
|
4224
4541
|
flags: "--diff",
|
|
4225
4542
|
description: "Show only changed documents (alias for --dry-run)"
|
|
4226
4543
|
}),
|
|
@@ -4229,7 +4546,7 @@ __legacyDecorateClassTS([
|
|
|
4229
4546
|
__legacyMetadataTS("design:returntype", Boolean)
|
|
4230
4547
|
], SyncCommand.prototype, "parseDiff", null);
|
|
4231
4548
|
__legacyDecorateClassTS([
|
|
4232
|
-
|
|
4549
|
+
Option8({
|
|
4233
4550
|
flags: "--skip-cascade",
|
|
4234
4551
|
description: "Skip cascade analysis (faster for large repos)"
|
|
4235
4552
|
}),
|
|
@@ -4238,7 +4555,7 @@ __legacyDecorateClassTS([
|
|
|
4238
4555
|
__legacyMetadataTS("design:returntype", Boolean)
|
|
4239
4556
|
], SyncCommand.prototype, "parseSkipCascade", null);
|
|
4240
4557
|
__legacyDecorateClassTS([
|
|
4241
|
-
|
|
4558
|
+
Option8({
|
|
4242
4559
|
flags: "--no-embeddings",
|
|
4243
4560
|
description: "Disable embedding generation during sync"
|
|
4244
4561
|
}),
|
|
@@ -4247,7 +4564,7 @@ __legacyDecorateClassTS([
|
|
|
4247
4564
|
__legacyMetadataTS("design:returntype", Boolean)
|
|
4248
4565
|
], SyncCommand.prototype, "parseNoEmbeddings", null);
|
|
4249
4566
|
__legacyDecorateClassTS([
|
|
4250
|
-
|
|
4567
|
+
Option8({
|
|
4251
4568
|
flags: "--skip-extraction",
|
|
4252
4569
|
description: "Skip AI entity extraction (sync without re-extracting entities)"
|
|
4253
4570
|
}),
|
|
@@ -4256,8 +4573,8 @@ __legacyDecorateClassTS([
|
|
|
4256
4573
|
__legacyMetadataTS("design:returntype", Boolean)
|
|
4257
4574
|
], SyncCommand.prototype, "parseSkipExtraction", null);
|
|
4258
4575
|
SyncCommand = __legacyDecorateClassTS([
|
|
4259
|
-
|
|
4260
|
-
|
|
4576
|
+
Injectable22(),
|
|
4577
|
+
Command11({
|
|
4261
4578
|
name: "sync",
|
|
4262
4579
|
arguments: "[paths...]",
|
|
4263
4580
|
description: "Synchronize documents to the knowledge graph"
|
|
@@ -4296,7 +4613,7 @@ GraphModule = __legacyDecorateClassTS([
|
|
|
4296
4613
|
import { Module as Module3 } from "@nestjs/common";
|
|
4297
4614
|
|
|
4298
4615
|
// src/query/query.service.ts
|
|
4299
|
-
import { Injectable as
|
|
4616
|
+
import { Injectable as Injectable23, Logger as Logger10 } from "@nestjs/common";
|
|
4300
4617
|
class QueryService {
|
|
4301
4618
|
graphService;
|
|
4302
4619
|
logger = new Logger10(QueryService.name);
|
|
@@ -4309,7 +4626,7 @@ class QueryService {
|
|
|
4309
4626
|
}
|
|
4310
4627
|
}
|
|
4311
4628
|
QueryService = __legacyDecorateClassTS([
|
|
4312
|
-
|
|
4629
|
+
Injectable23(),
|
|
4313
4630
|
__legacyMetadataTS("design:paramtypes", [
|
|
4314
4631
|
typeof GraphService === "undefined" ? Object : GraphService
|
|
4315
4632
|
])
|
|
@@ -4384,6 +4701,8 @@ AppModule = __legacyDecorateClassTS([
|
|
|
4384
4701
|
InitCommand,
|
|
4385
4702
|
MigrateCommand,
|
|
4386
4703
|
SiteCommand,
|
|
4704
|
+
ShareCommand,
|
|
4705
|
+
ReceiveCommand,
|
|
4387
4706
|
QuestionAddCommand,
|
|
4388
4707
|
QuestionLinkCommand,
|
|
4389
4708
|
QuestionUnansweredCommand
|
package/package.json
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
import { defineConfig } from 'astro/config';
|
|
2
2
|
import { astroSpaceship } from 'astro-spaceship';
|
|
3
|
+
import rehypeStripMdExtension from './src/plugins/rehype-strip-md-extension';
|
|
3
4
|
|
|
4
5
|
import websiteConfig from 'astro-spaceship/config';
|
|
5
6
|
|
|
6
7
|
export default defineConfig({
|
|
8
|
+
markdown: {
|
|
9
|
+
rehypePlugins: [rehypeStripMdExtension],
|
|
10
|
+
},
|
|
7
11
|
integrations: [
|
|
8
12
|
astroSpaceship(websiteConfig)
|
|
9
13
|
]
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { visit } from 'unist-util-visit';
|
|
2
|
+
import type { Root, Element } from 'hast';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Rehype plugin that strips .md extensions from relative links.
|
|
6
|
+
* This allows standard markdown links like [text](./file.md) to work
|
|
7
|
+
* correctly in Astro where routes don't include the .md extension.
|
|
8
|
+
*/
|
|
9
|
+
export default function rehypeStripMdExtension() {
|
|
10
|
+
return (tree: Root) => {
|
|
11
|
+
visit(tree, 'element', (node: Element) => {
|
|
12
|
+
if (
|
|
13
|
+
node.tagName === 'a' &&
|
|
14
|
+
typeof node.properties?.href === 'string'
|
|
15
|
+
) {
|
|
16
|
+
const href = node.properties.href;
|
|
17
|
+
// Only process relative links ending in .md
|
|
18
|
+
if (
|
|
19
|
+
!href.startsWith('http://') &&
|
|
20
|
+
!href.startsWith('https://') &&
|
|
21
|
+
!href.startsWith('//') &&
|
|
22
|
+
href.endsWith('.md')
|
|
23
|
+
) {
|
|
24
|
+
node.properties.href = href.slice(0, -3);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
};
|
|
29
|
+
}
|