@tangle-network/agent-knowledge 8.0.8 → 8.0.9

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.
@@ -1473,6 +1473,7 @@ const KnowledgePageSchema = z.object({
1473
1473
  sourceIds: z.array(z.string()),
1474
1474
  tags: z.array(z.string()),
1475
1475
  outLinks: z.array(z.string()),
1476
+ cites: z.array(z.string().min(1)).optional(),
1476
1477
  contradicts: z.array(z.string().min(1)).optional(),
1477
1478
  invalidation: KnowledgePageInvalidationSchema.optional()
1478
1479
  });
@@ -1708,6 +1709,7 @@ async function loadKnowledgePagesUnlocked(root, options) {
1708
1709
  const title = stringField(frontmatter.title) ?? firstHeading(body) ?? rel.split("/").pop().replace(/\.md$/, "");
1709
1710
  const sourceIds = arrayField(frontmatter.sources);
1710
1711
  const tags = arrayField(frontmatter.tags);
1712
+ const cites = idListField(frontmatter.cites);
1711
1713
  const contradicts = idListField(frontmatter.contradicts);
1712
1714
  const invalidation = KnowledgePageInvalidationSchema.safeParse(frontmatter.invalidation);
1713
1715
  const pageRelativePath = rel.startsWith(pagesPrefix) ? rel.slice(pagesPrefix.length) : rel;
@@ -1720,6 +1722,7 @@ async function loadKnowledgePagesUnlocked(root, options) {
1720
1722
  sourceIds,
1721
1723
  tags,
1722
1724
  outLinks: extractWikilinks(body).map(normalizeLinkTarget),
1725
+ ...cites.length > 0 ? { cites } : {},
1723
1726
  ...contradicts.length > 0 ? { contradicts } : {},
1724
1727
  ...invalidation.success ? { invalidation: invalidation.data } : {}
1725
1728
  });
@@ -1771,12 +1774,164 @@ function firstHeading(body) {
1771
1774
  return /^#\s+(.+)$/m.exec(body)?.[1]?.trim();
1772
1775
  }
1773
1776
  //#endregion
