@agentskit/doc-bridge 1.4.1 → 1.5.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.
Files changed (42) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/action.yml +1 -1
  3. package/dist/cli/program.js +2461 -274
  4. package/dist/cli/program.js.map +1 -1
  5. package/dist/config/index.d.ts +1 -1
  6. package/dist/config/index.js +77 -4
  7. package/dist/config/index.js.map +1 -1
  8. package/dist/{index-DAeq_OIi.d.ts → index-Di7PkJuf.d.ts} +209 -8
  9. package/dist/index.d.ts +1942 -4
  10. package/dist/index.js +2190 -193
  11. package/dist/index.js.map +1 -1
  12. package/docs/PRD-doc-bridge-knowledge-engine.md +338 -0
  13. package/docs/knowledge-engine-runbook.md +44 -0
  14. package/ecosystem-claims.json +19 -19
  15. package/ecosystem-upstream.json +2 -2
  16. package/ecosystem.json +117 -109
  17. package/mcpb/manifest.json +25 -1
  18. package/package.json +2 -2
  19. package/skills/doc-bridge-handoff/scripts/resolve-handoff.mjs +1 -1
  20. package/src/agents/registry-adapter.ts +97 -0
  21. package/src/cli/program.ts +285 -3
  22. package/src/config/defaults.ts +14 -1
  23. package/src/config/schema.ts +69 -0
  24. package/src/conformance/ecosystem-contract.ts +6 -3
  25. package/src/discovery/documentation.ts +320 -0
  26. package/src/discovery/repository.ts +514 -0
  27. package/src/fixes/proposals.ts +165 -0
  28. package/src/index-builder/content-hash.ts +9 -2
  29. package/src/index-builder/human-adapters/plain-markdown.ts +17 -1
  30. package/src/index-builder/llms-txt.ts +22 -2
  31. package/src/index-builder/scan-corpus.ts +17 -1
  32. package/src/index.ts +99 -2
  33. package/src/mcp/server.ts +178 -8
  34. package/src/reconciliation/reconcile.ts +227 -0
  35. package/src/report/html.ts +74 -0
  36. package/src/rules/engine.ts +180 -0
  37. package/src/safety/repository.ts +84 -0
  38. package/src/schemas/knowledge.ts +315 -0
  39. package/src/validate.ts +24 -0
  40. package/src/version.ts +1 -1
  41. package/src/workflow/engine.ts +238 -0
  42. package/tsup.config.ts +2 -1
