@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.
- package/CHANGELOG.md +19 -0
- package/action.yml +1 -1
- package/dist/cli/program.js +2461 -274
- package/dist/cli/program.js.map +1 -1
- package/dist/config/index.d.ts +1 -1
- package/dist/config/index.js +77 -4
- package/dist/config/index.js.map +1 -1
- package/dist/{index-DAeq_OIi.d.ts → index-Di7PkJuf.d.ts} +209 -8
- package/dist/index.d.ts +1942 -4
- package/dist/index.js +2190 -193
- package/dist/index.js.map +1 -1
- package/docs/PRD-doc-bridge-knowledge-engine.md +338 -0
- package/docs/knowledge-engine-runbook.md +44 -0
- package/ecosystem-claims.json +19 -19
- package/ecosystem-upstream.json +2 -2
- package/ecosystem.json +117 -109
- package/mcpb/manifest.json +25 -1
- package/package.json +2 -2
- package/skills/doc-bridge-handoff/scripts/resolve-handoff.mjs +1 -1
- package/src/agents/registry-adapter.ts +97 -0
- package/src/cli/program.ts +285 -3
- package/src/config/defaults.ts +14 -1
- package/src/config/schema.ts +69 -0
- package/src/conformance/ecosystem-contract.ts +6 -3
- package/src/discovery/documentation.ts +320 -0
- package/src/discovery/repository.ts +514 -0
- package/src/fixes/proposals.ts +165 -0
- package/src/index-builder/content-hash.ts +9 -2
- package/src/index-builder/human-adapters/plain-markdown.ts +17 -1
- package/src/index-builder/llms-txt.ts +22 -2
- package/src/index-builder/scan-corpus.ts +17 -1
- package/src/index.ts +99 -2
- package/src/mcp/server.ts +178 -8
- package/src/reconciliation/reconcile.ts +227 -0
- package/src/report/html.ts +74 -0
- package/src/rules/engine.ts +180 -0
- package/src/safety/repository.ts +84 -0
- package/src/schemas/knowledge.ts +315 -0
- package/src/validate.ts +24 -0
- package/src/version.ts +1 -1
- package/src/workflow/engine.ts +238 -0
- 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 =
|
|
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, {
|
|
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
|
-
|
|
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'
|