forge-openclaw-plugin 0.2.22 → 0.2.24

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.
@@ -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 = getNoteBySlugRaw(note.spaceId, left.trim(), note.id);
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 = getActiveNoteBySlugRaw(spaceId, input.slug.trim());
1642
+ const row = getActiveNoteByReferenceRaw(spaceId, input.slug.trim());
1560
1643
  if (!row) {
1561
1644
  return null;
1562
1645
  }
@@ -2,7 +2,7 @@
2
2
  "id": "forge-openclaw-plugin",
3
3
  "name": "Forge",
4
4
  "description": "Curated OpenClaw adapter for the Forge collaboration API, UI entrypoint, and localhost auto-start runtime.",
5
- "version": "0.2.22",
5
+ "version": "0.2.24",
6
6
  "skills": [
7
7
  "./skills"
8
8
  ],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "forge-openclaw-plugin",
3
- "version": "0.2.22",
3
+ "version": "0.2.24",
4
4
  "description": "Curated OpenClaw adapter for the Forge collaboration API, UI entrypoint, and localhost auto-start runtime.",
5
5
  "type": "module",
6
6
  "license": "MIT",