@@ -0,0 +1,165 @@
1
+ import { existsSync, readdirSync, readFileSync, realpathSync, renameSync, statSync, unlinkSync, writeFileSync } from 'node:fs'
2
+ import { basename, dirname, extname, join, relative, resolve, sep } from 'node:path'
3
+
4
+ import { contentHashForArtifactV1, sha256NormalizedV1 } from '../index-builder/content-hash.js'
5
+ import { FixProposalV1Schema, type FixProposalV1 } from '../schemas/knowledge.js'
6
+ import { containedPath } from '../safety/repository.js'
7
+
8
+ export type FixProposalOptions = {
9
+ readonly baseRevision: string
10
+ readonly configurationHash: string
11
+ readonly projectName?: string
12
+ readonly toolVersion?: string
13
+ }
14
+
15
+ export type FixApplyOptions = {
16
+ readonly currentRevision?: string
17
+ readonly verify?: (changedPaths: readonly string[]) => void
18
+ }
19
+
20
+ type FixChange = { readonly path: string; readonly before: string; readonly after: string }
21
+
22
+ const hash = (value: unknown): string => sha256NormalizedV1(value)
23
+
24
+ const artifactMetadata = (root: string, options: FixProposalOptions) => ({
25
+ schemaVersion: 1 as const,
26
+ contentHash: '0'.repeat(64),
27
+ contentHashAlgo: 'sha256-normalized-v1' as const,
28
+ project: { name: options.projectName ?? basename(resolve(root)), root: '.' },
29
+ sourceRevision: options.baseRevision,
30
+ sourceRevisionKind: options.baseRevision.length === 40 ? 'git' as const : 'content' as const,
31
+ configurationHash: options.configurationHash,
32
+ pipelineVersion: '1.0.0',
33
+ analyzerVersions: { fixes: options.toolVersion ?? '1.0.0' },
34
+ })
35
+
36
+ const unifiedDiff = (changes: readonly FixChange[]): string => changes.map((change) => {
37
+ const before = change.before.split('\n').map((line) => `-${line}`).join('\n')
38
+ const after = change.after.split('\n').map((line) => `+${line}`).join('\n')
39
+ return `--- a/${change.path}\n+++ b/${change.path}\n@@\n${before}\n${after}`
40
+ }).join('\n')
41
+
42
+ const makeProposal = (root: string, options: FixProposalOptions, changes: readonly FixChange[], preconditions: readonly string[], postconditions: readonly string[]): FixProposalV1 => {
43
+ const draft = {
44
+ ...artifactMetadata(root, options),
45
+ type: 'fix-proposal' as const,
46
+ proposalId: `fix-${hash(changes).slice(0, 20)}`,
47
+ baseRevision: options.baseRevision,
48
+ affectedFiles: changes.map(({ path, before }) => ({ path, contentHash: sha256NormalizedV1(before) })),
49
+ changes,
50
+ preconditions,
51
+ diff: unifiedDiff(changes),
52
+ postconditions,
53
+ status: 'proposed' as const,
54
+ }
55
+ return FixProposalV1Schema.parse({ ...draft, contentHash: contentHashForArtifactV1(draft) })
56
+ }
57
+
58
+ const walkMarkdown = (root: string, directory = root): string[] => readdirSync(directory, { withFileTypes: true }).flatMap((entry) => {
59
+ if (entry.name === '.git' || entry.name === 'node_modules' || entry.name === 'dist' || entry.name === 'build') return []
60
+ const path = join(directory, entry.name)
61
+ if (entry.isDirectory()) return walkMarkdown(root, path)
62
+ return entry.isFile() && ['.md', '.mdx'].includes(extname(entry.name).toLowerCase()) ? [relative(root, path).split(sep).join('/')] : []
63
+ })
64
+
65
+ const localLink = /(!?)\[([^\]]*)\]\(([^)\s]+)(?:\s+["'][^)]*["'])?\)/g
66
+
67
+ const sortJson = (value: unknown): unknown => Array.isArray(value)
68
+ ? value.map(sortJson)
69
+ : value && typeof value === 'object'
70
+ ? Object.fromEntries(Object.entries(value as Record<string, unknown>).sort(([left], [right]) => left.localeCompare(right)).map(([key, item]) => [key, sortJson(item)]))
71
+ : value
72
+
73
+ export const createMarkdownLinkFixProposal = (root: string, options: FixProposalOptions): FixProposalV1 | undefined => {
74
+ const projectRoot = realpathSync.native(resolve(root))
75
+ const paths = walkMarkdown(projectRoot)
76
+ const changes: FixChange[] = []
77
+ for (const path of paths) {
78
+ const content = readFileSync(join(projectRoot, path), 'utf8')
79
+ let next = content
80
+ for (const match of content.matchAll(localLink)) {
81
+ const target = match[3]
82
+ if (!target || match[1] === '!' || /^(?:[a-z]+:|\/|#)/i.test(target)) continue
83
+ const targetPath = target.split('#')[0]?.split('?')[0]
84
+ if (!targetPath || existsSync(resolve(projectRoot, dirname(path), targetPath))) continue
85
+ const targetStem = basename(targetPath, extname(targetPath)).toLowerCase()
86
+ const labelStem = (match[2] ?? '').trim().toLowerCase().replace(/[^a-z0-9]+/g, '')
87
+ const candidates = paths.filter((candidate) => basename(candidate, extname(candidate)).toLowerCase() === targetStem || basename(candidate, extname(candidate)).toLowerCase().replace(/[^a-z0-9]+/g, '') === labelStem)
88
+ if (candidates.length !== 1) continue
89
+ let replacement = relative(dirname(path), candidates[0]!).split(sep).join('/')
90
+ if (target.startsWith('./') && !replacement.startsWith('.')) replacement = `./${replacement}`
91
+ next = next.replace(match[0], match[0].replace(target, replacement))
92
+ }
93
+ if (next !== content) changes.push({ path, before: content, after: next })
94
+ }
95
+ return changes.length ? makeProposal(projectRoot, options, changes, ['Each replacement has exactly one Markdown target.'], ['All corrected local Markdown links resolve.']) : undefined
96
+ }
97
+
98
+ export const createArtifactNormalizationProposal = (root: string, artifactPath: string, options: FixProposalOptions): FixProposalV1 | undefined => {
99
+ const projectRoot = realpathSync.native(resolve(root))
100
+ const path = artifactPath.split(sep).join('/')
101
+ const absolute = containedPath(projectRoot, path)
102
+ if (!absolute || !existsSync(absolute) || !statSync(absolute).isFile()) return undefined
103
+ const before = readFileSync(absolute, 'utf8')
104
+ let after: string
105
+ try { after = `${JSON.stringify(sortJson(JSON.parse(before) as unknown), null, 2)}\n` } catch { return undefined }
106
+ return after === before ? undefined : makeProposal(projectRoot, options, [{ path: relative(projectRoot, absolute).split(sep).join('/'), before, after }], ['The artifact contains valid JSON.'], ['The artifact is valid canonical JSON with one trailing newline.'])
107
+ }
108
+
109
+ export const approveFixProposal = (proposalInput: unknown, approvedBy: string, approvedAt = new Date().toISOString()): FixProposalV1 => {
110
+ const proposal = FixProposalV1Schema.parse(proposalInput)
111
+ if (proposal.status !== 'proposed') throw new Error(`Only proposed fixes can be approved; received "${proposal.status}".`)
112
+ const approved = { ...proposal, status: 'approved' as const, approval: { proposalHash: proposal.contentHash, approvedAt, approvedBy }, contentHash: '0'.repeat(64) }
113
+ return FixProposalV1Schema.parse({ ...approved, contentHash: contentHashForArtifactV1(approved) })
114
+ }
115
+
116
+ const bindingHash = (proposal: FixProposalV1): string => {
117
+ const { approval: _approval, contentHash: _contentHash, status: _status, ...rest } = proposal
118
+ return contentHashForArtifactV1({ ...rest, contentHash: '0'.repeat(64), status: 'proposed' as const })
119
+ }
120
+
121
+ export const applyFixProposal = (root: string, proposalInput: unknown, options: FixApplyOptions = {}): FixProposalV1 => {
122
+ const proposal = FixProposalV1Schema.parse(proposalInput)
123
+ if (proposal.status !== 'approved' || !proposal.approval) throw new Error('Only an explicitly approved fix proposal can be applied.')
124
+ if (proposal.approval.proposalHash !== bindingHash(proposal)) throw new Error('Approval is not bound to the exact proposal content.')
125
+ if (options.currentRevision && options.currentRevision !== proposal.baseRevision) throw new Error('The repository revision changed since this proposal was created.')
126
+ if (!proposal.changes?.length) throw new Error('This proposal has no executable changes.')
127
+
128
+ const projectRoot = realpathSync.native(resolve(root))
129
+ const originals = new Map<string, string>()
130
+ const affected = new Map(proposal.affectedFiles.map((file) => [file.path, file]))
131
+ if (proposal.changes.some((change) => !affected.has(change.path) || affected.get(change.path)?.contentHash !== sha256NormalizedV1(change.before)) || affected.size !== proposal.changes.length) {
132
+ throw new Error('Proposal changes do not match its affected-file hashes.')
133
+ }
134
+ for (const file of proposal.affectedFiles) {
135
+ const absolute = containedPath(projectRoot, file.path)
136
+ if (!absolute || !existsSync(absolute)) throw new Error(`Affected file is unavailable or escapes the repository root: ${file.path}`)
137
+ const current = readFileSync(absolute, 'utf8')
138
+ if (sha256NormalizedV1(current) !== file.contentHash) throw new Error(`Affected file changed since proposal creation: ${file.path}`)
139
+ originals.set(absolute, current)
140
+ }
141
+
142
+ try {
143
+ for (const change of proposal.changes) {
144
+ const absolute = resolve(projectRoot, change.path)
145
+ writeFileSync(`${absolute}.docbridge-${process.pid}.tmp`, change.after, 'utf8')
146
+ }
147
+ for (const change of proposal.changes) {
148
+ const absolute = resolve(projectRoot, change.path)
149
+ renameSync(`${absolute}.docbridge-${process.pid}.tmp`, absolute)
150
+ }
151
+ for (const change of proposal.changes) {
152
+ if (readFileSync(resolve(projectRoot, change.path), 'utf8') !== change.after) throw new Error(`Postcondition failed for ${change.path}`)
153
+ }
154
+ options.verify?.(proposal.changes.map((change) => change.path))
155
+ } catch (error) {
156
+ for (const [absolute, content] of originals) writeFileSync(absolute, content, 'utf8')
157
+ for (const change of proposal.changes) {
158
+ const temp = `${resolve(projectRoot, change.path)}.docbridge-${process.pid}.tmp`
159
+ if (existsSync(temp)) unlinkSync(temp)
160
+ }
161
+ throw error
162
+ }
163
+ const applied = { ...proposal, status: 'applied' as const, contentHash: '0'.repeat(64) }
164
+ return FixProposalV1Schema.parse({ ...applied, contentHash: contentHashForArtifactV1(applied) })
165
+ }
@@ -13,7 +13,14 @@ const sortValue = (value: unknown): unknown => {
13
13
  return value
14
14
  }
15
15
 
16
+ export const canonicalJsonV1 = (payload: unknown): string => JSON.stringify(sortValue(payload))
17
+
16
18
  export const sha256NormalizedV1 = (payload: unknown): string => {
17
- const normalized = JSON.stringify(sortValue(payload))
19
+ const normalized = canonicalJsonV1(payload)
18
20
  return createHash('sha256').update(normalized, 'utf8').digest('hex')
19
- }
21
+ }
22
+
23
+ export const contentHashForArtifactV1 = <T extends { readonly contentHash: string }>(artifact: T): string => {
24
+ const { contentHash: _contentHash, ...payload } = artifact
25
+ return sha256NormalizedV1(payload)
26
+ }
@@ -1,10 +1,26 @@
1
+ import { minimatch } from 'minimatch'
2
+
1
3
  import { optionString, scanMarkdownDocs, type HumanAdapter } from './core.js'
2
4
 
5
+ const stringPatterns = (value: unknown): string[] =>
6
+ Array.isArray(value) ? value.filter((item): item is string => typeof item === 'string' && item.length > 0) : []
7
+
8
+ const matchesConfiguredPath = (relPath: string, options: Record<string, unknown> | undefined): boolean => {
9
+ const normalize = (pattern: string): string => pattern.replaceAll('\\', '/').replace(/^\.\//, '')
10
+ const include = stringPatterns(options?.include).map(normalize)
11
+ const exclude = stringPatterns(options?.exclude).map(normalize)
12
+ if (exclude.some((pattern) => minimatch(relPath, pattern, { dot: true }))) return false
13
+ return include.length === 0 || include.some((pattern) => minimatch(relPath, pattern, { dot: true }))
14
+ }
15
+
3
16
  export const plainMarkdownAdapter: HumanAdapter = {
4
17
  plugin: 'plain-markdown',
5
18
  scan: ({ root, config }) => {
6
19
  const humanRoot =
7
20
  optionString(config.options, ['contentDir', 'root', 'docsDir']) ?? 'docs'
8
- return scanMarkdownDocs(root, humanRoot, { urlPrefix: config.options?.urlPrefix })
21
+ return scanMarkdownDocs(root, humanRoot, {
22
+ urlPrefix: config.options?.urlPrefix,
23
+ includeRelPath: (relPath) => matchesConfiguredPath(relPath, config.options),
24
+ })
9
25
  },
10
26
  }
@@ -1,6 +1,25 @@
1
1
  import type { DocBridgeConfigV1 } from '../config/schema.js'
2
2
  import type { KnowledgeEntry } from '../schemas/doc-bridge-index.js'
3
3
 
4
+ const routePath = (path: string, pathPrefix: string | undefined): string => {
5
+ const normalizedPath = path.replaceAll('\\', '/').replace(/\.(?:md|mdx)$/, '')
6
+ const normalizedPrefix = pathPrefix?.replaceAll('\\', '/').replace(/\/$/, '')
7
+ const relativePath = normalizedPrefix && normalizedPath.startsWith(`${normalizedPrefix}/`)
8
+ ? normalizedPath.slice(normalizedPrefix.length + 1)
9
+ : normalizedPath
10
+ return relativePath.replace(/^\/+/, '')
11
+ }
12
+
13
+ export const knowledgeUrl = (
14
+ path: string,
15
+ options: { readonly urlPrefix?: string | undefined; readonly pathPrefix?: string | undefined } = {},
16
+ ): string => {
17
+ const relativePath = routePath(path, options.pathPrefix)
18
+ if (!options.urlPrefix) return path
19
+ const base = options.urlPrefix.endsWith('/') ? options.urlPrefix : `${options.urlPrefix}/`
20
+ return new URL(relativePath, base).toString()
21
+ }
22
+
4
23
  export const renderLlmsTxt = (
5
24
  config: DocBridgeConfigV1,
6
25
  knowledge: readonly KnowledgeEntry[],
@@ -12,8 +31,9 @@ export const renderLlmsTxt = (
12
31
 
13
32
  const lines = knowledge.slice(0, 500).map((entry) => {
14
33
  const desc = entry.description ? `: ${entry.description}` : ''
15
- return `- [${entry.title}](${entry.path})${desc}`
34
+ const url = knowledgeUrl(entry.path, config.index?.llmsTxt)
35
+ return `- [${entry.title}](${url})${desc}`
16
36
  })
17
37
 
18
38
  return `${preamble.trim()}\n\n## Knowledge\n\n${lines.join('\n')}\n`
19
- }
39
+ }
@@ -1,4 +1,5 @@
1
1
  import type { DocBridgeConfigV1 } from '../config/schema.js'
2
+ import { minimatch } from 'minimatch'
2
3
  import { readBoundedText } from '../lib/bounded-text.js'
3
4
  import {
4
5
  extractSearchBody,
@@ -31,10 +32,25 @@ export type OwnershipSeed = {
31
32
 
32
33
  const relFromRoot = (root: string, abs: string): string => toPosix(abs.replace(`${toPosix(root)}/`, ''))
33
34
 
35
+ const configuredPathMatches = (
36
+ relPath: string,
37
+ include: readonly string[] | undefined,
38
+ exclude: readonly string[] | undefined,
39
+ ): boolean => {
40
+ const normalize = (pattern: string): string => toPosix(pattern).replace(/^\.\//, '')
41
+ const included = include?.filter(Boolean).map(normalize) ?? []
42
+ const excluded = exclude?.filter(Boolean).map(normalize) ?? []
43
+ if (excluded.some((pattern) => minimatch(relPath, pattern, { dot: true }))) return false
44
+ return included.length === 0 || included.some((pattern) => minimatch(relPath, pattern, { dot: true }))
45
+ }
46
+
34
47
  export const scanAgentCorpus = (root: string, config: DocBridgeConfigV1): CorpusDoc[] => {
35
48
  const agentRoot = containedProjectPath(root, config.corpus.agent.root)
36
49
  if (!agentRoot) throw new Error('Agent corpus root escapes the project root.')
37
- const files = walkFiles(agentRoot, { extensions: ['.md', '.mdx'] })
50
+ const files = walkFiles(agentRoot, { extensions: ['.md', '.mdx'] }).filter((abs) => {
51
+ const relToCorpus = toPosix(abs.replace(`${toPosix(agentRoot)}/`, ''))
52
+ return configuredPathMatches(relToCorpus, config.corpus.agent.include, config.corpus.agent.exclude)
53
+ })
38
54
  const corpusRelRoot = toPosix(config.corpus.agent.root)
39
55
 
40
56
  const budget = { used: 0 }
package/src/index.ts CHANGED
@@ -15,6 +15,16 @@ export {
15
15
  type DocBridgeConfigV1,
16
16
  type AgentCorpusConfig,
17
17
  type DocumentationStandardV1Config,
18
+ RuleIdSchema,
19
+ RuleSeveritySchema,
20
+ RulesConfigSchema,
21
+ WorkflowConfigSchema,
22
+ RepositorySafetyConfigSchema,
23
+ type RuleId,
24
+ type RuleSeverity,
25
+ type RulesConfig,
26
+ type WorkflowConfig,
27
+ type RepositorySafetyConfig,
18
28
  } from './config/schema.js'
19
29
 
20
30
  export {
@@ -55,16 +65,63 @@ export {
55
65
 
56
66
  export {
57
67
  parseAgentHandoff,
68
+ parseAgentProposal,
58
69
  parseAgentSearch,
59
70
  parseDocBridgeConfig,
60
71
  parseDocBridgeIndex,
72
+ parseDiscoverySnapshot,
73
+ parseFixProposal,
61
74
  parseMemoryCandidate,
75
+ parseReconciliationReport,
76
+ parseWorkflowRun,
62
77
  safeParseAgentHandoff,
63
78
  type ParseIssue,
64
79
  type ParseResult,
65
80
  } from './validate.js'
66
81
 
67
82
  export { buildDocBridgeIndex, type BuildIndexOptions, type BuildIndexResult } from './index-builder/build-index.js'
83
+ export { discoverRepository, type DiscoveryOptions } from './discovery/repository.js'
84
+ export { containedPath, DEFAULT_SAFETY_EXCLUDES, redactSecrets, redactValue, safeWalkFiles, type SafeWalkOptions, type SafeWalkResult } from './safety/repository.js'
85
+ export { DEFAULT_REGISTRY_AGENT_ID, createRegistryAgentAdapter, loadRegistryAgentMetadata, loadRegistryAgentRunner, persistRegistryAgentProposal, type RegistryAgentAdapter, type RegistryAgentContext, type RegistryAgentMetadata, type RegistryAgentRunner } from './agents/registry-adapter.js'
86
+ export {
87
+ applyDocumentationDeclarations,
88
+ parseDocumentationDeclarations,
89
+ type DocumentationAnalysisResult,
90
+ type DocumentationDeclarationInput,
91
+ type DocumentationDeclarationOptions,
92
+ type DocumentationDeclarationResult,
93
+ type DocumentationDiagnostic,
94
+ } from './discovery/documentation.js'
95
+ export { reconcileKnowledge } from './reconciliation/reconcile.js'
96
+ export { renderOfflineReport, type OfflineReportInput, type OfflineReportOptions } from './report/html.js'
97
+ export {
98
+ applyFixProposal,
99
+ approveFixProposal,
100
+ createArtifactNormalizationProposal,
101
+ createMarkdownLinkFixProposal,
102
+ type FixApplyOptions,
103
+ type FixProposalOptions,
104
+ } from './fixes/proposals.js'
105
+ export {
106
+ WORKFLOW_STAGES,
107
+ loadWorkflowManifest,
108
+ loadWorkflowStepOutput,
109
+ runWorkflow,
110
+ type WorkflowExecutionResult,
111
+ type WorkflowOptions,
112
+ type WorkflowStage,
113
+ type WorkflowStageContext,
114
+ type WorkflowStageHandler,
115
+ } from './workflow/engine.js'
116
+ export {
117
+ evaluateRules,
118
+ parseRuleId,
119
+ parseRuleSeverity,
120
+ type RuleEngineOptions,
121
+ type RuleEvaluationResult,
122
+ type RuleFinding,
123
+ type RuleMode,
124
+ } from './rules/engine.js'
68
125
  export {
69
126
  formatEcosystemLlmsBlock,
70
127
  formatEcosystemLlmsSection,
@@ -98,7 +155,7 @@ export {
98
155
  type DocumentationStandardRuleResult,
99
156
  type DocumentationStandardRuleStatus,
100
157
  } from './conformance/documentation-standard-v1.js'
101
- export { MCP_TOOLS, handleMcpRequest, startMcpStdioServer } from './mcp/server.js'
158
+ export { MCP_TOOLS, handleMcpRequest, respondMcpRequest, startMcpStdioServer } from './mcp/server.js'
102
159
  export { installMcpConfig, mcpSnippet, type McpInstallResult, type McpInstallTarget } from './mcp/install.js'
103
160
  export { runDoctor, formatDoctorText, type DoctorReport, type DoctorIssue, type DoctorCoverage } from './doctor/run-doctor.js'
104
161
  export {
@@ -115,7 +172,47 @@ export {
115
172
  type GithubPrOptions,
116
173
  type GithubPrResult,
117
174
  } from './memory/github-pr.js'
118
- export { sha256NormalizedV1 } from './index-builder/content-hash.js'
175
+ export { canonicalJsonV1, contentHashForArtifactV1, sha256NormalizedV1 } from './index-builder/content-hash.js'
176
+ export {
177
+ AgentProposalV1Schema,
178
+ AffectedFileSchema,
179
+ CoverageSchema,
180
+ DiagnosticSeveritySchema,
181
+ DiscoverySnapshotV1Schema,
182
+ EntitySchema,
183
+ EvidenceSchema,
184
+ EvidenceSourceSchema,
185
+ FindingStatusSchema,
186
+ FixProposalStatusSchema,
187
+ FixChangeSchema,
188
+ FixProposalV1Schema,
189
+ KNOWLEDGE_CONTENT_HASH_ALGO,
190
+ KNOWLEDGE_SCHEMA_VERSION,
191
+ ProvenanceSchema,
192
+ ProjectIdentitySchema,
193
+ ProposalOriginSchema,
194
+ ReconciliationReportV1Schema,
195
+ RelationSchema,
196
+ WorkflowRunV1Schema,
197
+ WorkflowStepSchema,
198
+ WorkflowStateSchema,
199
+ WorkflowTransitionSchema,
200
+ type AgentProposalV1,
201
+ type DiagnosticSeverity,
202
+ type DiscoverySnapshotV1,
203
+ type Evidence,
204
+ type FindingStatus,
205
+ type FixProposalV1,
206
+ type FixChange,
207
+ type KnowledgeArtifactV1,
208
+ type KnowledgeDiagnostic,
209
+ type KnowledgeEntity,
210
+ type KnowledgeRelation,
211
+ type Provenance,
212
+ type ReconciliationReportV1,
213
+ type WorkflowRunV1,
214
+ type WorkflowState,
215
+ } from './schemas/knowledge.js'
119
216
  export { IndexNotFoundError, indexFilePath, loadDocBridgeIndex, resolveRoot } from './query/load-index.js'
120
217
  export { runQuery, type QueryKind, type QueryRequest, type QueryResult } from './query/query.js'
121
218
  export { searchIndex, type SearchMatch } from './query/search.js'