forge-openclaw-plugin 0.2.22 → 0.2.23
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/server/db.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
1
2
|
import { mkdir, readdir, readFile } from "node:fs/promises";
|
|
2
3
|
import path from "node:path";
|
|
3
4
|
import { fileURLToPath } from "node:url";
|
|
@@ -12,7 +13,21 @@ function dateOffsetIso(days) {
|
|
|
12
13
|
}
|
|
13
14
|
const projectRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..", "..");
|
|
14
15
|
const migrationsDir = path.join(projectRoot, "server", "migrations");
|
|
15
|
-
|
|
16
|
+
const monorepoForgeDataRoot = path.resolve(projectRoot, "..", "..", "data", "forge");
|
|
17
|
+
export function resolveDefaultDataRoot(currentWorkingDir = process.cwd()) {
|
|
18
|
+
const configured = process.env.FORGE_DATA_ROOT?.trim();
|
|
19
|
+
if (configured) {
|
|
20
|
+
return path.resolve(configured);
|
|
21
|
+
}
|
|
22
|
+
// Inside the private monorepo, prefer the tracked shared Forge data root so
|
|
23
|
+
// the local app, Hermes, OpenClaw, and repo-managed data all point at the
|
|
24
|
+
// same state by default.
|
|
25
|
+
if (existsSync(path.join(monorepoForgeDataRoot, "data"))) {
|
|
26
|
+
return monorepoForgeDataRoot;
|
|
27
|
+
}
|
|
28
|
+
return path.resolve(currentWorkingDir);
|
|
29
|
+
}
|
|
30
|
+
let dataRoot = resolveDefaultDataRoot();
|
|
16
31
|
let seedDemoDataEnabled = false;
|
|
17
32
|
let db = null;
|
|
18
33
|
let transactionDepth = 0;
|
|
@@ -529,6 +529,28 @@ function getNoteBySlugRaw(spaceId, slug, exceptNoteId) {
|
|
|
529
529
|
.get(...(exceptNoteId ? [spaceId, slug, exceptNoteId] : [spaceId, slug]));
|
|
530
530
|
return row;
|
|
531
531
|
}
|
|
532
|
+
function getNoteByTitleRaw(spaceId, title, exceptNoteId) {
|
|
533
|
+
return getDatabase()
|
|
534
|
+
.prepare(`SELECT id, kind, title, slug, space_id, aliases_json, summary, content_markdown, content_plain, author, source,
|
|
535
|
+
tags_json, destroy_at, source_path, frontmatter_json, revision_hash, last_synced_at, parent_slug, index_order, show_in_index, created_at, updated_at
|
|
536
|
+
FROM notes
|
|
537
|
+
WHERE space_id = ?
|
|
538
|
+
AND lower(title) = lower(?)
|
|
539
|
+
${exceptNoteId ? "AND id != ?" : ""}
|
|
540
|
+
LIMIT 1`)
|
|
541
|
+
.get(...(exceptNoteId ? [spaceId, title, exceptNoteId] : [spaceId, title]));
|
|
542
|
+
}
|
|
543
|
+
function listNotesByTitleRaw(spaceId, title, exceptNoteId) {
|
|
544
|
+
return getDatabase()
|
|
545
|
+
.prepare(`SELECT id, kind, title, slug, space_id, aliases_json, summary, content_markdown, content_plain, author, source,
|
|
546
|
+
tags_json, destroy_at, source_path, frontmatter_json, revision_hash, last_synced_at, parent_slug, index_order, show_in_index, created_at, updated_at
|
|
547
|
+
FROM notes
|
|
548
|
+
WHERE space_id = ?
|
|
549
|
+
AND lower(title) = lower(?)
|
|
550
|
+
${exceptNoteId ? "AND id != ?" : ""}
|
|
551
|
+
ORDER BY updated_at DESC`)
|
|
552
|
+
.all(...(exceptNoteId ? [spaceId, title, exceptNoteId] : [spaceId, title]));
|
|
553
|
+
}
|
|
532
554
|
function getActiveNoteByIdRaw(noteId) {
|
|
533
555
|
const row = getNoteByIdRaw(noteId);
|
|
534
556
|
if (!row || isEntityDeleted("note", row.id)) {
|
|
@@ -543,6 +565,67 @@ function getActiveNoteBySlugRaw(spaceId, slug, exceptNoteId) {
|
|
|
543
565
|
}
|
|
544
566
|
return row;
|
|
545
567
|
}
|
|
568
|
+
function scoreReferenceMatch(reference, row) {
|
|
569
|
+
const referenceSlug = slugify(reference);
|
|
570
|
+
const titleSlug = slugify(row.title);
|
|
571
|
+
if (referenceSlug && row.slug === referenceSlug) {
|
|
572
|
+
return 0;
|
|
573
|
+
}
|
|
574
|
+
if (titleSlug && row.slug === titleSlug) {
|
|
575
|
+
return 1;
|
|
576
|
+
}
|
|
577
|
+
const parseSuffix = (base) => {
|
|
578
|
+
if (!base || !row.slug.startsWith(`${base}-`)) {
|
|
579
|
+
return null;
|
|
580
|
+
}
|
|
581
|
+
const suffix = Number(row.slug.slice(base.length + 1));
|
|
582
|
+
return Number.isFinite(suffix) ? suffix : null;
|
|
583
|
+
};
|
|
584
|
+
const referenceSuffix = parseSuffix(referenceSlug);
|
|
585
|
+
if (referenceSuffix !== null) {
|
|
586
|
+
return 100 + referenceSuffix;
|
|
587
|
+
}
|
|
588
|
+
const titleSuffix = parseSuffix(titleSlug);
|
|
589
|
+
if (titleSuffix !== null) {
|
|
590
|
+
return 200 + titleSuffix;
|
|
591
|
+
}
|
|
592
|
+
return 10_000;
|
|
593
|
+
}
|
|
594
|
+
function chooseBestActiveReferenceMatch(reference, rows) {
|
|
595
|
+
const activeRows = rows.filter((row) => !isEntityDeleted("note", row.id));
|
|
596
|
+
if (activeRows.length === 0) {
|
|
597
|
+
return null;
|
|
598
|
+
}
|
|
599
|
+
return [...activeRows].sort((left, right) => {
|
|
600
|
+
const leftScore = scoreReferenceMatch(reference, left);
|
|
601
|
+
const rightScore = scoreReferenceMatch(reference, right);
|
|
602
|
+
if (leftScore !== rightScore) {
|
|
603
|
+
return leftScore - rightScore;
|
|
604
|
+
}
|
|
605
|
+
if (left.updated_at !== right.updated_at) {
|
|
606
|
+
return right.updated_at.localeCompare(left.updated_at);
|
|
607
|
+
}
|
|
608
|
+
return left.id.localeCompare(right.id);
|
|
609
|
+
})[0];
|
|
610
|
+
}
|
|
611
|
+
function getActiveNoteByReferenceRaw(spaceId, reference, exceptNoteId) {
|
|
612
|
+
const normalized = reference.trim();
|
|
613
|
+
if (!normalized) {
|
|
614
|
+
return null;
|
|
615
|
+
}
|
|
616
|
+
const slugMatch = getActiveNoteBySlugRaw(spaceId, normalized, exceptNoteId);
|
|
617
|
+
if (slugMatch) {
|
|
618
|
+
return slugMatch;
|
|
619
|
+
}
|
|
620
|
+
const titleMatch = chooseBestActiveReferenceMatch(normalized, listNotesByTitleRaw(spaceId, normalized, exceptNoteId));
|
|
621
|
+
if (titleMatch) {
|
|
622
|
+
return titleMatch;
|
|
623
|
+
}
|
|
624
|
+
const lowered = normalized.toLowerCase();
|
|
625
|
+
const aliasMatch = chooseBestActiveReferenceMatch(normalized, getNoteRows("WHERE space_id = ?", [spaceId]).filter((row) => row.id !== exceptNoteId &&
|
|
626
|
+
parseJsonStringArray(row.aliases_json).some((alias) => alias.trim().toLowerCase() === lowered)));
|
|
627
|
+
return aliasMatch ?? null;
|
|
628
|
+
}
|
|
546
629
|
function buildContentPlain(markdown) {
|
|
547
630
|
return markdown
|
|
548
631
|
.replace(/^---[\s\S]*?---\s*/m, "")
|
|
@@ -1443,7 +1526,7 @@ function rebuildWikiLinkEdges(note) {
|
|
|
1443
1526
|
continue;
|
|
1444
1527
|
}
|
|
1445
1528
|
}
|
|
1446
|
-
const targetNote =
|
|
1529
|
+
const targetNote = getActiveNoteByReferenceRaw(note.spaceId, left.trim(), note.id);
|
|
1447
1530
|
if (targetNote) {
|
|
1448
1531
|
insert.run(note.id, "page", targetNote.id, null, null, label, left.trim(), isEmbed ? 1 : 0, now, now);
|
|
1449
1532
|
continue;
|
|
@@ -1556,7 +1639,7 @@ export function getWikiHomePageDetail(input = {}) {
|
|
|
1556
1639
|
export function getWikiPageDetailBySlug(input) {
|
|
1557
1640
|
const spaceId = resolveSpaceId(input.spaceId, null);
|
|
1558
1641
|
ensureWikiSpaceSeedPages(spaceId);
|
|
1559
|
-
const row =
|
|
1642
|
+
const row = getActiveNoteByReferenceRaw(spaceId, input.slug.trim());
|
|
1560
1643
|
if (!row) {
|
|
1561
1644
|
return null;
|
|
1562
1645
|
}
|
package/openclaw.plugin.json
CHANGED
package/package.json
CHANGED