@agentskit/doc-bridge 0.1.0-alpha.1 → 0.1.0-alpha.2
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 +15 -0
- package/README.md +1 -1
- package/dist/cli/program.js +283 -105
- package/dist/cli/program.js.map +1 -1
- package/dist/config/index.d.ts +1 -1
- package/dist/config/index.js +6 -3
- package/dist/config/index.js.map +1 -1
- package/dist/{index-CD_zmKXf.d.ts → index-CPUJbTbg.d.ts} +19 -10
- package/dist/index.d.ts +5 -4
- package/dist/index.js +278 -100
- package/dist/index.js.map +1 -1
- package/docs/DOGFOOD.md +92 -0
- package/package.json +27 -9
- package/scripts/prepare.mjs +44 -0
- package/src/cli/program.ts +933 -0
- package/src/config/defaults.ts +63 -0
- package/src/config/define-config.ts +6 -0
- package/src/config/index.ts +15 -0
- package/src/config/load-config.ts +138 -0
- package/src/config/schema.ts +294 -0
- package/src/federation/llms.ts +145 -0
- package/src/gates/run-gates.ts +274 -0
- package/src/index-builder/build-handoffs.ts +217 -0
- package/src/index-builder/build-index.ts +137 -0
- package/src/index-builder/capabilities.ts +37 -0
- package/src/index-builder/content-hash.ts +19 -0
- package/src/index-builder/human-adapters/core.ts +100 -0
- package/src/index-builder/human-adapters/docusaurus.ts +113 -0
- package/src/index-builder/human-adapters/fumadocs.ts +70 -0
- package/src/index-builder/human-adapters/index.ts +52 -0
- package/src/index-builder/human-adapters/plain-markdown.ts +10 -0
- package/src/index-builder/llms-txt.ts +19 -0
- package/src/index-builder/plugins/human-markdown.ts +7 -0
- package/src/index-builder/plugins/pnpm-monorepo.ts +72 -0
- package/src/index-builder/scan-corpus.ts +181 -0
- package/src/index.ts +120 -0
- package/src/intelligence/adapter.ts +90 -0
- package/src/intelligence/chat.ts +148 -0
- package/src/intelligence/peers.ts +59 -0
- package/src/intelligence/rag.ts +98 -0
- package/src/lib/glob-expand.ts +33 -0
- package/src/lib/markdown.ts +90 -0
- package/src/lib/package-manager.ts +104 -0
- package/src/lib/paths.ts +6 -0
- package/src/lib/walk.ts +45 -0
- package/src/mcp/server.ts +276 -0
- package/src/memory/ingest.ts +51 -0
- package/src/memory/pipeline.ts +119 -0
- package/src/query/load-index.ts +25 -0
- package/src/query/query.ts +142 -0
- package/src/query/search.ts +58 -0
- package/src/retriever/doc-bridge-retriever.ts +62 -0
- package/src/schemas/agent-handoff.ts +82 -0
- package/src/schemas/doc-bridge-index.ts +106 -0
- package/src/schemas/json-schemas.ts +156 -0
- package/src/schemas/memory-candidate.ts +37 -0
- package/src/shims/agentskit-peers.d.ts +80 -0
- package/src/validate.ts +67 -0
- package/src/version.ts +1 -0
- package/tsconfig.json +21 -0
- package/tsup.config.ts +15 -0
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import type { DocBridgeConfigV1 } from '../config/schema.js'
|
|
2
|
+
import {
|
|
3
|
+
normalizeAgentHandoff,
|
|
4
|
+
type AgentHandoffV1,
|
|
5
|
+
type AgentSearchV1,
|
|
6
|
+
} from '../schemas/agent-handoff.js'
|
|
7
|
+
import type { DocBridgeIndexV1 } from '../schemas/doc-bridge-index.js'
|
|
8
|
+
import { searchIndex } from './search.js'
|
|
9
|
+
|
|
10
|
+
export type QueryKind = 'package' | 'ownership' | 'intent' | 'change' | 'search'
|
|
11
|
+
|
|
12
|
+
export type QueryRequest = {
|
|
13
|
+
readonly kind: QueryKind
|
|
14
|
+
readonly id?: string
|
|
15
|
+
readonly term?: string
|
|
16
|
+
readonly agent?: boolean
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export type QueryResult =
|
|
20
|
+
| { readonly type: 'package' | 'ownership' | 'intent' | 'change' | 'search'; readonly data: unknown }
|
|
21
|
+
| AgentHandoffV1
|
|
22
|
+
| AgentSearchV1
|
|
23
|
+
|
|
24
|
+
const handoffForPackage = (
|
|
25
|
+
index: DocBridgeIndexV1,
|
|
26
|
+
id: string,
|
|
27
|
+
config: DocBridgeConfigV1,
|
|
28
|
+
): AgentHandoffV1 => {
|
|
29
|
+
const fromIndex = index.handoffs?.[id]
|
|
30
|
+
if (fromIndex) return normalizeAgentHandoff(fromIndex)
|
|
31
|
+
|
|
32
|
+
const owner = index.lookup?.ownership?.[id]
|
|
33
|
+
if (!owner) throw new Error(`Unknown package/ownership id "${id}". Try: ak-docs list packages`)
|
|
34
|
+
|
|
35
|
+
return normalizeAgentHandoff({
|
|
36
|
+
type: 'agent-handoff',
|
|
37
|
+
source: config.index?.outFile ?? '.doc-bridge/index.json',
|
|
38
|
+
target: {
|
|
39
|
+
type: 'package',
|
|
40
|
+
id,
|
|
41
|
+
path: owner.path,
|
|
42
|
+
...(owner.group ? { group: owner.group } : {}),
|
|
43
|
+
...(owner.layer ? { layer: owner.layer } : {}),
|
|
44
|
+
},
|
|
45
|
+
startHere: owner.agentDoc ?? config.corpus.agent.index ?? '',
|
|
46
|
+
readBeforeEditing: [owner.agentDoc, 'AGENTS.md'].filter(Boolean),
|
|
47
|
+
editRoots: [owner.path],
|
|
48
|
+
checks: [...owner.checks],
|
|
49
|
+
...(owner.humanDoc ? { humanDoc: owner.humanDoc } : {}),
|
|
50
|
+
notes: owner.purpose ? [owner.purpose] : [],
|
|
51
|
+
})
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export const runQuery = (
|
|
55
|
+
index: DocBridgeIndexV1,
|
|
56
|
+
config: DocBridgeConfigV1,
|
|
57
|
+
req: QueryRequest,
|
|
58
|
+
): QueryResult => {
|
|
59
|
+
if (req.kind === 'search') {
|
|
60
|
+
const term = req.term ?? req.id ?? ''
|
|
61
|
+
const matches = searchIndex(index, term)
|
|
62
|
+
if (req.agent) {
|
|
63
|
+
const payload: AgentSearchV1 = {
|
|
64
|
+
type: 'agent-search',
|
|
65
|
+
schemaVersion: 1,
|
|
66
|
+
source: config.index?.outFile ?? '.doc-bridge/index.json',
|
|
67
|
+
term,
|
|
68
|
+
count: matches.length,
|
|
69
|
+
bestMatch: matches[0]
|
|
70
|
+
? {
|
|
71
|
+
type: matches[0].type,
|
|
72
|
+
id: matches[0].id,
|
|
73
|
+
path: matches[0].path,
|
|
74
|
+
...(matches[0].summary ? { summary: matches[0].summary } : {}),
|
|
75
|
+
score: matches[0].score,
|
|
76
|
+
}
|
|
77
|
+
: null,
|
|
78
|
+
matches: matches.slice(0, 8).map((m) => ({
|
|
79
|
+
type: m.type,
|
|
80
|
+
id: m.id,
|
|
81
|
+
path: m.path,
|
|
82
|
+
...(m.summary ? { summary: m.summary } : {}),
|
|
83
|
+
score: m.score,
|
|
84
|
+
})),
|
|
85
|
+
nextCommands: [...new Set(matches.slice(0, 5).map((m) =>
|
|
86
|
+
m.type === 'ownership' || index.lookup?.ownership?.[m.id]
|
|
87
|
+
? `ak-docs query ownership ${m.id} --agent`
|
|
88
|
+
: 'ak-docs list knowledge --text',
|
|
89
|
+
))],
|
|
90
|
+
}
|
|
91
|
+
return payload
|
|
92
|
+
}
|
|
93
|
+
return { type: 'search', data: { term, count: matches.length, matches } }
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const id = req.id
|
|
97
|
+
if (!id) throw new Error(`Missing id for query kind "${req.kind}"`)
|
|
98
|
+
|
|
99
|
+
if (req.kind === 'package' || req.kind === 'ownership') {
|
|
100
|
+
if (req.agent) return handoffForPackage(index, id, config)
|
|
101
|
+
const owner = index.lookup?.ownership?.[id]
|
|
102
|
+
return { type: req.kind, data: owner ?? index.handoffs?.[id] ?? null }
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (req.kind === 'intent') {
|
|
106
|
+
const intent = index.lookup?.intents?.[id]
|
|
107
|
+
if (!intent) throw new Error(`Unknown intent "${id}"`)
|
|
108
|
+
if (req.agent) {
|
|
109
|
+
return normalizeAgentHandoff({
|
|
110
|
+
type: 'agent-handoff',
|
|
111
|
+
source: config.index?.outFile ?? '.doc-bridge/index.json',
|
|
112
|
+
target: { type: 'intent', id },
|
|
113
|
+
startHere: intent.paths[0] ?? '',
|
|
114
|
+
readBeforeEditing: [...intent.paths],
|
|
115
|
+
editRoots: [],
|
|
116
|
+
checks: [],
|
|
117
|
+
notes: [intent.title],
|
|
118
|
+
})
|
|
119
|
+
}
|
|
120
|
+
return { type: 'intent', data: intent }
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if (req.kind === 'change') {
|
|
124
|
+
const change = index.lookup?.changes?.[id]
|
|
125
|
+
if (!change) throw new Error(`Unknown change route "${id}"`)
|
|
126
|
+
if (req.agent) {
|
|
127
|
+
return normalizeAgentHandoff({
|
|
128
|
+
type: 'agent-handoff',
|
|
129
|
+
source: config.index?.outFile ?? '.doc-bridge/index.json',
|
|
130
|
+
target: { type: 'change', id },
|
|
131
|
+
startHere: change.startHere,
|
|
132
|
+
readBeforeEditing: ['AGENTS.md', config.corpus.agent.index ?? ''].filter(Boolean),
|
|
133
|
+
editRoots: [change.startHere],
|
|
134
|
+
checks: [],
|
|
135
|
+
notes: [change.title],
|
|
136
|
+
})
|
|
137
|
+
}
|
|
138
|
+
return { type: 'change', data: change }
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
throw new Error(`Unsupported query kind: ${req.kind as string}`)
|
|
142
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type { DocBridgeIndexV1 } from '../schemas/doc-bridge-index.js'
|
|
2
|
+
|
|
3
|
+
export type SearchMatch = {
|
|
4
|
+
readonly type: string
|
|
5
|
+
readonly id: string
|
|
6
|
+
readonly path: string
|
|
7
|
+
readonly summary?: string
|
|
8
|
+
readonly score: number
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const tokenize = (value: string): string[] =>
|
|
12
|
+
value
|
|
13
|
+
.toLowerCase()
|
|
14
|
+
.split(/[^a-z0-9]+/)
|
|
15
|
+
.filter((t) => t.length >= 2)
|
|
16
|
+
|
|
17
|
+
export const searchIndex = (index: DocBridgeIndexV1, term: string, limit = 20): SearchMatch[] => {
|
|
18
|
+
const tokens = tokenize(term)
|
|
19
|
+
if (!tokens.length) return []
|
|
20
|
+
|
|
21
|
+
const matches: SearchMatch[] = []
|
|
22
|
+
|
|
23
|
+
for (const entry of index.knowledge) {
|
|
24
|
+
const hay = `${entry.id} ${entry.title} ${entry.description ?? ''} ${entry.path}`.toLowerCase()
|
|
25
|
+
let score = 0
|
|
26
|
+
for (const token of tokens) {
|
|
27
|
+
if (hay.includes(token)) score += token.length
|
|
28
|
+
}
|
|
29
|
+
if (score > 0) {
|
|
30
|
+
matches.push({
|
|
31
|
+
type: 'knowledge',
|
|
32
|
+
id: entry.id,
|
|
33
|
+
path: entry.path,
|
|
34
|
+
...(entry.description ? { summary: entry.description } : {}),
|
|
35
|
+
score,
|
|
36
|
+
})
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
for (const [id, owner] of Object.entries(index.lookup?.ownership ?? {})) {
|
|
41
|
+
const hay = `${id} ${owner.path} ${owner.purpose ?? ''} ${owner.group ?? ''}`.toLowerCase()
|
|
42
|
+
let score = 0
|
|
43
|
+
for (const token of tokens) {
|
|
44
|
+
if (hay.includes(token)) score += token.length * 2
|
|
45
|
+
}
|
|
46
|
+
if (score > 0) {
|
|
47
|
+
matches.push({
|
|
48
|
+
type: 'ownership',
|
|
49
|
+
id,
|
|
50
|
+
path: owner.agentDoc ?? owner.path,
|
|
51
|
+
...(owner.purpose ? { summary: owner.purpose } : {}),
|
|
52
|
+
score,
|
|
53
|
+
})
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return matches.sort((a, b) => b.score - a.score).slice(0, limit)
|
|
58
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import type { DocBridgeIndexV1 } from '../schemas/doc-bridge-index.js'
|
|
2
|
+
import { searchIndex } from '../query/search.js'
|
|
3
|
+
|
|
4
|
+
export type DocBridgeRetrieverOptions = {
|
|
5
|
+
readonly property?: string
|
|
6
|
+
readonly limit?: number
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export type DocBridgeRetrievedChunk = {
|
|
10
|
+
readonly chunkKey: string
|
|
11
|
+
readonly property: string
|
|
12
|
+
readonly type: string
|
|
13
|
+
readonly id: string
|
|
14
|
+
readonly path: string
|
|
15
|
+
readonly title?: string
|
|
16
|
+
readonly summary?: string
|
|
17
|
+
readonly score: number
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export type DocBridgeRetriever = {
|
|
21
|
+
readonly retrieve: (
|
|
22
|
+
query: string,
|
|
23
|
+
options?: Pick<DocBridgeRetrieverOptions, 'limit'>,
|
|
24
|
+
) => DocBridgeRetrievedChunk[]
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const chunkKey = (property: string, type: string, id: string): string =>
|
|
28
|
+
`${property}:${type}:${id}`
|
|
29
|
+
|
|
30
|
+
export const retrieveDocBridgeChunks = (
|
|
31
|
+
index: DocBridgeIndexV1,
|
|
32
|
+
query: string,
|
|
33
|
+
options: DocBridgeRetrieverOptions = {},
|
|
34
|
+
): DocBridgeRetrievedChunk[] => {
|
|
35
|
+
const property = options.property ?? index.project?.name ?? 'local'
|
|
36
|
+
const limit = options.limit ?? 8
|
|
37
|
+
|
|
38
|
+
return searchIndex(index, query, limit).map((match) => {
|
|
39
|
+
const knowledge = index.knowledge.find((entry) => entry.id === match.id && entry.path === match.path)
|
|
40
|
+
const owner = index.lookup?.ownership?.[match.id]
|
|
41
|
+
const type = match.type === 'ownership' ? 'ownership' : (knowledge?.type ?? match.type)
|
|
42
|
+
const summary = match.summary ?? owner?.purpose
|
|
43
|
+
return {
|
|
44
|
+
chunkKey: chunkKey(property, type, match.id),
|
|
45
|
+
property,
|
|
46
|
+
type,
|
|
47
|
+
id: match.id,
|
|
48
|
+
path: match.path,
|
|
49
|
+
...(knowledge?.title ? { title: knowledge.title } : {}),
|
|
50
|
+
...(summary ? { summary } : {}),
|
|
51
|
+
score: match.score,
|
|
52
|
+
}
|
|
53
|
+
})
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export const createDocBridgeRetriever = (
|
|
57
|
+
index: DocBridgeIndexV1,
|
|
58
|
+
options: DocBridgeRetrieverOptions = {},
|
|
59
|
+
): DocBridgeRetriever => ({
|
|
60
|
+
retrieve: (query, req = {}) =>
|
|
61
|
+
retrieveDocBridgeChunks(index, query, { ...options, ...req }),
|
|
62
|
+
})
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { z } from 'zod'
|
|
2
|
+
|
|
3
|
+
export const HANDOFF_SCHEMA_VERSION = 1 as const
|
|
4
|
+
|
|
5
|
+
export const HandoffTargetTypeSchema = z.enum([
|
|
6
|
+
'package',
|
|
7
|
+
'module',
|
|
8
|
+
'app',
|
|
9
|
+
'screen',
|
|
10
|
+
'flow',
|
|
11
|
+
'component',
|
|
12
|
+
'intent',
|
|
13
|
+
'change',
|
|
14
|
+
'search',
|
|
15
|
+
])
|
|
16
|
+
|
|
17
|
+
export type HandoffTargetType = z.infer<typeof HandoffTargetTypeSchema>
|
|
18
|
+
|
|
19
|
+
export const HandoffTargetSchema = z
|
|
20
|
+
.object({
|
|
21
|
+
type: HandoffTargetTypeSchema,
|
|
22
|
+
id: z.string().min(1).max(256),
|
|
23
|
+
path: z.string().min(1).max(512).optional(),
|
|
24
|
+
group: z.string().min(1).max(128).optional(),
|
|
25
|
+
layer: z.string().min(1).max(32).optional(),
|
|
26
|
+
})
|
|
27
|
+
.strict()
|
|
28
|
+
|
|
29
|
+
export type HandoffTarget = z.infer<typeof HandoffTargetSchema>
|
|
30
|
+
|
|
31
|
+
/** v1 — canonical AgentHandoff. Legacy payloads may omit schemaVersion. */
|
|
32
|
+
export const AgentHandoffV1Schema = z
|
|
33
|
+
.object({
|
|
34
|
+
type: z.literal('agent-handoff'),
|
|
35
|
+
schemaVersion: z.literal(HANDOFF_SCHEMA_VERSION).default(HANDOFF_SCHEMA_VERSION),
|
|
36
|
+
source: z.string().min(1).max(512),
|
|
37
|
+
target: HandoffTargetSchema,
|
|
38
|
+
startHere: z.string().min(1).max(512),
|
|
39
|
+
readBeforeEditing: z.array(z.string().min(1).max(512)).max(64),
|
|
40
|
+
editRoots: z.array(z.string().min(1).max(512)).max(32),
|
|
41
|
+
checks: z.array(z.string().min(1).max(256)).max(32),
|
|
42
|
+
humanDoc: z.string().min(1).max(512).nullable().optional(),
|
|
43
|
+
playbookPatterns: z.array(z.string().url()).max(16).optional(),
|
|
44
|
+
notes: z.array(z.string().min(1).max(1024)).max(16),
|
|
45
|
+
})
|
|
46
|
+
.strict()
|
|
47
|
+
|
|
48
|
+
export type AgentHandoffV1 = z.infer<typeof AgentHandoffV1Schema>
|
|
49
|
+
|
|
50
|
+
/** Accept legacy handoffs without schemaVersion. */
|
|
51
|
+
export const AgentHandoffLegacySchema = AgentHandoffV1Schema.omit({ schemaVersion: true }).extend({
|
|
52
|
+
schemaVersion: z.literal(HANDOFF_SCHEMA_VERSION).optional(),
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
export const AgentSearchMatchSchema = z
|
|
56
|
+
.object({
|
|
57
|
+
type: z.string().min(1).max(64),
|
|
58
|
+
id: z.string().min(1).max(256),
|
|
59
|
+
path: z.string().min(1).max(512),
|
|
60
|
+
summary: z.string().max(2048).optional(),
|
|
61
|
+
score: z.number().optional(),
|
|
62
|
+
refs: z.number().int().nonnegative().optional(),
|
|
63
|
+
})
|
|
64
|
+
.strict()
|
|
65
|
+
|
|
66
|
+
export const AgentSearchV1Schema = z
|
|
67
|
+
.object({
|
|
68
|
+
type: z.literal('agent-search'),
|
|
69
|
+
schemaVersion: z.literal(HANDOFF_SCHEMA_VERSION).default(HANDOFF_SCHEMA_VERSION),
|
|
70
|
+
source: z.string().min(1).max(512),
|
|
71
|
+
term: z.string().min(1).max(512),
|
|
72
|
+
count: z.number().int().nonnegative(),
|
|
73
|
+
bestMatch: AgentSearchMatchSchema.nullable(),
|
|
74
|
+
matches: z.array(AgentSearchMatchSchema).max(32),
|
|
75
|
+
nextCommands: z.array(z.string().min(1).max(512)).max(16),
|
|
76
|
+
})
|
|
77
|
+
.strict()
|
|
78
|
+
|
|
79
|
+
export type AgentSearchV1 = z.infer<typeof AgentSearchV1Schema>
|
|
80
|
+
|
|
81
|
+
export const normalizeAgentHandoff = (input: unknown): AgentHandoffV1 =>
|
|
82
|
+
AgentHandoffV1Schema.parse(AgentHandoffLegacySchema.parse(input))
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { z } from 'zod'
|
|
2
|
+
|
|
3
|
+
import { AgentHandoffLegacySchema } from './agent-handoff.js'
|
|
4
|
+
|
|
5
|
+
export const INDEX_SCHEMA_VERSION = 1 as const
|
|
6
|
+
|
|
7
|
+
export const ContentHashAlgoSchema = z.literal('sha256-normalized-v1')
|
|
8
|
+
|
|
9
|
+
export const EcosystemPropertySchema = z
|
|
10
|
+
.object({
|
|
11
|
+
id: z.string().min(1).max(64),
|
|
12
|
+
name: z.string().min(1).max(128),
|
|
13
|
+
url: z.string().url().optional(),
|
|
14
|
+
llms: z.string().url().optional(),
|
|
15
|
+
})
|
|
16
|
+
.strict()
|
|
17
|
+
|
|
18
|
+
export const KnowledgeEntrySchema = z
|
|
19
|
+
.object({
|
|
20
|
+
id: z.string().min(1).max(256),
|
|
21
|
+
type: z.string().min(1).max(128),
|
|
22
|
+
title: z.string().min(1).max(256),
|
|
23
|
+
path: z.string().min(1).max(512),
|
|
24
|
+
description: z.string().max(1024).optional(),
|
|
25
|
+
links: z.array(z.string().min(1).max(512)).max(64).optional(),
|
|
26
|
+
tags: z.array(z.string().min(1).max(64)).max(32).optional(),
|
|
27
|
+
})
|
|
28
|
+
.strict()
|
|
29
|
+
|
|
30
|
+
export const CapabilityRefSchema = z
|
|
31
|
+
.object({
|
|
32
|
+
id: z.string().min(1).max(256),
|
|
33
|
+
kind: z.string().min(1).max(64),
|
|
34
|
+
description: z.string().max(512).optional(),
|
|
35
|
+
})
|
|
36
|
+
.strict()
|
|
37
|
+
|
|
38
|
+
export const OwnershipRecordSchema = z
|
|
39
|
+
.object({
|
|
40
|
+
id: z.string().min(1).max(256),
|
|
41
|
+
path: z.string().min(1).max(512),
|
|
42
|
+
group: z.string().min(1).max(128).optional(),
|
|
43
|
+
layer: z.string().min(1).max(32).optional(),
|
|
44
|
+
purpose: z.string().max(1024).optional(),
|
|
45
|
+
checks: z.array(z.string().min(1).max(256)).max(32),
|
|
46
|
+
agentDoc: z.string().min(1).max(512).optional(),
|
|
47
|
+
humanDoc: z.string().min(1).max(512).optional(),
|
|
48
|
+
readme: z.string().min(1).max(512).optional(),
|
|
49
|
+
})
|
|
50
|
+
.strict()
|
|
51
|
+
|
|
52
|
+
export const IndexLookupSchema = z
|
|
53
|
+
.object({
|
|
54
|
+
packages: z.array(z.string().min(1).max(256)).max(2_000),
|
|
55
|
+
ownership: z.record(z.string().min(1).max(256), OwnershipRecordSchema).optional(),
|
|
56
|
+
intents: z
|
|
57
|
+
.record(
|
|
58
|
+
z.string().min(1).max(128),
|
|
59
|
+
z
|
|
60
|
+
.object({
|
|
61
|
+
id: z.string().min(1).max(128),
|
|
62
|
+
title: z.string().min(1).max(256),
|
|
63
|
+
paths: z.array(z.string().min(1).max(512)).max(32),
|
|
64
|
+
})
|
|
65
|
+
.strict(),
|
|
66
|
+
)
|
|
67
|
+
.optional(),
|
|
68
|
+
changes: z
|
|
69
|
+
.record(
|
|
70
|
+
z.string().min(1).max(128),
|
|
71
|
+
z
|
|
72
|
+
.object({
|
|
73
|
+
id: z.string().min(1).max(128),
|
|
74
|
+
title: z.string().min(1).max(256),
|
|
75
|
+
startHere: z.string().min(1).max(512),
|
|
76
|
+
relatedPackages: z.array(z.string().min(1).max(256)).max(32).optional(),
|
|
77
|
+
})
|
|
78
|
+
.strict(),
|
|
79
|
+
)
|
|
80
|
+
.optional(),
|
|
81
|
+
})
|
|
82
|
+
.strict()
|
|
83
|
+
|
|
84
|
+
export const DocBridgeIndexV1Schema = z
|
|
85
|
+
.object({
|
|
86
|
+
schemaVersion: z.literal(INDEX_SCHEMA_VERSION),
|
|
87
|
+
contentHash: z.string().regex(/^[a-f0-9]{64}$/),
|
|
88
|
+
contentHashAlgo: ContentHashAlgoSchema,
|
|
89
|
+
generatedAt: z.string().datetime().optional(),
|
|
90
|
+
project: z
|
|
91
|
+
.object({
|
|
92
|
+
name: z.string().min(1).max(128),
|
|
93
|
+
root: z.string().min(1).max(512).optional(),
|
|
94
|
+
})
|
|
95
|
+
.strict()
|
|
96
|
+
.optional(),
|
|
97
|
+
properties: z.array(EcosystemPropertySchema).max(16).optional(),
|
|
98
|
+
knowledge: z.array(KnowledgeEntrySchema).max(10_000),
|
|
99
|
+
capabilities: z.array(CapabilityRefSchema).max(5_000).optional(),
|
|
100
|
+
handoffs: z.record(z.string().min(1).max(256), AgentHandoffLegacySchema).optional(),
|
|
101
|
+
lookup: IndexLookupSchema.optional(),
|
|
102
|
+
})
|
|
103
|
+
.strict()
|
|
104
|
+
|
|
105
|
+
export type DocBridgeIndexV1 = z.infer<typeof DocBridgeIndexV1Schema>
|
|
106
|
+
export type KnowledgeEntry = z.infer<typeof KnowledgeEntrySchema>
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
type JsonSchema = {
|
|
2
|
+
readonly [key: string]: unknown
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
const stringArray = (maxItems: number): JsonSchema => ({
|
|
6
|
+
type: 'array',
|
|
7
|
+
items: { type: 'string', minLength: 1 },
|
|
8
|
+
maxItems,
|
|
9
|
+
})
|
|
10
|
+
|
|
11
|
+
export const AgentHandoffV1JsonSchema = {
|
|
12
|
+
$schema: 'https://json-schema.org/draft/2020-12/schema',
|
|
13
|
+
$id: 'https://agentskit.io/schemas/doc-bridge/agent-handoff-v1.schema.json',
|
|
14
|
+
title: 'AgentHandoff v1',
|
|
15
|
+
type: 'object',
|
|
16
|
+
additionalProperties: false,
|
|
17
|
+
required: [
|
|
18
|
+
'type',
|
|
19
|
+
'schemaVersion',
|
|
20
|
+
'source',
|
|
21
|
+
'target',
|
|
22
|
+
'startHere',
|
|
23
|
+
'readBeforeEditing',
|
|
24
|
+
'editRoots',
|
|
25
|
+
'checks',
|
|
26
|
+
'notes',
|
|
27
|
+
],
|
|
28
|
+
properties: {
|
|
29
|
+
type: { const: 'agent-handoff' },
|
|
30
|
+
schemaVersion: { const: 1 },
|
|
31
|
+
source: { type: 'string', minLength: 1, maxLength: 512 },
|
|
32
|
+
target: {
|
|
33
|
+
type: 'object',
|
|
34
|
+
additionalProperties: false,
|
|
35
|
+
required: ['type', 'id'],
|
|
36
|
+
properties: {
|
|
37
|
+
type: {
|
|
38
|
+
enum: ['package', 'module', 'app', 'screen', 'flow', 'component', 'intent', 'change', 'search'],
|
|
39
|
+
},
|
|
40
|
+
id: { type: 'string', minLength: 1, maxLength: 256 },
|
|
41
|
+
path: { type: 'string', minLength: 1, maxLength: 512 },
|
|
42
|
+
group: { type: 'string', minLength: 1, maxLength: 128 },
|
|
43
|
+
layer: { type: 'string', minLength: 1, maxLength: 32 },
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
startHere: { type: 'string', minLength: 1, maxLength: 512 },
|
|
47
|
+
readBeforeEditing: stringArray(64),
|
|
48
|
+
editRoots: stringArray(32),
|
|
49
|
+
checks: stringArray(32),
|
|
50
|
+
humanDoc: { anyOf: [{ type: 'string', minLength: 1, maxLength: 512 }, { type: 'null' }] },
|
|
51
|
+
playbookPatterns: { type: 'array', items: { type: 'string', format: 'uri' }, maxItems: 16 },
|
|
52
|
+
notes: stringArray(16),
|
|
53
|
+
},
|
|
54
|
+
} as const satisfies JsonSchema
|
|
55
|
+
|
|
56
|
+
export const MemoryCandidateV1JsonSchema = {
|
|
57
|
+
$schema: 'https://json-schema.org/draft/2020-12/schema',
|
|
58
|
+
$id: 'https://agentskit.io/schemas/doc-bridge/memory-candidate-v1.schema.json',
|
|
59
|
+
title: 'MemoryCandidate v1',
|
|
60
|
+
type: 'object',
|
|
61
|
+
additionalProperties: false,
|
|
62
|
+
required: ['schemaVersion', 'id', 'source', 'fact', 'suggestedType', 'confidence', 'references'],
|
|
63
|
+
properties: {
|
|
64
|
+
schemaVersion: { const: 1 },
|
|
65
|
+
id: { type: 'string', minLength: 1, maxLength: 256 },
|
|
66
|
+
source: { enum: ['cursor', 'claude', 'codex', 'copilot', 'agent-memory', 'manual'] },
|
|
67
|
+
rawPath: { type: 'string', minLength: 1, maxLength: 512 },
|
|
68
|
+
fact: { type: 'string', minLength: 1, maxLength: 8000 },
|
|
69
|
+
why: { type: 'string', maxLength: 4000 },
|
|
70
|
+
howToApply: { type: 'string', maxLength: 4000 },
|
|
71
|
+
suggestedType: { enum: ['user', 'feedback', 'project', 'reference', 'unknown'] },
|
|
72
|
+
confidence: { type: 'number', minimum: 0, maximum: 1 },
|
|
73
|
+
references: stringArray(64),
|
|
74
|
+
},
|
|
75
|
+
} as const satisfies JsonSchema
|
|
76
|
+
|
|
77
|
+
export const DocBridgeIndexV1JsonSchema = {
|
|
78
|
+
$schema: 'https://json-schema.org/draft/2020-12/schema',
|
|
79
|
+
$id: 'https://agentskit.io/schemas/doc-bridge/doc-bridge-index-v1.schema.json',
|
|
80
|
+
title: 'DocBridgeIndex v1',
|
|
81
|
+
type: 'object',
|
|
82
|
+
additionalProperties: false,
|
|
83
|
+
required: ['schemaVersion', 'contentHash', 'contentHashAlgo', 'knowledge'],
|
|
84
|
+
properties: {
|
|
85
|
+
schemaVersion: { const: 1 },
|
|
86
|
+
contentHash: { type: 'string', pattern: '^[a-f0-9]{64}$' },
|
|
87
|
+
contentHashAlgo: { const: 'sha256-normalized-v1' },
|
|
88
|
+
generatedAt: { type: 'string', format: 'date-time' },
|
|
89
|
+
project: {
|
|
90
|
+
type: 'object',
|
|
91
|
+
additionalProperties: false,
|
|
92
|
+
properties: {
|
|
93
|
+
name: { type: 'string', minLength: 1, maxLength: 128 },
|
|
94
|
+
root: { type: 'string', minLength: 1, maxLength: 512 },
|
|
95
|
+
},
|
|
96
|
+
},
|
|
97
|
+
properties: {
|
|
98
|
+
type: 'array',
|
|
99
|
+
maxItems: 16,
|
|
100
|
+
items: {
|
|
101
|
+
type: 'object',
|
|
102
|
+
additionalProperties: false,
|
|
103
|
+
required: ['id', 'name'],
|
|
104
|
+
properties: {
|
|
105
|
+
id: { type: 'string', minLength: 1, maxLength: 64 },
|
|
106
|
+
name: { type: 'string', minLength: 1, maxLength: 128 },
|
|
107
|
+
url: { type: 'string', format: 'uri' },
|
|
108
|
+
llms: { type: 'string', format: 'uri' },
|
|
109
|
+
},
|
|
110
|
+
},
|
|
111
|
+
},
|
|
112
|
+
knowledge: {
|
|
113
|
+
type: 'array',
|
|
114
|
+
maxItems: 10000,
|
|
115
|
+
items: {
|
|
116
|
+
type: 'object',
|
|
117
|
+
additionalProperties: false,
|
|
118
|
+
required: ['id', 'type', 'title', 'path'],
|
|
119
|
+
properties: {
|
|
120
|
+
id: { type: 'string', minLength: 1, maxLength: 256 },
|
|
121
|
+
type: { type: 'string', minLength: 1, maxLength: 128 },
|
|
122
|
+
title: { type: 'string', minLength: 1, maxLength: 256 },
|
|
123
|
+
path: { type: 'string', minLength: 1, maxLength: 512 },
|
|
124
|
+
description: { type: 'string', maxLength: 1024 },
|
|
125
|
+
links: stringArray(64),
|
|
126
|
+
tags: stringArray(32),
|
|
127
|
+
},
|
|
128
|
+
},
|
|
129
|
+
},
|
|
130
|
+
capabilities: {
|
|
131
|
+
type: 'array',
|
|
132
|
+
maxItems: 5000,
|
|
133
|
+
items: {
|
|
134
|
+
type: 'object',
|
|
135
|
+
additionalProperties: false,
|
|
136
|
+
required: ['id', 'kind'],
|
|
137
|
+
properties: {
|
|
138
|
+
id: { type: 'string', minLength: 1, maxLength: 256 },
|
|
139
|
+
kind: { type: 'string', minLength: 1, maxLength: 64 },
|
|
140
|
+
description: { type: 'string', maxLength: 512 },
|
|
141
|
+
},
|
|
142
|
+
},
|
|
143
|
+
},
|
|
144
|
+
handoffs: {
|
|
145
|
+
type: 'object',
|
|
146
|
+
additionalProperties: { type: 'object' },
|
|
147
|
+
},
|
|
148
|
+
lookup: { type: 'object' },
|
|
149
|
+
},
|
|
150
|
+
} as const satisfies JsonSchema
|
|
151
|
+
|
|
152
|
+
export const DocBridgeJsonSchemas = {
|
|
153
|
+
agentHandoffV1: AgentHandoffV1JsonSchema,
|
|
154
|
+
docBridgeIndexV1: DocBridgeIndexV1JsonSchema,
|
|
155
|
+
memoryCandidateV1: MemoryCandidateV1JsonSchema,
|
|
156
|
+
} as const
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { z } from 'zod'
|
|
2
|
+
|
|
3
|
+
export const MEMORY_CANDIDATE_SCHEMA_VERSION = 1 as const
|
|
4
|
+
|
|
5
|
+
export const MemorySourceSchema = z.enum([
|
|
6
|
+
'cursor',
|
|
7
|
+
'claude',
|
|
8
|
+
'codex',
|
|
9
|
+
'copilot',
|
|
10
|
+
'agent-memory',
|
|
11
|
+
'manual',
|
|
12
|
+
])
|
|
13
|
+
|
|
14
|
+
export const MemorySuggestedTypeSchema = z.enum([
|
|
15
|
+
'user',
|
|
16
|
+
'feedback',
|
|
17
|
+
'project',
|
|
18
|
+
'reference',
|
|
19
|
+
'unknown',
|
|
20
|
+
])
|
|
21
|
+
|
|
22
|
+
export const MemoryCandidateV1Schema = z
|
|
23
|
+
.object({
|
|
24
|
+
schemaVersion: z.literal(MEMORY_CANDIDATE_SCHEMA_VERSION),
|
|
25
|
+
id: z.string().min(1).max(256),
|
|
26
|
+
source: MemorySourceSchema,
|
|
27
|
+
rawPath: z.string().min(1).max(512).optional(),
|
|
28
|
+
fact: z.string().min(1).max(8_000),
|
|
29
|
+
why: z.string().max(4_000).optional(),
|
|
30
|
+
howToApply: z.string().max(4_000).optional(),
|
|
31
|
+
suggestedType: MemorySuggestedTypeSchema,
|
|
32
|
+
confidence: z.number().min(0).max(1),
|
|
33
|
+
references: z.array(z.string().min(1).max(512)).max(64),
|
|
34
|
+
})
|
|
35
|
+
.strict()
|
|
36
|
+
|
|
37
|
+
export type MemoryCandidateV1 = z.infer<typeof MemoryCandidateV1Schema>
|