1777
+ //#region src/citation-resolution.ts
1778
+ /** A batch contains at least one citation that is missing or ambiguous. */
1779
+ var KnowledgeCitationResolutionError = class extends Error {
1780
+ resolutions;
1781
+ constructor(resolutions) {
1782
+ const unresolved = resolutions.filter((resolution) => resolution.status !== "resolved");
1783
+ const missing = unresolved.filter((resolution) => resolution.status === "missing").map((resolution) => formatKnowledgeCitationReference(resolution.reference));
1784
+ const ambiguous = unresolved.filter((resolution) => resolution.status === "ambiguous").map((resolution) => `${formatKnowledgeCitationReference(resolution.reference)} (${resolution.candidates.length} matches)`);
1785
+ const parts = [missing.length > 0 ? `missing: ${missing.join(", ")}` : "", ambiguous.length > 0 ? `ambiguous: ${ambiguous.join(", ")}` : ""].filter(Boolean);
1786
+ super(`knowledge citation resolution failed: ${parts.join("; ")}`);
1787
+ this.name = "KnowledgeCitationResolutionError";
1788
+ this.resolutions = Object.freeze([...unresolved]);
1789
+ }
1790
+ };
1791
+ /** A persisted page contains a self, missing, or ambiguous citation. */
1792
+ var KnowledgeCitationAuditError = class extends Error {
1793
+ report;
1794
+ constructor(report) {
1795
+ const counts = /* @__PURE__ */ new Map();
1796
+ for (const issue of report.issues) counts.set(issue.kind, (counts.get(issue.kind) ?? 0) + 1);
1797
+ const summary = [...counts.entries()].map(([kind, count]) => `${kind}=${count}`).join(", ");
1798
+ super(`knowledge citation audit failed: ${summary}`);
1799
+ this.name = "KnowledgeCitationAuditError";
1800
+ this.report = report;
1801
+ }
1802
+ };
1803
+ /**
1804
+ * Parse the persisted citation form.
1805
+ *
1806
+ * `page-id` is unqualified. `here::page-id`, `shared::page-id`, and
1807
+ * `inherited:<runId>::page-id` bind an intentional duplicate to one origin.
1808
+ */
1809
+ function parseKnowledgeCitationReference(value) {
1810
+ if (typeof value !== "string" || value.trim().length === 0) throw new TypeError("persisted knowledge citation must be a non-empty string");
1811
+ const normalized = value.trim();
1812
+ const separator = normalized.indexOf("::");
1813
+ if (separator < 0) return Object.freeze({ pageId: normalized });
1814
+ const possibleOrigin = normalized.slice(0, separator);
1815
+ const pageId = normalized.slice(separator + 2);
1816
+ if (!isPageOrigin(possibleOrigin)) return Object.freeze({ pageId: normalized });
1817
+ return normalizeReference({
1818
+ pageId,
1819
+ origin: possibleOrigin
1820
+ });
1821
+ }
1822
+ /** Serialize one reference into the canonical frontmatter representation. */
1823
+ function formatKnowledgeCitationReference(reference) {
1824
+ const normalized = normalizeReference(reference);
1825
+ return normalized.origin === void 0 ? normalized.pageId : `${normalized.origin}::${normalized.pageId}`;
1826
+ }
1827
+ /** Resolve one reference against an already materialized visibility chain. */
1828
+ function resolveKnowledgeCitation(visiblePages, reference) {
1829
+ const normalized = normalizeReference(reference);
1830
+ const candidates = visiblePages.filter((entry) => entry.page.id === normalized.pageId && (normalized.origin === void 0 || entry.origin === normalized.origin)).map((entry) => Object.freeze({
1831
+ pageId: entry.page.id,
1832
+ origin: entry.origin,
1833
+ page: entry.page
1834
+ }));
1835
+ const status = candidates.length === 0 ? "missing" : candidates.length === 1 ? "resolved" : "ambiguous";
1836
+ return Object.freeze({
1837
+ reference: normalized,
1838
+ status,
1839
+ candidates: Object.freeze(candidates),
1840
+ ...status === "resolved" ? { resolved: candidates[0] } : {}
1841
+ });
1842
+ }
1843
+ /** Resolve a batch without discarding missing or ambiguous rows. */
1844
+ function resolveKnowledgeCitations(visiblePages, references) {
1845
+ return Object.freeze(references.map((reference) => resolveKnowledgeCitation(visiblePages, reference)));
1846
+ }
1847
+ /**
1848
+ * Resolve a batch and fail closed unless every reference names exactly one
1849
+ * visible page. Returned candidates preserve the caller's reference order.
1850
+ */
1851
+ function assertKnowledgeCitationsResolved(visiblePages, references) {
1852
+ const resolutions = resolveKnowledgeCitations(visiblePages, references);
1853
+ if (resolutions.some((resolution) => resolution.status !== "resolved")) throw new KnowledgeCitationResolutionError(resolutions);
1854
+ return Object.freeze(resolutions.map((resolution) => resolution.resolved));
1855
+ }
1856
+ /** Audit persisted `cites` relations against one immutable visibility snapshot. */
1857
+ function auditKnowledgeCitations(visiblePages, options = {}) {
1858
+ const origins = options.sourceOrigins ? new Set(options.sourceOrigins.map((origin) => validatePageOrigin(origin))) : null;
1859
+ const sources = visiblePages.filter((entry) => origins === null || origins.has(entry.origin));
1860
+ const issues = [];
1861
+ let checkedCitations = 0;
1862
+ for (const source of sources) for (const persistedCitation of new Set(source.page.cites ?? [])) {
1863
+ checkedCitations += 1;
1864
+ const reference = parseKnowledgeCitationReference(persistedCitation);
1865
+ const resolution = resolveKnowledgeCitation(visiblePages, reference);
1866
+ const kind = resolution.candidates.some((candidate) => candidate.page === source.page || candidate.origin === source.origin && candidate.page.path === source.page.path) ? "self" : resolution.status === "missing" ? "missing" : resolution.status === "ambiguous" ? "ambiguous" : null;
1867
+ if (kind === null) continue;
1868
+ issues.push(Object.freeze({
1869
+ kind,
1870
+ sourcePageId: source.page.id,
1871
+ sourcePath: source.page.path,
1872
+ sourceOrigin: source.origin,
1873
+ persistedCitation,
1874
+ reference,
1875
+ candidates: resolution.candidates
1876
+ }));
1877
+ }
1878
+ return Object.freeze({
1879
+ ok: issues.length === 0,
1880
+ checkedPages: sources.length,
1881
+ checkedCitations,
1882
+ issues: Object.freeze(issues)
1883
+ });
1884
+ }
1885
+ /** Audit and fail closed when any persisted citation is unresolved. */
1886
+ function assertKnowledgeCitationAudit(report) {
1887
+ if (!report.ok) throw new KnowledgeCitationAuditError(report);
1888
+ }
1889
+ /** Resolve one citation using a run-scoped store's declared visibility chain. */
1890
+ async function resolveRunScopedCitation(stores, runId, reference) {
1891
+ return resolveKnowledgeCitation(await stores.loadChain(runId), reference);
1892
+ }
1893
+ /** Resolve citations using one chain read so every row sees the same snapshot. */
1894
+ async function resolveRunScopedCitations(stores, runId, references) {
1895
+ return resolveKnowledgeCitations(await stores.loadChain(runId), references);
1896
+ }
1897
+ /** Resolve a run-scoped batch and fail closed on any missing or ambiguous id. */
1898
+ async function assertRunScopedCitationsResolved(stores, runId, references) {
1899
+ return assertKnowledgeCitationsResolved(await stores.loadChain(runId), references);
1900
+ }
1901
+ /** Audit only pages authored in the current run against the full visible chain. */
1902
+ async function auditCurrentRunCitations(stores, runId) {
1903
+ return auditKnowledgeCitations(await stores.loadChain(runId), { sourceOrigins: ["here"] });
1904
+ }
1905
+ /** Audit current-run citations and fail closed on every unresolved relation. */
1906
+ async function assertCurrentRunCitationsResolved(stores, runId) {
1907
+ const report = await auditCurrentRunCitations(stores, runId);
1908
+ assertKnowledgeCitationAudit(report);
1909
+ return report;
1910
+ }
1911
+ function normalizeReference(reference) {
1912
+ if (!reference || typeof reference !== "object") throw new TypeError("knowledge citation reference must be an object");
1913
+ if (typeof reference.pageId !== "string" || reference.pageId.trim().length === 0) throw new TypeError("knowledge citation pageId must be a non-empty string");
1914
+ if (reference.origin !== void 0) validatePageOrigin(reference.origin);
1915
+ return Object.freeze({
1916
+ pageId: reference.pageId.trim(),
1917
+ ...reference.origin === void 0 ? {} : { origin: reference.origin }
1918
+ });
1919
+ }
1920
+ function validatePageOrigin(value) {
1921
+ if (!isPageOrigin(value)) throw new TypeError(`knowledge citation origin is invalid: ${String(value)}`);
1922
+ return value;
1923
+ }
1924
+ function isPageOrigin(value) {
1925
+ if (value === "here" || value === "shared") return true;
1926
+ return typeof value === "string" && value.startsWith("inherited:") && value.slice(10).trim().length > 0;
1927
+ }
1928
+ //#endregion
1774
1929
  //#region src/graph.ts
