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.
- package/LICENSE +21 -0
- package/README.md +660 -0
- package/apps/cli/bin/docorbit.js +8 -0
- package/apps/cli/src/commands/add.ts +44 -0
- package/apps/cli/src/commands/api.ts +38 -0
- package/apps/cli/src/commands/context.ts +47 -0
- package/apps/cli/src/commands/dashboard.ts +55 -0
- package/apps/cli/src/commands/diff.ts +30 -0
- package/apps/cli/src/commands/evaluate.ts +133 -0
- package/apps/cli/src/commands/examples.ts +39 -0
- package/apps/cli/src/commands/export.ts +89 -0
- package/apps/cli/src/commands/impact.ts +31 -0
- package/apps/cli/src/commands/init.ts +69 -0
- package/apps/cli/src/commands/inspect.ts +30 -0
- package/apps/cli/src/commands/mcp.ts +72 -0
- package/apps/cli/src/commands/pitfalls.ts +38 -0
- package/apps/cli/src/commands/recipes.ts +35 -0
- package/apps/cli/src/commands/search.ts +48 -0
- package/apps/cli/src/commands/update.ts +73 -0
- package/apps/cli/src/commands/verify.ts +48 -0
- package/apps/cli/src/formatters/colors.ts +23 -0
- package/apps/cli/src/formatters/inspection.ts +102 -0
- package/apps/cli/src/formatters/knowledge.ts +272 -0
- package/apps/cli/src/formatters/retrieval.ts +74 -0
- package/apps/cli/src/formatters/terminal.ts +6 -0
- package/apps/cli/src/formatters/verification.ts +126 -0
- package/apps/cli/src/index.ts +409 -0
- package/bin/docorbit.js +8 -0
- package/package.json +46 -0
- package/packages/core/src/dashboard/server.ts +314 -0
- package/packages/core/src/dashboard/ui.ts +586 -0
- package/packages/core/src/implementation-service.ts +451 -0
- package/packages/core/src/index.ts +7 -0
- package/packages/core/src/inspector.ts +71 -0
- package/packages/core/src/pipeline.ts +331 -0
- package/packages/crawler/src/config.ts +12 -0
- package/packages/crawler/src/fetcher.ts +185 -0
- package/packages/crawler/src/index.ts +2 -0
- package/packages/discovery/src/index.ts +31 -0
- package/packages/discovery/src/provider.ts +47 -0
- package/packages/discovery/src/providers/generic.ts +98 -0
- package/packages/discovery/src/providers/github.ts +61 -0
- package/packages/discovery/src/providers/llms-txt.ts +73 -0
- package/packages/discovery/src/providers/markdown.ts +48 -0
- package/packages/discovery/src/providers/openapi.ts +91 -0
- package/packages/discovery/src/providers/sitemap.ts +62 -0
- package/packages/discovery/src/providers/skill.ts +54 -0
- package/packages/discovery/src/ranker.ts +123 -0
- package/packages/evaluation/src/dataset.ts +963 -0
- package/packages/evaluation/src/index.ts +8 -0
- package/packages/evaluation/src/runner.ts +241 -0
- package/packages/evaluation/src/strategies/context7-runner.ts +269 -0
- package/packages/evaluation/src/strategies/docorbit-runner.ts +228 -0
- package/packages/evaluation/src/strategies/firecrawl-runner.ts +172 -0
- package/packages/evaluation/src/strategies/web-search-runner.ts +194 -0
- package/packages/evaluation/src/types.ts +34 -0
- package/packages/evaluation/src/version-matcher.ts +73 -0
- package/packages/export/src/agents-md.ts +200 -0
- package/packages/export/src/claude-md.ts +141 -0
- package/packages/export/src/docs-map.ts +150 -0
- package/packages/export/src/index.ts +6 -0
- package/packages/export/src/llms-txt.ts +96 -0
- package/packages/export/src/service.ts +250 -0
- package/packages/export/src/skill-md.ts +128 -0
- package/packages/mcp/src/index.ts +46 -0
- package/packages/mcp/src/resources/index.ts +189 -0
- package/packages/mcp/src/server.ts +278 -0
- package/packages/mcp/src/tools/analyze-impact.ts +74 -0
- package/packages/mcp/src/tools/check-api.ts +86 -0
- package/packages/mcp/src/tools/diff-docs.ts +68 -0
- package/packages/mcp/src/tools/export-context.ts +73 -0
- package/packages/mcp/src/tools/find-api.ts +99 -0
- package/packages/mcp/src/tools/find-example.ts +100 -0
- package/packages/mcp/src/tools/find-pitfall.ts +94 -0
- package/packages/mcp/src/tools/find-recipe.ts +98 -0
- package/packages/mcp/src/tools/get-doc.ts +130 -0
- package/packages/mcp/src/tools/get-docs-map.ts +64 -0
- package/packages/mcp/src/tools/get-version.ts +118 -0
- package/packages/mcp/src/tools/implementation-context.ts +88 -0
- package/packages/mcp/src/tools/index.ts +59 -0
- package/packages/mcp/src/tools/list-sources.ts +85 -0
- package/packages/mcp/src/tools/search-docs.ts +123 -0
- package/packages/mcp/src/tools/types.ts +28 -0
- package/packages/mcp/src/transports/http.ts +256 -0
- package/packages/mcp/src/transports/stdio.ts +105 -0
- package/packages/mcp/src/transports/types.ts +6 -0
- package/packages/mcp/src/types.ts +102 -0
- package/packages/normalizer/src/example-indexer.ts +240 -0
- package/packages/normalizer/src/html.ts +253 -0
- package/packages/normalizer/src/index.ts +8 -0
- package/packages/normalizer/src/llms.ts +83 -0
- package/packages/normalizer/src/openapi/endpoint-parser.ts +406 -0
- package/packages/normalizer/src/openapi/schema-resolver.ts +111 -0
- package/packages/normalizer/src/openapi.ts +2 -0
- package/packages/normalizer/src/page.ts +184 -0
- package/packages/normalizer/src/pitfall-extractor.ts +190 -0
- package/packages/normalizer/src/slicer.ts +455 -0
- package/packages/retrieval/src/engine.ts +120 -0
- package/packages/retrieval/src/index.ts +7 -0
- package/packages/retrieval/src/intent.ts +43 -0
- package/packages/retrieval/src/packer.ts +145 -0
- package/packages/retrieval/src/recipe-engine.ts +313 -0
- package/packages/retrieval/src/scorer.ts +139 -0
- package/packages/retrieval/src/weights.ts +31 -0
- package/packages/security/src/annotations.ts +112 -0
- package/packages/security/src/index.ts +2 -0
- package/packages/security/src/ssrf.ts +153 -0
- package/packages/shared/src/errors.ts +53 -0
- package/packages/shared/src/hashing.ts +23 -0
- package/packages/shared/src/index.ts +3 -0
- package/packages/shared/src/types.ts +881 -0
- package/packages/storage/src/db.ts +72 -0
- package/packages/storage/src/index.ts +11 -0
- package/packages/storage/src/interfaces.ts +115 -0
- package/packages/storage/src/repositories/api-repository.ts +219 -0
- package/packages/storage/src/repositories/chunk-repository.ts +316 -0
- package/packages/storage/src/repositories/example-repository.ts +206 -0
- package/packages/storage/src/repositories/page-repository.ts +205 -0
- package/packages/storage/src/repositories/pitfall-repository.ts +188 -0
- package/packages/storage/src/repositories/source-repository.ts +205 -0
- package/packages/storage/src/repository.ts +256 -0
- package/packages/storage/src/schema.ts +269 -0
- package/packages/storage/src/search-tokens.ts +28 -0
- package/packages/verification/src/diff-engine.ts +258 -0
- package/packages/verification/src/extractor.ts +339 -0
- package/packages/verification/src/impact-scanner.ts +203 -0
- package/packages/verification/src/index.ts +5 -0
- package/packages/verification/src/services.ts +238 -0
- package/packages/verification/src/verifier.ts +375 -0
- package/packages/workspace/src/detector.ts +143 -0
- package/packages/workspace/src/ecosystems/cargo.ts +84 -0
- package/packages/workspace/src/ecosystems/composer.ts +42 -0
- package/packages/workspace/src/ecosystems/go.ts +54 -0
- package/packages/workspace/src/ecosystems/index.ts +34 -0
- package/packages/workspace/src/ecosystems/maven.ts +34 -0
- package/packages/workspace/src/ecosystems/npm.ts +83 -0
- package/packages/workspace/src/ecosystems/pub.ts +40 -0
- package/packages/workspace/src/ecosystems/pypi.ts +100 -0
- package/packages/workspace/src/ecosystems/rubygems.ts +30 -0
- package/packages/workspace/src/ecosystems/types.ts +18 -0
- package/packages/workspace/src/index.ts +5 -0
- package/packages/workspace/src/lockfile.ts +194 -0
- package/packages/workspace/src/resolver.ts +234 -0
- package/packages/workspace/src/semver.ts +259 -0
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { DocOrbitDb, DocOrbitRepository } from '../../../../packages/storage/src/index.ts';
|
|
2
|
+
import { WorkspaceResolver } from '../../../../packages/workspace/src/index.ts';
|
|
3
|
+
import {
|
|
4
|
+
McpServer,
|
|
5
|
+
StdioServerTransport,
|
|
6
|
+
StreamableHttpTransport,
|
|
7
|
+
} from '../../../../packages/mcp/src/index.ts';
|
|
8
|
+
|
|
9
|
+
export interface McpCommandOptions {
|
|
10
|
+
stdio?: boolean;
|
|
11
|
+
port?: number;
|
|
12
|
+
host?: string;
|
|
13
|
+
dbPath?: string;
|
|
14
|
+
projectDir?: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export async function runMcpCommand(options: McpCommandOptions = {}): Promise<void> {
|
|
18
|
+
const dbPath = options.dbPath || '.docorbit/docorbit.db';
|
|
19
|
+
const projectDir = options.projectDir || process.cwd();
|
|
20
|
+
|
|
21
|
+
const db = new DocOrbitDb(dbPath);
|
|
22
|
+
const repo = new DocOrbitRepository(db);
|
|
23
|
+
const resolver = new WorkspaceResolver(repo);
|
|
24
|
+
|
|
25
|
+
const server = new McpServer({
|
|
26
|
+
repo,
|
|
27
|
+
resolver,
|
|
28
|
+
projectDir,
|
|
29
|
+
serverName: 'docorbit-mcp',
|
|
30
|
+
serverVersion: '0.5.0',
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
const isHttp = typeof options.port === 'number' && options.port > 0;
|
|
34
|
+
|
|
35
|
+
if (isHttp) {
|
|
36
|
+
const port = options.port!;
|
|
37
|
+
const host = options.host || '127.0.0.1';
|
|
38
|
+
const transport = new StreamableHttpTransport({ port, host });
|
|
39
|
+
|
|
40
|
+
await transport.start(server);
|
|
41
|
+
const activePort = transport.getPort();
|
|
42
|
+
process.stderr.write(
|
|
43
|
+
`[DocOrbit MCP] Streamable HTTP server listening on http://${host}:${activePort}\n` +
|
|
44
|
+
` - MCP endpoint: POST http://${host}:${activePort}/mcp\n` +
|
|
45
|
+
` - SSE fallback: GET http://${host}:${activePort}/sse\n` +
|
|
46
|
+
` - Health check: GET http://${host}:${activePort}/health\n`
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
const shutdown = async () => {
|
|
50
|
+
process.stderr.write('[DocOrbit MCP] Shutting down HTTP server...\n');
|
|
51
|
+
await transport.close();
|
|
52
|
+
db.close();
|
|
53
|
+
process.exit(0);
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
process.on('SIGINT', shutdown);
|
|
57
|
+
process.on('SIGTERM', shutdown);
|
|
58
|
+
} else {
|
|
59
|
+
// Default to Stdio transport
|
|
60
|
+
const transport = new StdioServerTransport();
|
|
61
|
+
await transport.start(server);
|
|
62
|
+
|
|
63
|
+
const shutdown = async () => {
|
|
64
|
+
await transport.close();
|
|
65
|
+
db.close();
|
|
66
|
+
process.exit(0);
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
process.on('SIGINT', shutdown);
|
|
70
|
+
process.on('SIGTERM', shutdown);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { DocOrbitDb, DocOrbitRepository } from '../../../../packages/storage/src/index.ts';
|
|
2
|
+
import { resolveProjectContext } from '../../../../packages/workspace/src/index.ts';
|
|
3
|
+
import type { PitfallsCommandOptions } from '../../../../packages/shared/src/index.ts';
|
|
4
|
+
import { formatPitfalls } from '../formatters/terminal.ts';
|
|
5
|
+
|
|
6
|
+
export async function runPitfallsCommand(task: string = '', options: PitfallsCommandOptions = {}): Promise<void> {
|
|
7
|
+
const dbPath = options.dbPath || '.docorbit/docorbit.db';
|
|
8
|
+
const db = new DocOrbitDb(dbPath);
|
|
9
|
+
const repository = new DocOrbitRepository(db);
|
|
10
|
+
|
|
11
|
+
try {
|
|
12
|
+
let effectiveDocVersion = options.docVersion;
|
|
13
|
+
|
|
14
|
+
if (options.projectDir) {
|
|
15
|
+
const projContext = resolveProjectContext(options.projectDir, task, repository);
|
|
16
|
+
if (projContext.matchedDependency && !effectiveDocVersion) {
|
|
17
|
+
effectiveDocVersion = projContext.matchedDependency.targetDocVersion;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const pitfalls = repository.searchPitfalls(task, {
|
|
22
|
+
kind: options.kind,
|
|
23
|
+
docVersion: effectiveDocVersion,
|
|
24
|
+
limit: options.limit || 10,
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
if (options.json) {
|
|
28
|
+
console.log(JSON.stringify(pitfalls, null, 2));
|
|
29
|
+
} else {
|
|
30
|
+
console.log(formatPitfalls(pitfalls, task));
|
|
31
|
+
}
|
|
32
|
+
} catch (err: unknown) {
|
|
33
|
+
console.error(`DocOrbit Pitfalls Error: ${err instanceof Error ? err.message : String(err)}`);
|
|
34
|
+
process.exit(1);
|
|
35
|
+
} finally {
|
|
36
|
+
db.close();
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { DocOrbitDb, DocOrbitRepository } from '../../../../packages/storage/src/index.ts';
|
|
2
|
+
import { RecipeEngine } from '../../../../packages/retrieval/src/index.ts';
|
|
3
|
+
import type { RecipesCommandOptions } from '../../../../packages/shared/src/index.ts';
|
|
4
|
+
import { formatRecipe } from '../formatters/terminal.ts';
|
|
5
|
+
|
|
6
|
+
export async function runRecipesCommand(goal: string, options: RecipesCommandOptions = {}): Promise<void> {
|
|
7
|
+
if (!goal) {
|
|
8
|
+
console.error('Error: Please provide an implementation goal.');
|
|
9
|
+
console.error('Usage: docorbit recipes "<goal>" [--doc-version <ver>] [--project <dir>] [--json] [--db <path>]');
|
|
10
|
+
process.exit(1);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const dbPath = options.dbPath || '.docorbit/docorbit.db';
|
|
14
|
+
const db = new DocOrbitDb(dbPath);
|
|
15
|
+
const repository = new DocOrbitRepository(db);
|
|
16
|
+
const recipeEngine = new RecipeEngine(repository);
|
|
17
|
+
|
|
18
|
+
try {
|
|
19
|
+
const recipe = await recipeEngine.assembleRecipe(goal, {
|
|
20
|
+
docVersion: options.docVersion,
|
|
21
|
+
projectDir: options.projectDir,
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
if (options.json) {
|
|
25
|
+
console.log(JSON.stringify(recipe, null, 2));
|
|
26
|
+
} else {
|
|
27
|
+
console.log(formatRecipe(recipe));
|
|
28
|
+
}
|
|
29
|
+
} catch (err: unknown) {
|
|
30
|
+
console.error(`DocOrbit Recipes Error: ${err instanceof Error ? err.message : String(err)}`);
|
|
31
|
+
process.exit(1);
|
|
32
|
+
} finally {
|
|
33
|
+
db.close();
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { DocOrbitDb, DocOrbitRepository } from '../../../../packages/storage/src/index.ts';
|
|
2
|
+
import { RetrievalEngine } from '../../../../packages/retrieval/src/index.ts';
|
|
3
|
+
import type { ChunkType } from '../../../../packages/shared/src/index.ts';
|
|
4
|
+
import { formatSearchResults } from '../formatters/terminal.ts';
|
|
5
|
+
|
|
6
|
+
export interface SearchCommandOptions {
|
|
7
|
+
json?: boolean;
|
|
8
|
+
dbPath?: string;
|
|
9
|
+
limit?: number;
|
|
10
|
+
chunkType?: ChunkType;
|
|
11
|
+
snapshotId?: string;
|
|
12
|
+
docVersion?: string;
|
|
13
|
+
projectDir?: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export async function runSearchCommand(query: string, options: SearchCommandOptions = {}): Promise<void> {
|
|
17
|
+
if (!query) {
|
|
18
|
+
console.error('Error: Please provide a search query.');
|
|
19
|
+
console.error('Usage: docorbit search "<query>" [--limit <n>] [--type <type>] [--doc-version <ver>] [--project <dir>] [--json] [--db <path>]');
|
|
20
|
+
process.exit(1);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const dbPath = options.dbPath || '.docorbit/docorbit.db';
|
|
24
|
+
const db = new DocOrbitDb(dbPath);
|
|
25
|
+
const repository = new DocOrbitRepository(db);
|
|
26
|
+
const engine = new RetrievalEngine(repository);
|
|
27
|
+
|
|
28
|
+
try {
|
|
29
|
+
const results = await engine.search(query, {
|
|
30
|
+
limit: options.limit || 10,
|
|
31
|
+
chunkType: options.chunkType,
|
|
32
|
+
snapshotId: options.snapshotId,
|
|
33
|
+
docVersion: options.docVersion,
|
|
34
|
+
projectDir: options.projectDir,
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
if (options.json) {
|
|
38
|
+
console.log(JSON.stringify(results, null, 2));
|
|
39
|
+
} else {
|
|
40
|
+
console.log(formatSearchResults(query, results));
|
|
41
|
+
}
|
|
42
|
+
} catch (err: unknown) {
|
|
43
|
+
console.error(`DocOrbit Search Error: ${err instanceof Error ? err.message : String(err)}`);
|
|
44
|
+
process.exit(1);
|
|
45
|
+
} finally {
|
|
46
|
+
db.close();
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { resolve } from 'node:path';
|
|
2
|
+
import { DocOrbitDb, DocOrbitRepository } from '../../../../packages/storage/src/index.ts';
|
|
3
|
+
import {
|
|
4
|
+
detectWorkspaceDependencies,
|
|
5
|
+
readDocsLock,
|
|
6
|
+
updateDocsLock,
|
|
7
|
+
writeDocsLock,
|
|
8
|
+
} from '../../../../packages/workspace/src/index.ts';
|
|
9
|
+
import { runInitCommand } from './init.ts';
|
|
10
|
+
|
|
11
|
+
export interface UpdateCommandOptions {
|
|
12
|
+
json?: boolean;
|
|
13
|
+
dbPath?: string;
|
|
14
|
+
projectDir?: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export async function runUpdateCommand(
|
|
18
|
+
targetPackage?: string,
|
|
19
|
+
options: UpdateCommandOptions = {}
|
|
20
|
+
): Promise<void> {
|
|
21
|
+
const projectDir = resolve(options.projectDir || '.');
|
|
22
|
+
const existingLock = readDocsLock(projectDir);
|
|
23
|
+
|
|
24
|
+
if (!existingLock) {
|
|
25
|
+
console.log(`No docs.lock found at ${projectDir}. Initializing first...`);
|
|
26
|
+
await runInitCommand(projectDir, { json: options.json, dbPath: options.dbPath });
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const dbPath = options.dbPath || '.docorbit/docorbit.db';
|
|
31
|
+
const db = new DocOrbitDb(dbPath);
|
|
32
|
+
const repository = new DocOrbitRepository(db);
|
|
33
|
+
|
|
34
|
+
try {
|
|
35
|
+
const scanResult = detectWorkspaceDependencies(projectDir);
|
|
36
|
+
const updated = updateDocsLock(scanResult, repository, existingLock, targetPackage);
|
|
37
|
+
|
|
38
|
+
writeDocsLock(projectDir, updated);
|
|
39
|
+
|
|
40
|
+
if (options.json) {
|
|
41
|
+
console.log(JSON.stringify(updated, null, 2));
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
console.log(`\n=== DocOrbit docs.lock Updated ===`);
|
|
46
|
+
if (targetPackage) {
|
|
47
|
+
console.log(`Target Package: ${targetPackage}`);
|
|
48
|
+
} else {
|
|
49
|
+
console.log(`Updated all resolved dependencies.`);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const lockedCount = Object.keys(updated.dependencies).length;
|
|
53
|
+
console.log(`Total Locked Docs: ${lockedCount}\n`);
|
|
54
|
+
|
|
55
|
+
console.log('-----------------------------------------------------------------------------');
|
|
56
|
+
console.log('| Package | Project Ver | Doc Ver | Match | Confidence |');
|
|
57
|
+
console.log('-----------------------------------------------------------------------------');
|
|
58
|
+
for (const [key, dep] of Object.entries(updated.dependencies)) {
|
|
59
|
+
const pkgPad = key.padEnd(21).slice(0, 21);
|
|
60
|
+
const projPad = dep.resolvedDependencyVersion.padEnd(11).slice(0, 11);
|
|
61
|
+
const docPad = dep.docVersion.padEnd(8).slice(0, 8);
|
|
62
|
+
const matchPad = dep.matchType.padEnd(11).slice(0, 11);
|
|
63
|
+
const confPad = (dep.confidence * 100).toFixed(0) + '%';
|
|
64
|
+
console.log(`| ${pkgPad} | ${projPad} | ${docPad} | ${matchPad} | ${confPad.padEnd(10)} |`);
|
|
65
|
+
}
|
|
66
|
+
console.log('-----------------------------------------------------------------------------\n');
|
|
67
|
+
} catch (err: unknown) {
|
|
68
|
+
console.error(`DocOrbit Update Error: ${err instanceof Error ? err.message : String(err)}`);
|
|
69
|
+
process.exit(1);
|
|
70
|
+
} finally {
|
|
71
|
+
db.close();
|
|
72
|
+
}
|
|
73
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import * as fs from 'node:fs';
|
|
2
|
+
import { DocOrbitDb, DocOrbitRepository } from '../../../../packages/storage/src/index.ts';
|
|
3
|
+
import { VerificationService } from '../../../../packages/verification/src/index.ts';
|
|
4
|
+
import type { VerifyCommandOptions } from '../../../../packages/shared/src/index.ts';
|
|
5
|
+
import { formatVerificationReport } from '../formatters/terminal.ts';
|
|
6
|
+
|
|
7
|
+
export async function runVerifyCommand(codeOrFile: string = '', options: VerifyCommandOptions = {}): Promise<void> {
|
|
8
|
+
if (!codeOrFile) {
|
|
9
|
+
console.error('Error: "verify" command requires code snippet or file path as an argument.');
|
|
10
|
+
process.exit(1);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
let code = codeOrFile;
|
|
14
|
+
let filePath: string | undefined;
|
|
15
|
+
|
|
16
|
+
// Check if argument is a file path
|
|
17
|
+
if (fs.existsSync(codeOrFile) && fs.statSync(codeOrFile).isFile()) {
|
|
18
|
+
filePath = codeOrFile;
|
|
19
|
+
code = fs.readFileSync(codeOrFile, 'utf8');
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const dbPath = options.dbPath || '.docorbit/docorbit.db';
|
|
23
|
+
const db = new DocOrbitDb(dbPath);
|
|
24
|
+
const repo = new DocOrbitRepository(db);
|
|
25
|
+
|
|
26
|
+
try {
|
|
27
|
+
const service = new VerificationService(repo);
|
|
28
|
+
const { result } = service.verifyCode({
|
|
29
|
+
code,
|
|
30
|
+
filePath,
|
|
31
|
+
language: options.language,
|
|
32
|
+
library: options.library,
|
|
33
|
+
version: options.docVersion,
|
|
34
|
+
projectDir: options.projectDir || process.cwd(),
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
if (options.json) {
|
|
38
|
+
console.log(JSON.stringify(result, null, 2));
|
|
39
|
+
} else {
|
|
40
|
+
console.log(formatVerificationReport(result));
|
|
41
|
+
}
|
|
42
|
+
} catch (err: unknown) {
|
|
43
|
+
console.error(`DocOrbit Verify Error: ${err instanceof Error ? err.message : String(err)}`);
|
|
44
|
+
process.exit(1);
|
|
45
|
+
} finally {
|
|
46
|
+
db.close();
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// ANSI colors
|
|
2
|
+
export const RESET = '\x1b[0m';
|
|
3
|
+
export const BOLD = '\x1b[1m';
|
|
4
|
+
export const DIM = '\x1b[2m';
|
|
5
|
+
export const GREEN = '\x1b[32m';
|
|
6
|
+
export const BLUE = '\x1b[34m';
|
|
7
|
+
export const CYAN = '\x1b[36m';
|
|
8
|
+
export const YELLOW = '\x1b[33m';
|
|
9
|
+
export const RED = '\x1b[31m';
|
|
10
|
+
export const MAGENTA = '\x1b[35m';
|
|
11
|
+
|
|
12
|
+
export const c = {
|
|
13
|
+
bold: (s: string) => `${BOLD}${s}${RESET}`,
|
|
14
|
+
dim: (s: string) => `${DIM}${s}${RESET}`,
|
|
15
|
+
green: (s: string) => `${GREEN}${s}${RESET}`,
|
|
16
|
+
blue: (s: string) => `${BLUE}${s}${RESET}`,
|
|
17
|
+
cyan: (s: string) => `${CYAN}${s}${RESET}`,
|
|
18
|
+
yellow: (s: string) => `${YELLOW}${s}${RESET}`,
|
|
19
|
+
red: (s: string) => `${RED}${s}${RESET}`,
|
|
20
|
+
magenta: (s: string) => `${MAGENTA}${s}${RESET}`,
|
|
21
|
+
gray: (s: string) => `${DIM}${s}${RESET}`,
|
|
22
|
+
underline: (s: string) => `\x1b[4m${s}${RESET}`,
|
|
23
|
+
};
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import type { InspectionReport, IngestionResult } from '../../../../packages/core/src/index.ts';
|
|
2
|
+
import { RESET, BOLD, DIM, GREEN, BLUE, CYAN, YELLOW, RED, MAGENTA } from './colors.ts';
|
|
3
|
+
|
|
4
|
+
export function formatInspectionReport(report: InspectionReport): string {
|
|
5
|
+
const lines: string[] = [];
|
|
6
|
+
|
|
7
|
+
lines.push('');
|
|
8
|
+
lines.push(`${BOLD}${CYAN}DocOrbit${RESET} ${DIM}— Documentation Intelligence Report${RESET}`);
|
|
9
|
+
lines.push(`${DIM}${'═'.repeat(64)}${RESET}`);
|
|
10
|
+
lines.push(`${BOLD}Target URL:${RESET} ${BLUE}${report.targetUrl}${RESET}`);
|
|
11
|
+
lines.push('');
|
|
12
|
+
|
|
13
|
+
// Sources Table
|
|
14
|
+
lines.push(`${BOLD}Discovered Sources (${report.summary.totalFound}):${RESET}`);
|
|
15
|
+
lines.push(`${DIM}${'─'.repeat(64)}${RESET}`);
|
|
16
|
+
|
|
17
|
+
if (report.sourcesDiscovered.length === 0) {
|
|
18
|
+
lines.push(` ${YELLOW}No machine-readable sources discovered.${RESET}`);
|
|
19
|
+
} else {
|
|
20
|
+
for (const src of report.sourcesDiscovered) {
|
|
21
|
+
const icon = src.status === 'valid' ? `${GREEN}✓${RESET}` : `${RED}✗${RESET}`;
|
|
22
|
+
const typeStr = `[${src.type}]`.padEnd(16);
|
|
23
|
+
const mr = src.machineReadable ? `${GREEN}machine-readable${RESET}` : `${DIM}human-html${RESET}`;
|
|
24
|
+
const auth = `${src.authority}`;
|
|
25
|
+
lines.push(` ${icon} ${BOLD}${typeStr}${RESET} ${mr.padEnd(26)} ${DIM}(${auth}, conf: ${Math.round(src.confidence * 100)}%)${RESET}`);
|
|
26
|
+
lines.push(` ${DIM}↳ ${src.url}${RESET}`);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
lines.push('');
|
|
31
|
+
lines.push(`${BOLD}Purpose-Based Source Recommendations:${RESET}`);
|
|
32
|
+
lines.push(`${DIM}${'─'.repeat(64)}${RESET}`);
|
|
33
|
+
|
|
34
|
+
const purposes = [
|
|
35
|
+
{ key: 'navigation', label: 'Navigation ' },
|
|
36
|
+
{ key: 'conceptual', label: 'Conceptual ' },
|
|
37
|
+
{ key: 'api', label: 'API Reference ' },
|
|
38
|
+
{ key: 'examples', label: 'Code Examples ' },
|
|
39
|
+
{ key: 'implementation', label: 'Implementation' },
|
|
40
|
+
] as const;
|
|
41
|
+
|
|
42
|
+
for (const p of purposes) {
|
|
43
|
+
const rec = report.recommendations[p.key];
|
|
44
|
+
if (rec && rec.recommended) {
|
|
45
|
+
lines.push(` ${CYAN}${p.label}${RESET} → ${GREEN}${rec.recommended.type}${RESET} ${DIM}(${rec.recommended.url})${RESET}`);
|
|
46
|
+
} else {
|
|
47
|
+
lines.push(` ${CYAN}${p.label}${RESET} → ${DIM}No dedicated source${RESET}`);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
lines.push('');
|
|
52
|
+
lines.push(`${BOLD}Summary:${RESET}`);
|
|
53
|
+
lines.push(` Machine-readable sources: ${GREEN}${report.summary.machineReadableCount}${RESET}`);
|
|
54
|
+
lines.push(` Official sources: ${GREEN}${report.summary.officialCount}${RESET}`);
|
|
55
|
+
lines.push(` OpenAPI detected: ${report.summary.hasOpenApi ? `${GREEN}Yes${RESET}` : `${DIM}No${RESET}`}`);
|
|
56
|
+
lines.push(` llms.txt detected: ${report.summary.hasLlmsTxt ? `${GREEN}Yes${RESET}` : `${DIM}No${RESET}`}`);
|
|
57
|
+
lines.push(` skill.md detected: ${report.summary.hasSkill ? `${GREEN}Yes${RESET}` : `${DIM}No${RESET}`}`);
|
|
58
|
+
lines.push(`${DIM}${'═'.repeat(64)}${RESET}`);
|
|
59
|
+
lines.push('');
|
|
60
|
+
|
|
61
|
+
return lines.join('\n');
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function formatIngestionResult(result: IngestionResult): string {
|
|
65
|
+
const lines: string[] = [];
|
|
66
|
+
|
|
67
|
+
lines.push('');
|
|
68
|
+
lines.push(`${BOLD}${GREEN}DocOrbit${RESET} ${DIM}— Documentation Ingested Successfully${RESET}`);
|
|
69
|
+
lines.push(`${DIM}${'═'.repeat(64)}${RESET}`);
|
|
70
|
+
lines.push(`${BOLD}Target URL:${RESET} ${BLUE}${result.targetUrl}${RESET}`);
|
|
71
|
+
lines.push(`${BOLD}Snapshot ID:${RESET} ${MAGENTA}${result.snapshotId}${RESET}`);
|
|
72
|
+
lines.push(`${BOLD}Duration:${RESET} ${result.durationMs}ms`);
|
|
73
|
+
lines.push('');
|
|
74
|
+
|
|
75
|
+
lines.push(`${BOLD}Ingested Pages (${result.pages.length}):${RESET}`);
|
|
76
|
+
lines.push(`${DIM}${'─'.repeat(64)}${RESET}`);
|
|
77
|
+
|
|
78
|
+
for (let i = 0; i < result.pages.length; i++) {
|
|
79
|
+
const p = result.pages[i];
|
|
80
|
+
const warnBadge = p.securityAnnotations.length > 0
|
|
81
|
+
? ` ${YELLOW}[${p.securityAnnotations.length} alert(s)]${RESET}`
|
|
82
|
+
: '';
|
|
83
|
+
lines.push(` ${BOLD}${i + 1}.${RESET} ${CYAN}${p.title}${RESET}${warnBadge}`);
|
|
84
|
+
lines.push(` ${DIM}URL: ${p.url}${RESET}`);
|
|
85
|
+
lines.push(` ${DIM}Tokens: ~${p.estimatedTokens} | Code blocks: ${p.codeExamples.length} | Hash: ${p.contentHash.slice(0, 8)}${RESET}`);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
lines.push('');
|
|
89
|
+
lines.push(`${BOLD}Ingestion Summary:${RESET}`);
|
|
90
|
+
lines.push(` Total Pages: ${BOLD}${result.stats.totalPages}${RESET}`);
|
|
91
|
+
lines.push(` Total Raw Bytes: ${(result.stats.totalBytes / 1024).toFixed(1)} KB`);
|
|
92
|
+
lines.push(` Estimated Tokens: ~${result.stats.totalEstimatedTokens}`);
|
|
93
|
+
lines.push(` Total Code Examples: ${result.stats.totalCodeExamples}`);
|
|
94
|
+
lines.push(` Machine-readable types: ${result.stats.machineReadableSources}`);
|
|
95
|
+
if (result.stats.totalChunks !== undefined) {
|
|
96
|
+
lines.push(` Total Chunks: ${BOLD}${result.stats.totalChunks}${RESET}`);
|
|
97
|
+
}
|
|
98
|
+
lines.push(`${DIM}${'═'.repeat(64)}${RESET}`);
|
|
99
|
+
lines.push('');
|
|
100
|
+
|
|
101
|
+
return lines.join('\n');
|
|
102
|
+
}
|