@agentskit/doc-bridge 1.2.6 → 1.4.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/README.md +32 -6
- package/action.yml +1 -1
- package/dist/cli/program.js +344 -130
- package/dist/cli/program.js.map +1 -1
- package/dist/config/index.d.ts +1 -1
- package/dist/config/index.js +3 -1
- package/dist/config/index.js.map +1 -1
- package/dist/{index-DGI9TBLE.d.ts → index-DAeq_OIi.d.ts} +22 -22
- package/dist/index.d.ts +7 -4
- package/dist/index.js +320 -105
- package/dist/index.js.map +1 -1
- package/docs/MARKETPLACE.md +1 -1
- package/docs/POSITIONING.md +1 -1
- package/docs/examples.md +4 -0
- package/docs/getting-started.md +1 -1
- package/docs/guides/choose-context-layer.md +129 -0
- package/docs/guides/gate-ci.md +1 -1
- package/docs/guides/meta.json +1 -0
- package/docs/landing/index.html +2 -2
- package/docs/playbook/doc-bridge-pattern.md +1 -1
- package/docs/qa/vitepress-starlight-adapters.md +19 -0
- package/docs/recipes/index-pipeline.md +1 -1
- package/docs/spec/config-v1.md +33 -2
- package/examples/nextra-only.config.ts +17 -0
- package/examples/nx-monorepo.config.ts +11 -0
- package/examples/starlight-only.config.ts +17 -0
- package/examples/vitepress-only.config.ts +19 -0
- package/mcpb/manifest.json +1 -1
- package/package.json +15 -4
- package/skills/doc-bridge-handoff/SKILL.md +38 -0
- package/skills/doc-bridge-handoff/fixtures/synthetic-repo/doc-bridge.config.json +23 -0
- package/skills/doc-bridge-handoff/fixtures/synthetic-repo/docs/for-agents/packages/payments.md +5 -0
- package/skills/doc-bridge-handoff/fixtures/synthetic-repo/packages/payments/package.json +4 -0
- package/skills/doc-bridge-handoff/scripts/resolve-handoff.mjs +70 -0
- package/src/config/schema.ts +3 -1
- package/src/index-builder/build-handoffs.ts +2 -0
- package/src/index-builder/build-index.ts +7 -1
- package/src/index-builder/human-adapters/index.ts +6 -0
- package/src/index-builder/human-adapters/nextra.ts +43 -0
- package/src/index-builder/human-adapters/starlight.ts +40 -0
- package/src/index-builder/human-adapters/vitepress.ts +43 -0
- package/src/index-builder/plugins/nx.ts +161 -0
- package/src/index-builder/plugins/pnpm-monorepo.ts +1 -0
- package/src/index-builder/watch-index.ts +11 -2
- package/src/index.ts +1 -0
- package/src/version.ts +1 -1
|
@@ -9,6 +9,7 @@ import { renderCapabilitiesJson } from './capabilities.js'
|
|
|
9
9
|
import { sha256NormalizedV1 } from './content-hash.js'
|
|
10
10
|
import { renderLlmsTxt } from './llms-txt.js'
|
|
11
11
|
import { scanHumanDocs } from './human-adapters/index.js'
|
|
12
|
+
import { discoverNxProjects } from './plugins/nx.js'
|
|
12
13
|
import { discoverPnpmPackages } from './plugins/pnpm-monorepo.js'
|
|
13
14
|
import { scanAgentCorpus } from './scan-corpus.js'
|
|
14
15
|
|
|
@@ -66,7 +67,12 @@ export const buildDocBridgeIndex = (opts: BuildIndexOptions): BuildIndexResult =
|
|
|
66
67
|
config.routing?.plugin === 'npm-workspaces' ||
|
|
67
68
|
config.routing?.plugin === 'yarn-workspaces'
|
|
68
69
|
|
|
69
|
-
const discovered =
|
|
70
|
+
const discovered =
|
|
71
|
+
config.routing?.plugin === 'nx'
|
|
72
|
+
? discoverNxProjects(root, config)
|
|
73
|
+
: shouldDiscover
|
|
74
|
+
? discoverPnpmPackages(root, config)
|
|
75
|
+
: []
|
|
70
76
|
const packages = collectPackages(config, discovered, corpus)
|
|
71
77
|
const humanDocs = scanHumanDocs(root, config)
|
|
72
78
|
|
|
@@ -4,8 +4,11 @@ import { resolve, sep } from 'node:path'
|
|
|
4
4
|
import type { DocBridgeConfigV1, HumanCorpusConfig } from '../../config/schema.js'
|
|
5
5
|
import { docusaurusAdapter } from './docusaurus.js'
|
|
6
6
|
import { fumadocsAdapter } from './fumadocs.js'
|
|
7
|
+
import { nextraAdapter } from './nextra.js'
|
|
7
8
|
import type { HumanAdapter, HumanDocMap, HumanDocRecord } from './core.js'
|
|
8
9
|
import { plainMarkdownAdapter } from './plain-markdown.js'
|
|
10
|
+
import { starlightAdapter } from './starlight.js'
|
|
11
|
+
import { vitepressAdapter } from './vitepress.js'
|
|
9
12
|
|
|
10
13
|
export type { HumanAdapter, HumanDocMap, HumanDocRecord } from './core.js'
|
|
11
14
|
|
|
@@ -13,6 +16,9 @@ const ADAPTERS: readonly HumanAdapter[] = [
|
|
|
13
16
|
plainMarkdownAdapter,
|
|
14
17
|
fumadocsAdapter,
|
|
15
18
|
docusaurusAdapter,
|
|
19
|
+
vitepressAdapter,
|
|
20
|
+
starlightAdapter,
|
|
21
|
+
nextraAdapter,
|
|
16
22
|
]
|
|
17
23
|
|
|
18
24
|
const humanConfigs = (config: DocBridgeConfigV1): HumanCorpusConfig[] => {
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import {
|
|
2
|
+
optionString,
|
|
3
|
+
parseFrontmatter,
|
|
4
|
+
routeSlug,
|
|
5
|
+
scanMarkdownDocs,
|
|
6
|
+
type HumanAdapter,
|
|
7
|
+
type HumanDocRecord,
|
|
8
|
+
} from './core.js'
|
|
9
|
+
|
|
10
|
+
const nextraRecordId = (relPath: string, raw: string): string => {
|
|
11
|
+
const frontmatter = parseFrontmatter(raw)
|
|
12
|
+
return frontmatter.package ?? frontmatter.module ?? frontmatter.id ?? (routeSlug(relPath) || 'index')
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const isIndexPage = (path: string): boolean => /(^|[/\\])index\.mdx?$/i.test(path)
|
|
16
|
+
|
|
17
|
+
const resolveRouteCollisions = (records: readonly HumanDocRecord[]): HumanDocRecord[] => {
|
|
18
|
+
const byUrl = new Map<string, { readonly record: HumanDocRecord; readonly indexPage: boolean }>()
|
|
19
|
+
for (const record of records) {
|
|
20
|
+
const normalized = { ...record, url: record.url || '/' }
|
|
21
|
+
const indexPage = isIndexPage(record.path)
|
|
22
|
+
const existing = byUrl.get(normalized.url)
|
|
23
|
+
if (!existing || indexPage || !existing.indexPage) {
|
|
24
|
+
byUrl.set(normalized.url, { record: normalized, indexPage })
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return [...byUrl.values()].map(({ record }) => record)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export const nextraAdapter: HumanAdapter = {
|
|
31
|
+
plugin: 'nextra',
|
|
32
|
+
scan: ({ root, config }) => {
|
|
33
|
+
const contentDir = optionString(config.options, ['contentDir', 'docsDir', 'root'])
|
|
34
|
+
if (!contentDir) return []
|
|
35
|
+
|
|
36
|
+
return resolveRouteCollisions(
|
|
37
|
+
scanMarkdownDocs(root, contentDir, {
|
|
38
|
+
idForDoc: nextraRecordId,
|
|
39
|
+
urlPrefix: optionString(config.options, ['urlPrefix', 'contentDirBasePath']) ?? '/',
|
|
40
|
+
}),
|
|
41
|
+
)
|
|
42
|
+
},
|
|
43
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { slug as githubSlug } from 'github-slugger'
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
optionString,
|
|
5
|
+
parseFrontmatter,
|
|
6
|
+
routeSlug,
|
|
7
|
+
scanMarkdownDocs,
|
|
8
|
+
type HumanAdapter,
|
|
9
|
+
} from './core.js'
|
|
10
|
+
|
|
11
|
+
const isStarlightPage = (relPath: string, raw: string): boolean => {
|
|
12
|
+
if (relPath.split('/').some((part) => part.startsWith('.') || part.startsWith('_'))) return false
|
|
13
|
+
return parseFrontmatter(raw).draft !== 'true'
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const starlightFileSlug = (relPath: string): string =>
|
|
17
|
+
routeSlug(relPath)
|
|
18
|
+
.split('/')
|
|
19
|
+
.map((part) => githubSlug(part))
|
|
20
|
+
.filter(Boolean)
|
|
21
|
+
.join('/')
|
|
22
|
+
|
|
23
|
+
const starlightSlug = (relPath: string, raw: string): string => {
|
|
24
|
+
const slug = parseFrontmatter(raw).slug
|
|
25
|
+
return slug ? slug.replace(/^\/+|\/+$/g, '') : starlightFileSlug(relPath)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export const starlightAdapter: HumanAdapter = {
|
|
29
|
+
plugin: 'starlight',
|
|
30
|
+
scan: ({ root, config }) => {
|
|
31
|
+
const contentDir = optionString(config.options, ['contentDir', 'docsDir', 'root'])
|
|
32
|
+
if (!contentDir) return []
|
|
33
|
+
|
|
34
|
+
return scanMarkdownDocs(root, contentDir, {
|
|
35
|
+
includeRelPath: isStarlightPage,
|
|
36
|
+
slugForDoc: starlightSlug,
|
|
37
|
+
urlPrefix: config.options?.urlPrefix,
|
|
38
|
+
})
|
|
39
|
+
},
|
|
40
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { minimatch } from 'minimatch'
|
|
2
|
+
|
|
3
|
+
import { optionString, routeSlug, scanMarkdownDocs, type HumanAdapter } from './core.js'
|
|
4
|
+
|
|
5
|
+
const isVitePressPage = (relPath: string): boolean =>
|
|
6
|
+
!relPath.split('/').some((part) => part === '.vitepress' || part.startsWith('.'))
|
|
7
|
+
|
|
8
|
+
const srcExcludePatterns = (value: unknown): readonly string[] => {
|
|
9
|
+
if (value === undefined) return []
|
|
10
|
+
if (!Array.isArray(value) || value.length > 64) {
|
|
11
|
+
throw new Error('VitePress srcExclude must be an array of at most 64 glob patterns.')
|
|
12
|
+
}
|
|
13
|
+
return value.map((pattern) => {
|
|
14
|
+
if (typeof pattern !== 'string' || !pattern || pattern.length > 256 || pattern.includes('\0')) {
|
|
15
|
+
throw new Error('Each VitePress srcExclude pattern must be a non-empty string up to 256 characters.')
|
|
16
|
+
}
|
|
17
|
+
return pattern
|
|
18
|
+
})
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const isExcluded = (relPath: string, patterns: readonly string[]): boolean =>
|
|
22
|
+
patterns.some((pattern) => minimatch(relPath, pattern, { dot: true }))
|
|
23
|
+
|
|
24
|
+
const vitepressSlug = (relPath: string, cleanUrls: boolean): string => {
|
|
25
|
+
const slug = routeSlug(relPath)
|
|
26
|
+
if (cleanUrls || /(?:^|\/)index\.mdx?$/.test(relPath)) return slug
|
|
27
|
+
return `${slug}.html`
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export const vitepressAdapter: HumanAdapter = {
|
|
31
|
+
plugin: 'vitepress',
|
|
32
|
+
scan: ({ root, config }) => {
|
|
33
|
+
const docsDir = optionString(config.options, ['docsDir', 'root', 'srcDir'])
|
|
34
|
+
if (!docsDir) return []
|
|
35
|
+
const srcExclude = srcExcludePatterns(config.options?.srcExclude)
|
|
36
|
+
|
|
37
|
+
return scanMarkdownDocs(root, docsDir, {
|
|
38
|
+
includeRelPath: (relPath) => isVitePressPage(relPath) && !isExcluded(relPath, srcExclude),
|
|
39
|
+
slugForDoc: (relPath) => vitepressSlug(relPath, config.options?.cleanUrls === true),
|
|
40
|
+
urlPrefix: config.options?.urlPrefix,
|
|
41
|
+
})
|
|
42
|
+
},
|
|
43
|
+
}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { existsSync, lstatSync, readFileSync, realpathSync } from 'node:fs'
|
|
2
|
+
import { basename, dirname, isAbsolute, relative, resolve, sep } from 'node:path'
|
|
3
|
+
|
|
4
|
+
import type { DocBridgeConfigV1 } from '../../config/schema.js'
|
|
5
|
+
import { detectPackageManager } from '../../lib/package-manager.js'
|
|
6
|
+
import { toPosix } from '../../lib/paths.js'
|
|
7
|
+
import { walkFiles } from '../../lib/walk.js'
|
|
8
|
+
import type { DiscoveredPackage } from './pnpm-monorepo.js'
|
|
9
|
+
|
|
10
|
+
const NX_SCAN_SKIP = new Set([
|
|
11
|
+
'node_modules',
|
|
12
|
+
'.git',
|
|
13
|
+
'.nx',
|
|
14
|
+
'dist',
|
|
15
|
+
'coverage',
|
|
16
|
+
'.doc-bridge',
|
|
17
|
+
])
|
|
18
|
+
const NX_PROJECT_NAME = /^(?:@[A-Za-z0-9._-]+\/)?[A-Za-z0-9][A-Za-z0-9._-]*$/
|
|
19
|
+
|
|
20
|
+
type JsonRecord = Record<string, unknown>
|
|
21
|
+
|
|
22
|
+
const isRecord = (value: unknown): value is JsonRecord =>
|
|
23
|
+
typeof value === 'object' && value !== null && !Array.isArray(value)
|
|
24
|
+
|
|
25
|
+
const readJsonRecord = (path: string): JsonRecord | undefined => {
|
|
26
|
+
try {
|
|
27
|
+
const parsed: unknown = JSON.parse(readFileSync(path, 'utf8'))
|
|
28
|
+
return isRecord(parsed) ? parsed : undefined
|
|
29
|
+
} catch {
|
|
30
|
+
return undefined
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const safeProjectPath = (
|
|
35
|
+
root: string,
|
|
36
|
+
manifestDir: string,
|
|
37
|
+
declaredRoot?: unknown,
|
|
38
|
+
): string | undefined => {
|
|
39
|
+
const candidate = typeof declaredRoot === 'string' ? resolve(root, declaredRoot) : manifestDir
|
|
40
|
+
const rel = toPosix(relative(root, candidate)) || '.'
|
|
41
|
+
if (isAbsolute(rel) || rel === '..' || rel.startsWith('../')) return undefined
|
|
42
|
+
try {
|
|
43
|
+
if (!lstatSync(candidate).isDirectory()) return undefined
|
|
44
|
+
const canonicalRoot = realpathSync.native(root)
|
|
45
|
+
const canonicalCandidate = realpathSync.native(candidate)
|
|
46
|
+
const canonicalRel = relative(canonicalRoot, canonicalCandidate)
|
|
47
|
+
if (
|
|
48
|
+
isAbsolute(canonicalRel) ||
|
|
49
|
+
canonicalRel === '..' ||
|
|
50
|
+
canonicalRel.startsWith(`..${sep}`)
|
|
51
|
+
) {
|
|
52
|
+
return undefined
|
|
53
|
+
}
|
|
54
|
+
} catch {
|
|
55
|
+
return undefined
|
|
56
|
+
}
|
|
57
|
+
return rel
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const packageId = (name: string): string =>
|
|
61
|
+
name.startsWith('@') ? (name.split('/').at(-1) ?? name) : name
|
|
62
|
+
|
|
63
|
+
const commandPrefix = (root: string): string => {
|
|
64
|
+
const manager = detectPackageManager(root)
|
|
65
|
+
if (manager === 'pnpm') return 'pnpm exec nx run'
|
|
66
|
+
if (manager === 'yarn') return 'yarn nx run'
|
|
67
|
+
if (manager === 'bun') return 'bunx nx run'
|
|
68
|
+
return 'npx nx run'
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const inferredChecks = (
|
|
72
|
+
root: string,
|
|
73
|
+
config: DocBridgeConfigV1,
|
|
74
|
+
projectName: string,
|
|
75
|
+
targets: ReadonlySet<string>,
|
|
76
|
+
): string[] | undefined => {
|
|
77
|
+
const prefix = commandPrefix(root)
|
|
78
|
+
const strict = (config.gates?.preset ?? 'minimal') !== 'minimal'
|
|
79
|
+
const checks = [
|
|
80
|
+
...(targets.has('test') ? [`${prefix} ${projectName}:test`] : []),
|
|
81
|
+
...(strict && targets.has('lint') ? [`${prefix} ${projectName}:lint`] : []),
|
|
82
|
+
]
|
|
83
|
+
return checks.length ? checks : undefined
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
type RankedProject = DiscoveredPackage & {
|
|
87
|
+
readonly rank: number
|
|
88
|
+
readonly targets: readonly string[]
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export const discoverNxProjects = (
|
|
92
|
+
root: string,
|
|
93
|
+
config: DocBridgeConfigV1,
|
|
94
|
+
): DiscoveredPackage[] => {
|
|
95
|
+
if (!existsSync(resolve(root, 'nx.json'))) return []
|
|
96
|
+
|
|
97
|
+
const manifests = walkFiles(root, {
|
|
98
|
+
extensions: ['project.json', 'package.json'],
|
|
99
|
+
skipDirs: NX_SCAN_SKIP,
|
|
100
|
+
maxFiles: 10_000,
|
|
101
|
+
})
|
|
102
|
+
const projects = new Map<string, RankedProject>()
|
|
103
|
+
|
|
104
|
+
for (const manifest of manifests) {
|
|
105
|
+
const json = readJsonRecord(manifest)
|
|
106
|
+
if (!json) continue
|
|
107
|
+
const manifestDir = dirname(manifest)
|
|
108
|
+
const manifestName = basename(manifest)
|
|
109
|
+
const isProjectJson = manifestName === 'project.json'
|
|
110
|
+
if (!isProjectJson && manifestName !== 'package.json') continue
|
|
111
|
+
const nx = json.nx
|
|
112
|
+
if (!isProjectJson && !isRecord(nx)) continue
|
|
113
|
+
|
|
114
|
+
const path = safeProjectPath(root, manifestDir, isProjectJson ? json.root : undefined)
|
|
115
|
+
if (!path) continue
|
|
116
|
+
const projectPackage = isProjectJson
|
|
117
|
+
? readJsonRecord(resolve(root, path, 'package.json'))
|
|
118
|
+
: undefined
|
|
119
|
+
const projectName =
|
|
120
|
+
typeof json.name === 'string'
|
|
121
|
+
? json.name
|
|
122
|
+
: typeof projectPackage?.name === 'string'
|
|
123
|
+
? projectPackage.name
|
|
124
|
+
: basename(path === '.' ? root : path)
|
|
125
|
+
if (!NX_PROJECT_NAME.test(projectName)) continue
|
|
126
|
+
|
|
127
|
+
const targets = new Set<string>()
|
|
128
|
+
const targetRecord = isProjectJson ? json.targets : isRecord(nx) ? nx.targets : undefined
|
|
129
|
+
if (isRecord(targetRecord)) {
|
|
130
|
+
for (const target of Object.keys(targetRecord)) targets.add(target)
|
|
131
|
+
}
|
|
132
|
+
if (!isProjectJson && isRecord(json.scripts)) {
|
|
133
|
+
for (const script of Object.keys(json.scripts)) targets.add(script)
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const id = packageId(projectName)
|
|
137
|
+
const rank = isProjectJson ? 2 : 1
|
|
138
|
+
const existing = projects.get(id)
|
|
139
|
+
if (existing && existing.path !== path) {
|
|
140
|
+
throw new Error(
|
|
141
|
+
`Nx project identity collision for "${id}": "${existing.name ?? id}" at "${existing.path}" and "${projectName}" at "${path}". Use unique Nx project names.`,
|
|
142
|
+
)
|
|
143
|
+
}
|
|
144
|
+
const mergedTargets = [...new Set([...(existing?.targets ?? []), ...targets])]
|
|
145
|
+
const projectJsonWins = rank >= (existing?.rank ?? 0)
|
|
146
|
+
const resolvedName = projectJsonWins ? projectName : (existing?.name ?? projectName)
|
|
147
|
+
const checks = inferredChecks(root, config, resolvedName, new Set(mergedTargets))
|
|
148
|
+
projects.set(id, {
|
|
149
|
+
id,
|
|
150
|
+
path,
|
|
151
|
+
name: resolvedName,
|
|
152
|
+
...(checks ? { checks } : {}),
|
|
153
|
+
rank: projectJsonWins ? rank : (existing?.rank ?? rank),
|
|
154
|
+
targets: mergedTargets,
|
|
155
|
+
})
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
return [...projects.values()]
|
|
159
|
+
.sort((a, b) => a.id.localeCompare(b.id))
|
|
160
|
+
.map(({ rank: _rank, targets: _targets, ...project }) => project)
|
|
161
|
+
}
|
|
@@ -13,6 +13,7 @@ export type WatchIndexOptions = {
|
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
const WATCH_PATTERN = /\.(md|mdx|json|ya?ml|mdc)$/i
|
|
16
|
+
const NX_MANIFEST_PATTERN = /(^|[/\\])(project|package)\.json$/i
|
|
16
17
|
|
|
17
18
|
const collectWatchRoots = (root: string, config: DocBridgeConfigV1, configPath?: string): string[] => {
|
|
18
19
|
const roots = new Set<string>()
|
|
@@ -24,7 +25,7 @@ const collectWatchRoots = (root: string, config: DocBridgeConfigV1, configPath?:
|
|
|
24
25
|
: []
|
|
25
26
|
for (const source of humanSources) {
|
|
26
27
|
const humanOpts = source.options ?? {}
|
|
27
|
-
for (const key of ['contentDir', 'docsDir', 'root']) {
|
|
28
|
+
for (const key of ['contentDir', 'docsDir', 'root', 'srcDir']) {
|
|
28
29
|
const value = humanOpts[key]
|
|
29
30
|
if (typeof value === 'string' && value.length) roots.add(resolve(root, value))
|
|
30
31
|
}
|
|
@@ -74,6 +75,14 @@ export const watchDocBridgeIndex = (opts: WatchIndexOptions): Promise<number> =>
|
|
|
74
75
|
})
|
|
75
76
|
}
|
|
76
77
|
|
|
78
|
+
const nxRoot = resolve(opts.root)
|
|
79
|
+
if (opts.config.routing?.plugin === 'nx' && existsSync(nxRoot)) {
|
|
80
|
+
watch(nxRoot, { recursive: true }, (_event, filename) => {
|
|
81
|
+
if (!filename || !NX_MANIFEST_PATTERN.test(filename)) return
|
|
82
|
+
rebuild()
|
|
83
|
+
})
|
|
84
|
+
}
|
|
85
|
+
|
|
77
86
|
const configDir = resolve(opts.root)
|
|
78
87
|
if (existsSync(configDir)) {
|
|
79
88
|
watch(configDir, (_event, filename) => {
|
|
@@ -91,4 +100,4 @@ export const watchDocBridgeIndex = (opts: WatchIndexOptions): Promise<number> =>
|
|
|
91
100
|
process.once('SIGINT', onSignal)
|
|
92
101
|
process.once('SIGTERM', onSignal)
|
|
93
102
|
})
|
|
94
|
-
}
|
|
103
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -155,6 +155,7 @@ export {
|
|
|
155
155
|
export { PACKAGE_VERSION } from './version.js'
|
|
156
156
|
|
|
157
157
|
export { collectPackages, buildLookup } from './index-builder/build-handoffs.js'
|
|
158
|
+
export { discoverNxProjects } from './index-builder/plugins/nx.js'
|
|
158
159
|
export { projectRootFromConfigPath } from './config/load-config.js'
|
|
159
160
|
export { createDocBridgeRag } from './intelligence/rag.js'
|
|
160
161
|
export { runChatOnce, startInkChat } from './intelligence/chat.js'
|
package/src/version.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const PACKAGE_VERSION = '1.
|
|
1
|
+
export const PACKAGE_VERSION = '1.4.0'
|