@tangle-network/agent-knowledge 1.1.0 → 1.2.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/README.md CHANGED
@@ -58,6 +58,13 @@ from `@tangle-network/agent-knowledge`.
58
58
  - Agent write proposals can be safely applied with `apply-write-blocks`.
59
59
  - `KbStore` keeps storage consumer-owned; use `MemoryKbStore`, `FileSystemKbStore`, or implement D1 in the app.
60
60
  - Discovery uses worker/dispatcher contracts, with a local dispatcher for dev and tests.
61
+ - `runKnowledgeResearchLoop()` provides thin loop mechanics for researcher
62
+ agents: ingest sources, apply safe write blocks, rebuild the index,
63
+ lint/validate, score readiness, and return a transcript. The agent still
64
+ decides what to research, what to write, and when the wiki is good enough.
65
+ - `createKnowledgeControlLoopAdapter()` maps those mechanics into
66
+ `agent-eval`'s `runAgentControlLoop()` so products can plug in their own
67
+ proposer, reviewer, and driver policies.
61
68
  - Zod schemas define the stable wire shape.
62
69
  - Graph/search/lint are deterministic and fast.
63
70
  - `searchKnowledge` returns hits with three score fields. `score` and
@@ -111,3 +118,83 @@ console.log(readiness.report.recommendedAction)
111
118
  Pass `readiness.report` to `blockingKnowledgeEval()` from
112
119
  `@tangle-network/agent-eval`; use `readiness.questions` and
113
120
  `readiness.acquisitionPlans` to drive UI or connector workflows.
121
+
122
+ ## Research Loop
123
+
124
+ Use `runKnowledgeResearchLoop()` when an agent is acting as a researcher or
125
+ librarian. Keep the loop small: the package handles deterministic mechanics;
126
+ your agent handles judgment.
127
+
128
+ ```ts
129
+ import {
130
+ defineReadinessSpec,
131
+ runKnowledgeResearchLoop,
132
+ } from '@tangle-network/agent-knowledge'
133
+
134
+ await runKnowledgeResearchLoop({
135
+ root: './kb',
136
+ goal: 'Build a grounded onboarding wiki for billing support',
137
+ readinessSpecs: [defineReadinessSpec({
138
+ id: 'refund-policy',
139
+ description: 'Refund policy grounding',
140
+ query: 'refund policy customer request',
141
+ requiredFor: ['support-agent'],
142
+ })],
143
+ async step({ iteration, index, readiness }) {
144
+ // Call your researcher/LLM/browser/connector workflow here.
145
+ if (iteration > 1 && readiness?.report.blockingMissingRequirements.length === 0) {
146
+ return { done: true, notes: 'ready for eval' }
147
+ }
148
+ return {
149
+ sourceTexts: [{
150
+ uri: 'research://refund-policy',
151
+ title: 'Refund Policy Source',
152
+ text: 'Source text gathered by the researcher.',
153
+ }],
154
+ proposalText: [
155
+ '---FILE: knowledge/support/refund-policy.md---',
156
+ '---',
157
+ 'id: refund-policy',
158
+ 'title: Refund Policy',
159
+ '---',
160
+ '# Refund Policy',
161
+ 'Grounded summary written by the researcher.',
162
+ '---END FILE---',
163
+ ].join('\n'),
164
+ }
165
+ },
166
+ })
167
+ ```
168
+
169
+ This is intentionally not a crawler, prompt framework, or agent. It is the
170
+ repeatable shell around one.
171
+
172
+ For full `agent-eval` control-loop integration, use
173
+ `createKnowledgeControlLoopAdapter()` and provide `decide` yourself:
174
+
175
+ ```ts
176
+ import { runAgentControlLoop } from '@tangle-network/agent-eval'
177
+ import { createKnowledgeControlLoopAdapter } from '@tangle-network/agent-knowledge'
178
+
179
+ const adapter = createKnowledgeControlLoopAdapter({
180
+ root: './kb',
181
+ goal: 'Maintain the billing support wiki',
182
+ readinessSpecs,
183
+ })
184
+
185
+ await runAgentControlLoop({
186
+ ...adapter,
187
+ async decide({ state, evals }) {
188
+ if (state.previousSteps.length > 0 && evals.every((e) => e.passed)) {
189
+ return { type: 'stop', pass: true, reason: 'knowledge ready' }
190
+ }
191
+ const proposal = await proposerAgent(state)
192
+ const review = await reviewerAgent({ ...state, proposal })
193
+ return {
194
+ type: 'continue',
195
+ reason: review.summary,
196
+ action: driverPolicy({ proposal, review }),
197
+ }
198
+ },
199
+ })
200
+ ```
@@ -548,6 +548,44 @@ async function addSourcePath(root, sourcePath, options = {}) {
548
548
  await writeSourceRegistry(root, next);
549
549
  return [record];
550
550
  }
551
+ async function addSourceText(root, input, options = {}) {
552
+ const text = input.text;
553
+ const contentHash = sha256(text);
554
+ const fileName = basename(input.uri) || `${slugify(input.title ?? input.uri)}.txt`;
555
+ const adapterInput = { uri: input.uri, text, metadata: input.metadata };
556
+ const adapter = (options.adapters ?? [textSourceAdapter]).find((candidate) => candidate.canLoad(adapterInput));
557
+ const loaded = adapter ? await adapter.load(adapterInput) : {};
558
+ const id = stableId("src", `${contentHash}:${input.uri}`);
559
+ const targetRel = join3("raw", "sources", `${slugify(fileName.replace(/\.[^.]+$/, ""))}-${contentHash.slice(0, 8)}.txt`).replace(/\\/g, "/");
560
+ const targetAbs = join3(root, targetRel);
561
+ await mkdir3(dirname3(targetAbs), { recursive: true });
562
+ await writeFile3(targetAbs, text.endsWith("\n") ? text : `${text}
563
+ `, "utf8");
564
+ const existing = await loadSourceRegistry(root);
565
+ const record = {
566
+ id,
567
+ uri: targetRel,
568
+ title: input.title ?? loaded.title ?? fileName,
569
+ mediaType: input.mediaType ?? loaded.mediaType ?? "text/plain",
570
+ contentHash,
571
+ text: loaded.text ?? text.slice(0, 2e5),
572
+ anchors: (loaded.anchors ?? []).map((anchor) => ({ ...anchor, sourceId: id })),
573
+ validUntil: input.validUntil,
574
+ lastVerifiedAt: input.lastVerifiedAt,
575
+ createdAt: (options.now ?? (() => /* @__PURE__ */ new Date()))().toISOString(),
576
+ metadata: {
577
+ ...loaded.metadata ?? {},
578
+ ...input.metadata ?? {},
579
+ originalUri: input.uri,
580
+ sizeBytes: Buffer.byteLength(text, "utf8")
581
+ }
582
+ };
583
+ await writeSourceRegistry(root, {
584
+ generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
585
+ sources: [record, ...existing.sources.filter((source) => source.id !== id)]
586
+ });
587
+ return record;
588
+ }
551
589
  function sourceRegistryPath(root) {
552
590
  return join3(layoutFor(root).cacheDir, "sources.json");
553
591
  }
@@ -775,19 +813,34 @@ function extractSourceRefs(text) {
775
813
  }
776
814
 
777
815
  // src/inspect.ts