1775
1930
  function buildKnowledgeGraph(pages) {
1776
- const byId = /* @__PURE__ */ new Map();
1777
1931
  const bySlug = /* @__PURE__ */ new Map();
1932
+ const byId = /* @__PURE__ */ new Map();
1778
1933
  for (const page of pages) {
1779
- byId.set(page.id, page);
1934
+ byId.set(page.id, [...byId.get(page.id) ?? [], page]);
1780
1935
  bySlug.set(normalizeLinkTarget(page.id), page);
1781
1936
  bySlug.set(normalizeLinkTarget(page.title), page);
1782
1937
  bySlug.set(normalizeLinkTarget(page.path.split("/").pop().replace(/\.md$/, "")), page);
@@ -1788,20 +1943,17 @@ function buildKnowledgeGraph(pages) {
1788
1943
  outgoing.set(page.id, 0);
1789
1944
  incoming.set(page.id, 0);
1790
1945
  }
1791
- for (const page of pages) for (const raw of page.outLinks) {
1792
- const target = bySlug.get(normalizeLinkTarget(raw));
1793
- if (!target || target.id === page.id) continue;
1794
- const key = `${page.id}->${target.id}`;
1795
- const edge = edgesByKey.get(key);
1796
- if (edge) edge.weight += 1;
1797
- else edgesByKey.set(key, {
1798
- source: page.id,
1799
- target: target.id,
1800
- weight: 1,
1801
- reasons: ["wikilink"]
1802
- });
1803
- outgoing.set(page.id, (outgoing.get(page.id) ?? 0) + 1);
1804
- incoming.set(target.id, (incoming.get(target.id) ?? 0) + 1);
1946
+ for (const page of pages) {
1947
+ for (const raw of page.outLinks) {
1948
+ const target = bySlug.get(normalizeLinkTarget(raw));
1949
+ if (!target || target.id === page.id) continue;
1950
+ addDirectedEdge(page, target, "wikilink", edgesByKey, incoming, outgoing);
1951
+ }
1952
+ for (const persisted of page.cites ?? []) {
1953
+ const targets = byId.get(citedPageId(persisted)) ?? [];
1954
+ if (targets.length !== 1 || targets[0].id === page.id) continue;
1955
+ addDirectedEdge(page, targets[0], "citation", edgesByKey, incoming, outgoing);
1956
+ }
1805
1957
  }
1806
1958
  addSourceOverlapEdges(pages, edgesByKey);
1807
1959
  return {
@@ -1817,6 +1969,34 @@ function buildKnowledgeGraph(pages) {
1817
1969
  edges: [...edgesByKey.values()].sort((a, b) => b.weight - a.weight)
1818
1970
  };
1819
1971
  }
1972
+ /**
1973
+ * An origin-qualified citation (`here::x`, `inherited:<run>::x`, `shared::x`)
1974
+ * must keep its graph edge: qualification is the documented remedy for an
1975
+ * ambiguous id, so it cannot cost the citation signal. A value the parser
1976
+ * rejects stays a literal page id so index builds never fail on stored data.
1977
+ */
1978
+ function citedPageId(persisted) {
1979
+ try {
1980
+ return parseKnowledgeCitationReference(persisted).pageId;
1981
+ } catch {
1982
+ return persisted;
1983
+ }
1984
+ }
1985
+ function addDirectedEdge(source, target, reason, edges, incoming, outgoing) {
1986
+ const key = `${source.id}->${target.id}`;
1987
+ const edge = edges.get(key);
1988
+ if (edge) {
1989
+ edge.weight += 1;
1990
+ if (!edge.reasons.includes(reason)) edge.reasons.push(reason);
1991
+ } else edges.set(key, {
1992
+ source: source.id,
1993
+ target: target.id,
1994
+ weight: 1,
1995
+ reasons: [reason]
1996
+ });
1997
+ outgoing.set(source.id, (outgoing.get(source.id) ?? 0) + 1);
1998
+ incoming.set(target.id, (incoming.get(target.id) ?? 0) + 1);
1999
+ }
1820
2000
  function addSourceOverlapEdges(pages, edges) {
1821
2001
  for (let i = 0; i < pages.length; i++) for (let j = i + 1; j < pages.length; j++) {
1822
2002
  const a = pages[i];
@@ -1827,7 +2007,7 @@ function addSourceOverlapEdges(pages, edges) {
1827
2007
  const edge = edges.get(key);
1828
2008
  if (edge) {
1829
2009
  edge.weight += overlap.length * .5;
1830
- edge.reasons.push("shared-source");
2010
+ if (!edge.reasons.includes("shared-source")) edge.reasons.push("shared-source");
1831
2011
  } else edges.set(key, {
1832
2012
  source: a.id,
1833
2013
  target: b.id,
@@ -2969,6 +3149,6 @@ function explainKnowledgeTarget(index, target) {
2969
3149
  };
2970
3150
  }
2971
3151
  //#endregion
2972
- export { ResearchSourceVersionSchema as $, MemoryKbStore as A, prepareKnowledgeFileTransaction as At, extractWikilinks as B, withSafeDescendant as Bt, writeSourceRegistry as C, recoverPendingKnowledgeMutation as Ct, KB_EVENTS_PATH as D, assertKnowledgeMutationPath as Dt, KB_CLAIM_LEDGER_DIR as E, applyKnowledgeFileTransaction as Et, isScaffoldPath as F, readRegularFileNoFollow as Ft, KnowledgeGraphEdgeSchema as G, writeJsonDurableWithinRoot as Gt, DeepQuestionSchema as H, writeFileDurable as Ht, layoutFor as I, readRegularFileWithinRoot as It, KnowledgePageInvalidationSchema as J, KnowledgeGraphNodeSchema as K, mediaTypeFor$1 as Kt, loadKnowledgePages as L, removeDurable as Lt, buildKnowledgeGraph as M, isKernelAnchoredPath as Mt, SCAFFOLD_PAGE_BASENAMES as N, isMissingFile as Nt, KB_INDEX_PATH as O, finishKnowledgeFileTransaction as Ot, initKnowledgeBase as P, listRegularFilesWithinRoot as Pt, ResearchClaimRecordSchema as Q, writeJson as R, renameDurable as Rt, sourceRegistryPath as S, inspectPendingKnowledgeMutation as St, FileSystemKbStore as T, withKnowledgeRead as Tt, KnowledgeBaseCandidateSchema as U, writeFileDurableWithinRoot as Ut, normalizeLinkTarget as V, withSafeDirectory as Vt, KnowledgeEventSchema as W, writeJsonDurable as Wt, ResearchClaimEvidenceSchema as X, KnowledgePageSchema as Y, ResearchClaimLedgerSchema as Z, writeKnowledgeIndex as _, normalizeClaimText as _t, applyKnowledgeWriteBlocksFile as a, assertResearchClaimEvidenceIntegrity as at, loadSourceRegistry as b, parseFrontmatter as bt, validateKnowledgeIndex as c, claimEvidenceId as ct, UncheckableClaimError as d, deepQuestionId as dt, SourceAnchorSchema as et, assertGradeableEvidence as f, emptyClaimLedger as ft, buildKnowledgeIndex as g, mergeTrackedClaims as gt, verifyGradeableEvidence as h, mergeClaimLedgers as ht, applyKnowledgeWriteBlocks as i, assertDeepQuestionIntegrity as it, assertClaimLedgerId as j, rollbackKnowledgeFileTransaction as jt, KB_STORE_DIR as k, knowledgeFileTransactionPlanHash as kt, lintKnowledgeIndex as l, claimId as lt, verdictFor as m, materializeRegisteredClaimEvidence as mt, inspectKnowledgeIndex as n, KNOWLEDGE_EVENT_TYPES as nt, isSafeKnowledgePath as o, assertResearchClaimLedgerIntegrity as ot, gradeFor as p, linkClaimContradictions as pt, KnowledgeIndexSchema as q, textSourceAdapter as qt, stringMetadata as r, ClaimLedgerGoalConflictError as rt, parseKnowledgeWriteBlocks as s, assertTrackedClaimIntegrity as st, explainKnowledgeTarget as t, SourceRecordSchema as tt, CHECKABLE_RUNG_THRESHOLD as u, claimSourceHost as ut, addSourcePath as v, researchSourceVersionKey as vt, ClaimLedgerMigrationRequiredError as w, withKnowledgeMutation as wt, snapshotSourceTextInput as x, acquireDurableFileLock as xt, addSourceText as y, formatFrontmatter as yt, WIKILINK_REGEX as z, syncDirectory as zt };
3152
+ export { WIKILINK_REGEX as $, syncDirectory as $t, MemoryKbStore as A, mergeTrackedClaims as At, auditKnowledgeCitations as B, applyKnowledgeFileTransaction as Bt, writeSourceRegistry as C, claimId as Ct, KB_EVENTS_PATH as D, linkClaimContradictions as Dt, KB_CLAIM_LEDGER_DIR as E, emptyClaimLedger as Et, assertCurrentRunCitationsResolved as F, acquireDurableFileLock as Ft, resolveRunScopedCitation as G, rollbackKnowledgeFileTransaction as Gt, parseKnowledgeCitationReference as H, finishKnowledgeFileTransaction as Ht, assertKnowledgeCitationAudit as I, inspectPendingKnowledgeMutation as It, initKnowledgeBase as J, listRegularFilesWithinRoot as Jt, resolveRunScopedCitations as K, isKernelAnchoredPath as Kt, assertKnowledgeCitationsResolved as L, recoverPendingKnowledgeMutation as Lt, buildKnowledgeGraph as M, researchSourceVersionKey as Mt, KnowledgeCitationAuditError as N, formatFrontmatter as Nt, KB_INDEX_PATH as O, materializeRegisteredClaimEvidence as Ot, KnowledgeCitationResolutionError as P, parseFrontmatter as Pt, writeJson as Q, renameDurable as Qt, assertRunScopedCitationsResolved as R, withKnowledgeMutation as Rt, sourceRegistryPath as S, claimEvidenceId as St, FileSystemKbStore as T, deepQuestionId as Tt, resolveKnowledgeCitation as U, knowledgeFileTransactionPlanHash as Ut, formatKnowledgeCitationReference as V, assertKnowledgeMutationPath as Vt, resolveKnowledgeCitations as W, prepareKnowledgeFileTransaction as Wt, layoutFor as X, readRegularFileWithinRoot as Xt, isScaffoldPath as Y, readRegularFileNoFollow as Yt, loadKnowledgePages as Z, removeDurable as Zt, writeKnowledgeIndex as _, ClaimLedgerGoalConflictError as _t, applyKnowledgeWriteBlocksFile as a, writeJsonDurableWithinRoot as an, KnowledgeGraphEdgeSchema as at, loadSourceRegistry as b, assertResearchClaimLedgerIntegrity as bt, validateKnowledgeIndex as c, KnowledgePageInvalidationSchema as ct, UncheckableClaimError as d, ResearchClaimLedgerSchema as dt, withSafeDescendant as en, extractWikilinks as et, assertGradeableEvidence as f, ResearchClaimRecordSchema as ft, buildKnowledgeIndex as g, KNOWLEDGE_EVENT_TYPES as gt, verifyGradeableEvidence as h, SourceRecordSchema as ht, applyKnowledgeWriteBlocks as i, writeJsonDurable as in, KnowledgeEventSchema as it, assertClaimLedgerId as j, normalizeClaimText as jt, KB_STORE_DIR as k, mergeClaimLedgers as kt, lintKnowledgeIndex as l, KnowledgePageSchema as lt, verdictFor as m, SourceAnchorSchema as mt, inspectKnowledgeIndex as n, writeFileDurable as nn, DeepQuestionSchema as nt, isSafeKnowledgePath as o, mediaTypeFor$1 as on, KnowledgeGraphNodeSchema as ot, gradeFor as p, ResearchSourceVersionSchema as pt, SCAFFOLD_PAGE_BASENAMES as q, isMissingFile as qt, stringMetadata as r, writeFileDurableWithinRoot as rn, KnowledgeBaseCandidateSchema as rt, parseKnowledgeWriteBlocks as s, textSourceAdapter as sn, KnowledgeIndexSchema as st, explainKnowledgeTarget as t, withSafeDirectory as tn, normalizeLinkTarget as tt, CHECKABLE_RUNG_THRESHOLD as u, ResearchClaimEvidenceSchema as ut, addSourcePath as v, assertDeepQuestionIntegrity as vt, ClaimLedgerMigrationRequiredError as w, claimSourceHost as wt, snapshotSourceTextInput as x, assertTrackedClaimIntegrity as xt, addSourceText as y, assertResearchClaimEvidenceIntegrity as yt, auditCurrentRunCitations as z, withKnowledgeRead as zt };
2973
3153
 
2974
- //# sourceMappingURL=inspect-B7AJ7CZS.js.map
3154
+ //# sourceMappingURL=inspect-0tmv3xV8.js.map