docorbit 0.1.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 (144) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +660 -0
  3. package/apps/cli/bin/docorbit.js +8 -0
  4. package/apps/cli/src/commands/add.ts +44 -0
  5. package/apps/cli/src/commands/api.ts +38 -0
  6. package/apps/cli/src/commands/context.ts +47 -0
  7. package/apps/cli/src/commands/dashboard.ts +55 -0
  8. package/apps/cli/src/commands/diff.ts +30 -0
  9. package/apps/cli/src/commands/evaluate.ts +133 -0
  10. package/apps/cli/src/commands/examples.ts +39 -0
  11. package/apps/cli/src/commands/export.ts +89 -0
  12. package/apps/cli/src/commands/impact.ts +31 -0
  13. package/apps/cli/src/commands/init.ts +69 -0
  14. package/apps/cli/src/commands/inspect.ts +30 -0
  15. package/apps/cli/src/commands/mcp.ts +72 -0
  16. package/apps/cli/src/commands/pitfalls.ts +38 -0
  17. package/apps/cli/src/commands/recipes.ts +35 -0
  18. package/apps/cli/src/commands/search.ts +48 -0
  19. package/apps/cli/src/commands/update.ts +73 -0
  20. package/apps/cli/src/commands/verify.ts +48 -0
  21. package/apps/cli/src/formatters/colors.ts +23 -0
  22. package/apps/cli/src/formatters/inspection.ts +102 -0
  23. package/apps/cli/src/formatters/knowledge.ts +272 -0
  24. package/apps/cli/src/formatters/retrieval.ts +74 -0
  25. package/apps/cli/src/formatters/terminal.ts +6 -0
  26. package/apps/cli/src/formatters/verification.ts +126 -0
  27. package/apps/cli/src/index.ts +409 -0
  28. package/bin/docorbit.js +8 -0
  29. package/package.json +46 -0
  30. package/packages/core/src/dashboard/server.ts +314 -0
  31. package/packages/core/src/dashboard/ui.ts +586 -0
  32. package/packages/core/src/implementation-service.ts +451 -0
  33. package/packages/core/src/index.ts +7 -0
  34. package/packages/core/src/inspector.ts +71 -0
  35. package/packages/core/src/pipeline.ts +331 -0
  36. package/packages/crawler/src/config.ts +12 -0
  37. package/packages/crawler/src/fetcher.ts +185 -0
  38. package/packages/crawler/src/index.ts +2 -0
  39. package/packages/discovery/src/index.ts +31 -0
  40. package/packages/discovery/src/provider.ts +47 -0
  41. package/packages/discovery/src/providers/generic.ts +98 -0
  42. package/packages/discovery/src/providers/github.ts +61 -0
  43. package/packages/discovery/src/providers/llms-txt.ts +73 -0
  44. package/packages/discovery/src/providers/markdown.ts +48 -0
  45. package/packages/discovery/src/providers/openapi.ts +91 -0
  46. package/packages/discovery/src/providers/sitemap.ts +62 -0
  47. package/packages/discovery/src/providers/skill.ts +54 -0
  48. package/packages/discovery/src/ranker.ts +123 -0
  49. package/packages/evaluation/src/dataset.ts +963 -0
  50. package/packages/evaluation/src/index.ts +8 -0
  51. package/packages/evaluation/src/runner.ts +241 -0
  52. package/packages/evaluation/src/strategies/context7-runner.ts +269 -0
  53. package/packages/evaluation/src/strategies/docorbit-runner.ts +228 -0
  54. package/packages/evaluation/src/strategies/firecrawl-runner.ts +172 -0
  55. package/packages/evaluation/src/strategies/web-search-runner.ts +194 -0
  56. package/packages/evaluation/src/types.ts +34 -0
  57. package/packages/evaluation/src/version-matcher.ts +73 -0
  58. package/packages/export/src/agents-md.ts +200 -0
  59. package/packages/export/src/claude-md.ts +141 -0
  60. package/packages/export/src/docs-map.ts +150 -0
  61. package/packages/export/src/index.ts +6 -0
  62. package/packages/export/src/llms-txt.ts +96 -0
  63. package/packages/export/src/service.ts +250 -0
  64. package/packages/export/src/skill-md.ts +128 -0
  65. package/packages/mcp/src/index.ts +46 -0
  66. package/packages/mcp/src/resources/index.ts +189 -0
  67. package/packages/mcp/src/server.ts +278 -0
  68. package/packages/mcp/src/tools/analyze-impact.ts +74 -0
  69. package/packages/mcp/src/tools/check-api.ts +86 -0
  70. package/packages/mcp/src/tools/diff-docs.ts +68 -0
  71. package/packages/mcp/src/tools/export-context.ts +73 -0
  72. package/packages/mcp/src/tools/find-api.ts +99 -0
  73. package/packages/mcp/src/tools/find-example.ts +100 -0
  74. package/packages/mcp/src/tools/find-pitfall.ts +94 -0
  75. package/packages/mcp/src/tools/find-recipe.ts +98 -0
  76. package/packages/mcp/src/tools/get-doc.ts +130 -0
  77. package/packages/mcp/src/tools/get-docs-map.ts +64 -0
  78. package/packages/mcp/src/tools/get-version.ts +118 -0
  79. package/packages/mcp/src/tools/implementation-context.ts +88 -0
  80. package/packages/mcp/src/tools/index.ts +59 -0
  81. package/packages/mcp/src/tools/list-sources.ts +85 -0
  82. package/packages/mcp/src/tools/search-docs.ts +123 -0
  83. package/packages/mcp/src/tools/types.ts +28 -0
  84. package/packages/mcp/src/transports/http.ts +256 -0
  85. package/packages/mcp/src/transports/stdio.ts +105 -0
  86. package/packages/mcp/src/transports/types.ts +6 -0
  87. package/packages/mcp/src/types.ts +102 -0
  88. package/packages/normalizer/src/example-indexer.ts +240 -0
  89. package/packages/normalizer/src/html.ts +253 -0
  90. package/packages/normalizer/src/index.ts +8 -0
  91. package/packages/normalizer/src/llms.ts +83 -0
  92. package/packages/normalizer/src/openapi/endpoint-parser.ts +406 -0
  93. package/packages/normalizer/src/openapi/schema-resolver.ts +111 -0
  94. package/packages/normalizer/src/openapi.ts +2 -0
  95. package/packages/normalizer/src/page.ts +184 -0
  96. package/packages/normalizer/src/pitfall-extractor.ts +190 -0
  97. package/packages/normalizer/src/slicer.ts +455 -0
  98. package/packages/retrieval/src/engine.ts +120 -0
  99. package/packages/retrieval/src/index.ts +7 -0
  100. package/packages/retrieval/src/intent.ts +43 -0
  101. package/packages/retrieval/src/packer.ts +145 -0
  102. package/packages/retrieval/src/recipe-engine.ts +313 -0
  103. package/packages/retrieval/src/scorer.ts +139 -0
  104. package/packages/retrieval/src/weights.ts +31 -0
  105. package/packages/security/src/annotations.ts +112 -0
  106. package/packages/security/src/index.ts +2 -0
  107. package/packages/security/src/ssrf.ts +153 -0
  108. package/packages/shared/src/errors.ts +53 -0
  109. package/packages/shared/src/hashing.ts +23 -0
  110. package/packages/shared/src/index.ts +3 -0
  111. package/packages/shared/src/types.ts +881 -0
  112. package/packages/storage/src/db.ts +72 -0
  113. package/packages/storage/src/index.ts +11 -0
  114. package/packages/storage/src/interfaces.ts +115 -0
  115. package/packages/storage/src/repositories/api-repository.ts +219 -0
  116. package/packages/storage/src/repositories/chunk-repository.ts +316 -0
  117. package/packages/storage/src/repositories/example-repository.ts +206 -0
  118. package/packages/storage/src/repositories/page-repository.ts +205 -0
  119. package/packages/storage/src/repositories/pitfall-repository.ts +188 -0
  120. package/packages/storage/src/repositories/source-repository.ts +205 -0
  121. package/packages/storage/src/repository.ts +256 -0
  122. package/packages/storage/src/schema.ts +269 -0
  123. package/packages/storage/src/search-tokens.ts +28 -0
  124. package/packages/verification/src/diff-engine.ts +258 -0
  125. package/packages/verification/src/extractor.ts +339 -0
  126. package/packages/verification/src/impact-scanner.ts +203 -0
  127. package/packages/verification/src/index.ts +5 -0
  128. package/packages/verification/src/services.ts +238 -0
  129. package/packages/verification/src/verifier.ts +375 -0
  130. package/packages/workspace/src/detector.ts +143 -0
  131. package/packages/workspace/src/ecosystems/cargo.ts +84 -0
  132. package/packages/workspace/src/ecosystems/composer.ts +42 -0
  133. package/packages/workspace/src/ecosystems/go.ts +54 -0
  134. package/packages/workspace/src/ecosystems/index.ts +34 -0
  135. package/packages/workspace/src/ecosystems/maven.ts +34 -0
  136. package/packages/workspace/src/ecosystems/npm.ts +83 -0
  137. package/packages/workspace/src/ecosystems/pub.ts +40 -0
  138. package/packages/workspace/src/ecosystems/pypi.ts +100 -0
  139. package/packages/workspace/src/ecosystems/rubygems.ts +30 -0
  140. package/packages/workspace/src/ecosystems/types.ts +18 -0
  141. package/packages/workspace/src/index.ts +5 -0
  142. package/packages/workspace/src/lockfile.ts +194 -0
  143. package/packages/workspace/src/resolver.ts +234 -0
  144. package/packages/workspace/src/semver.ts +259 -0
