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,314 @@
1
+ import http from 'node:http';
2
+ import { URL } from 'node:url';
3
+ import type {
4
+ DocOrbitRepository,
5
+ } from '../../../storage/src/index.ts';
6
+ import { ExportService } from '../../../export/src/index.ts';
7
+ import {
8
+ VerificationService,
9
+ DiffService,
10
+ ImpactAnalysisService,
11
+ } from '../../../verification/src/index.ts';
12
+ import type {
13
+ DashboardStats,
14
+ ExportFormat,
15
+ PitfallKind,
16
+ } from '../../../shared/src/index.ts';
17
+ import { renderDashboardHtml } from './ui.ts';
18
+
19
+ export interface DashboardServerOptions {
20
+ repo: DocOrbitRepository;
21
+ projectDir?: string;
22
+ dbPath?: string;
23
+ }
24
+
25
+ export class DashboardServer {
26
+ private repo: DocOrbitRepository;
27
+ private projectDir?: string;
28
+ private dbPath: string;
29
+ private exportService: ExportService;
30
+ private verificationService: VerificationService;
31
+ private diffService: DiffService;
32
+ private impactService: ImpactAnalysisService;
33
+ private server: http.Server | null = null;
34
+
35
+ constructor(options: DashboardServerOptions) {
36
+ this.repo = options.repo;
37
+ this.projectDir = options.projectDir;
38
+ this.dbPath = options.dbPath || '.docorbit/docorbit.db';
39
+ this.exportService = new ExportService(this.repo);
40
+ this.verificationService = new VerificationService(this.repo);
41
+ this.diffService = new DiffService(this.repo);
42
+ this.impactService = new ImpactAnalysisService(this.repo);
43
+ }
44
+
45
+ /**
46
+ * Starts the local dashboard HTTP server.
47
+ */
48
+ start(port = 3737, host = '127.0.0.1'): Promise<{ server: http.Server; url: string; port: number }> {
49
+ return new Promise((resolve, reject) => {
50
+ this.server = http.createServer(async (req, res) => {
51
+ try {
52
+ await this.handleRequest(req, res);
53
+ } catch (err: any) {
54
+ res.writeHead(500, { 'Content-Type': 'application/json' });
55
+ res.end(JSON.stringify({ error: err.message || 'Internal Server Error' }));
56
+ }
57
+ });
58
+
59
+ this.server.on('error', (err) => {
60
+ reject(err);
61
+ });
62
+
63
+ this.server.listen(port, host, () => {
64
+ const address = this.server!.address() as { port: number; address: string };
65
+ const actualPort = address.port;
66
+ const url = `http://${host}:${actualPort}/`;
67
+ resolve({ server: this.server!, url, port: actualPort });
68
+ });
69
+ });
70
+ }
71
+
72
+ /**
73
+ * Stops the server gracefully.
74
+ */
75
+ stop(): Promise<void> {
76
+ return new Promise((resolve) => {
77
+ if (this.server) {
78
+ this.server.close(() => {
79
+ this.server = null;
80
+ resolve();
81
+ });
82
+ } else {
83
+ resolve();
84
+ }
85
+ });
86
+ }
87
+
88
+ async handleRequest(req: http.IncomingMessage, res: http.ServerResponse): Promise<void> {
89
+ const parsedUrl = new URL(req.url || '/', `http://${req.headers.host || '127.0.0.1'}`);
90
+ const pathname = parsedUrl.pathname;
91
+ const method = (req.method || 'GET').toUpperCase();
92
+
93
+ // CORS for local development
94
+ res.setHeader('Access-Control-Allow-Origin', '*');
95
+ res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
96
+ res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
97
+
98
+ if (method === 'OPTIONS') {
99
+ res.writeHead(204);
100
+ res.end();
101
+ return;
102
+ }
103
+
104
+ // Root UI
105
+ if (pathname === '/' || pathname === '/index.html') {
106
+ res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
107
+ res.end(renderDashboardHtml());
108
+ return;
109
+ }
110
+
111
+ // JSON REST API
112
+ if (pathname.startsWith('/api/')) {
113
+ res.setHeader('Content-Type', 'application/json; charset=utf-8');
114
+
115
+ if (pathname === '/api/stats' && method === 'GET') {
116
+ const stats = this.getStats();
117
+ res.writeHead(200);
118
+ res.end(JSON.stringify(stats));
119
+ return;
120
+ }
121
+
122
+ if (pathname === '/api/sources' && method === 'GET') {
123
+ const sources = this.repo.sources.listSources();
124
+ res.writeHead(200);
125
+ res.end(JSON.stringify(sources));
126
+ return;
127
+ }
128
+
129
+ if (pathname === '/api/pages' && method === 'GET') {
130
+ const pages = this.repo.pages.listPages(200);
131
+ res.writeHead(200);
132
+ res.end(JSON.stringify(pages));
133
+ return;
134
+ }
135
+
136
+ if (pathname === '/api/apis' && method === 'GET') {
137
+ const q = parsedUrl.searchParams.get('q') || '';
138
+ const apiMethod = parsedUrl.searchParams.get('method') || undefined;
139
+ const docVersion = parsedUrl.searchParams.get('docVersion') || undefined;
140
+ const apis = this.repo.apis.searchApiEndpoints(q, {
141
+ method: apiMethod,
142
+ docVersion,
143
+ limit: 100,
144
+ });
145
+ res.writeHead(200);
146
+ res.end(JSON.stringify(apis));
147
+ return;
148
+ }
149
+
150
+ if (pathname === '/api/pitfalls' && method === 'GET') {
151
+ const q = parsedUrl.searchParams.get('q') || '';
152
+ const kind = (parsedUrl.searchParams.get('kind') as PitfallKind) || undefined;
153
+ const docVersion = parsedUrl.searchParams.get('docVersion') || undefined;
154
+ const pitfalls = this.repo.pitfalls.searchPitfalls(q, {
155
+ kind,
156
+ docVersion,
157
+ limit: 100,
158
+ });
159
+ res.writeHead(200);
160
+ res.end(JSON.stringify(pitfalls));
161
+ return;
162
+ }
163
+
164
+ if (pathname === '/api/examples' && method === 'GET') {
165
+ const q = parsedUrl.searchParams.get('q') || '';
166
+ const language = parsedUrl.searchParams.get('language') || undefined;
167
+ const framework = parsedUrl.searchParams.get('framework') || undefined;
168
+ const docVersion = parsedUrl.searchParams.get('docVersion') || undefined;
169
+ const examples = this.repo.examples.searchIndexedExamples(q, {
170
+ language,
171
+ framework,
172
+ docVersion,
173
+ limit: 50,
174
+ });
175
+ res.writeHead(200);
176
+ res.end(JSON.stringify(examples));
177
+ return;
178
+ }
179
+
180
+ if (pathname === '/api/docs-map' && method === 'GET') {
181
+ const sourceId = parsedUrl.searchParams.get('sourceId') || undefined;
182
+ const docVersion = parsedUrl.searchParams.get('docVersion') || undefined;
183
+ const map = this.exportService.getDocumentationMap({ sourceId, docVersion });
184
+ res.writeHead(200);
185
+ res.end(JSON.stringify(map));
186
+ return;
187
+ }
188
+
189
+ if (pathname === '/api/export' && method === 'GET') {
190
+ const format = (parsedUrl.searchParams.get('format') || 'agents.md') as ExportFormat;
191
+ const docVersion = parsedUrl.searchParams.get('docVersion') || undefined;
192
+ const exp = await this.exportService.generateExport({
193
+ format,
194
+ docVersion,
195
+ projectDir: this.projectDir,
196
+ });
197
+ res.writeHead(200);
198
+ res.end(JSON.stringify(exp));
199
+ return;
200
+ }
201
+
202
+ if (pathname === '/api/verify' && method === 'POST') {
203
+ const body = await this.readJsonBody(req);
204
+ const code = body.code || '';
205
+ const version = body.version || body.docVersion;
206
+ const library = body.library;
207
+ const language = body.language;
208
+
209
+ const verifyResult = this.verificationService.verifyCode({
210
+ code,
211
+ version,
212
+ library,
213
+ language,
214
+ projectDir: this.projectDir,
215
+ });
216
+
217
+ res.writeHead(200);
218
+ res.end(JSON.stringify(verifyResult));
219
+ return;
220
+ }
221
+
222
+ if (pathname === '/api/diff' && method === 'GET') {
223
+ const from = parsedUrl.searchParams.get('from') || undefined;
224
+ const to = parsedUrl.searchParams.get('to') || undefined;
225
+ const source = parsedUrl.searchParams.get('source') || undefined;
226
+ const diffResult = this.diffService.diff({ from, to, source });
227
+ res.writeHead(200);
228
+ res.end(JSON.stringify(diffResult));
229
+ return;
230
+ }
231
+
232
+ if (pathname === '/api/impact' && method === 'GET') {
233
+ const from = parsedUrl.searchParams.get('from') || undefined;
234
+ const to = parsedUrl.searchParams.get('to') || undefined;
235
+ const targetDir = parsedUrl.searchParams.get('projectDir') || this.projectDir || process.cwd();
236
+ const impactResult = this.impactService.analyzeWorkspaceImpact({
237
+ from,
238
+ to,
239
+ projectDir: targetDir,
240
+ });
241
+ res.writeHead(200);
242
+ res.end(JSON.stringify(impactResult));
243
+ return;
244
+ }
245
+
246
+ res.writeHead(404);
247
+ res.end(JSON.stringify({ error: `Route not found: ${pathname}` }));
248
+ return;
249
+ }
250
+
251
+ res.writeHead(404, { 'Content-Type': 'text/plain' });
252
+ res.end('Not Found');
253
+ }
254
+
255
+ private getStats(): DashboardStats {
256
+ const sources = this.repo.sources.listSources();
257
+ const totalPages = this.repo.pages.countPages();
258
+ const totalChunks = this.repo.chunks.countChunks();
259
+
260
+ let totalApis = 0;
261
+ let totalPitfalls = 0;
262
+ let totalExamples = 0;
263
+ const activeVersions = new Set<string>();
264
+
265
+ try {
266
+ const raw = this.repo.db.getRawDb();
267
+ const apiRow = raw.prepare('SELECT COUNT(*) as c FROM api_endpoints').get() as { c: number } | undefined;
268
+ totalApis = apiRow?.c || 0;
269
+
270
+ const pitRow = raw.prepare('SELECT COUNT(*) as c FROM pitfalls').get() as { c: number } | undefined;
271
+ totalPitfalls = pitRow?.c || 0;
272
+
273
+ const exRow = raw.prepare('SELECT COUNT(*) as c FROM indexed_examples').get() as { c: number } | undefined;
274
+ totalExamples = exRow?.c || 0;
275
+
276
+ const verRows = raw.prepare('SELECT DISTINCT doc_version FROM snapshots WHERE doc_version IS NOT NULL').all() as Array<{ doc_version: string }>;
277
+ for (const r of verRows) {
278
+ if (r.doc_version) activeVersions.add(r.doc_version);
279
+ }
280
+ } catch {
281
+ // Best-effort stats aggregation
282
+ }
283
+
284
+ return {
285
+ totalSources: sources.length,
286
+ totalPages,
287
+ totalChunks,
288
+ totalApis,
289
+ totalPitfalls,
290
+ totalExamples,
291
+ totalRecipes: 5,
292
+ activeVersions: Array.from(activeVersions).sort(),
293
+ dbPath: this.dbPath,
294
+ untrusted: true,
295
+ };
296
+ }
297
+
298
+ private readJsonBody(req: http.IncomingMessage): Promise<any> {
299
+ return new Promise((resolve, reject) => {
300
+ let body = '';
301
+ req.on('data', (chunk) => {
302
+ body += chunk.toString();
303
+ });
304
+ req.on('end', () => {
305
+ try {
306
+ resolve(body ? JSON.parse(body) : {});
307
+ } catch (err) {
308
+ reject(new Error('Invalid JSON payload'));
309
+ }
310
+ });
311
+ req.on('error', (err) => reject(err));
312
+ });
313
+ }
314
+ }