778
- function inspectKnowledgeIndex(index) {
816
+ function inspectKnowledgeIndex(index, options = {}) {
817
+ const now = options.now ?? /* @__PURE__ */ new Date();
779
818
  const findings = lintKnowledgeIndex(index);
780
819
  const degree = new Map(index.graph.nodes.map((node) => [node.id, node.inDegree + node.outDegree]));
820
+ const sourceFreshness = index.sources.map((source) => inspectSourceFreshness(source, now));
781
821
  return {
782
822
  pageCount: index.pages.length,
783
823
  sourceCount: index.sources.length,
824
+ expiredSourceCount: sourceFreshness.filter((source) => source.status === "expired").length,
825
+ staleSourceCount: sourceFreshness.filter((source) => source.status !== "fresh").length,
784
826
  edgeCount: index.graph.edges.length,
785
827
  findingCount: findings.length,
786
828
  blockingFindingCount: findings.filter((finding) => finding.severity === "error").length,
787
829
  topPages: [...index.pages].sort((a, b) => (degree.get(b.id) ?? 0) - (degree.get(a.id) ?? 0)).slice(0, 10).map((page) => ({ path: page.path, title: page.title, degree: degree.get(page.id) ?? 0, sources: page.sourceIds.length })),
830
+ sourceFreshness,
788
831
  findings
789
832
  };
790
833
  }
834
+ function inspectSourceFreshness(source, now) {
835
+ const validUntil = source.validUntil ?? stringMetadata(source.metadata, "validUntil") ?? stringMetadata(source.metadata, "expiresAt");
836
+ const lastVerifiedAt = source.lastVerifiedAt ?? stringMetadata(source.metadata, "lastVerifiedAt");
837
+ const status = validUntil && Number.isFinite(Date.parse(validUntil)) ? Date.parse(validUntil) <= now.getTime() ? "expired" : "fresh" : "unknown";
838
+ return { id: source.id, title: source.title, uri: source.uri, status, validUntil, lastVerifiedAt };
839
+ }
840
+ function stringMetadata(metadata, key) {
841
+ const value = metadata?.[key];
842
+ return typeof value === "string" ? value : void 0;
843
+ }
791
844
  function explainKnowledgeTarget(index, target) {
792
845
  const page = index.pages.find((candidate) => candidate.path === target || candidate.id === target || candidate.title.toLowerCase() === target.toLowerCase());
793
846
  const inbound = page ? index.graph.edges.filter((edge) => edge.target === page.id).map((edge) => index.pages.find((candidate) => candidate.id === edge.source)?.path ?? edge.source) : [];
@@ -865,6 +918,7 @@ export {
865
918
  loadSourceRegistry,
866
919
  writeSourceRegistry,
867
920
  addSourcePath,
921
+ addSourceText,
868
922
  sourceRegistryPath,
869
923
  searchKnowledge,
870
924
  tokenizeQuery,
@@ -876,4 +930,4 @@ export {
876
930
  explainKnowledgeTarget,
877
931
  validateKnowledgeIndex
878
932
  };
879
- //# sourceMappingURL=chunk-BEFAI2HO.js.map
933
+ //# sourceMappingURL=chunk-JLCQ6O7W.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/ids.ts","../src/frontmatter.ts","../src/wikilinks.ts","../src/write-protocol.ts","../src/adapters.ts","../src/proposals.ts","../src/schemas.ts","../src/graph.ts","../src/store.ts","../src/sources.ts","../src/search.ts","../src/indexer.ts","../src/lint.ts","../src/inspect.ts","../src/validate.ts"],"sourcesContent":["import { createHash } from 'node:crypto'\n\nexport function sha256(text: string): string {\n return createHash('sha256').update(text).digest('hex')\n}\n\nexport function slugify(input: string): string {\n const out = input\n .trim()\n .toLowerCase()\n .normalize('NFKD')\n .replace(/[\\u0300-\\u036f]/g, '')\n .replace(/[^a-z0-9\\u4e00-\\u9fff]+/g, '-')\n .replace(/^-+|-+$/g, '')\n return out || 'untitled'\n}\n\nexport function stableId(prefix: string, content: string): string {\n return `${prefix}_${sha256(content).slice(0, 16)}`\n}\n","export interface ParsedFrontmatter {\n frontmatter: Record<string, unknown>\n body: string\n}\n\nexport function parseFrontmatter(content: string): ParsedFrontmatter {\n const normalized = content.replace(/\\r\\n/g, '\\n')\n if (!normalized.startsWith('---\\n')) return { frontmatter: {}, body: normalized }\n const end = normalized.indexOf('\\n---', 4)\n if (end < 0) return { frontmatter: {}, body: normalized }\n const raw = normalized.slice(4, end)\n const after = normalized.slice(end).replace(/^\\n---\\s*\\n?/, '')\n return { frontmatter: parseSimpleYaml(raw), body: after }\n}\n\nexport function formatFrontmatter(frontmatter: Record<string, unknown>, body: string): string {\n const lines = Object.entries(frontmatter)\n .filter(([, value]) => value !== undefined)\n .flatMap(([key, value]) => formatYamlField(key, value))\n if (lines.length === 0) return body\n return `---\\n${lines.join('\\n')}\\n---\\n${body.replace(/^\\n+/, '')}`\n}\n\nfunction parseSimpleYaml(raw: string): Record<string, unknown> {\n const out: Record<string, unknown> = {}\n const lines = raw.split('\\n')\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i]!\n const scalar = /^([A-Za-z0-9_-]+):\\s*(.*)$/.exec(line)\n if (!scalar) continue\n const key = scalar[1]!\n const rest = scalar[2]!.trim()\n if (rest === '') {\n const items: string[] = []\n while (i + 1 < lines.length) {\n const item = /^\\s*-\\s*(.+?)\\s*$/.exec(lines[i + 1]!)\n if (!item) break\n items.push(unquote(item[1]!))\n i++\n }\n out[key] = items\n continue\n }\n if (rest.startsWith('[') && rest.endsWith(']')) {\n out[key] = rest.slice(1, -1).split(',').map((part) => unquote(part.trim())).filter(Boolean)\n } else if (rest === 'true' || rest === 'false') {\n out[key] = rest === 'true'\n } else if (/^-?\\d+(?:\\.\\d+)?$/.test(rest)) {\n out[key] = Number(rest)\n } else {\n out[key] = unquote(rest)\n }\n }\n return out\n}\n\nfunction formatYamlField(key: string, value: unknown): string[] {\n if (Array.isArray(value)) {\n return [key + ':', ...value.map((item) => ` - ${String(item)}`)]\n }\n if (typeof value === 'string') return [`${key}: ${value}`]\n if (typeof value === 'number' || typeof value === 'boolean') return [`${key}: ${String(value)}`]\n return [`${key}: ${JSON.stringify(value)}`]\n}\n\nfunction unquote(value: string): string {\n return value.replace(/^['\"]|['\"]$/g, '')\n}\n","export const WIKILINK_REGEX = /\\[\\[([^\\]|]+?)(?:\\|[^\\]]+?)?\\]\\]/g\n\nexport function extractWikilinks(content: string): string[] {\n const links: string[] = []\n const regex = new RegExp(WIKILINK_REGEX.source, 'g')\n let match: RegExpExecArray | null\n while ((match = regex.exec(content)) !== null) {\n links.push(match[1]!.trim())\n }\n return [...new Set(links)]\n}\n\nexport function normalizeLinkTarget(target: string): string {\n return target.trim().replace(/\\.md$/i, '').toLowerCase().replace(/\\s+/g, '-')\n}\n","import type { KnowledgeWriteParseResult } from './types'\n\nconst OPENER_LINE = /^---\\s*FILE:\\s*(.+?)\\s*---\\s*$/i\nconst CLOSER_LINE = /^---\\s*END\\s+FILE\\s*---\\s*$/i\nconst FENCE_LINE = /^\\s{0,3}(```+|~~~+)/\n\nexport function isSafeKnowledgePath(path: string, allowedPrefixes = ['knowledge/']): boolean {\n if (typeof path !== 'string' || path.trim() === '') return false\n if (/[\\x00-\\x1f]/.test(path)) return false\n if (path.startsWith('/') || path.startsWith('\\\\')) return false\n if (/^[a-zA-Z]:/.test(path)) return false\n const normalized = path.replace(/\\\\/g, '/')\n if (normalized.split('/').some((part) => part === '..')) return false\n return allowedPrefixes.some((prefix) => normalized.startsWith(prefix))\n}\n\nexport function parseKnowledgeWriteBlocks(text: string, allowedPrefixes = ['knowledge/']): KnowledgeWriteParseResult {\n const lines = text.replace(/\\r\\n/g, '\\n').split('\\n')\n const blocks: KnowledgeWriteParseResult['blocks'] = []\n const warnings: string[] = []\n let i = 0\n\n while (i < lines.length) {\n const opener = OPENER_LINE.exec(lines[i]!)\n if (!opener) {\n i++\n continue\n }\n const path = opener[1]!.trim()\n i++\n const contentLines: string[] = []\n let fenceMarker: string | null = null\n let fenceLen = 0\n let closed = false\n\n while (i < lines.length) {\n const line = lines[i]!\n const fence = FENCE_LINE.exec(line)\n if (fence) {\n const run = fence[1]!\n const char = run[0]!\n if (fenceMarker === null) {\n fenceMarker = char\n fenceLen = run.length\n } else if (char === fenceMarker && run.length >= fenceLen) {\n fenceMarker = null\n fenceLen = 0\n }\n contentLines.push(line)\n i++\n continue\n }\n if (fenceMarker === null && CLOSER_LINE.test(line)) {\n closed = true\n i++\n break\n }\n contentLines.push(line)\n i++\n }\n\n if (!closed) {\n warnings.push(`FILE block \"${path || '(empty)'}\" was not closed before end of stream.`)\n continue\n }\n if (!isSafeKnowledgePath(path, allowedPrefixes)) {\n warnings.push(`FILE block with unsafe path \"${path}\" rejected.`)\n continue\n }\n blocks.push({ path, content: contentLines.join('\\n') })\n }\n\n return { blocks, warnings }\n}\n","import type { SourceRecord } from './types'\n\nexport interface SourceAdapterInput {\n uri: string\n bytes?: Uint8Array\n text?: string\n metadata?: Record<string, unknown>\n}\n\nexport interface SourceAdapterOutput {\n title?: string\n mediaType?: string\n text?: string\n anchors?: SourceRecord['anchors']\n metadata?: Record<string, unknown>\n}\n\nexport interface SourceAdapter {\n id: string\n canLoad(input: SourceAdapterInput): boolean\n load(input: SourceAdapterInput): Promise<SourceAdapterOutput> | SourceAdapterOutput\n}\n\nexport const textSourceAdapter: SourceAdapter = {\n id: 'text',\n canLoad: (input) => Boolean(input.text) || /\\.(md|txt|json|csv)$/i.test(input.uri),\n load: (input) => ({\n title: input.uri.split('/').pop(),\n mediaType: mediaTypeFor(input.uri),\n text: decodeText(input),\n anchors: anchorsForText(input.uri, decodeText(input)),\n metadata: input.metadata,\n }),\n}\n\nexport function mediaTypeFor(uri: string): string {\n const lower = uri.toLowerCase()\n if (lower.endsWith('.md')) return 'text/markdown'\n if (lower.endsWith('.txt')) return 'text/plain'\n if (lower.endsWith('.json')) return 'application/json'\n if (lower.endsWith('.csv')) return 'text/csv'\n if (lower.endsWith('.pdf')) return 'application/pdf'\n return 'application/octet-stream'\n}\n\nfunction decodeText(input: SourceAdapterInput): string | undefined {\n return input.text ?? (input.bytes ? new TextDecoder().decode(input.bytes).slice(0, 200_000) : undefined)\n}\n\nfunction anchorsForText(uri: string, text: string | undefined): SourceAdapterOutput['anchors'] {\n if (!text) return []\n const lines = text.split('\\n')\n const anchors: NonNullable<SourceAdapterOutput['anchors']> = [{ id: 'all', sourceId: '', label: 'Full source', lineStart: 1, lineEnd: lines.length }]\n for (let i = 0; i < lines.length; i += 50) {\n anchors.push({\n id: `l${i + 1}`,\n sourceId: '',\n label: `${uri}:${i + 1}`,\n lineStart: i + 1,\n lineEnd: Math.min(lines.length, i + 50),\n })\n }\n return anchors\n}\n","import { mkdir, readFile, writeFile } from 'node:fs/promises'\nimport { dirname, join } from 'node:path'\nimport { parseKnowledgeWriteBlocks } from './write-protocol'\n\nexport interface ApplyWriteBlocksResult {\n written: string[]\n warnings: string[]\n}\n\nexport async function applyKnowledgeWriteBlocks(\n root: string,\n proposalText: string,\n): Promise<ApplyWriteBlocksResult> {\n const parsed = parseKnowledgeWriteBlocks(proposalText)\n const written: string[] = []\n for (const block of parsed.blocks) {\n const path = join(root, block.path)\n await mkdir(dirname(path), { recursive: true })\n await writeFile(path, block.content.endsWith('\\n') ? block.content : `${block.content}\\n`, 'utf8')\n written.push(block.path)\n }\n return { written, warnings: parsed.warnings }\n}\n\nexport async function applyKnowledgeWriteBlocksFile(root: string, proposalPath: string): Promise<ApplyWriteBlocksResult> {\n return applyKnowledgeWriteBlocks(root, await readFile(proposalPath, 'utf8'))\n}\n","import { z } from 'zod'\n\nexport const SourceAnchorSchema = z.object({\n id: z.string().min(1),\n sourceId: z.string().min(1),\n label: z.string().optional(),\n page: z.number().int().positive().optional(),\n lineStart: z.number().int().positive().optional(),\n lineEnd: z.number().int().positive().optional(),\n charStart: z.number().int().nonnegative().optional(),\n charEnd: z.number().int().nonnegative().optional(),\n timestampMs: z.number().nonnegative().optional(),\n metadata: z.record(z.string(), z.unknown()).optional(),\n})\n\nexport const SourceRecordSchema = z.object({\n id: z.string().min(1),\n uri: z.string().min(1),\n title: z.string().optional(),\n mediaType: z.string().optional(),\n contentHash: z.string().min(16),\n text: z.string().optional(),\n anchors: z.array(SourceAnchorSchema).optional(),\n metadata: z.record(z.string(), z.unknown()).optional(),\n createdAt: z.string().min(1),\n})\n\nexport const KnowledgePageSchema = z.object({\n id: z.string().min(1),\n path: z.string().min(1),\n title: z.string().min(1),\n text: z.string(),\n frontmatter: z.record(z.string(), z.unknown()),\n sourceIds: z.array(z.string()),\n tags: z.array(z.string()),\n outLinks: z.array(z.string()),\n})\n\nexport const KnowledgeGraphNodeSchema = z.object({\n id: z.string(),\n title: z.string(),\n path: z.string(),\n tags: z.array(z.string()),\n sourceIds: z.array(z.string()),\n outDegree: z.number().int().nonnegative(),\n inDegree: z.number().int().nonnegative(),\n})\n\nexport const KnowledgeGraphEdgeSchema = z.object({\n source: z.string(),\n target: z.string(),\n weight: z.number(),\n reasons: z.array(z.string()),\n})\n\nexport const KnowledgeIndexSchema = z.object({\n root: z.string(),\n generatedAt: z.string(),\n sources: z.array(SourceRecordSchema),\n pages: z.array(KnowledgePageSchema),\n graph: z.object({\n nodes: z.array(KnowledgeGraphNodeSchema),\n edges: z.array(KnowledgeGraphEdgeSchema),\n }),\n})\n\nexport const KnowledgeEventSchema = z.object({\n id: z.string().min(1),\n type: z.enum(['source.added', 'proposal.applied', 'index.built', 'lint.run', 'optimization.run', 'release.promoted', 'release.rejected']),\n createdAt: z.string().min(1),\n actor: z.string().optional(),\n target: z.string().optional(),\n metadata: z.record(z.string(), z.unknown()).optional(),\n})\n\nexport const KnowledgeBaseCandidateSchema = z.object({\n id: z.string().min(1),\n units: z.array(z.object({\n id: z.string().min(1),\n title: z.string().min(1),\n text: z.string(),\n claims: z.array(z.object({\n id: z.string().min(1),\n text: z.string().min(1),\n refs: z.array(z.object({\n sourceId: z.string().min(1),\n anchorId: z.string().optional(),\n quote: z.string().optional(),\n })),\n confidence: z.number().min(0).max(1).optional(),\n status: z.enum(['draft', 'active', 'superseded', 'rejected']).optional(),\n metadata: z.record(z.string(), z.unknown()).optional(),\n })).optional(),\n relations: z.array(z.object({\n sourceId: z.string(),\n targetId: z.string(),\n predicate: z.string(),\n weight: z.number().optional(),\n metadata: z.record(z.string(), z.unknown()).optional(),\n })).optional(),\n sourceIds: z.array(z.string()).optional(),\n tags: z.array(z.string()).optional(),\n metadata: z.record(z.string(), z.unknown()).optional(),\n updatedAt: z.string().optional(),\n })),\n retrievalPolicy: z.string().optional(),\n synthesisPolicy: z.string().optional(),\n questionPolicy: z.string().optional(),\n updatePolicy: z.string().optional(),\n metadata: z.record(z.string(), z.unknown()).optional(),\n})\n","import type { KnowledgeGraph, KnowledgeGraphEdge, KnowledgeGraphNode, KnowledgePage } from './types'\nimport { normalizeLinkTarget } from './wikilinks'\n\nexport function buildKnowledgeGraph(pages: KnowledgePage[]): KnowledgeGraph {\n const byId = new Map<string, KnowledgePage>()\n const bySlug = new Map<string, KnowledgePage>()\n for (const page of pages) {\n byId.set(page.id, page)\n bySlug.set(normalizeLinkTarget(page.id), page)\n bySlug.set(normalizeLinkTarget(page.title), page)\n bySlug.set(normalizeLinkTarget(page.path.split('/').pop()!.replace(/\\.md$/, '')), page)\n }\n\n const incoming = new Map<string, number>()\n const outgoing = new Map<string, number>()\n const edgesByKey = new Map<string, KnowledgeGraphEdge>()\n for (const page of pages) {\n outgoing.set(page.id, 0)\n incoming.set(page.id, 0)\n }\n\n for (const page of pages) {\n for (const raw of page.outLinks) {\n const target = bySlug.get(normalizeLinkTarget(raw))\n if (!target || target.id === page.id) continue\n const key = `${page.id}->${target.id}`\n const edge = edgesByKey.get(key)\n if (edge) edge.weight += 1\n else edgesByKey.set(key, { source: page.id, target: target.id, weight: 1, reasons: ['wikilink'] })\n outgoing.set(page.id, (outgoing.get(page.id) ?? 0) + 1)\n incoming.set(target.id, (incoming.get(target.id) ?? 0) + 1)\n }\n }\n\n addSourceOverlapEdges(pages, edgesByKey)\n\n const nodes: KnowledgeGraphNode[] = pages.map((page) => ({\n id: page.id,\n title: page.title,\n path: page.path,\n tags: page.tags,\n sourceIds: page.sourceIds,\n outDegree: outgoing.get(page.id) ?? 0,\n inDegree: incoming.get(page.id) ?? 0,\n }))\n return { nodes, edges: [...edgesByKey.values()].sort((a, b) => b.weight - a.weight) }\n}\n\nfunction addSourceOverlapEdges(pages: KnowledgePage[], edges: Map<string, KnowledgeGraphEdge>): void {\n for (let i = 0; i < pages.length; i++) {\n for (let j = i + 1; j < pages.length; j++) {\n const a = pages[i]!\n const b = pages[j]!\n const overlap = a.sourceIds.filter((source) => b.sourceIds.includes(source))\n if (overlap.length === 0) continue\n const key = `${a.id}->${b.id}`\n const edge = edges.get(key)\n if (edge) {\n edge.weight += overlap.length * 0.5\n edge.reasons.push('shared-source')\n } else {\n edges.set(key, {\n source: a.id,\n target: b.id,\n weight: overlap.length * 0.5,\n reasons: ['shared-source'],\n })\n }\n }\n }\n}\n","import { mkdir, readFile, readdir, stat, writeFile } from 'node:fs/promises'\nimport { dirname, join, relative } from 'node:path'\nimport type { KnowledgePage } from './types'\nimport { parseFrontmatter } from './frontmatter'\nimport { slugify } from './ids'\nimport { extractWikilinks, normalizeLinkTarget } from './wikilinks'\n\nexport interface KnowledgeLayout {\n root: string\n knowledgeDir: string\n rawSourcesDir: string\n sourceRegistryPath: string\n indexPath: string\n logPath: string\n cacheDir: string\n}\n\nexport function layoutFor(root: string): KnowledgeLayout {\n return {\n root,\n knowledgeDir: join(root, 'knowledge'),\n rawSourcesDir: join(root, 'raw', 'sources'),\n sourceRegistryPath: join(root, '.agent-knowledge', 'sources.json'),\n indexPath: join(root, 'knowledge', 'index.md'),\n logPath: join(root, 'knowledge', 'log.md'),\n cacheDir: join(root, '.agent-knowledge'),\n }\n}\n\n/**\n * Filenames that `initKnowledgeBase` writes as human-navigation scaffolding.\n * These are excluded from the page index — they exist on disk so authors can\n * curate their vault, but they are not searchable content.\n *\n * Add new scaffold filenames here (and only here) to keep lint, validate, viz,\n * and the indexer consistent.\n */\nexport const SCAFFOLD_PAGE_BASENAMES: readonly string[] = ['index.md', 'log.md']\n\n/**\n * True when a knowledge-relative path points at a scaffold file rather than\n * authored content. Accepts both repo-relative paths (`knowledge/index.md`)\n * and any nested `<dir>/index.md` or `<dir>/log.md` (for example\n * `knowledge/concepts/index.md`) so subdirectory README-style scaffolds are\n * also excluded.\n */\nexport function isScaffoldPath(path: string): boolean {\n const normalized = path.replace(/\\\\/g, '/')\n for (const basename of SCAFFOLD_PAGE_BASENAMES) {\n if (normalized === `knowledge/${basename}`) return true\n if (normalized.endsWith(`/${basename}`)) return true\n }\n return false\n}\n\nexport async function initKnowledgeBase(root: string): Promise<KnowledgeLayout> {\n const layout = layoutFor(root)\n await mkdir(layout.knowledgeDir, { recursive: true })\n await mkdir(layout.rawSourcesDir, { recursive: true })\n await mkdir(layout.cacheDir, { recursive: true })\n await writeIfMissing(layout.indexPath, '# Knowledge Index\\n\\n')\n await writeIfMissing(layout.logPath, '# Knowledge Log\\n\\n')\n await writeIfMissing(layout.sourceRegistryPath, '{\\n \"generatedAt\": \"1970-01-01T00:00:00.000Z\",\\n \"sources\": []\\n}\\n')\n return layout\n}\n\nexport async function loadKnowledgePages(root: string): Promise<KnowledgePage[]> {\n const layout = layoutFor(root)\n const files = await listMarkdownFiles(layout.knowledgeDir)\n const pages: KnowledgePage[] = []\n for (const file of files) {\n const rel = relative(root, file).replace(/\\\\/g, '/')\n if (isScaffoldPath(rel)) continue\n const content = await readFile(file, 'utf8')\n const { frontmatter, body } = parseFrontmatter(content)\n const title = stringField(frontmatter.title) ?? firstHeading(body) ?? rel.split('/').pop()!.replace(/\\.md$/, '')\n const sourceIds = arrayField(frontmatter.sources)\n const tags = arrayField(frontmatter.tags)\n pages.push({\n id: stringField(frontmatter.id) ?? slugify(rel.replace(/^knowledge\\//, '').replace(/\\.md$/, '')),\n path: rel,\n title,\n text: body,\n frontmatter,\n sourceIds,\n tags,\n outLinks: extractWikilinks(body).map(normalizeLinkTarget),\n })\n }\n pages.sort((a, b) => a.path.localeCompare(b.path))\n return pages\n}\n\nexport async function writeJson(path: string, value: unknown): Promise<void> {\n await mkdir(dirname(path), { recursive: true })\n await writeFile(path, JSON.stringify(value, null, 2) + '\\n', 'utf8')\n}\n\nasync function writeIfMissing(path: string, content: string): Promise<void> {\n try {\n await stat(path)\n } catch {\n await mkdir(dirname(path), { recursive: true })\n await writeFile(path, content, 'utf8')\n }\n}\n\nasync function listMarkdownFiles(root: string): Promise<string[]> {\n try {\n const entries = await readdir(root, { withFileTypes: true })\n const out: string[] = []\n for (const entry of entries) {\n const full = join(root, entry.name)\n if (entry.isDirectory()) out.push(...await listMarkdownFiles(full))\n else if (entry.isFile() && entry.name.endsWith('.md')) out.push(full)\n }\n return out\n } catch {\n return []\n }\n}\n\nfunction stringField(value: unknown): string | undefined {\n return typeof value === 'string' && value.trim() !== '' ? value.trim() : undefined\n}\n\nfunction arrayField(value: unknown): string[] {\n return Array.isArray(value) ? value.filter((item): item is string => typeof item === 'string') : []\n}\n\nfunction firstHeading(body: string): string | undefined {\n return /^#\\s+(.+)$/m.exec(body)?.[1]?.trim()\n}\n","import { copyFile, mkdir, readFile, readdir, stat, writeFile } from 'node:fs/promises'\nimport { basename, dirname, join, relative } from 'node:path'\nimport { textSourceAdapter, type SourceAdapter } from './adapters'\nimport type { SourceRecord, SourceRegistry } from './types'\nimport { sha256, slugify, stableId } from './ids'\nimport { layoutFor } from './store'\n\nexport interface AddSourceOptions {\n copyIntoRaw?: boolean\n adapters?: SourceAdapter[]\n now?: () => Date\n}\n\nexport interface AddSourceTextInput {\n uri: string\n text: string\n title?: string\n mediaType?: string\n validUntil?: string\n lastVerifiedAt?: string\n metadata?: Record<string, unknown>\n}\n\nexport async function loadSourceRegistry(root: string): Promise<SourceRegistry> {\n const path = sourceRegistryPath(root)\n try {\n const parsed = JSON.parse(await readFile(path, 'utf8')) as SourceRegistry\n return {\n generatedAt: typeof parsed.generatedAt === 'string' ? parsed.generatedAt : new Date(0).toISOString(),\n sources: Array.isArray(parsed.sources) ? parsed.sources : [],\n }\n } catch {\n return { generatedAt: new Date(0).toISOString(), sources: [] }\n }\n}\n\nexport async function writeSourceRegistry(root: string, registry: SourceRegistry): Promise<void> {\n const path = sourceRegistryPath(root)\n await mkdir(dirname(path), { recursive: true })\n await writeFile(path, JSON.stringify(registry, null, 2) + '\\n', 'utf8')\n}\n\nexport async function addSourcePath(root: string, sourcePath: string, options: AddSourceOptions = {}): Promise<SourceRecord[]> {\n const s = await stat(sourcePath)\n if (s.isDirectory()) {\n const out: SourceRecord[] = []\n for (const file of await listFiles(sourcePath)) {\n out.push(...await addSourcePath(root, file, options))\n }\n return out\n }\n\n const layout = layoutFor(root)\n await mkdir(layout.rawSourcesDir, { recursive: true })\n const bytes = await readFile(sourcePath)\n const contentHash = sha256(bytes.toString('base64'))\n const fileName = basename(sourcePath)\n const adapters = options.adapters ?? [textSourceAdapter]\n const adapter = adapters.find((candidate) => candidate.canLoad({ uri: sourcePath, bytes }))\n const loaded = adapter ? await adapter.load({ uri: sourcePath, bytes }) : {}\n const id = stableId('src', `${contentHash}:${fileName}`)\n const targetRel = join('raw', 'sources', `${slugify(fileName.replace(/\\.[^.]+$/, ''))}-${contentHash.slice(0, 8)}${ext(fileName)}`).replace(/\\\\/g, '/')\n const targetAbs = join(root, targetRel)\n\n if (options.copyIntoRaw ?? true) {\n await mkdir(dirname(targetAbs), { recursive: true })\n await copyFile(sourcePath, targetAbs)\n }\n\n const existing = await loadSourceRegistry(root)\n const record: SourceRecord = {\n id,\n uri: targetRel,\n title: loaded.title ?? fileName,\n mediaType: loaded.mediaType ?? mediaTypeFor(fileName),\n contentHash,\n text: loaded.text ?? textPreview(fileName, bytes),\n anchors: (loaded.anchors ?? []).map((anchor) => ({ ...anchor, sourceId: id })),\n createdAt: (options.now ?? (() => new Date()))().toISOString(),\n metadata: {\n ...(loaded.metadata ?? {}),\n originalPath: sourcePath,\n sizeBytes: bytes.length,\n projectRelativePath: relative(root, sourcePath).replace(/\\\\/g, '/'),\n },\n }\n const next: SourceRegistry = {\n generatedAt: new Date().toISOString(),\n sources: [record, ...existing.sources.filter((source) => source.id !== id)],\n }\n await writeSourceRegistry(root, next)\n return [record]\n}\n\nexport async function addSourceText(\n root: string,\n input: AddSourceTextInput,\n options: Pick<AddSourceOptions, 'adapters' | 'now'> = {},\n): Promise<SourceRecord> {\n const text = input.text\n const contentHash = sha256(text)\n const fileName = basename(input.uri) || `${slugify(input.title ?? input.uri)}.txt`\n const adapterInput = { uri: input.uri, text, metadata: input.metadata }\n const adapter = (options.adapters ?? [textSourceAdapter]).find((candidate) => candidate.canLoad(adapterInput))\n const loaded = adapter ? await adapter.load(adapterInput) : {}\n const id = stableId('src', `${contentHash}:${input.uri}`)\n const targetRel = join('raw', 'sources', `${slugify(fileName.replace(/\\.[^.]+$/, ''))}-${contentHash.slice(0, 8)}.txt`).replace(/\\\\/g, '/')\n const targetAbs = join(root, targetRel)\n await mkdir(dirname(targetAbs), { recursive: true })\n await writeFile(targetAbs, text.endsWith('\\n') ? text : `${text}\\n`, 'utf8')\n\n const existing = await loadSourceRegistry(root)\n const record: SourceRecord = {\n id,\n uri: targetRel,\n title: input.title ?? loaded.title ?? fileName,\n mediaType: input.mediaType ?? loaded.mediaType ?? 'text/plain',\n contentHash,\n text: loaded.text ?? text.slice(0, 200_000),\n anchors: (loaded.anchors ?? []).map((anchor) => ({ ...anchor, sourceId: id })),\n validUntil: input.validUntil,\n lastVerifiedAt: input.lastVerifiedAt,\n createdAt: (options.now ?? (() => new Date()))().toISOString(),\n metadata: {\n ...(loaded.metadata ?? {}),\n ...(input.metadata ?? {}),\n originalUri: input.uri,\n sizeBytes: Buffer.byteLength(text, 'utf8'),\n },\n }\n await writeSourceRegistry(root, {\n generatedAt: new Date().toISOString(),\n sources: [record, ...existing.sources.filter((source) => source.id !== id)],\n })\n return record\n}\n\nexport function sourceRegistryPath(root: string): string {\n return join(layoutFor(root).cacheDir, 'sources.json')\n}\n\nasync function listFiles(root: string): Promise<string[]> {\n const entries = await readdir(root, { withFileTypes: true })\n const out: string[] = []\n for (const entry of entries) {\n const full = join(root, entry.name)\n if (entry.isDirectory()) out.push(...await listFiles(full))\n else if (entry.isFile()) out.push(full)\n }\n return out\n}\n\nfunction ext(fileName: string): string {\n const idx = fileName.lastIndexOf('.')\n return idx >= 0 ? fileName.slice(idx) : ''\n}\n\nfunction mediaTypeFor(fileName: string): string {\n const lower = fileName.toLowerCase()\n if (lower.endsWith('.md')) return 'text/markdown'\n if (lower.endsWith('.txt')) return 'text/plain'\n if (lower.endsWith('.json')) return 'application/json'\n if (lower.endsWith('.csv')) return 'text/csv'\n if (lower.endsWith('.pdf')) return 'application/pdf'\n return 'application/octet-stream'\n}\n\nfunction textPreview(fileName: string, bytes: Buffer): string | undefined {\n const mediaType = mediaTypeFor(fileName)\n if (!mediaType.startsWith('text/') && mediaType !== 'application/json') return undefined\n return bytes.toString('utf8').slice(0, 200_000)\n}\n","import type { KnowledgeIndex, KnowledgePage, KnowledgeSearchResult } from './types'\n\nconst RRF_K = 60\nconst STOP_WORDS = new Set(['the', 'is', 'a', 'an', 'what', 'how', 'are', 'was', 'were', 'to', 'for', 'of', 'with', 'by', 'in', 'on', 'and'])\n\nexport function searchKnowledge(index: KnowledgeIndex, query: string, limit = 10): KnowledgeSearchResult[] {\n const trimmed = query.trim()\n if (trimmed === '') return []\n const tokenRanked = rankByTokens(index.pages, trimmed)\n const graphRanked = rankByGraph(index.pages, tokenRanked)\n const scores = reciprocalRankFusion([tokenRanked.map((p) => p.id), graphRanked.map((p) => p.id)])\n const byId = new Map(index.pages.map((page) => [page.id, page]))\n\n const ranked = [...scores.entries()]\n .map(([id, score]) => ({ page: byId.get(id), score }))\n .filter((item): item is { page: KnowledgePage; score: number } => Boolean(item.page))\n .sort((a, b) => b.score - a.score || a.page.path.localeCompare(b.page.path))\n .slice(0, limit)\n\n // Normalize against the top hit so callers can compare against natural\n // [0, 1] thresholds. Raw RRF values are typically ~0.016, which reads as\n // \"no relevance\" to humans even when the result is the best available.\n // The top hit becomes 1 by definition; lower-ranked hits scale linearly.\n const topScore = ranked[0]?.score ?? 0\n\n return ranked.map((item, i) => ({\n page: item.page,\n score: item.score,\n rrfScore: item.score,\n normalizedScore: topScore > 0 ? item.score / topScore : 0,\n rank: i + 1,\n snippet: buildSnippet(item.page.text, trimmed),\n reasons: reasonsFor(item.page, trimmed),\n }))\n}\n\nexport function tokenizeQuery(query: string): string[] {\n const raw = query\n .toLowerCase()\n .split(/[\\s,,。!?、;:\"\"''()()\\-_/\\\\·~~…]+/)\n .filter((token) => token.length > 1 && !STOP_WORDS.has(token))\n const tokens: string[] = []\n for (const token of raw) {\n if (/[\\u4e00-\\u9fff\\u3400-\\u4dbf]/.test(token) && token.length > 2) {\n const chars = [...token]\n for (let i = 0; i < chars.length - 1; i++) tokens.push(chars[i]! + chars[i + 1]!)\n tokens.push(...chars)\n }\n tokens.push(token)\n }\n return [...new Set(tokens)]\n}\n\nexport function reciprocalRankFusion(rankLists: string[][], k = RRF_K): Map<string, number> {\n const scores = new Map<string, number>()\n for (const list of rankLists) {\n list.forEach((id, idx) => {\n scores.set(id, (scores.get(id) ?? 0) + 1 / (k + idx + 1))\n })\n }\n return scores\n}\n\nfunction rankByTokens(pages: KnowledgePage[], query: string): KnowledgePage[] {\n const tokens = tokenizeQuery(query)\n const effective = tokens.length > 0 ? tokens : [query.toLowerCase()]\n return pages\n .map((page) => ({ page, score: tokenScore(page, query, effective) }))\n .filter((item) => item.score > 0)\n .sort((a, b) => b.score - a.score || a.page.path.localeCompare(b.page.path))\n .map((item) => item.page)\n}\n\nfunction rankByGraph(pages: KnowledgePage[], tokenRanked: KnowledgePage[]): KnowledgePage[] {\n if (tokenRanked.length === 0) return []\n const seeds = new Set(tokenRanked.slice(0, 5).map((page) => page.id))\n return pages\n .map((page) => ({\n page,\n score: page.outLinks.filter((link) => seeds.has(link)).length + page.sourceIds.filter((source) => tokenRanked.some((seed) => seed.sourceIds.includes(source))).length,\n }))\n .filter((item) => item.score > 0)\n .sort((a, b) => b.score - a.score || a.page.path.localeCompare(b.page.path))\n .map((item) => item.page)\n}\n\nfunction tokenScore(page: KnowledgePage, query: string, tokens: string[]): number {\n const title = page.title.toLowerCase()\n const path = page.path.toLowerCase()\n const body = page.text.toLowerCase()\n const phrase = query.toLowerCase()\n let score = 0\n if (path.endsWith(`${phrase}.md`) || title === phrase) score += 200\n if (title.includes(phrase)) score += 50\n if (body.includes(phrase)) score += 20\n for (const token of tokens) {\n if (title.includes(token)) score += 5\n if (body.includes(token)) score += 1\n if (path.includes(token)) score += 3\n }\n return score\n}\n\nfunction buildSnippet(text: string, query: string): string {\n const compact = text.replace(/\\s+/g, ' ').trim()\n const idx = compact.toLowerCase().indexOf(query.toLowerCase())\n if (idx < 0) return compact.slice(0, 180)\n return compact.slice(Math.max(0, idx - 80), Math.min(compact.length, idx + query.length + 100))\n}\n\nfunction reasonsFor(page: KnowledgePage, query: string): string[] {\n const lower = `${page.title}\\n${page.text}`.toLowerCase()\n const reasons: string[] = []\n if (lower.includes(query.toLowerCase())) reasons.push('phrase')\n if (page.sourceIds.length > 0) reasons.push('sourced')\n if (page.outLinks.length > 0) reasons.push('linked')\n return reasons\n}\n","import { join } from 'node:path'\nimport type { KnowledgeIndex } from './types'\nimport { buildKnowledgeGraph } from './graph'\nimport { loadSourceRegistry } from './sources'\nimport { layoutFor, loadKnowledgePages, writeJson } from './store'\n\nexport async function buildKnowledgeIndex(root: string): Promise<KnowledgeIndex> {\n const [pages, sourceRegistry] = await Promise.all([\n loadKnowledgePages(root),\n loadSourceRegistry(root),\n ])\n const index: KnowledgeIndex = {\n root,\n generatedAt: new Date().toISOString(),\n sources: sourceRegistry.sources,\n pages,\n graph: buildKnowledgeGraph(pages),\n }\n return index\n}\n\nexport async function writeKnowledgeIndex(root: string): Promise<KnowledgeIndex> {\n const index = await buildKnowledgeIndex(root)\n await writeJson(join(layoutFor(root).cacheDir, 'index.json'), index)\n return index\n}\n","import type { KnowledgeIndex, KnowledgeLintFinding } from './types'\nimport { normalizeLinkTarget } from './wikilinks'\n\nexport function lintKnowledgeIndex(index: KnowledgeIndex): KnowledgeLintFinding[] {\n const findings: KnowledgeLintFinding[] = []\n const byTarget = new Set<string>()\n const titles = new Map<string, string[]>()\n const sourceIds = new Set(index.sources.map((source) => source.id))\n const anchorIds = new Map(index.sources.map((source) => [source.id, new Set((source.anchors ?? []).map((anchor) => anchor.id))]))\n const pageIds = new Map<string, string[]>()\n const sourceHashes = new Map<string, string[]>()\n for (const page of index.pages) {\n pageIds.set(page.id, [...(pageIds.get(page.id) ?? []), page.path])\n byTarget.add(normalizeLinkTarget(page.id))\n byTarget.add(normalizeLinkTarget(page.title))\n byTarget.add(normalizeLinkTarget(page.path.split('/').pop()!.replace(/\\.md$/, '')))\n const titleKey = page.title.toLowerCase()\n titles.set(titleKey, [...(titles.get(titleKey) ?? []), page.path])\n }\n for (const source of index.sources) {\n sourceHashes.set(source.contentHash, [...(sourceHashes.get(source.contentHash) ?? []), source.id])\n }\n\n const inbound = new Map<string, number>()\n for (const page of index.pages) inbound.set(page.id, 0)\n for (const page of index.pages) {\n if (page.outLinks.length === 0 && !isStructural(page.path)) {\n findings.push({ type: 'no-outlinks', severity: 'info', page: page.path, message: 'Page has no wikilinks to other knowledge pages.' })\n }\n for (const link of page.outLinks) {\n if (!byTarget.has(normalizeLinkTarget(link))) {\n findings.push({ type: 'broken-link', severity: 'warning', page: page.path, message: `Broken wikilink [[${link}]].` })\n }\n }\n }\n\n for (const edge of index.graph.edges) inbound.set(edge.target, (inbound.get(edge.target) ?? 0) + 1)\n for (const page of index.pages) {\n if (!isStructural(page.path) && (inbound.get(page.id) ?? 0) === 0) {\n findings.push({ type: 'orphan', severity: 'info', page: page.path, message: 'No other page links to this page.' })\n }\n if (/\\bclaim\\b/i.test(page.text) && page.sourceIds.length === 0) {\n findings.push({ type: 'uncited-claim', severity: 'warning', page: page.path, message: 'Page appears to contain claims but has no sources frontmatter.' })\n }\n for (const sourceId of page.sourceIds) {\n if (!sourceIds.has(sourceId)) {\n findings.push({ type: 'missing-source', severity: 'error', page: page.path, message: `Page cites unknown source \"${sourceId}\".`, metadata: { sourceId } })\n }\n }\n for (const ref of extractSourceRefs(page.text)) {\n if (!sourceIds.has(ref.sourceId)) {\n findings.push({ type: 'missing-source', severity: 'error', page: page.path, message: `Page cites unknown source \"${ref.sourceId}\".`, metadata: ref })\n } else if (ref.anchorId && !(anchorIds.get(ref.sourceId)?.has(ref.anchorId))) {\n findings.push({ type: 'missing-source', severity: 'error', page: page.path, message: `Page cites unknown source anchor \"${ref.sourceId}#${ref.anchorId}\".`, metadata: ref })\n }\n }\n }\n\n for (const [title, paths] of titles) {\n if (title && paths.length > 1) {\n findings.push({ type: 'duplicate-title', severity: 'warning', message: `Duplicate title \"${title}\" in ${paths.join(', ')}.`, metadata: { paths } })\n }\n }\n for (const [id, paths] of pageIds) {\n if (id && paths.length > 1) {\n findings.push({ type: 'duplicate-page-id', severity: 'error', message: `Duplicate page id \"${id}\" in ${paths.join(', ')}.`, metadata: { paths } })\n }\n }\n for (const [hash, ids] of sourceHashes) {\n if (hash && ids.length > 1) {\n findings.push({ type: 'duplicate-source-hash', severity: 'warning', message: `Duplicate source content hash across ${ids.join(', ')}.`, metadata: { sourceIds: ids } })\n }\n }\n return findings\n}\n\nfunction isStructural(path: string): boolean {\n return path.endsWith('/index.md') || path.endsWith('/log.md') || path === 'knowledge/index.md' || path === 'knowledge/log.md'\n}\n\nfunction extractSourceRefs(text: string): Array<{ sourceId: string; anchorId?: string }> {\n const refs: Array<{ sourceId: string; anchorId?: string }> = []\n const regex = /\\[\\^([A-Za-z0-9_-]+)(?:#([A-Za-z0-9_.:-]+))?\\]/g\n let match: RegExpExecArray | null\n while ((match = regex.exec(text)) !== null) {\n refs.push({ sourceId: match[1]!, anchorId: match[2] })\n }\n return refs\n}\n","import type { KnowledgeIndex, KnowledgeLintFinding, KnowledgePage } from './types'\nimport { lintKnowledgeIndex } from './lint'\nimport { searchKnowledge } from './search'\n\nexport interface KnowledgeInspection {\n pageCount: number\n sourceCount: number\n expiredSourceCount: number\n staleSourceCount: number\n edgeCount: number\n findingCount: number\n blockingFindingCount: number\n topPages: Array<{ path: string; title: string; degree: number; sources: number }>\n sourceFreshness: SourceFreshnessInspection[]\n findings: KnowledgeLintFinding[]\n}\n\nexport interface SourceFreshnessInspection {\n id: string\n title?: string\n uri: string\n status: 'fresh' | 'expired' | 'unknown'\n validUntil?: string\n lastVerifiedAt?: string\n}\n\nexport function inspectKnowledgeIndex(index: KnowledgeIndex, options: { now?: Date } = {}): KnowledgeInspection {\n const now = options.now ?? new Date()\n const findings = lintKnowledgeIndex(index)\n const degree = new Map(index.graph.nodes.map((node) => [node.id, node.inDegree + node.outDegree]))\n const sourceFreshness = index.sources.map((source) => inspectSourceFreshness(source, now))\n return {\n pageCount: index.pages.length,\n sourceCount: index.sources.length,\n expiredSourceCount: sourceFreshness.filter((source) => source.status === 'expired').length,\n staleSourceCount: sourceFreshness.filter((source) => source.status !== 'fresh').length,\n edgeCount: index.graph.edges.length,\n findingCount: findings.length,\n blockingFindingCount: findings.filter((finding) => finding.severity === 'error').length,\n topPages: [...index.pages]\n .sort((a, b) => (degree.get(b.id) ?? 0) - (degree.get(a.id) ?? 0))\n .slice(0, 10)\n .map((page) => ({ path: page.path, title: page.title, degree: degree.get(page.id) ?? 0, sources: page.sourceIds.length })),\n sourceFreshness,\n findings,\n }\n}\n\nfunction inspectSourceFreshness(source: KnowledgeIndex['sources'][number], now: Date): SourceFreshnessInspection {\n const validUntil = source.validUntil ?? stringMetadata(source.metadata, 'validUntil') ?? stringMetadata(source.metadata, 'expiresAt')\n const lastVerifiedAt = source.lastVerifiedAt ?? stringMetadata(source.metadata, 'lastVerifiedAt')\n const status = validUntil && Number.isFinite(Date.parse(validUntil))\n ? Date.parse(validUntil) <= now.getTime() ? 'expired' : 'fresh'\n : 'unknown'\n return { id: source.id, title: source.title, uri: source.uri, status, validUntil, lastVerifiedAt }\n}\n\nfunction stringMetadata(metadata: Record<string, unknown> | undefined, key: string): string | undefined {\n const value = metadata?.[key]\n return typeof value === 'string' ? value : undefined\n}\n\nexport interface KnowledgeExplanation {\n target: string\n page?: KnowledgePage\n sources: Array<{ id: string; title?: string; uri: string }>\n links: string[]\n inbound: string[]\n related: Array<{ path: string; title: string; score: number }>\n}\n\nexport function explainKnowledgeTarget(index: KnowledgeIndex, target: string): KnowledgeExplanation {\n const page = index.pages.find((candidate) => candidate.path === target || candidate.id === target || candidate.title.toLowerCase() === target.toLowerCase())\n const inbound = page\n ? index.graph.edges.filter((edge) => edge.target === page.id).map((edge) => index.pages.find((candidate) => candidate.id === edge.source)?.path ?? edge.source)\n : []\n const related = page\n ? searchKnowledge(index, `${page.title} ${page.tags.join(' ')}`, 6)\n .filter((result) => result.page.id !== page.id)\n .map((result) => ({ path: result.page.path, title: result.page.title, score: result.score }))\n : searchKnowledge(index, target, 6).map((result) => ({ path: result.page.path, title: result.page.title, score: result.score }))\n return {\n target,\n page,\n sources: page ? index.sources.filter((source) => page.sourceIds.includes(source.id)).map((source) => ({ id: source.id, title: source.title, uri: source.uri })) : [],\n links: page?.outLinks ?? [],\n inbound,\n related,\n }\n}\n","import type { KnowledgeIndex, KnowledgeLintFinding } from './types'\nimport { lintKnowledgeIndex } from './lint'\nimport { KnowledgeIndexSchema } from './schemas'\n\nexport interface ValidateKnowledgeOptions {\n strict?: boolean\n}\n\nexport interface ValidateKnowledgeResult {\n ok: boolean\n findings: KnowledgeLintFinding[]\n}\n\nexport function validateKnowledgeIndex(index: KnowledgeIndex, options: ValidateKnowledgeOptions = {}): ValidateKnowledgeResult {\n const findings = [...lintKnowledgeIndex(index)]\n const parsed = KnowledgeIndexSchema.safeParse(index)\n if (!parsed.success) {\n findings.push({\n type: 'missing-frontmatter',\n severity: 'error',\n message: parsed.error.issues.map((issue) => `${issue.path.join('.')}: ${issue.message}`).join('; '),\n })\n }\n if (options.strict) {\n for (const page of index.pages) {\n if (isStructuralPage(page.path)) continue\n if (!page.frontmatter.id || !page.frontmatter.title) {\n findings.push({\n type: 'missing-frontmatter',\n severity: 'error',\n page: page.path,\n message: 'Strict mode requires id and title frontmatter.',\n })\n }\n }\n }\n return { ok: !findings.some((finding) => finding.severity === 'error'), findings }\n}\n\nfunction isStructuralPage(path: string): boolean {\n return path === 'knowledge/index.md' || path === 'knowledge/log.md' || path.endsWith('/index.md') || path.endsWith('/log.md')\n}\n"],"mappings":";AAAA,SAAS,kBAAkB;AAEpB,SAAS,OAAO,MAAsB;AAC3C,SAAO,WAAW,QAAQ,EAAE,OAAO,IAAI,EAAE,OAAO,KAAK;AACvD;AAEO,SAAS,QAAQ,OAAuB;AAC7C,QAAM,MAAM,MACT,KAAK,EACL,YAAY,EACZ,UAAU,MAAM,EAChB,QAAQ,oBAAoB,EAAE,EAC9B,QAAQ,4BAA4B,GAAG,EACvC,QAAQ,YAAY,EAAE;AACzB,SAAO,OAAO;AAChB;AAEO,SAAS,SAAS,QAAgB,SAAyB;AAChE,SAAO,GAAG,MAAM,IAAI,OAAO,OAAO,EAAE,MAAM,GAAG,EAAE,CAAC;AAClD;;;ACdO,SAAS,iBAAiB,SAAoC;AACnE,QAAM,aAAa,QAAQ,QAAQ,SAAS,IAAI;AAChD,MAAI,CAAC,WAAW,WAAW,OAAO,EAAG,QAAO,EAAE,aAAa,CAAC,GAAG,MAAM,WAAW;AAChF,QAAM,MAAM,WAAW,QAAQ,SAAS,CAAC;AACzC,MAAI,MAAM,EAAG,QAAO,EAAE,aAAa,CAAC,GAAG,MAAM,WAAW;AACxD,QAAM,MAAM,WAAW,MAAM,GAAG,GAAG;AACnC,QAAM,QAAQ,WAAW,MAAM,GAAG,EAAE,QAAQ,gBAAgB,EAAE;AAC9D,SAAO,EAAE,aAAa,gBAAgB,GAAG,GAAG,MAAM,MAAM;AAC1D;AAEO,SAAS,kBAAkB,aAAsC,MAAsB;AAC5F,QAAM,QAAQ,OAAO,QAAQ,WAAW,EACrC,OAAO,CAAC,CAAC,EAAE,KAAK,MAAM,UAAU,MAAS,EACzC,QAAQ,CAAC,CAAC,KAAK,KAAK,MAAM,gBAAgB,KAAK,KAAK,CAAC;AACxD,MAAI,MAAM,WAAW,EAAG,QAAO;AAC/B,SAAO;AAAA,EAAQ,MAAM,KAAK,IAAI,CAAC;AAAA;AAAA,EAAU,KAAK,QAAQ,QAAQ,EAAE,CAAC;AACnE;AAEA,SAAS,gBAAgB,KAAsC;AAC7D,QAAM,MAA+B,CAAC;AACtC,QAAM,QAAQ,IAAI,MAAM,IAAI;AAC5B,WAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,UAAM,OAAO,MAAM,CAAC;AACpB,UAAM,SAAS,6BAA6B,KAAK,IAAI;AACrD,QAAI,CAAC,OAAQ;AACb,UAAM,MAAM,OAAO,CAAC;AACpB,UAAM,OAAO,OAAO,CAAC,EAAG,KAAK;AAC7B,QAAI,SAAS,IAAI;AACf,YAAM,QAAkB,CAAC;AACzB,aAAO,IAAI,IAAI,MAAM,QAAQ;AAC3B,cAAM,OAAO,oBAAoB,KAAK,MAAM,IAAI,CAAC,CAAE;AACnD,YAAI,CAAC,KAAM;AACX,cAAM,KAAK,QAAQ,KAAK,CAAC,CAAE,CAAC;AAC5B;AAAA,MACF;AACA,UAAI,GAAG,IAAI;AACX;AAAA,IACF;AACA,QAAI,KAAK,WAAW,GAAG,KAAK,KAAK,SAAS,GAAG,GAAG;AAC9C,UAAI,GAAG,IAAI,KAAK,MAAM,GAAG,EAAE,EAAE,MAAM,GAAG,EAAE,IAAI,CAAC,SAAS,QAAQ,KAAK,KAAK,CAAC,CAAC,EAAE,OAAO,OAAO;AAAA,IAC5F,WAAW,SAAS,UAAU,SAAS,SAAS;AAC9C,UAAI,GAAG,IAAI,SAAS;AAAA,IACtB,WAAW,oBAAoB,KAAK,IAAI,GAAG;AACzC,UAAI,GAAG,IAAI,OAAO,IAAI;AAAA,IACxB,OAAO;AACL,UAAI,GAAG,IAAI,QAAQ,IAAI;AAAA,IACzB;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,gBAAgB,KAAa,OAA0B;AAC9D,MAAI,MAAM,QAAQ,KAAK,GAAG;AACxB,WAAO,CAAC,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,SAAS,OAAO,OAAO,IAAI,CAAC,EAAE,CAAC;AAAA,EAClE;AACA,MAAI,OAAO,UAAU,SAAU,QAAO,CAAC,GAAG,GAAG,KAAK,KAAK,EAAE;AACzD,MAAI,OAAO,UAAU,YAAY,OAAO,UAAU,UAAW,QAAO,CAAC,GAAG,GAAG,KAAK,OAAO,KAAK,CAAC,EAAE;AAC/F,SAAO,CAAC,GAAG,GAAG,KAAK,KAAK,UAAU,KAAK,CAAC,EAAE;AAC5C;AAEA,SAAS,QAAQ,OAAuB;AACtC,SAAO,MAAM,QAAQ,gBAAgB,EAAE;AACzC;;;ACnEO,IAAM,iBAAiB;AAEvB,SAAS,iBAAiB,SAA2B;AAC1D,QAAM,QAAkB,CAAC;AACzB,QAAM,QAAQ,IAAI,OAAO,eAAe,QAAQ,GAAG;AACnD,MAAI;AACJ,UAAQ,QAAQ,MAAM,KAAK,OAAO,OAAO,MAAM;AAC7C,UAAM,KAAK,MAAM,CAAC,EAAG,KAAK,CAAC;AAAA,EAC7B;AACA,SAAO,CAAC,GAAG,IAAI,IAAI,KAAK,CAAC;AAC3B;AAEO,SAAS,oBAAoB,QAAwB;AAC1D,SAAO,OAAO,KAAK,EAAE,QAAQ,UAAU,EAAE,EAAE,YAAY,EAAE,QAAQ,QAAQ,GAAG;AAC9E;;;ACZA,IAAM,cAAc;AACpB,IAAM,cAAc;AACpB,IAAM,aAAa;AAEZ,SAAS,oBAAoB,MAAc,kBAAkB,CAAC,YAAY,GAAY;AAC3F,MAAI,OAAO,SAAS,YAAY,KAAK,KAAK,MAAM,GAAI,QAAO;AAC3D,MAAI,cAAc,KAAK,IAAI,EAAG,QAAO;AACrC,MAAI,KAAK,WAAW,GAAG,KAAK,KAAK,WAAW,IAAI,EAAG,QAAO;AAC1D,MAAI,aAAa,KAAK,IAAI,EAAG,QAAO;AACpC,QAAM,aAAa,KAAK,QAAQ,OAAO,GAAG;AAC1C,MAAI,WAAW,MAAM,GAAG,EAAE,KAAK,CAAC,SAAS,SAAS,IAAI,EAAG,QAAO;AAChE,SAAO,gBAAgB,KAAK,CAAC,WAAW,WAAW,WAAW,MAAM,CAAC;AACvE;AAEO,SAAS,0BAA0B,MAAc,kBAAkB,CAAC,YAAY,GAA8B;AACnH,QAAM,QAAQ,KAAK,QAAQ,SAAS,IAAI,EAAE,MAAM,IAAI;AACpD,QAAM,SAA8C,CAAC;AACrD,QAAM,WAAqB,CAAC;AAC5B,MAAI,IAAI;AAER,SAAO,IAAI,MAAM,QAAQ;AACvB,UAAM,SAAS,YAAY,KAAK,MAAM,CAAC,CAAE;AACzC,QAAI,CAAC,QAAQ;AACX;AACA;AAAA,IACF;AACA,UAAM,OAAO,OAAO,CAAC,EAAG,KAAK;AAC7B;AACA,UAAM,eAAyB,CAAC;AAChC,QAAI,cAA6B;AACjC,QAAI,WAAW;AACf,QAAI,SAAS;AAEb,WAAO,IAAI,MAAM,QAAQ;AACvB,YAAM,OAAO,MAAM,CAAC;AACpB,YAAM,QAAQ,WAAW,KAAK,IAAI;AAClC,UAAI,OAAO;AACT,cAAM,MAAM,MAAM,CAAC;AACnB,cAAM,OAAO,IAAI,CAAC;AAClB,YAAI,gBAAgB,MAAM;AACxB,wBAAc;AACd,qBAAW,IAAI;AAAA,QACjB,WAAW,SAAS,eAAe,IAAI,UAAU,UAAU;AACzD,wBAAc;AACd,qBAAW;AAAA,QACb;AACA,qBAAa,KAAK,IAAI;AACtB;AACA;AAAA,MACF;AACA,UAAI,gBAAgB,QAAQ,YAAY,KAAK,IAAI,GAAG;AAClD,iBAAS;AACT;AACA;AAAA,MACF;AACA,mBAAa,KAAK,IAAI;AACtB;AAAA,IACF;AAEA,QAAI,CAAC,QAAQ;AACX,eAAS,KAAK,eAAe,QAAQ,SAAS,wCAAwC;AACtF;AAAA,IACF;AACA,QAAI,CAAC,oBAAoB,MAAM,eAAe,GAAG;AAC/C,eAAS,KAAK,gCAAgC,IAAI,aAAa;AAC/D;AAAA,IACF;AACA,WAAO,KAAK,EAAE,MAAM,SAAS,aAAa,KAAK,IAAI,EAAE,CAAC;AAAA,EACxD;AAEA,SAAO,EAAE,QAAQ,SAAS;AAC5B;;;AClDO,IAAM,oBAAmC;AAAA,EAC9C,IAAI;AAAA,EACJ,SAAS,CAAC,UAAU,QAAQ,MAAM,IAAI,KAAK,wBAAwB,KAAK,MAAM,GAAG;AAAA,EACjF,MAAM,CAAC,WAAW;AAAA,IAChB,OAAO,MAAM,IAAI,MAAM,GAAG,EAAE,IAAI;AAAA,IAChC,WAAW,aAAa,MAAM,GAAG;AAAA,IACjC,MAAM,WAAW,KAAK;AAAA,IACtB,SAAS,eAAe,MAAM,KAAK,WAAW,KAAK,CAAC;AAAA,IACpD,UAAU,MAAM;AAAA,EAClB;AACF;AAEO,SAAS,aAAa,KAAqB;AAChD,QAAM,QAAQ,IAAI,YAAY;AAC9B,MAAI,MAAM,SAAS,KAAK,EAAG,QAAO;AAClC,MAAI,MAAM,SAAS,MAAM,EAAG,QAAO;AACnC,MAAI,MAAM,SAAS,OAAO,EAAG,QAAO;AACpC,MAAI,MAAM,SAAS,MAAM,EAAG,QAAO;AACnC,MAAI,MAAM,SAAS,MAAM,EAAG,QAAO;AACnC,SAAO;AACT;AAEA,SAAS,WAAW,OAA+C;AACjE,SAAO,MAAM,SAAS,MAAM,QAAQ,IAAI,YAAY,EAAE,OAAO,MAAM,KAAK,EAAE,MAAM,GAAG,GAAO,IAAI;AAChG;AAEA,SAAS,eAAe,KAAa,MAA0D;AAC7F,MAAI,CAAC,KAAM,QAAO,CAAC;AACnB,QAAM,QAAQ,KAAK,MAAM,IAAI;AAC7B,QAAM,UAAuD,CAAC,EAAE,IAAI,OAAO,UAAU,IAAI,OAAO,eAAe,WAAW,GAAG,SAAS,MAAM,OAAO,CAAC;AACpJ,WAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK,IAAI;AACzC,YAAQ,KAAK;AAAA,MACX,IAAI,IAAI,IAAI,CAAC;AAAA,MACb,UAAU;AAAA,MACV,OAAO,GAAG,GAAG,IAAI,IAAI,CAAC;AAAA,MACtB,WAAW,IAAI;AAAA,MACf,SAAS,KAAK,IAAI,MAAM,QAAQ,IAAI,EAAE;AAAA,IACxC,CAAC;AAAA,EACH;AACA,SAAO;AACT;;;AC/DA,SAAS,OAAO,UAAU,iBAAiB;AAC3C,SAAS,SAAS,YAAY;AAQ9B,eAAsB,0BACpB,MACA,cACiC;AACjC,QAAM,SAAS,0BAA0B,YAAY;AACrD,QAAM,UAAoB,CAAC;AAC3B,aAAW,SAAS,OAAO,QAAQ;AACjC,UAAM,OAAO,KAAK,MAAM,MAAM,IAAI;AAClC,UAAM,MAAM,QAAQ,IAAI,GAAG,EAAE,WAAW,KAAK,CAAC;AAC9C,UAAM,UAAU,MAAM,MAAM,QAAQ,SAAS,IAAI,IAAI,MAAM,UAAU,GAAG,MAAM,OAAO;AAAA,GAAM,MAAM;AACjG,YAAQ,KAAK,MAAM,IAAI;AAAA,EACzB;AACA,SAAO,EAAE,SAAS,UAAU,OAAO,SAAS;AAC9C;AAEA,eAAsB,8BAA8B,MAAc,cAAuD;AACvH,SAAO,0BAA0B,MAAM,MAAM,SAAS,cAAc,MAAM,CAAC;AAC7E;;;AC1BA,SAAS,SAAS;AAEX,IAAM,qBAAqB,EAAE,OAAO;AAAA,EACzC,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EACpB,UAAU,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EAC1B,OAAO,EAAE,OAAO,EAAE,SAAS;AAAA,EAC3B,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS;AAAA,EAC3C,WAAW,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS;AAAA,EAChD,SAAS,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS;AAAA,EAC9C,WAAW,EAAE,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,SAAS;AAAA,EACnD,SAAS,EAAE,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,SAAS;AAAA,EACjD,aAAa,EAAE,OAAO,EAAE,YAAY,EAAE,SAAS;AAAA,EAC/C,UAAU,EAAE,OAAO,EAAE,OAAO,GAAG,EAAE,QAAQ,CAAC,EAAE,SAAS;AACvD,CAAC;AAEM,IAAM,qBAAqB,EAAE,OAAO;AAAA,EACzC,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EACpB,KAAK,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EACrB,OAAO,EAAE,OAAO,EAAE,SAAS;AAAA,EAC3B,WAAW,EAAE,OAAO,EAAE,SAAS;AAAA,EAC/B,aAAa,EAAE,OAAO,EAAE,IAAI,EAAE;AAAA,EAC9B,MAAM,EAAE,OAAO,EAAE,SAAS;AAAA,EAC1B,SAAS,EAAE,MAAM,kBAAkB,EAAE,SAAS;AAAA,EAC9C,UAAU,EAAE,OAAO,EAAE,OAAO,GAAG,EAAE,QAAQ,CAAC,EAAE,SAAS;AAAA,EACrD,WAAW,EAAE,OAAO,EAAE,IAAI,CAAC;AAC7B,CAAC;AAEM,IAAM,sBAAsB,EAAE,OAAO;AAAA,EAC1C,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EACpB,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EACtB,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EACvB,MAAM,EAAE,OAAO;AAAA,EACf,aAAa,EAAE,OAAO,EAAE,OAAO,GAAG,EAAE,QAAQ,CAAC;AAAA,EAC7C,WAAW,EAAE,MAAM,EAAE,OAAO,CAAC;AAAA,EAC7B,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC;AAAA,EACxB,UAAU,EAAE,MAAM,EAAE,OAAO,CAAC;AAC9B,CAAC;AAEM,IAAM,2BAA2B,EAAE,OAAO;AAAA,EAC/C,IAAI,EAAE,OAAO;AAAA,EACb,OAAO,EAAE,OAAO;AAAA,EAChB,MAAM,EAAE,OAAO;AAAA,EACf,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC;AAAA,EACxB,WAAW,EAAE,MAAM,EAAE,OAAO,CAAC;AAAA,EAC7B,WAAW,EAAE,OAAO,EAAE,IAAI,EAAE,YAAY;AAAA,EACxC,UAAU,EAAE,OAAO,EAAE,IAAI,EAAE,YAAY;AACzC,CAAC;AAEM,IAAM,2BAA2B,EAAE,OAAO;AAAA,EAC/C,QAAQ,EAAE,OAAO;AAAA,EACjB,QAAQ,EAAE,OAAO;AAAA,EACjB,QAAQ,EAAE,OAAO;AAAA,EACjB,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC;AAC7B,CAAC;AAEM,IAAM,uBAAuB,EAAE,OAAO;AAAA,EAC3C,MAAM,EAAE,OAAO;AAAA,EACf,aAAa,EAAE,OAAO;AAAA,EACtB,SAAS,EAAE,MAAM,kBAAkB;AAAA,EACnC,OAAO,EAAE,MAAM,mBAAmB;AAAA,EAClC,OAAO,EAAE,OAAO;AAAA,IACd,OAAO,EAAE,MAAM,wBAAwB;AAAA,IACvC,OAAO,EAAE,MAAM,wBAAwB;AAAA,EACzC,CAAC;AACH,CAAC;AAEM,IAAM,uBAAuB,EAAE,OAAO;AAAA,EAC3C,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EACpB,MAAM,EAAE,KAAK,CAAC,gBAAgB,oBAAoB,eAAe,YAAY,oBAAoB,oBAAoB,kBAAkB,CAAC;AAAA,EACxI,WAAW,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EAC3B,OAAO,EAAE,OAAO,EAAE,SAAS;AAAA,EAC3B,QAAQ,EAAE,OAAO,EAAE,SAAS;AAAA,EAC5B,UAAU,EAAE,OAAO,EAAE,OAAO,GAAG,EAAE,QAAQ,CAAC,EAAE,SAAS;AACvD,CAAC;AAEM,IAAM,+BAA+B,EAAE,OAAO;AAAA,EACnD,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EACpB,OAAO,EAAE,MAAM,EAAE,OAAO;AAAA,IACtB,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,IACpB,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,IACvB,MAAM,EAAE,OAAO;AAAA,IACf,QAAQ,EAAE,MAAM,EAAE,OAAO;AAAA,MACvB,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,MACpB,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,MACtB,MAAM,EAAE,MAAM,EAAE,OAAO;AAAA,QACrB,UAAU,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,QAC1B,UAAU,EAAE,OAAO,EAAE,SAAS;AAAA,QAC9B,OAAO,EAAE,OAAO,EAAE,SAAS;AAAA,MAC7B,CAAC,CAAC;AAAA,MACF,YAAY,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,EAAE,SAAS;AAAA,MAC9C,QAAQ,EAAE,KAAK,CAAC,SAAS,UAAU,cAAc,UAAU,CAAC,EAAE,SAAS;AAAA,MACvE,UAAU,EAAE,OAAO,EAAE,OAAO,GAAG,EAAE,QAAQ,CAAC,EAAE,SAAS;AAAA,IACvD,CAAC,CAAC,EAAE,SAAS;AAAA,IACb,WAAW,EAAE,MAAM,EAAE,OAAO;AAAA,MAC1B,UAAU,EAAE,OAAO;AAAA,MACnB,UAAU,EAAE,OAAO;AAAA,MACnB,WAAW,EAAE,OAAO;AAAA,MACpB,QAAQ,EAAE,OAAO,EAAE,SAAS;AAAA,MAC5B,UAAU,EAAE,OAAO,EAAE,OAAO,GAAG,EAAE,QAAQ,CAAC,EAAE,SAAS;AAAA,IACvD,CAAC,CAAC,EAAE,SAAS;AAAA,IACb,WAAW,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,SAAS;AAAA,IACxC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,SAAS;AAAA,IACnC,UAAU,EAAE,OAAO,EAAE,OAAO,GAAG,EAAE,QAAQ,CAAC,EAAE,SAAS;AAAA,IACrD,WAAW,EAAE,OAAO,EAAE,SAAS;AAAA,EACjC,CAAC,CAAC;AAAA,EACF,iBAAiB,EAAE,OAAO,EAAE,SAAS;AAAA,EACrC,iBAAiB,EAAE,OAAO,EAAE,SAAS;AAAA,EACrC,gBAAgB,EAAE,OAAO,EAAE,SAAS;AAAA,EACpC,cAAc,EAAE,OAAO,EAAE,SAAS;AAAA,EAClC,UAAU,EAAE,OAAO,EAAE,OAAO,GAAG,EAAE,QAAQ,CAAC,EAAE,SAAS;AACvD,CAAC;;;AC3GM,SAAS,oBAAoB,OAAwC;AAC1E,QAAM,OAAO,oBAAI,IAA2B;AAC5C,QAAM,SAAS,oBAAI,IAA2B;AAC9C,aAAW,QAAQ,OAAO;AACxB,SAAK,IAAI,KAAK,IAAI,IAAI;AACtB,WAAO,IAAI,oBAAoB,KAAK,EAAE,GAAG,IAAI;AAC7C,WAAO,IAAI,oBAAoB,KAAK,KAAK,GAAG,IAAI;AAChD,WAAO,IAAI,oBAAoB,KAAK,KAAK,MAAM,GAAG,EAAE,IAAI,EAAG,QAAQ,SAAS,EAAE,CAAC,GAAG,IAAI;AAAA,EACxF;AAEA,QAAM,WAAW,oBAAI,IAAoB;AACzC,QAAM,WAAW,oBAAI,IAAoB;AACzC,QAAM,aAAa,oBAAI,IAAgC;AACvD,aAAW,QAAQ,OAAO;AACxB,aAAS,IAAI,KAAK,IAAI,CAAC;AACvB,aAAS,IAAI,KAAK,IAAI,CAAC;AAAA,EACzB;AAEA,aAAW,QAAQ,OAAO;AACxB,eAAW,OAAO,KAAK,UAAU;AAC/B,YAAM,SAAS,OAAO,IAAI,oBAAoB,GAAG,CAAC;AAClD,UAAI,CAAC,UAAU,OAAO,OAAO,KAAK,GAAI;AACtC,YAAM,MAAM,GAAG,KAAK,EAAE,KAAK,OAAO,EAAE;AACpC,YAAM,OAAO,WAAW,IAAI,GAAG;AAC/B,UAAI,KAAM,MAAK,UAAU;AAAA,UACpB,YAAW,IAAI,KAAK,EAAE,QAAQ,KAAK,IAAI,QAAQ,OAAO,IAAI,QAAQ,GAAG,SAAS,CAAC,UAAU,EAAE,CAAC;AACjG,eAAS,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,EAAE,KAAK,KAAK,CAAC;AACtD,eAAS,IAAI,OAAO,KAAK,SAAS,IAAI,OAAO,EAAE,KAAK,KAAK,CAAC;AAAA,IAC5D;AAAA,EACF;AAEA,wBAAsB,OAAO,UAAU;AAEvC,QAAM,QAA8B,MAAM,IAAI,CAAC,UAAU;AAAA,IACvD,IAAI,KAAK;AAAA,IACT,OAAO,KAAK;AAAA,IACZ,MAAM,KAAK;AAAA,IACX,MAAM,KAAK;AAAA,IACX,WAAW,KAAK;AAAA,IAChB,WAAW,SAAS,IAAI,KAAK,EAAE,KAAK;AAAA,IACpC,UAAU,SAAS,IAAI,KAAK,EAAE,KAAK;AAAA,EACrC,EAAE;AACF,SAAO,EAAE,OAAO,OAAO,CAAC,GAAG,WAAW,OAAO,CAAC,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE;AACtF;AAEA,SAAS,sBAAsB,OAAwB,OAA8C;AACnG,WAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,aAAS,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACzC,YAAM,IAAI,MAAM,CAAC;AACjB,YAAM,IAAI,MAAM,CAAC;AACjB,YAAM,UAAU,EAAE,UAAU,OAAO,CAAC,WAAW,EAAE,UAAU,SAAS,MAAM,CAAC;AAC3E,UAAI,QAAQ,WAAW,EAAG;AAC1B,YAAM,MAAM,GAAG,EAAE,EAAE,KAAK,EAAE,EAAE;AAC5B,YAAM,OAAO,MAAM,IAAI,GAAG;AAC1B,UAAI,MAAM;AACR,aAAK,UAAU,QAAQ,SAAS;AAChC,aAAK,QAAQ,KAAK,eAAe;AAAA,MACnC,OAAO;AACL,cAAM,IAAI,KAAK;AAAA,UACb,QAAQ,EAAE;AAAA,UACV,QAAQ,EAAE;AAAA,UACV,QAAQ,QAAQ,SAAS;AAAA,UACzB,SAAS,CAAC,eAAe;AAAA,QAC3B,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AACF;;;ACtEA,SAAS,SAAAA,QAAO,YAAAC,WAAU,SAAS,MAAM,aAAAC,kBAAiB;AAC1D,SAAS,WAAAC,UAAS,QAAAC,OAAM,gBAAgB;AAgBjC,SAAS,UAAU,MAA+B;AACvD,SAAO;AAAA,IACL;AAAA,IACA,cAAcC,MAAK,MAAM,WAAW;AAAA,IACpC,eAAeA,MAAK,MAAM,OAAO,SAAS;AAAA,IAC1C,oBAAoBA,MAAK,MAAM,oBAAoB,cAAc;AAAA,IACjE,WAAWA,MAAK,MAAM,aAAa,UAAU;AAAA,IAC7C,SAASA,MAAK,MAAM,aAAa,QAAQ;AAAA,IACzC,UAAUA,MAAK,MAAM,kBAAkB;AAAA,EACzC;AACF;AAUO,IAAM,0BAA6C,CAAC,YAAY,QAAQ;AASxE,SAAS,eAAe,MAAuB;AACpD,QAAM,aAAa,KAAK,QAAQ,OAAO,GAAG;AAC1C,aAAWC,aAAY,yBAAyB;AAC9C,QAAI,eAAe,aAAaA,SAAQ,GAAI,QAAO;AACnD,QAAI,WAAW,SAAS,IAAIA,SAAQ,EAAE,EAAG,QAAO;AAAA,EAClD;AACA,SAAO;AACT;AAEA,eAAsB,kBAAkB,MAAwC;AAC9E,QAAM,SAAS,UAAU,IAAI;AAC7B,QAAMC,OAAM,OAAO,cAAc,EAAE,WAAW,KAAK,CAAC;AACpD,QAAMA,OAAM,OAAO,eAAe,EAAE,WAAW,KAAK,CAAC;AACrD,QAAMA,OAAM,OAAO,UAAU,EAAE,WAAW,KAAK,CAAC;AAChD,QAAM,eAAe,OAAO,WAAW,uBAAuB;AAC9D,QAAM,eAAe,OAAO,SAAS,qBAAqB;AAC1D,QAAM,eAAe,OAAO,oBAAoB,uEAAuE;AACvH,SAAO;AACT;AAEA,eAAsB,mBAAmB,MAAwC;AAC/E,QAAM,SAAS,UAAU,IAAI;AAC7B,QAAM,QAAQ,MAAM,kBAAkB,OAAO,YAAY;AACzD,QAAM,QAAyB,CAAC;AAChC,aAAW,QAAQ,OAAO;AACxB,UAAM,MAAM,SAAS,MAAM,IAAI,EAAE,QAAQ,OAAO,GAAG;AACnD,QAAI,eAAe,GAAG,EAAG;AACzB,UAAM,UAAU,MAAMC,UAAS,MAAM,MAAM;AAC3C,UAAM,EAAE,aAAa,KAAK,IAAI,iBAAiB,OAAO;AACtD,UAAM,QAAQ,YAAY,YAAY,KAAK,KAAK,aAAa,IAAI,KAAK,IAAI,MAAM,GAAG,EAAE,IAAI,EAAG,QAAQ,SAAS,EAAE;AAC/G,UAAM,YAAY,WAAW,YAAY,OAAO;AAChD,UAAM,OAAO,WAAW,YAAY,IAAI;AACxC,UAAM,KAAK;AAAA,MACT,IAAI,YAAY,YAAY,EAAE,KAAK,QAAQ,IAAI,QAAQ,gBAAgB,EAAE,EAAE,QAAQ,SAAS,EAAE,CAAC;AAAA,MAC/F,MAAM;AAAA,MACN;AAAA,MACA,MAAM;AAAA,MACN;AAAA,MACA;AAAA,MACA;AAAA,MACA,UAAU,iBAAiB,IAAI,EAAE,IAAI,mBAAmB;AAAA,IAC1D,CAAC;AAAA,EACH;AACA,QAAM,KAAK,CAAC,GAAG,MAAM,EAAE,KAAK,cAAc,EAAE,IAAI,CAAC;AACjD,SAAO;AACT;AAEA,eAAsB,UAAU,MAAc,OAA+B;AAC3E,QAAMD,OAAME,SAAQ,IAAI,GAAG,EAAE,WAAW,KAAK,CAAC;AAC9C,QAAMC,WAAU,MAAM,KAAK,UAAU,OAAO,MAAM,CAAC,IAAI,MAAM,MAAM;AACrE;AAEA,eAAe,eAAe,MAAc,SAAgC;AAC1E,MAAI;AACF,UAAM,KAAK,IAAI;AAAA,EACjB,QAAQ;AACN,UAAMH,OAAME,SAAQ,IAAI,GAAG,EAAE,WAAW,KAAK,CAAC;AAC9C,UAAMC,WAAU,MAAM,SAAS,MAAM;AAAA,EACvC;AACF;AAEA,eAAe,kBAAkB,MAAiC;AAChE,MAAI;AACF,UAAM,UAAU,MAAM,QAAQ,MAAM,EAAE,eAAe,KAAK,CAAC;AAC3D,UAAM,MAAgB,CAAC;AACvB,eAAW,SAAS,SAAS;AAC3B,YAAM,OAAOL,MAAK,MAAM,MAAM,IAAI;AAClC,UAAI,MAAM,YAAY,EAAG,KAAI,KAAK,GAAG,MAAM,kBAAkB,IAAI,CAAC;AAAA,eACzD,MAAM,OAAO,KAAK,MAAM,KAAK,SAAS,KAAK,EAAG,KAAI,KAAK,IAAI;AAAA,IACtE;AACA,WAAO;AAAA,EACT,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACF;AAEA,SAAS,YAAY,OAAoC;AACvD,SAAO,OAAO,UAAU,YAAY,MAAM,KAAK,MAAM,KAAK,MAAM,KAAK,IAAI;AAC3E;AAEA,SAAS,WAAW,OAA0B;AAC5C,SAAO,MAAM,QAAQ,KAAK,IAAI,MAAM,OAAO,CAAC,SAAyB,OAAO,SAAS,QAAQ,IAAI,CAAC;AACpG;AAEA,SAAS,aAAa,MAAkC;AACtD,SAAO,cAAc,KAAK,IAAI,IAAI,CAAC,GAAG,KAAK;AAC7C;;;ACpIA,SAAS,UAAU,SAAAM,QAAO,YAAAC,WAAU,WAAAC,UAAS,QAAAC,OAAM,aAAAC,kBAAiB;AACpE,SAAS,UAAU,WAAAC,UAAS,QAAAC,OAAM,YAAAC,iBAAgB;AAsBlD,eAAsB,mBAAmB,MAAuC;AAC9E,QAAM,OAAO,mBAAmB,IAAI;AACpC,MAAI;AACF,UAAM,SAAS,KAAK,MAAM,MAAMC,UAAS,MAAM,MAAM,CAAC;AACtD,WAAO;AAAA,MACL,aAAa,OAAO,OAAO,gBAAgB,WAAW,OAAO,eAAc,oBAAI,KAAK,CAAC,GAAE,YAAY;AAAA,MACnG,SAAS,MAAM,QAAQ,OAAO,OAAO,IAAI,OAAO,UAAU,CAAC;AAAA,IAC7D;AAAA,EACF,QAAQ;AACN,WAAO,EAAE,cAAa,oBAAI,KAAK,CAAC,GAAE,YAAY,GAAG,SAAS,CAAC,EAAE;AAAA,EAC/D;AACF;AAEA,eAAsB,oBAAoB,MAAc,UAAyC;AAC/F,QAAM,OAAO,mBAAmB,IAAI;AACpC,QAAMC,OAAMC,SAAQ,IAAI,GAAG,EAAE,WAAW,KAAK,CAAC;AAC9C,QAAMC,WAAU,MAAM,KAAK,UAAU,UAAU,MAAM,CAAC,IAAI,MAAM,MAAM;AACxE;AAEA,eAAsB,cAAc,MAAc,YAAoB,UAA4B,CAAC,GAA4B;AAC7H,QAAM,IAAI,MAAMC,MAAK,UAAU;AAC/B,MAAI,EAAE,YAAY,GAAG;AACnB,UAAM,MAAsB,CAAC;AAC7B,eAAW,QAAQ,MAAM,UAAU,UAAU,GAAG;AAC9C,UAAI,KAAK,GAAG,MAAM,cAAc,MAAM,MAAM,OAAO,CAAC;AAAA,IACtD;AACA,WAAO;AAAA,EACT;AAEA,QAAM,SAAS,UAAU,IAAI;AAC7B,QAAMH,OAAM,OAAO,eAAe,EAAE,WAAW,KAAK,CAAC;AACrD,QAAM,QAAQ,MAAMD,UAAS,UAAU;AACvC,QAAM,cAAc,OAAO,MAAM,SAAS,QAAQ,CAAC;AACnD,QAAM,WAAW,SAAS,UAAU;AACpC,QAAM,WAAW,QAAQ,YAAY,CAAC,iBAAiB;AACvD,QAAM,UAAU,SAAS,KAAK,CAAC,cAAc,UAAU,QAAQ,EAAE,KAAK,YAAY,MAAM,CAAC,CAAC;AAC1F,QAAM,SAAS,UAAU,MAAM,QAAQ,KAAK,EAAE,KAAK,YAAY,MAAM,CAAC,IAAI,CAAC;AAC3E,QAAM,KAAK,SAAS,OAAO,GAAG,WAAW,IAAI,QAAQ,EAAE;AACvD,QAAM,YAAYK,MAAK,OAAO,WAAW,GAAG,QAAQ,SAAS,QAAQ,YAAY,EAAE,CAAC,CAAC,IAAI,YAAY,MAAM,GAAG,CAAC,CAAC,GAAG,IAAI,QAAQ,CAAC,EAAE,EAAE,QAAQ,OAAO,GAAG;AACtJ,QAAM,YAAYA,MAAK,MAAM,SAAS;AAEtC,MAAI,QAAQ,eAAe,MAAM;AAC/B,UAAMJ,OAAMC,SAAQ,SAAS,GAAG,EAAE,WAAW,KAAK,CAAC;AACnD,UAAM,SAAS,YAAY,SAAS;AAAA,EACtC;AAEA,QAAM,WAAW,MAAM,mBAAmB,IAAI;AAC9C,QAAM,SAAuB;AAAA,IAC3B;AAAA,IACA,KAAK;AAAA,IACL,OAAO,OAAO,SAAS;AAAA,IACvB,WAAW,OAAO,aAAaI,cAAa,QAAQ;AAAA,IACpD;AAAA,IACA,MAAM,OAAO,QAAQ,YAAY,UAAU,KAAK;AAAA,IAChD,UAAU,OAAO,WAAW,CAAC,GAAG,IAAI,CAAC,YAAY,EAAE,GAAG,QAAQ,UAAU,GAAG,EAAE;AAAA,IAC7E,YAAY,QAAQ,QAAQ,MAAM,oBAAI,KAAK,IAAI,EAAE,YAAY;AAAA,IAC7D,UAAU;AAAA,MACR,GAAI,OAAO,YAAY,CAAC;AAAA,MACxB,cAAc;AAAA,MACd,WAAW,MAAM;AAAA,MACjB,qBAAqBC,UAAS,MAAM,UAAU,EAAE,QAAQ,OAAO,GAAG;AAAA,IACpE;AAAA,EACF;AACA,QAAM,OAAuB;AAAA,IAC3B,cAAa,oBAAI,KAAK,GAAE,YAAY;AAAA,IACpC,SAAS,CAAC,QAAQ,GAAG,SAAS,QAAQ,OAAO,CAAC,WAAW,OAAO,OAAO,EAAE,CAAC;AAAA,EAC5E;AACA,QAAM,oBAAoB,MAAM,IAAI;AACpC,SAAO,CAAC,MAAM;AAChB;AAEA,eAAsB,cACpB,MACA,OACA,UAAsD,CAAC,GAChC;AACvB,QAAM,OAAO,MAAM;AACnB,QAAM,cAAc,OAAO,IAAI;AAC/B,QAAM,WAAW,SAAS,MAAM,GAAG,KAAK,GAAG,QAAQ,MAAM,SAAS,MAAM,GAAG,CAAC;AAC5E,QAAM,eAAe,EAAE,KAAK,MAAM,KAAK,MAAM,UAAU,MAAM,SAAS;AACtE,QAAM,WAAW,QAAQ,YAAY,CAAC,iBAAiB,GAAG,KAAK,CAAC,cAAc,UAAU,QAAQ,YAAY,CAAC;AAC7G,QAAM,SAAS,UAAU,MAAM,QAAQ,KAAK,YAAY,IAAI,CAAC;AAC7D,QAAM,KAAK,SAAS,OAAO,GAAG,WAAW,IAAI,MAAM,GAAG,EAAE;AACxD,QAAM,YAAYF,MAAK,OAAO,WAAW,GAAG,QAAQ,SAAS,QAAQ,YAAY,EAAE,CAAC,CAAC,IAAI,YAAY,MAAM,GAAG,CAAC,CAAC,MAAM,EAAE,QAAQ,OAAO,GAAG;AAC1I,QAAM,YAAYA,MAAK,MAAM,SAAS;AACtC,QAAMJ,OAAMC,SAAQ,SAAS,GAAG,EAAE,WAAW,KAAK,CAAC;AACnD,QAAMC,WAAU,WAAW,KAAK,SAAS,IAAI,IAAI,OAAO,GAAG,IAAI;AAAA,GAAM,MAAM;AAE3E,QAAM,WAAW,MAAM,mBAAmB,IAAI;AAC9C,QAAM,SAAuB;AAAA,IAC3B;AAAA,IACA,KAAK;AAAA,IACL,OAAO,MAAM,SAAS,OAAO,SAAS;AAAA,IACtC,WAAW,MAAM,aAAa,OAAO,aAAa;AAAA,IAClD;AAAA,IACA,MAAM,OAAO,QAAQ,KAAK,MAAM,GAAG,GAAO;AAAA,IAC1C,UAAU,OAAO,WAAW,CAAC,GAAG,IAAI,CAAC,YAAY,EAAE,GAAG,QAAQ,UAAU,GAAG,EAAE;AAAA,IAC7E,YAAY,MAAM;AAAA,IAClB,gBAAgB,MAAM;AAAA,IACtB,YAAY,QAAQ,QAAQ,MAAM,oBAAI,KAAK,IAAI,EAAE,YAAY;AAAA,IAC7D,UAAU;AAAA,MACR,GAAI,OAAO,YAAY,CAAC;AAAA,MACxB,GAAI,MAAM,YAAY,CAAC;AAAA,MACvB,aAAa,MAAM;AAAA,MACnB,WAAW,OAAO,WAAW,MAAM,MAAM;AAAA,IAC3C;AAAA,EACF;AACA,QAAM,oBAAoB,MAAM;AAAA,IAC9B,cAAa,oBAAI,KAAK,GAAE,YAAY;AAAA,IACpC,SAAS,CAAC,QAAQ,GAAG,SAAS,QAAQ,OAAO,CAAC,WAAW,OAAO,OAAO,EAAE,CAAC;AAAA,EAC5E,CAAC;AACD,SAAO;AACT;AAEO,SAAS,mBAAmB,MAAsB;AACvD,SAAOE,MAAK,UAAU,IAAI,EAAE,UAAU,cAAc;AACtD;AAEA,eAAe,UAAU,MAAiC;AACxD,QAAM,UAAU,MAAMG,SAAQ,MAAM,EAAE,eAAe,KAAK,CAAC;AAC3D,QAAM,MAAgB,CAAC;AACvB,aAAW,SAAS,SAAS;AAC3B,UAAM,OAAOH,MAAK,MAAM,MAAM,IAAI;AAClC,QAAI,MAAM,YAAY,EAAG,KAAI,KAAK,GAAG,MAAM,UAAU,IAAI,CAAC;AAAA,aACjD,MAAM,OAAO,EAAG,KAAI,KAAK,IAAI;AAAA,EACxC;AACA,SAAO;AACT;AAEA,SAAS,IAAI,UAA0B;AACrC,QAAM,MAAM,SAAS,YAAY,GAAG;AACpC,SAAO,OAAO,IAAI,SAAS,MAAM,GAAG,IAAI;AAC1C;AAEA,SAASC,cAAa,UAA0B;AAC9C,QAAM,QAAQ,SAAS,YAAY;AACnC,MAAI,MAAM,SAAS,KAAK,EAAG,QAAO;AAClC,MAAI,MAAM,SAAS,MAAM,EAAG,QAAO;AACnC,MAAI,MAAM,SAAS,OAAO,EAAG,QAAO;AACpC,MAAI,MAAM,SAAS,MAAM,EAAG,QAAO;AACnC,MAAI,MAAM,SAAS,MAAM,EAAG,QAAO;AACnC,SAAO;AACT;AAEA,SAAS,YAAY,UAAkB,OAAmC;AACxE,QAAM,YAAYA,cAAa,QAAQ;AACvC,MAAI,CAAC,UAAU,WAAW,OAAO,KAAK,cAAc,mBAAoB,QAAO;AAC/E,SAAO,MAAM,SAAS,MAAM,EAAE,MAAM,GAAG,GAAO;AAChD;;;ACzKA,IAAM,QAAQ;AACd,IAAM,aAAa,oBAAI,IAAI,CAAC,OAAO,MAAM,KAAK,MAAM,QAAQ,OAAO,OAAO,OAAO,QAAQ,MAAM,OAAO,MAAM,QAAQ,MAAM,MAAM,MAAM,KAAK,CAAC;AAErI,SAAS,gBAAgB,OAAuB,OAAe,QAAQ,IAA6B;AACzG,QAAM,UAAU,MAAM,KAAK;AAC3B,MAAI,YAAY,GAAI,QAAO,CAAC;AAC5B,QAAM,cAAc,aAAa,MAAM,OAAO,OAAO;AACrD,QAAM,cAAc,YAAY,MAAM,OAAO,WAAW;AACxD,QAAM,SAAS,qBAAqB,CAAC,YAAY,IAAI,CAAC,MAAM,EAAE,EAAE,GAAG,YAAY,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;AAChG,QAAM,OAAO,IAAI,IAAI,MAAM,MAAM,IAAI,CAAC,SAAS,CAAC,KAAK,IAAI,IAAI,CAAC,CAAC;AAE/D,QAAM,SAAS,CAAC,GAAG,OAAO,QAAQ,CAAC,EAChC,IAAI,CAAC,CAAC,IAAI,KAAK,OAAO,EAAE,MAAM,KAAK,IAAI,EAAE,GAAG,MAAM,EAAE,EACpD,OAAO,CAAC,SAAyD,QAAQ,KAAK,IAAI,CAAC,EACnF,KAAK,CAAC,GAAG,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,KAAK,cAAc,EAAE,KAAK,IAAI,CAAC,EAC1E,MAAM,GAAG,KAAK;AAMjB,QAAM,WAAW,OAAO,CAAC,GAAG,SAAS;AAErC,SAAO,OAAO,IAAI,CAAC,MAAM,OAAO;AAAA,IAC9B,MAAM,KAAK;AAAA,IACX,OAAO,KAAK;AAAA,IACZ,UAAU,KAAK;AAAA,IACf,iBAAiB,WAAW,IAAI,KAAK,QAAQ,WAAW;AAAA,IACxD,MAAM,IAAI;AAAA,IACV,SAAS,aAAa,KAAK,KAAK,MAAM,OAAO;AAAA,IAC7C,SAAS,WAAW,KAAK,MAAM,OAAO;AAAA,EACxC,EAAE;AACJ;AAEO,SAAS,cAAc,OAAyB;AACrD,QAAM,MAAM,MACT,YAAY,EACZ,MAAM,iCAAiC,EACvC,OAAO,CAAC,UAAU,MAAM,SAAS,KAAK,CAAC,WAAW,IAAI,KAAK,CAAC;AAC/D,QAAM,SAAmB,CAAC;AAC1B,aAAW,SAAS,KAAK;AACvB,QAAI,+BAA+B,KAAK,KAAK,KAAK,MAAM,SAAS,GAAG;AAClE,YAAM,QAAQ,CAAC,GAAG,KAAK;AACvB,eAAS,IAAI,GAAG,IAAI,MAAM,SAAS,GAAG,IAAK,QAAO,KAAK,MAAM,CAAC,IAAK,MAAM,IAAI,CAAC,CAAE;AAChF,aAAO,KAAK,GAAG,KAAK;AAAA,IACtB;AACA,WAAO,KAAK,KAAK;AAAA,EACnB;AACA,SAAO,CAAC,GAAG,IAAI,IAAI,MAAM,CAAC;AAC5B;AAEO,SAAS,qBAAqB,WAAuB,IAAI,OAA4B;AAC1F,QAAM,SAAS,oBAAI,IAAoB;AACvC,aAAW,QAAQ,WAAW;AAC5B,SAAK,QAAQ,CAAC,IAAI,QAAQ;AACxB,aAAO,IAAI,KAAK,OAAO,IAAI,EAAE,KAAK,KAAK,KAAK,IAAI,MAAM,EAAE;AAAA,IAC1D,CAAC;AAAA,EACH;AACA,SAAO;AACT;AAEA,SAAS,aAAa,OAAwB,OAAgC;AAC5E,QAAM,SAAS,cAAc,KAAK;AAClC,QAAM,YAAY,OAAO,SAAS,IAAI,SAAS,CAAC,MAAM,YAAY,CAAC;AACnE,SAAO,MACJ,IAAI,CAAC,UAAU,EAAE,MAAM,OAAO,WAAW,MAAM,OAAO,SAAS,EAAE,EAAE,EACnE,OAAO,CAAC,SAAS,KAAK,QAAQ,CAAC,EAC/B,KAAK,CAAC,GAAG,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,KAAK,cAAc,EAAE,KAAK,IAAI,CAAC,EAC1E,IAAI,CAAC,SAAS,KAAK,IAAI;AAC5B;AAEA,SAAS,YAAY,OAAwB,aAA+C;AAC1F,MAAI,YAAY,WAAW,EAAG,QAAO,CAAC;AACtC,QAAM,QAAQ,IAAI,IAAI,YAAY,MAAM,GAAG,CAAC,EAAE,IAAI,CAAC,SAAS,KAAK,EAAE,CAAC;AACpE,SAAO,MACJ,IAAI,CAAC,UAAU;AAAA,IACd;AAAA,IACA,OAAO,KAAK,SAAS,OAAO,CAAC,SAAS,MAAM,IAAI,IAAI,CAAC,EAAE,SAAS,KAAK,UAAU,OAAO,CAAC,WAAW,YAAY,KAAK,CAAC,SAAS,KAAK,UAAU,SAAS,MAAM,CAAC,CAAC,EAAE;AAAA,EACjK,EAAE,EACD,OAAO,CAAC,SAAS,KAAK,QAAQ,CAAC,EAC/B,KAAK,CAAC,GAAG,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,KAAK,cAAc,EAAE,KAAK,IAAI,CAAC,EAC1E,IAAI,CAAC,SAAS,KAAK,IAAI;AAC5B;AAEA,SAAS,WAAW,MAAqB,OAAe,QAA0B;AAChF,QAAM,QAAQ,KAAK,MAAM,YAAY;AACrC,QAAM,OAAO,KAAK,KAAK,YAAY;AACnC,QAAM,OAAO,KAAK,KAAK,YAAY;AACnC,QAAM,SAAS,MAAM,YAAY;AACjC,MAAI,QAAQ;AACZ,MAAI,KAAK,SAAS,GAAG,MAAM,KAAK,KAAK,UAAU,OAAQ,UAAS;AAChE,MAAI,MAAM,SAAS,MAAM,EAAG,UAAS;AACrC,MAAI,KAAK,SAAS,MAAM,EAAG,UAAS;AACpC,aAAW,SAAS,QAAQ;AAC1B,QAAI,MAAM,SAAS,KAAK,EAAG,UAAS;AACpC,QAAI,KAAK,SAAS,KAAK,EAAG,UAAS;AACnC,QAAI,KAAK,SAAS,KAAK,EAAG,UAAS;AAAA,EACrC;AACA,SAAO;AACT;AAEA,SAAS,aAAa,MAAc,OAAuB;AACzD,QAAM,UAAU,KAAK,QAAQ,QAAQ,GAAG,EAAE,KAAK;AAC/C,QAAM,MAAM,QAAQ,YAAY,EAAE,QAAQ,MAAM,YAAY,CAAC;AAC7D,MAAI,MAAM,EAAG,QAAO,QAAQ,MAAM,GAAG,GAAG;AACxC,SAAO,QAAQ,MAAM,KAAK,IAAI,GAAG,MAAM,EAAE,GAAG,KAAK,IAAI,QAAQ,QAAQ,MAAM,MAAM,SAAS,GAAG,CAAC;AAChG;AAEA,SAAS,WAAW,MAAqB,OAAyB;AAChE,QAAM,QAAQ,GAAG,KAAK,KAAK;AAAA,EAAK,KAAK,IAAI,GAAG,YAAY;AACxD,QAAM,UAAoB,CAAC;AAC3B,MAAI,MAAM,SAAS,MAAM,YAAY,CAAC,EAAG,SAAQ,KAAK,QAAQ;AAC9D,MAAI,KAAK,UAAU,SAAS,EAAG,SAAQ,KAAK,SAAS;AACrD,MAAI,KAAK,SAAS,SAAS,EAAG,SAAQ,KAAK,QAAQ;AACnD,SAAO;AACT;;;ACrHA,SAAS,QAAAG,aAAY;AAMrB,eAAsB,oBAAoB,MAAuC;AAC/E,QAAM,CAAC,OAAO,cAAc,IAAI,MAAM,QAAQ,IAAI;AAAA,IAChD,mBAAmB,IAAI;AAAA,IACvB,mBAAmB,IAAI;AAAA,EACzB,CAAC;AACD,QAAM,QAAwB;AAAA,IAC5B;AAAA,IACA,cAAa,oBAAI,KAAK,GAAE,YAAY;AAAA,IACpC,SAAS,eAAe;AAAA,IACxB;AAAA,IACA,OAAO,oBAAoB,KAAK;AAAA,EAClC;AACA,SAAO;AACT;AAEA,eAAsB,oBAAoB,MAAuC;AAC/E,QAAM,QAAQ,MAAM,oBAAoB,IAAI;AAC5C,QAAM,UAAUC,MAAK,UAAU,IAAI,EAAE,UAAU,YAAY,GAAG,KAAK;AACnE,SAAO;AACT;;;ACtBO,SAAS,mBAAmB,OAA+C;AAChF,QAAM,WAAmC,CAAC;AAC1C,QAAM,WAAW,oBAAI,IAAY;AACjC,QAAM,SAAS,oBAAI,IAAsB;AACzC,QAAM,YAAY,IAAI,IAAI,MAAM,QAAQ,IAAI,CAAC,WAAW,OAAO,EAAE,CAAC;AAClE,QAAM,YAAY,IAAI,IAAI,MAAM,QAAQ,IAAI,CAAC,WAAW,CAAC,OAAO,IAAI,IAAI,KAAK,OAAO,WAAW,CAAC,GAAG,IAAI,CAAC,WAAW,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC;AAChI,QAAM,UAAU,oBAAI,IAAsB;AAC1C,QAAM,eAAe,oBAAI,IAAsB;AAC/C,aAAW,QAAQ,MAAM,OAAO;AAC9B,YAAQ,IAAI,KAAK,IAAI,CAAC,GAAI,QAAQ,IAAI,KAAK,EAAE,KAAK,CAAC,GAAI,KAAK,IAAI,CAAC;AACjE,aAAS,IAAI,oBAAoB,KAAK,EAAE,CAAC;AACzC,aAAS,IAAI,oBAAoB,KAAK,KAAK,CAAC;AAC5C,aAAS,IAAI,oBAAoB,KAAK,KAAK,MAAM,GAAG,EAAE,IAAI,EAAG,QAAQ,SAAS,EAAE,CAAC,CAAC;AAClF,UAAM,WAAW,KAAK,MAAM,YAAY;AACxC,WAAO,IAAI,UAAU,CAAC,GAAI,OAAO,IAAI,QAAQ,KAAK,CAAC,GAAI,KAAK,IAAI,CAAC;AAAA,EACnE;AACA,aAAW,UAAU,MAAM,SAAS;AAClC,iBAAa,IAAI,OAAO,aAAa,CAAC,GAAI,aAAa,IAAI,OAAO,WAAW,KAAK,CAAC,GAAI,OAAO,EAAE,CAAC;AAAA,EACnG;AAEA,QAAM,UAAU,oBAAI,IAAoB;AACxC,aAAW,QAAQ,MAAM,MAAO,SAAQ,IAAI,KAAK,IAAI,CAAC;AACtD,aAAW,QAAQ,MAAM,OAAO;AAC9B,QAAI,KAAK,SAAS,WAAW,KAAK,CAAC,aAAa,KAAK,IAAI,GAAG;AAC1D,eAAS,KAAK,EAAE,MAAM,eAAe,UAAU,QAAQ,MAAM,KAAK,MAAM,SAAS,kDAAkD,CAAC;AAAA,IACtI;AACA,eAAW,QAAQ,KAAK,UAAU;AAChC,UAAI,CAAC,SAAS,IAAI,oBAAoB,IAAI,CAAC,GAAG;AAC5C,iBAAS,KAAK,EAAE,MAAM,eAAe,UAAU,WAAW,MAAM,KAAK,MAAM,SAAS,qBAAqB,IAAI,MAAM,CAAC;AAAA,MACtH;AAAA,IACF;AAAA,EACF;AAEA,aAAW,QAAQ,MAAM,MAAM,MAAO,SAAQ,IAAI,KAAK,SAAS,QAAQ,IAAI,KAAK,MAAM,KAAK,KAAK,CAAC;AAClG,aAAW,QAAQ,MAAM,OAAO;AAC9B,QAAI,CAAC,aAAa,KAAK,IAAI,MAAM,QAAQ,IAAI,KAAK,EAAE,KAAK,OAAO,GAAG;AACjE,eAAS,KAAK,EAAE,MAAM,UAAU,UAAU,QAAQ,MAAM,KAAK,MAAM,SAAS,oCAAoC,CAAC;AAAA,IACnH;AACA,QAAI,aAAa,KAAK,KAAK,IAAI,KAAK,KAAK,UAAU,WAAW,GAAG;AAC/D,eAAS,KAAK,EAAE,MAAM,iBAAiB,UAAU,WAAW,MAAM,KAAK,MAAM,SAAS,iEAAiE,CAAC;AAAA,IAC1J;AACA,eAAW,YAAY,KAAK,WAAW;AACrC,UAAI,CAAC,UAAU,IAAI,QAAQ,GAAG;AAC5B,iBAAS,KAAK,EAAE,MAAM,kBAAkB,UAAU,SAAS,MAAM,KAAK,MAAM,SAAS,8BAA8B,QAAQ,MAAM,UAAU,EAAE,SAAS,EAAE,CAAC;AAAA,MAC3J;AAAA,IACF;AACA,eAAW,OAAO,kBAAkB,KAAK,IAAI,GAAG;AAC9C,UAAI,CAAC,UAAU,IAAI,IAAI,QAAQ,GAAG;AAChC,iBAAS,KAAK,EAAE,MAAM,kBAAkB,UAAU,SAAS,MAAM,KAAK,MAAM,SAAS,8BAA8B,IAAI,QAAQ,MAAM,UAAU,IAAI,CAAC;AAAA,MACtJ,WAAW,IAAI,YAAY,CAAE,UAAU,IAAI,IAAI,QAAQ,GAAG,IAAI,IAAI,QAAQ,GAAI;AAC5E,iBAAS,KAAK,EAAE,MAAM,kBAAkB,UAAU,SAAS,MAAM,KAAK,MAAM,SAAS,qCAAqC,IAAI,QAAQ,IAAI,IAAI,QAAQ,MAAM,UAAU,IAAI,CAAC;AAAA,MAC7K;AAAA,IACF;AAAA,EACF;AAEA,aAAW,CAAC,OAAO,KAAK,KAAK,QAAQ;AACnC,QAAI,SAAS,MAAM,SAAS,GAAG;AAC7B,eAAS,KAAK,EAAE,MAAM,mBAAmB,UAAU,WAAW,SAAS,oBAAoB,KAAK,QAAQ,MAAM,KAAK,IAAI,CAAC,KAAK,UAAU,EAAE,MAAM,EAAE,CAAC;AAAA,IACpJ;AAAA,EACF;AACA,aAAW,CAAC,IAAI,KAAK,KAAK,SAAS;AACjC,QAAI,MAAM,MAAM,SAAS,GAAG;AAC1B,eAAS,KAAK,EAAE,MAAM,qBAAqB,UAAU,SAAS,SAAS,sBAAsB,EAAE,QAAQ,MAAM,KAAK,IAAI,CAAC,KAAK,UAAU,EAAE,MAAM,EAAE,CAAC;AAAA,IACnJ;AAAA,EACF;AACA,aAAW,CAAC,MAAM,GAAG,KAAK,cAAc;AACtC,QAAI,QAAQ,IAAI,SAAS,GAAG;AAC1B,eAAS,KAAK,EAAE,MAAM,yBAAyB,UAAU,WAAW,SAAS,wCAAwC,IAAI,KAAK,IAAI,CAAC,KAAK,UAAU,EAAE,WAAW,IAAI,EAAE,CAAC;AAAA,IACxK;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,aAAa,MAAuB;AAC3C,SAAO,KAAK,SAAS,WAAW,KAAK,KAAK,SAAS,SAAS,KAAK,SAAS,wBAAwB,SAAS;AAC7G;AAEA,SAAS,kBAAkB,MAA8D;AACvF,QAAM,OAAuD,CAAC;AAC9D,QAAM,QAAQ;AACd,MAAI;AACJ,UAAQ,QAAQ,MAAM,KAAK,IAAI,OAAO,MAAM;AAC1C,SAAK,KAAK,EAAE,UAAU,MAAM,CAAC,GAAI,UAAU,MAAM,CAAC,EAAE,CAAC;AAAA,EACvD;AACA,SAAO;AACT;;;AC9DO,SAAS,sBAAsB,OAAuB,UAA0B,CAAC,GAAwB;AAC9G,QAAM,MAAM,QAAQ,OAAO,oBAAI,KAAK;AACpC,QAAM,WAAW,mBAAmB,KAAK;AACzC,QAAM,SAAS,IAAI,IAAI,MAAM,MAAM,MAAM,IAAI,CAAC,SAAS,CAAC,KAAK,IAAI,KAAK,WAAW,KAAK,SAAS,CAAC,CAAC;AACjG,QAAM,kBAAkB,MAAM,QAAQ,IAAI,CAAC,WAAW,uBAAuB,QAAQ,GAAG,CAAC;AACzF,SAAO;AAAA,IACL,WAAW,MAAM,MAAM;AAAA,IACvB,aAAa,MAAM,QAAQ;AAAA,IAC3B,oBAAoB,gBAAgB,OAAO,CAAC,WAAW,OAAO,WAAW,SAAS,EAAE;AAAA,IACpF,kBAAkB,gBAAgB,OAAO,CAAC,WAAW,OAAO,WAAW,OAAO,EAAE;AAAA,IAChF,WAAW,MAAM,MAAM,MAAM;AAAA,IAC7B,cAAc,SAAS;AAAA,IACvB,sBAAsB,SAAS,OAAO,CAAC,YAAY,QAAQ,aAAa,OAAO,EAAE;AAAA,IACjF,UAAU,CAAC,GAAG,MAAM,KAAK,EACtB,KAAK,CAAC,GAAG,OAAO,OAAO,IAAI,EAAE,EAAE,KAAK,MAAM,OAAO,IAAI,EAAE,EAAE,KAAK,EAAE,EAChE,MAAM,GAAG,EAAE,EACX,IAAI,CAAC,UAAU,EAAE,MAAM,KAAK,MAAM,OAAO,KAAK,OAAO,QAAQ,OAAO,IAAI,KAAK,EAAE,KAAK,GAAG,SAAS,KAAK,UAAU,OAAO,EAAE;AAAA,IAC3H;AAAA,IACA;AAAA,EACF;AACF;AAEA,SAAS,uBAAuB,QAA2C,KAAsC;AAC/G,QAAM,aAAa,OAAO,cAAc,eAAe,OAAO,UAAU,YAAY,KAAK,eAAe,OAAO,UAAU,WAAW;AACpI,QAAM,iBAAiB,OAAO,kBAAkB,eAAe,OAAO,UAAU,gBAAgB;AAChG,QAAM,SAAS,cAAc,OAAO,SAAS,KAAK,MAAM,UAAU,CAAC,IAC/D,KAAK,MAAM,UAAU,KAAK,IAAI,QAAQ,IAAI,YAAY,UACtD;AACJ,SAAO,EAAE,IAAI,OAAO,IAAI,OAAO,OAAO,OAAO,KAAK,OAAO,KAAK,QAAQ,YAAY,eAAe;AACnG;AAEA,SAAS,eAAe,UAA+C,KAAiC;AACtG,QAAM,QAAQ,WAAW,GAAG;AAC5B,SAAO,OAAO,UAAU,WAAW,QAAQ;AAC7C;AAWO,SAAS,uBAAuB,OAAuB,QAAsC;AAClG,QAAM,OAAO,MAAM,MAAM,KAAK,CAAC,cAAc,UAAU,SAAS,UAAU,UAAU,OAAO,UAAU,UAAU,MAAM,YAAY,MAAM,OAAO,YAAY,CAAC;AAC3J,QAAM,UAAU,OACZ,MAAM,MAAM,MAAM,OAAO,CAAC,SAAS,KAAK,WAAW,KAAK,EAAE,EAAE,IAAI,CAAC,SAAS,MAAM,MAAM,KAAK,CAAC,cAAc,UAAU,OAAO,KAAK,MAAM,GAAG,QAAQ,KAAK,MAAM,IAC5J,CAAC;AACL,QAAM,UAAU,OACZ,gBAAgB,OAAO,GAAG,KAAK,KAAK,IAAI,KAAK,KAAK,KAAK,GAAG,CAAC,IAAI,CAAC,EAC7D,OAAO,CAAC,WAAW,OAAO,KAAK,OAAO,KAAK,EAAE,EAC7C,IAAI,CAAC,YAAY,EAAE,MAAM,OAAO,KAAK,MAAM,OAAO,OAAO,KAAK,OAAO,OAAO,OAAO,MAAM,EAAE,IAC9F,gBAAgB,OAAO,QAAQ,CAAC,EAAE,IAAI,CAAC,YAAY,EAAE,MAAM,OAAO,KAAK,MAAM,OAAO,OAAO,KAAK,OAAO,OAAO,OAAO,MAAM,EAAE;AACjI,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,SAAS,OAAO,MAAM,QAAQ,OAAO,CAAC,WAAW,KAAK,UAAU,SAAS,OAAO,EAAE,CAAC,EAAE,IAAI,CAAC,YAAY,EAAE,IAAI,OAAO,IAAI,OAAO,OAAO,OAAO,KAAK,OAAO,IAAI,EAAE,IAAI,CAAC;AAAA,IACnK,OAAO,MAAM,YAAY,CAAC;AAAA,IAC1B;AAAA,IACA;AAAA,EACF;AACF;;;AC5EO,SAAS,uBAAuB,OAAuB,UAAoC,CAAC,GAA4B;AAC7H,QAAM,WAAW,CAAC,GAAG,mBAAmB,KAAK,CAAC;AAC9C,QAAM,SAAS,qBAAqB,UAAU,KAAK;AACnD,MAAI,CAAC,OAAO,SAAS;AACnB,aAAS,KAAK;AAAA,MACZ,MAAM;AAAA,MACN,UAAU;AAAA,MACV,SAAS,OAAO,MAAM,OAAO,IAAI,CAAC,UAAU,GAAG,MAAM,KAAK,KAAK,GAAG,CAAC,KAAK,MAAM,OAAO,EAAE,EAAE,KAAK,IAAI;AAAA,IACpG,CAAC;AAAA,EACH;AACA,MAAI,QAAQ,QAAQ;AAClB,eAAW,QAAQ,MAAM,OAAO;AAC9B,UAAI,iBAAiB,KAAK,IAAI,EAAG;AACjC,UAAI,CAAC,KAAK,YAAY,MAAM,CAAC,KAAK,YAAY,OAAO;AACnD,iBAAS,KAAK;AAAA,UACZ,MAAM;AAAA,UACN,UAAU;AAAA,UACV,MAAM,KAAK;AAAA,UACX,SAAS;AAAA,QACX,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AACA,SAAO,EAAE,IAAI,CAAC,SAAS,KAAK,CAAC,YAAY,QAAQ,aAAa,OAAO,GAAG,SAAS;AACnF;AAEA,SAAS,iBAAiB,MAAuB;AAC/C,SAAO,SAAS,wBAAwB,SAAS,sBAAsB,KAAK,SAAS,WAAW,KAAK,KAAK,SAAS,SAAS;AAC9H;","names":["mkdir","readFile","writeFile","dirname","join","join","basename","mkdir","readFile","dirname","writeFile","mkdir","readFile","readdir","stat","writeFile","dirname","join","relative","readFile","mkdir","dirname","writeFile","stat","join","mediaTypeFor","relative","readdir","join","join"]}
package/dist/cli.js CHANGED
@@ -11,7 +11,7 @@ import {
11
11
  searchKnowledge,
12
12
  validateKnowledgeIndex,
13
13
  writeKnowledgeIndex
14
- } from "./chunk-BEFAI2HO.js";
14
+ } from "./chunk-JLCQ6O7W.js";
15
15
  import {
16
16
  detectKnowledgeGaps,
17
17
  findSurprisingConnections,
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
- import { c as KnowledgeWriteParseResult, S as SourceRecord, d as KnowledgeEventType, e as KnowledgeEvent, f as KnowledgePage, g as KnowledgeIndex, h as SourceRegistry, b as KnowledgeGraph, i as KnowledgeSearchResult, j as KnowledgeLintFinding, k as KnowledgeBaseCandidate, l as KnowledgeRelease } from './types-CWbf3JSE.js';
2
- export { C as ClaimRef, m as KnowledgeClaim, K as KnowledgeGraphEdge, a as KnowledgeGraphNode, n as KnowledgeId, o as KnowledgePolicy, p as KnowledgeRelation, q as KnowledgeUnit, r as KnowledgeWriteBlock, s as SourceAnchor } from './types-CWbf3JSE.js';
1
+ import { c as KnowledgeWriteParseResult, S as SourceRecord, d as KnowledgeEventType, e as KnowledgeEvent, f as KnowledgePage, g as KnowledgeIndex, h as SourceRegistry, b as KnowledgeGraph, i as KnowledgeSearchResult, j as KnowledgeLintFinding, k as KnowledgeBaseCandidate, l as KnowledgeRelease } from './types-DTUp66Gr.js';
2
+ export { C as ClaimRef, m as KnowledgeClaim, K as KnowledgeGraphEdge, a as KnowledgeGraphNode, n as KnowledgeId, o as KnowledgePolicy, p as KnowledgeRelation, q as KnowledgeUnit, r as KnowledgeWriteBlock, s as SourceAnchor } from './types-DTUp66Gr.js';
3
3
  import { z } from 'zod';
4
- import { MultiShotVariant, MultiShotOptimizationConfig, MultiShotRunner, MultiShotScorer, MultiShotMutateAdapter, MultiShotOptimizationResult, ReleaseConfidenceScorecard, RunRecord, KnowledgeRequirementCategory, KnowledgeAcquisitionMode, KnowledgeImportance, KnowledgeFreshness, KnowledgeSensitivity, KnowledgeRequirement, KnowledgeBundle, KnowledgeReadinessReport, UserQuestion, DataAcquisitionPlan } from '@tangle-network/agent-eval';
4
+ import { MultiShotVariant, MultiShotOptimizationConfig, MultiShotRunner, MultiShotScorer, MultiShotMutateAdapter, MultiShotOptimizationResult, ReleaseConfidenceScorecard, RunRecord, KnowledgeRequirementCategory, KnowledgeAcquisitionMode, KnowledgeImportance, KnowledgeFreshness, KnowledgeSensitivity, KnowledgeRequirement, KnowledgeBundle, KnowledgeReadinessReport, UserQuestion, DataAcquisitionPlan, ControlRuntimeConfig, ControlEvalResult } from '@tangle-network/agent-eval';
5
5
 
6
6
  declare function sha256(text: string): string;
7
7
  declare function slugify(input: string): string;
@@ -354,9 +354,19 @@ interface AddSourceOptions {
354
354
  adapters?: SourceAdapter[];
355
355
  now?: () => Date;
356
356
  }
357
+ interface AddSourceTextInput {
358
+ uri: string;
359
+ text: string;
360
+ title?: string;
361
+ mediaType?: string;
362
+ validUntil?: string;
363
+ lastVerifiedAt?: string;
364
+ metadata?: Record<string, unknown>;
365
+ }
357
366
  declare function loadSourceRegistry(root: string): Promise<SourceRegistry>;
358
367
  declare function writeSourceRegistry(root: string, registry: SourceRegistry): Promise<void>;
359
368
  declare function addSourcePath(root: string, sourcePath: string, options?: AddSourceOptions): Promise<SourceRecord[]>;
369
+ declare function addSourceText(root: string, input: AddSourceTextInput, options?: Pick<AddSourceOptions, 'adapters' | 'now'>): Promise<SourceRecord>;
360
370
  declare function sourceRegistryPath(root: string): string;
361
371
 
362
372
  declare function buildKnowledgeGraph(pages: KnowledgePage[]): KnowledgeGraph;
@@ -373,6 +383,8 @@ declare function lintKnowledgeIndex(index: KnowledgeIndex): KnowledgeLintFinding
373
383
  interface KnowledgeInspection {
374
384
  pageCount: number;
375
385
  sourceCount: number;
386
+ expiredSourceCount: number;
387
+ staleSourceCount: number;
376
388
  edgeCount: number;
377
389
  findingCount: number;
378
390
  blockingFindingCount: number;
@@ -382,9 +394,20 @@ interface KnowledgeInspection {
382
394
  degree: number;
383
395
  sources: number;
384
396
  }>;
397
+ sourceFreshness: SourceFreshnessInspection[];
385
398
  findings: KnowledgeLintFinding[];
386
399
  }
387
- declare function inspectKnowledgeIndex(index: KnowledgeIndex): KnowledgeInspection;
400
+ interface SourceFreshnessInspection {
401
+ id: string;
402
+ title?: string;
403
+ uri: string;
404
+ status: 'fresh' | 'expired' | 'unknown';
405
+ validUntil?: string;
406
+ lastVerifiedAt?: string;
407
+ }
408
+ declare function inspectKnowledgeIndex(index: KnowledgeIndex, options?: {
409
+ now?: Date;
410
+ }): KnowledgeInspection;
388
411
  interface KnowledgeExplanation {
389
412
  target: string;
390
413
  page?: KnowledgePage;
@@ -454,6 +477,61 @@ interface KnowledgeReadinessSpec {
454
477
  minHits?: number;
455
478
  metadata?: Record<string, unknown>;
456
479
  }
480
+ /**
481
+ * Defaults applied by `defineReadinessSpec` when the caller omits the field.
482
+ *
483
+ * These are deliberately conservative: a domain-specific topic that an agent
484
+ * needs grounded to a high-confidence threshold from at least one authoritative
485
+ * source. Override any field to specialise (e.g. `freshness: 'daily'` for a
486
+ * topic that must reflect today's regulatory state).
487
+ */
488
+ declare const READINESS_SPEC_DEFAULTS: {
489
+ readonly category: "domain_specific";
490
+ readonly acquisitionMode: "search_web";
491
+ readonly importance: "high";
492
+ readonly freshness: "monthly";
493
+ readonly sensitivity: "public";
494
+ readonly confidenceNeeded: 0.7;
495
+ readonly minSources: 1;
496
+ readonly minHits: 2;
497
+ };
498
+ /**
499
+ * Inputs accepted by `defineReadinessSpec`. The four fields the caller cannot
500
+ * sanely default (id, description, query, requiredFor) are required; everything
501
+ * else is optional and pulls from `READINESS_SPEC_DEFAULTS`.
502
+ */
503
+ type DefineReadinessSpecInput = Pick<KnowledgeReadinessSpec, 'id' | 'description' | 'query' | 'requiredFor'> & Partial<Omit<KnowledgeReadinessSpec, 'id' | 'description' | 'query' | 'requiredFor'>>;
504
+ /**
505
+ * Builder that returns a fully-typed `KnowledgeReadinessSpec` from a slim input.
506
+ *
507
+ * Motivation: `KnowledgeReadinessSpec` has eleven required fields. Most of them
508
+ * (category, acquisition mode, importance, freshness, sensitivity, confidence
509
+ * threshold, source/hit minima) have a clear default for domain-specific KB
510
+ * topics — agents end up copy-pasting the same boilerplate across every spec.
511
+ * This helper collapses that boilerplate while keeping every field overridable.
512
+ *
513
+ * @example
514
+ * defineReadinessSpec({
515
+ * id: 'coop/intent-grounding',
516
+ * description: 'Required grounding for coop pack intent stage',
517
+ * query: 'flock size space ventilation predator',
518
+ * requiredFor: ['IntentIntakeAgent', 'requirements'],
519
+ * })
520
+ *
521
+ * @example // override defaults where the topic demands it
522
+ * defineReadinessSpec({
523
+ * id: 'medical/dosing',
524
+ * description: 'Dosing guidance for compounding pharmacy',
525
+ * query: 'compounding dose schedule',
526
+ * requiredFor: ['DosingAgent'],
527
+ * importance: 'blocking',
528
+ * freshness: 'daily',
529
+ * sensitivity: 'private',
530
+ * confidenceNeeded: 0.95,
531
+ * minSources: 3,
532
+ * })
533
+ */
534
+ declare function defineReadinessSpec(input: DefineReadinessSpecInput): KnowledgeReadinessSpec;
457
535
  interface BuildEvalKnowledgeBundleOptions {
458
536
  taskId: string;
459
537
  index: KnowledgeIndex;
@@ -461,6 +539,7 @@ interface BuildEvalKnowledgeBundleOptions {
461
539
  userAnswers?: Record<string, string>;
462
540
  searchLimit?: number;
463
541
  metadata?: Record<string, unknown>;
542
+ now?: Date;
464
543
  }
465
544
  interface EvalKnowledgeBundleBuildResult {
466
545
  bundle: KnowledgeBundle;
@@ -472,4 +551,101 @@ interface EvalKnowledgeBundleBuildResult {
472
551
  }
473
552
  declare function buildEvalKnowledgeBundle(options: BuildEvalKnowledgeBundleOptions): EvalKnowledgeBundleBuildResult;
474
553
 
475
- export { type AddSourceOptions, type ApplyWriteBlocksResult, type BuildEvalKnowledgeBundleOptions, type ChunkingOptions, type DiscoveryResult, type DiscoveryTask, type EvalKnowledgeBundleBuildResult, FileSystemKbStore, type KbStore, KnowledgeBaseCandidate, KnowledgeBaseCandidateSchema, type KnowledgeBaseVariant, type KnowledgeChunk, type KnowledgeDiscoveryDispatcher, type KnowledgeDiscoveryWorker, KnowledgeEvent, type KnowledgeEventQuery, KnowledgeEventSchema, KnowledgeEventType, type KnowledgeExplanation, KnowledgeGraph, KnowledgeGraphEdgeSchema, KnowledgeGraphNodeSchema, KnowledgeIndex, KnowledgeIndexSchema, type KnowledgeInspection, type KnowledgeLayout, KnowledgeLintFinding, type KnowledgeOptimizationConfig, KnowledgePage, KnowledgePageSchema, type KnowledgeReadinessSpec, KnowledgeRelease, type KnowledgeReleaseReport, KnowledgeSearchResult, KnowledgeWriteParseResult, MemoryKbStore, type ParsedFrontmatter, SCAFFOLD_PAGE_BASENAMES, type SourceAdapter, type SourceAdapterInput, type SourceAdapterOutput, SourceAnchorSchema, SourceRecord, SourceRecordSchema, SourceRegistry, type ValidateKnowledgeOptions, type ValidateKnowledgeResult, WIKILINK_REGEX, addSourcePath, applyKnowledgeWriteBlocks, applyKnowledgeWriteBlocksFile, buildEvalKnowledgeBundle, buildKnowledgeGraph, buildKnowledgeIndex, chunkMarkdown, createKnowledgeEvent, createLocalDiscoveryDispatcher, explainKnowledgeTarget, extractWikilinks, formatFrontmatter, initKnowledgeBase, inspectKnowledgeIndex, isSafeKnowledgePath, isScaffoldPath, knowledgeReleaseReportFromOptimization, knowledgeVariantFromCandidate, layoutFor, lintKnowledgeIndex, loadKnowledgePages, loadSourceRegistry, mediaTypeFor, normalizeLinkTarget, parseFrontmatter, parseKnowledgeWriteBlocks, reciprocalRankFusion, runKnowledgeBaseOptimization, searchKnowledge, sha256, slugify, sourceRegistryPath, stableId, stripFrontmatter, textSourceAdapter, tokenizeQuery, validateKnowledgeIndex, writeJson, writeKnowledgeIndex, writeSourceRegistry };
554
+ interface KnowledgeResearchLoopContext {
555
+ root: string;
556
+ goal: string;
557
+ iteration: number;
558
+ index: KnowledgeIndex;
559
+ lintFindings: KnowledgeLintFinding[];
560
+ validation: ValidateKnowledgeResult;
561
+ readiness?: EvalKnowledgeBundleBuildResult;
562
+ previousSteps: KnowledgeResearchLoopStep[];
563
+ signal?: AbortSignal;
564
+ }
565
+ interface KnowledgeResearchLoopDecision {
566
+ /**
567
+ * Free-form notes from the researcher. Keep this human-readable; products can
568
+ * store it as the research transcript.
569
+ */
570
+ notes?: string;
571
+ /**
572
+ * Local files to register as immutable sources before applying proposals.
573
+ */
574
+ sourcePaths?: string[];
575
+ /**
576
+ * Textual source artifacts discovered by an agent, browser worker, connector,
577
+ * or deep-research process.
578
+ */
579
+ sourceTexts?: AddSourceTextInput[];
580
+ /**
581
+ * Safe write protocol text. The loop parses and applies only accepted
582
+ * `---FILE: knowledge/...---` blocks.
583
+ */
584
+ proposalText?: string;
585
+ /**
586
+ * The researcher decides when the wiki is good enough. The loop deliberately
587
+ * does not encode a domain-specific definition of "done".
588
+ */
589
+ done?: boolean;
590
+ metadata?: Record<string, unknown>;
591
+ }
592
+ interface KnowledgeResearchLoopStep {
593
+ iteration: number;
594
+ notes?: string;
595
+ addedSources: SourceRecord[];
596
+ applied?: ApplyWriteBlocksResult;
597
+ lintFindings: KnowledgeLintFinding[];
598
+ validation: ValidateKnowledgeResult;
599
+ readiness?: EvalKnowledgeBundleBuildResult;
600
+ event: KnowledgeEvent;
601
+ done: boolean;
602
+ metadata?: Record<string, unknown>;
603
+ }
604
+ interface RunKnowledgeResearchLoopOptions {
605
+ root: string;
606
+ goal: string;
607
+ maxIterations?: number;
608
+ actor?: string;
609
+ strict?: ValidateKnowledgeOptions['strict'];
610
+ readinessSpecs?: KnowledgeReadinessSpec[];
611
+ readinessTaskId?: string;
612
+ readiness?: Omit<BuildEvalKnowledgeBundleOptions, 'taskId' | 'index' | 'specs'>;
613
+ sourceOptions?: Pick<AddSourceOptions, 'adapters' | 'now'>;
614
+ signal?: AbortSignal;
615
+ step(context: KnowledgeResearchLoopContext): Promise<KnowledgeResearchLoopDecision> | KnowledgeResearchLoopDecision;
616
+ onStep?: (step: KnowledgeResearchLoopStep) => Promise<void> | void;
617
+ }
618
+ interface KnowledgeResearchLoopResult {
619
+ root: string;
620
+ goal: string;
621
+ iterations: number;
622
+ done: boolean;
623
+ index: KnowledgeIndex;
624
+ lintFindings: KnowledgeLintFinding[];
625
+ validation: ValidateKnowledgeResult;
626
+ readiness?: EvalKnowledgeBundleBuildResult;
627
+ steps: KnowledgeResearchLoopStep[];
628
+ }
629
+ type KnowledgeControlLoopState = KnowledgeResearchLoopContext;
630
+ type KnowledgeControlLoopAction = KnowledgeResearchLoopDecision;
631
+ type KnowledgeControlLoopActionResult = KnowledgeResearchLoopStep;
632
+ interface KnowledgeControlLoopAdapterOptions {
633
+ root: string;
634
+ goal: string;
635
+ actor?: string;
636
+ strict?: ValidateKnowledgeOptions['strict'];
637
+ readinessSpecs?: KnowledgeReadinessSpec[];
638
+ readinessTaskId?: string;
639
+ readiness?: Omit<BuildEvalKnowledgeBundleOptions, 'taskId' | 'index' | 'specs'>;
640
+ sourceOptions?: Pick<AddSourceOptions, 'adapters' | 'now'>;
641
+ }
642
+ type KnowledgeControlLoopAdapter = Pick<ControlRuntimeConfig<KnowledgeControlLoopState, KnowledgeControlLoopAction, KnowledgeControlLoopActionResult, ControlEvalResult>, 'intent' | 'observe' | 'validate' | 'act' | 'shouldStop'>;
643
+ /**
644
+ * Adapter for running knowledge growth through `agent-eval`'s generic control
645
+ * runtime. The caller still owns `decide`: that can be a proposer agent,
646
+ * reviewer agent, deterministic policy, or a composition of all three.
647
+ */
648
+ declare function createKnowledgeControlLoopAdapter(options: KnowledgeControlLoopAdapterOptions): KnowledgeControlLoopAdapter;
649
+ declare function runKnowledgeResearchLoop(options: RunKnowledgeResearchLoopOptions): Promise<KnowledgeResearchLoopResult>;
650
+
651
+ export { type AddSourceOptions, type AddSourceTextInput, type ApplyWriteBlocksResult, type BuildEvalKnowledgeBundleOptions, type ChunkingOptions, type DefineReadinessSpecInput, type DiscoveryResult, type DiscoveryTask, type EvalKnowledgeBundleBuildResult, FileSystemKbStore, type KbStore, KnowledgeBaseCandidate, KnowledgeBaseCandidateSchema, type KnowledgeBaseVariant, type KnowledgeChunk, type KnowledgeControlLoopAction, type KnowledgeControlLoopActionResult, type KnowledgeControlLoopAdapter, type KnowledgeControlLoopAdapterOptions, type KnowledgeControlLoopState, type KnowledgeDiscoveryDispatcher, type KnowledgeDiscoveryWorker, KnowledgeEvent, type KnowledgeEventQuery, KnowledgeEventSchema, KnowledgeEventType, type KnowledgeExplanation, KnowledgeGraph, KnowledgeGraphEdgeSchema, KnowledgeGraphNodeSchema, KnowledgeIndex, KnowledgeIndexSchema, type KnowledgeInspection, type KnowledgeLayout, KnowledgeLintFinding, type KnowledgeOptimizationConfig, KnowledgePage, KnowledgePageSchema, type KnowledgeReadinessSpec, KnowledgeRelease, type KnowledgeReleaseReport, type KnowledgeResearchLoopContext, type KnowledgeResearchLoopDecision, type KnowledgeResearchLoopResult, type KnowledgeResearchLoopStep, KnowledgeSearchResult, KnowledgeWriteParseResult, MemoryKbStore, type ParsedFrontmatter, READINESS_SPEC_DEFAULTS, type RunKnowledgeResearchLoopOptions, SCAFFOLD_PAGE_BASENAMES, type SourceAdapter, type SourceAdapterInput, type SourceAdapterOutput, SourceAnchorSchema, type SourceFreshnessInspection, SourceRecord, SourceRecordSchema, SourceRegistry, type ValidateKnowledgeOptions, type ValidateKnowledgeResult, WIKILINK_REGEX, addSourcePath, addSourceText, applyKnowledgeWriteBlocks, applyKnowledgeWriteBlocksFile, buildEvalKnowledgeBundle, buildKnowledgeGraph, buildKnowledgeIndex, chunkMarkdown, createKnowledgeControlLoopAdapter, createKnowledgeEvent, createLocalDiscoveryDispatcher, defineReadinessSpec, explainKnowledgeTarget, extractWikilinks, formatFrontmatter, initKnowledgeBase, inspectKnowledgeIndex, isSafeKnowledgePath, isScaffoldPath, knowledgeReleaseReportFromOptimization, knowledgeVariantFromCandidate, layoutFor, lintKnowledgeIndex, loadKnowledgePages, loadSourceRegistry, mediaTypeFor, normalizeLinkTarget, parseFrontmatter, parseKnowledgeWriteBlocks, reciprocalRankFusion, runKnowledgeBaseOptimization, runKnowledgeResearchLoop, searchKnowledge, sha256, slugify, sourceRegistryPath, stableId, stripFrontmatter, textSourceAdapter, tokenizeQuery, validateKnowledgeIndex, writeJson, writeKnowledgeIndex, writeSourceRegistry };