@@ -0,0 +1,451 @@
1
+ import type {
2
+ DocOrbitRepository,
3
+ } from '../../storage/src/index.ts';
4
+ import {
5
+ RetrievalEngine,
6
+ RecipeEngine,
7
+ detectQueryIntent,
8
+ } from '../../retrieval/src/index.ts';
9
+ import {
10
+ detectWorkspaceDependencies,
11
+ WorkspaceResolver,
12
+ } from '../../workspace/src/index.ts';
13
+ import {
14
+ estimateTokenCount,
15
+ } from '../../shared/src/index.ts';
16
+ import type {
17
+ QueryIntent,
18
+ Recipe,
19
+ ApiEndpoint,
20
+ IndexedExample,
21
+ Pitfall,
22
+ DocumentChunk,
23
+ SearchResult,
24
+ DocVersionMatch,
25
+ } from '../../shared/src/index.ts';
26
+
27
+ export interface ImplementationContextRequest {
28
+ task: string;
29
+ projectPath?: string;
30
+ library?: string;
31
+ version?: string;
32
+ tokenBudget?: number;
33
+ }
34
+
35
+ export interface ProjectResolutionInfo {
36
+ root: string;
37
+ matchedDependency?: {
38
+ name: string;
39
+ ecosystem: string;
40
+ requestedVersion: string;
41
+ resolvedVersion?: string;
42
+ };
43
+ versionResolution?: {
44
+ targetVersion: string;
45
+ confidence: number;
46
+ snapshotId?: string;
47
+ matchedBy?: string;
48
+ };
49
+ resolvedDependency?: string;
50
+ projectVersion?: string;
51
+ docVersion?: string;
52
+ confidence?: number;
53
+ }
54
+
55
+ export interface ProvenanceItem {
56
+ sourceUrl: string;
57
+ authority: string;
58
+ retrievedAt?: string;
59
+ untrusted: true;
60
+ }
61
+
62
+ export interface VerificationHint {
63
+ endpoint: string;
64
+ method: string;
65
+ requiredParameters: string[];
66
+ requiredBodyFields: string[];
67
+ deprecated?: boolean;
68
+ warnings?: string[];
69
+ }
70
+
71
+ export interface ImplementationContextResult {
72
+ task: string;
73
+ detectedIntent: QueryIntent;
74
+ project?: ProjectResolutionInfo;
75
+ recipe: Recipe;
76
+ apiEndpoints: ApiEndpoint[];
77
+ examples: IndexedExample[];
78
+ pitfalls: Pitfall[];
79
+ chunks: DocumentChunk[];
80
+ totalEstimatedTokens: number;
81
+ tokenBudget: number;
82
+ markdown: string;
83
+ provenance: ProvenanceItem[];
84
+ verificationHints?: VerificationHint[];
85
+ untrusted: true;
86
+ untrustedContentNotice?: string;
87
+ }
88
+
89
+ export class ImplementationContextService {
90
+ private repo: DocOrbitRepository;
91
+ private retrievalEngine: RetrievalEngine;
92
+ private recipeEngine: RecipeEngine;
93
+ private workspaceResolver: WorkspaceResolver;
94
+
95
+ constructor(repo: DocOrbitRepository) {
96
+ this.repo = repo;
97
+ this.retrievalEngine = new RetrievalEngine(repo);
98
+ this.recipeEngine = new RecipeEngine(repo);
99
+ this.workspaceResolver = new WorkspaceResolver(repo);
100
+ }
101
+
102
+ /**
103
+ * Orchestrates the complete documentation intelligence pipeline for an agent task:
104
+ * task → project/dependency detection → version resolution → intent → retrieval →
105
+ * APIs → examples → pitfalls → recipe → token-budgeted context → provenance.
106
+ */
107
+ async getContext(request: ImplementationContextRequest): Promise<ImplementationContextResult> {
108
+ const task = request.task.trim();
109
+ const tokenBudget = request.tokenBudget || 4000;
110
+ let targetVersion = request.version;
111
+
112
+ // 1. Intent Detection
113
+ const detectedIntent = detectQueryIntent(task);
114
+
115
+ // 2. Project Awareness & Version Resolution
116
+ let projectInfo: ProjectResolutionInfo | undefined;
117
+
118
+ if (request.projectPath) {
119
+ try {
120
+ const scan = detectWorkspaceDependencies(request.projectPath);
121
+ const resolution = this.workspaceResolver.resolveWorkspace(scan);
122
+
123
+ let matchedDep = undefined;
124
+ let versionRes = undefined;
125
+
126
+ // If library was specified, look for it specifically
127
+ if (request.library) {
128
+ const libLower = request.library.toLowerCase();
129
+ matchedDep = scan.dependencies.find(d => d.name.toLowerCase() === libLower);
130
+ const match = resolution.matches.find(m => m.dependency.name.toLowerCase() === libLower);
131
+ if (match && match.targetVersion) {
132
+ targetVersion = targetVersion || match.targetVersion;
133
+ versionRes = {
134
+ targetVersion: match.targetVersion,
135
+ confidence: match.confidence,
136
+ snapshotId: match.snapshotId,
137
+ matchedBy: match.matchedBy,
138
+ };
139
+ }
140
+ } else {
141
+ // Find any relevant dependency mentioned in the task
142
+ const taskLower = task.toLowerCase();
143
+ for (const m of resolution.matches) {
144
+ if (taskLower.includes(m.dependency.name.toLowerCase()) && m.targetVersion) {
145
+ matchedDep = m.dependency;
146
+ targetVersion = targetVersion || m.targetVersion;
147
+ versionRes = {
148
+ targetVersion: m.targetVersion,
149
+ confidence: m.confidence,
150
+ snapshotId: m.snapshotId,
151
+ matchedBy: m.matchedBy,
152
+ };
153
+ break;
154
+ }
155
+ }
156
+ }
157
+
158
+ projectInfo = {
159
+ root: request.projectPath,
160
+ matchedDependency: matchedDep ? {
161
+ name: matchedDep.name,
162
+ ecosystem: matchedDep.ecosystem,
163
+ requestedVersion: matchedDep.requestedVersion,
164
+ resolvedVersion: matchedDep.resolvedVersion,
165
+ } : undefined,
166
+ versionResolution: versionRes,
167
+ resolvedDependency: matchedDep?.name,
168
+ projectVersion: matchedDep?.requestedVersion,
169
+ docVersion: versionRes?.targetVersion,
170
+ confidence: versionRes?.confidence,
171
+ };
172
+ } catch {
173
+ // Continue if workspace scan fails
174
+ }
175
+ }
176
+
177
+ // 3. Structured Recipe Generation
178
+ const recipe = await this.recipeEngine.assembleRecipe(task, {
179
+ docVersion: targetVersion,
180
+ projectDir: request.projectPath,
181
+ });
182
+
183
+ // 4. API Endpoints
184
+ const apiEndpoints = this.repo.searchApiEndpoints(task, {
185
+ docVersion: targetVersion,
186
+ limit: 5,
187
+ });
188
+
189
+ // 5. Verified Examples
190
+ const examples = this.repo.searchIndexedExamples(task, {
191
+ docVersion: targetVersion,
192
+ limit: 5,
193
+ });
194
+
195
+ // 6. Pitfalls & Deprecations
196
+ const pitfalls = this.repo.searchPitfalls(task, {
197
+ docVersion: targetVersion,
198
+ limit: 5,
199
+ });
200
+
201
+ // 7. Targeted Chunk Retrieval
202
+ const searchResults = await this.retrievalEngine.search(task, {
203
+ docVersion: targetVersion,
204
+ limit: 8,
205
+ projectDir: request.projectPath,
206
+ });
207
+ const chunks = searchResults.map(r => r.chunk);
208
+
209
+ // 8. Compile Provenance & Untrusted Boundaries
210
+ const provenanceMap = new Map<string, ProvenanceItem>();
211
+
212
+ const recordProvenance = (url?: string, authority?: string, date?: string) => {
213
+ if (url && !provenanceMap.has(url)) {
214
+ provenanceMap.set(url, {
215
+ sourceUrl: url,
216
+ authority: authority || 'official',
217
+ retrievedAt: date,
218
+ untrusted: true,
219
+ });
220
+ }
221
+ };
222
+
223
+ for (const c of chunks) {
224
+ if (c.provenance?.sourceUrl) {
225
+ recordProvenance(c.provenance.sourceUrl, undefined, c.provenance.fetchedAt);
226
+ }
227
+ }
228
+ for (const ep of apiEndpoints) {
229
+ if (ep.provenance?.sourceUrl) {
230
+ recordProvenance(ep.provenance.sourceUrl, ep.provenance.sourceAuthority, ep.provenance.retrievedAt);
231
+ }
232
+ }
233
+ for (const ex of examples) {
234
+ if (ex.sourceUrl) {
235
+ recordProvenance(ex.sourceUrl, ex.sourceAuthority);
236
+ }
237
+ }
238
+ for (const pf of pitfalls) {
239
+ if (pf.provenance?.sourceUrl) {
240
+ recordProvenance(pf.provenance.sourceUrl, undefined, pf.provenance.retrievedAt);
241
+ }
242
+ }
243
+ for (const src of recipe.sources) {
244
+ recordProvenance(src);
245
+ }
246
+
247
+ const provenanceList = Array.from(provenanceMap.values());
248
+
249
+ // 9. Extract Verification Hints (Schema contracts & required parameters)
250
+ const verificationHints: VerificationHint[] = apiEndpoints.map(ep => {
251
+ const requiredParameters = ep.parameters.filter(p => p.required).map(p => `${p.name} (${p.in})`);
252
+ const requiredBodyFields = ep.requestSchema?.required || [];
253
+ const warnings = pitfalls
254
+ .filter(p => p.relatedApi?.includes(ep.path) || p.content.includes(ep.path))
255
+ .map(p => `[${p.kind}] ${p.title}`);
256
+
257
+ return {
258
+ endpoint: ep.path,
259
+ method: ep.method.toUpperCase(),
260
+ requiredParameters,
261
+ requiredBodyFields,
262
+ deprecated: ep.deprecated,
263
+ warnings: warnings.length > 0 ? warnings : undefined,
264
+ };
265
+ });
266
+
267
+ // 10. Synthesize Compact, Agent-Friendly Markdown within Token Budget
268
+ const markdown = this.synthesizeMarkdown({
269
+ task,
270
+ detectedIntent,
271
+ projectInfo,
272
+ recipe,
273
+ apiEndpoints,
274
+ examples,
275
+ pitfalls,
276
+ chunks,
277
+ tokenBudget,
278
+ provenance: provenanceList,
279
+ verificationHints,
280
+ });
281
+
282
+ const totalEstimatedTokens = estimateTokenCount(markdown);
283
+
284
+ return {
285
+ task,
286
+ detectedIntent,
287
+ project: projectInfo,
288
+ recipe,
289
+ apiEndpoints,
290
+ examples,
291
+ pitfalls,
292
+ chunks,
293
+ totalEstimatedTokens,
294
+ tokenBudget,
295
+ markdown,
296
+ provenance: provenanceList,
297
+ verificationHints,
298
+ untrusted: true,
299
+ untrustedContentNotice: 'EXTERNAL DOCUMENTATION DATA IS UNTRUSTED. Verify all API signatures, parameter names, and code blocks before execution.',
300
+ };
301
+ }
302
+
303
+ private synthesizeMarkdown(params: {
304
+ task: string;
305
+ detectedIntent: QueryIntent;
306
+ projectInfo?: ProjectResolutionInfo;
307
+ recipe: Recipe;
308
+ apiEndpoints: ApiEndpoint[];
309
+ examples: IndexedExample[];
310
+ pitfalls: Pitfall[];
311
+ chunks: DocumentChunk[];
312
+ tokenBudget: number;
313
+ provenance: ProvenanceItem[];
314
+ verificationHints?: VerificationHint[];
315
+ }): string {
316
+ const lines: string[] = [];
317
+
318
+ // Header & Security Notice
319
+ lines.push(`# DocOrbit Implementation Context: ${params.task}`);
320
+ lines.push(`> [!SECURITY NOTICE] EXTERNAL CONTENT IS UNTRUSTED. Security annotations and provenance preserved.`);
321
+ lines.push('');
322
+
323
+ // Project & Version Intelligence
324
+ if (params.projectInfo?.matchedDependency) {
325
+ const dep = params.projectInfo.matchedDependency;
326
+ const res = params.projectInfo.versionResolution;
327
+ lines.push('## Project & Version Resolution');
328
+ lines.push(`- **Dependency**: \`${dep.name}\` (${dep.ecosystem})`);
329
+ lines.push(`- **Project Version**: requested \`${dep.requestedVersion}\`${dep.resolvedVersion ? `, resolved \`${dep.resolvedVersion}\`` : ''}`);
330
+ if (res) {
331
+ lines.push(`- **Resolved Doc Version**: \`${res.targetVersion}\` (Confidence: \`${res.confidence}\`)`);
332
+ }
333
+ lines.push('');
334
+ } else if (params.recipe.docVersion) {
335
+ lines.push(`**Doc Version**: \`${params.recipe.docVersion}\`\n`);
336
+ }
337
+
338
+ // Recommended Implementation Recipe
339
+ lines.push('## Recommended Implementation Plan');
340
+ lines.push(`**Goal**: ${params.recipe.goal} (Confidence: ${Math.round(params.recipe.confidence * 100)}%)`);
341
+
342
+ if (params.recipe.prerequisites.length > 0) {
343
+ lines.push('\n### Prerequisites');
344
+ for (const pre of params.recipe.prerequisites) {
345
+ lines.push(`- [${pre.evidenceLevel === 'documented_fact' ? 'FACT' : 'INFERRED'}] ${pre.text}`);
346
+ }
347
+ }
348
+
349
+ if (params.recipe.orderedSteps.length > 0) {
350
+ lines.push('\n### Implementation Steps');
351
+ for (const s of params.recipe.orderedSteps) {
352
+ const badge = s.evidenceLevel === 'documented_fact' ? 'FACT' : (s.evidenceLevel === 'missing_information' ? 'MISSING' : 'INFERRED');
353
+ lines.push(`${s.step}. **[${badge}] ${s.title}**`);
354
+ if (s.apiEndpoint) lines.push(` - Endpoint: \`${s.apiEndpoint}\``);
355
+ lines.push(` - ${s.description}`);
356
+ }
357
+ }
358
+
359
+ if (params.recipe.validationSteps.length > 0) {
360
+ lines.push('\n### Validation & Verification');
361
+ for (const vs of params.recipe.validationSteps) {
362
+ lines.push(`${vs.step}. **[FACT]** ${vs.description}`);
363
+ if (vs.expectedResponse) lines.push(` - Expected: \`${vs.expectedResponse}\``);
364
+ }
365
+ }
366
+ lines.push('');
367
+
368
+ // Structured Required APIs
369
+ if (params.apiEndpoints.length > 0) {
370
+ lines.push('## Required API Endpoints');
371
+ for (const ep of params.apiEndpoints.slice(0, 3)) {
372
+ lines.push(`### \`${ep.method.toUpperCase()} ${ep.path}\`${ep.deprecated ? ' (DEPRECATED)' : ''}`);
373
+ if (ep.summary) lines.push(`*${ep.summary}*`);
374
+ if (ep.parameters.length > 0) {
375
+ const req = ep.parameters.filter(p => p.required).map(p => `\`${p.name}\` (${p.in}:${p.type || 'any'})`).join(', ');
376
+ const opt = ep.parameters.filter(p => !p.required).map(p => `\`${p.name}\``).join(', ');
377
+ if (req) lines.push(`- **Required Parameters**: ${req}`);
378
+ if (opt) lines.push(`- **Optional Parameters**: ${opt}`);
379
+ }
380
+ if (ep.auth.length > 0) {
381
+ lines.push(`- **Auth**: ${ep.auth.map(a => `${a.type}${a.scheme ? `:${a.scheme}` : ''}`).join(', ')}`);
382
+ }
383
+ if (ep.pagination) {
384
+ lines.push(`- **Pagination**: ${ep.pagination.type} (${ep.pagination.parameters.join(', ')})`);
385
+ }
386
+ lines.push('');
387
+ }
388
+ }
389
+
390
+ // Best Code Examples
391
+ if (params.examples.length > 0) {
392
+ lines.push('## Verified Code Examples');
393
+ for (const ex of params.examples.slice(0, 2)) {
394
+ lines.push(`### ${ex.task} (${ex.language}${ex.framework ? `, ${ex.framework}` : ''})`);
395
+ lines.push('```' + ex.language);
396
+ lines.push(ex.code);
397
+ lines.push('```\n');
398
+ }
399
+ }
400
+
401
+ // Pitfalls, Gotchas & Deprecations
402
+ if (params.pitfalls.length > 0) {
403
+ lines.push('## Pitfalls & Warnings');
404
+ for (const pf of params.pitfalls.slice(0, 4)) {
405
+ lines.push(`- ⚠️ **[${pf.kind.toUpperCase()}] ${pf.title}**: ${pf.content}`);
406
+ }
407
+ lines.push('');
408
+ }
409
+
410
+ // Verification Constraints & Schema Contracts
411
+ if (params.verificationHints && params.verificationHints.length > 0) {
412
+ lines.push('## Verification Constraints & Schema Contracts');
413
+ for (const hint of params.verificationHints.slice(0, 3)) {
414
+ lines.push(`- **\`${hint.method} ${hint.endpoint}\`**${hint.deprecated ? ' (DEPRECATED)' : ''}`);
415
+ if (hint.requiredParameters.length > 0) {
416
+ lines.push(` - *Required Query/Path Params*: \`${hint.requiredParameters.join('`, `')}\``);
417
+ }
418
+ if (hint.requiredBodyFields.length > 0) {
419
+ lines.push(` - *Required Body Fields*: \`${hint.requiredBodyFields.join('`, `')}\``);
420
+ }
421
+ if (hint.warnings && hint.warnings.length > 0) {
422
+ for (const w of hint.warnings) {
423
+ lines.push(` - ⚠️ ${w}`);
424
+ }
425
+ }
426
+ }
427
+ lines.push('');
428
+ }
429
+
430
+ // Sources & Provenance
431
+ if (params.provenance.length > 0) {
432
+ lines.push('## Documentation Sources & Provenance');
433
+ for (const prov of params.provenance) {
434
+ lines.push(`- \`${prov.authority}\`: ${prov.sourceUrl} (untrusted)`);
435
+ }
436
+ lines.push('');
437
+ }
438
+
439
+ // Budget enforcement
440
+ let fullText = lines.join('\n');
441
+ let tokens = estimateTokenCount(fullText);
442
+
443
+ if (tokens > params.tokenBudget) {
444
+ // Trim examples or documentation chunks to fit strictly in budget
445
+ const truncated = fullText.slice(0, Math.floor(params.tokenBudget * 3.5)) + '\n\n... [Context truncated to fit token budget]';
446
+ return truncated;
447
+ }
448
+
449
+ return fullText;
450
+ }
451
+ }
@@ -0,0 +1,7 @@
1
+ export * from './inspector.ts';
2
+ export * from './pipeline.ts';
3
+ export * from './implementation-service.ts';
4
+ export * from '../../verification/src/index.ts';
5
+ export * from '../../export/src/index.ts';
6
+ export * from './dashboard/server.ts';
7
+
@@ -0,0 +1,71 @@
1
+ import type {
2
+ DiscoveredSource,
3
+ SourcePurpose,
4
+ SourceRankResult,
5
+ Target,
6
+ } from '../../shared/src/index.ts';
7
+ import { validateTargetUrl } from '../../security/src/index.ts';
8
+ import { SecureFetcher } from '../../crawler/src/index.ts';
9
+ import { createDefaultDiscoveryCoordinator, rankSources } from '../../discovery/src/index.ts';
10
+
11
+ export interface InspectionReport {
12
+ targetUrl: string;
13
+ target?: Target;
14
+ sourcesDiscovered: DiscoveredSource[];
15
+ recommendations: Record<SourcePurpose, SourceRankResult>;
16
+ summary: {
17
+ totalFound: number;
18
+ machineReadableCount: number;
19
+ officialCount: number;
20
+ hasOpenApi: boolean;
21
+ hasLlmsTxt: boolean;
22
+ hasLlmsFullTxt: boolean;
23
+ hasSkill: boolean;
24
+ hasSitemap: boolean;
25
+ };
26
+ }
27
+
28
+ export async function inspectDocumentation(
29
+ targetUrl: string,
30
+ options: { allowLocalhostForTesting?: boolean; fetcher?: SecureFetcher } = {}
31
+ ): Promise<InspectionReport> {
32
+ // Validate target URL against SSRF and illegal protocols before probing
33
+ await validateTargetUrl(targetUrl, {
34
+ allowLocalhostForTesting: options.allowLocalhostForTesting,
35
+ });
36
+
37
+ const fetcher = options.fetcher || new SecureFetcher({ allowLocalhostForTesting: options.allowLocalhostForTesting });
38
+ const coordinator = createDefaultDiscoveryCoordinator();
39
+
40
+ const discovered = await coordinator.discoverAll(targetUrl, fetcher);
41
+
42
+ const purposes: SourcePurpose[] = ['navigation', 'conceptual', 'api', 'examples', 'implementation'];
43
+ const recommendations: Partial<Record<SourcePurpose, SourceRankResult>> = {};
44
+
45
+ for (const p of purposes) {
46
+ recommendations[p] = rankSources(discovered, p);
47
+ }
48
+
49
+ const validSources = discovered.filter(s => s.status === 'valid');
50
+
51
+ return {
52
+ targetUrl,
53
+ target: {
54
+ type: 'url',
55
+ value: targetUrl,
56
+ normalizedUrl: targetUrl,
57
+ },
58
+ sourcesDiscovered: discovered,
59
+ recommendations: recommendations as Record<SourcePurpose, SourceRankResult>,
60
+ summary: {
61
+ totalFound: discovered.length,
62
+ machineReadableCount: validSources.filter(s => s.machineReadable).length,
63
+ officialCount: validSources.filter(s => s.authority === 'official').length,
64
+ hasOpenApi: validSources.some(s => s.type === 'openapi'),
65
+ hasLlmsTxt: validSources.some(s => s.type === 'llms_txt'),
66
+ hasLlmsFullTxt: validSources.some(s => s.type === 'llms_full_txt'),
67
+ hasSkill: validSources.some(s => s.type === 'skill'),
68
+ hasSitemap: validSources.some(s => s.type === 'sitemap'),
69
+ },
70
+ };
71
+ }