@doccov/sdk 0.12.0 → 0.13.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 (3) hide show
  1. package/dist/index.d.ts +243 -208
  2. package/dist/index.js +262 -131
  3. package/package.json +2 -2
package/dist/index.d.ts CHANGED
@@ -45,8 +45,8 @@ declare function runExamples(examples: string[], options?: RunExampleOptions): P
45
45
  * runs all examples, then cleans up.
46
46
  */
47
47
  declare function runExamplesWithPackage(examples: string[], options: RunExamplesWithPackageOptions): Promise<RunExamplesWithPackageResult>;
48
- import { OpenPkg } from "@openpkg-ts/spec";
49
- type OpenPkgSpec = OpenPkg;
48
+ import { OpenPkg as OpenPkg2 } from "@openpkg-ts/spec";
49
+ type OpenPkgSpec = OpenPkg2;
50
50
  /**
51
51
  * Result of computing drift for a single export.
52
52
  */
@@ -225,7 +225,7 @@ declare function ensureSpecCoverage(spec: OpenPkgSpec): OpenPkgSpec & {
225
225
  coverageScore: number;
226
226
  };
227
227
  };
228
- import { OpenPkg as OpenPkg2, SpecDocDrift as SpecDocDrift2, SpecDocsMetadata, SpecExport as SpecExport3 } from "@openpkg-ts/spec";
228
+ import { OpenPkg as OpenPkg3, SpecDocDrift as SpecDocDrift2, SpecDocsMetadata, SpecExport as SpecExport3 } from "@openpkg-ts/spec";
229
229
  import { SpecExport as SpecExport2, SpecExportKind } from "@openpkg-ts/spec";
230
230
  import * as TS from "typescript";
231
231
  /**
@@ -445,7 +445,7 @@ type EnrichedDocsMetadata = SpecDocsMetadata & {
445
445
  * An enriched OpenPkg spec with computed documentation metadata.
446
446
  * Extends OpenPkg with per-and aggregate coverage data.
447
447
  */
448
- type EnrichedOpenPkg = Omit<OpenPkg2, "exports"> & {
448
+ type EnrichedOpenPkg = Omit<OpenPkg3, "exports"> & {
449
449
  exports: EnrichedExport[];
450
450
  docs?: EnrichedDocsMetadata;
451
451
  /** Drift summary with category breakdown (if drift exists) */
@@ -490,8 +490,8 @@ interface EnrichOptions {
490
490
  * console.log(enriched.docs?.missing); // e.g., ['has-examples']
491
491
  * ```
492
492
  */
493
- declare function enrichSpec(spec: OpenPkg2, options?: EnrichOptions): EnrichedOpenPkg;
494
- import { OpenPkg as OpenPkg3 } from "@openpkg-ts/spec";
493
+ declare function enrichSpec(spec: OpenPkg3, options?: EnrichOptions): EnrichedOpenPkg;
494
+ import { OpenPkg as OpenPkg4 } from "@openpkg-ts/spec";
495
495
  import { DriftCategory as DriftCategory2, SpecDocDrift as SpecDocDrift3 } from "@openpkg-ts/spec";
496
496
  /**
497
497
  * DocCov report schema version.
@@ -686,7 +686,7 @@ interface DocCovReport {
686
686
  * console.log(`Coverage: ${report.coverage.score}%`);
687
687
  * ```
688
688
  */
689
- declare function generateReport(spec: OpenPkg3): DocCovReport;
689
+ declare function generateReport(spec: OpenPkg4): DocCovReport;
690
690
  /**
691
691
  * Generate a DocCov report from an already-enriched spec.
692
692
  *
@@ -755,7 +755,7 @@ declare function hashFiles(filePaths: string[], cwd: string): Record<string, str
755
755
  * @returns Array of file paths that changed, were added, or were removed
756
756
  */
757
757
  declare function diffHashes(cached: Record<string, string>, current: Record<string, string>): string[];
758
- import { OpenPkg as OpenPkg4 } from "@openpkg-ts/spec";
758
+ import { OpenPkg as OpenPkg5 } from "@openpkg-ts/spec";
759
759
  /** Current cache format version */
760
760
  declare const CACHE_VERSION = "1.0.0";
761
761
  /** Default cache file path */
@@ -790,7 +790,7 @@ interface SpecCache {
790
790
  /** Analysis configuration that affects output */
791
791
  config: SpecCacheConfig;
792
792
  /** The cached OpenPkg spec */
793
- spec: OpenPkg4;
793
+ spec: OpenPkg5;
794
794
  }
795
795
  /**
796
796
  * Result of cache validation.
@@ -833,7 +833,7 @@ declare function loadSpecCache(cwd: string): SpecCache | null;
833
833
  * @param spec - OpenPkg spec to cache
834
834
  * @param context - Cache context with file paths and config
835
835
  */
836
- declare function saveSpecCache(spec: OpenPkg4, context: CacheContext): void;
836
+ declare function saveSpecCache(spec: OpenPkg5, context: CacheContext): void;
837
837
  /**
838
838
  * Validate if cached spec is still valid.
839
839
  *
@@ -1477,7 +1477,7 @@ declare function categorizeDrifts(drifts: SpecDocDrift4[]): {
1477
1477
  fixable: SpecDocDrift4[];
1478
1478
  nonFixable: SpecDocDrift4[];
1479
1479
  };
1480
- import { OpenPkg as OpenPkg5 } from "@openpkg-ts/spec";
1480
+ import { OpenPkg as OpenPkg6 } from "@openpkg-ts/spec";
1481
1481
  /**
1482
1482
  * Parsed components of a GitHub URL.
1483
1483
  */
@@ -1570,7 +1570,7 @@ declare function buildRawUrl(parsed: ParsedGitHubUrl, filePath: string): string;
1570
1570
  * }
1571
1571
  * ```
1572
1572
  */
1573
- declare function fetchSpecFromGitHub(parsed: ParsedGitHubUrl): Promise<OpenPkg5 | null>;
1573
+ declare function fetchSpecFromGitHub(parsed: ParsedGitHubUrl): Promise<OpenPkg6 | null>;
1574
1574
  /**
1575
1575
  * Fetch an OpenPkg spec from a GitHub repository by owner/repo/branch.
1576
1576
  *
@@ -1581,84 +1581,22 @@ declare function fetchSpecFromGitHub(parsed: ParsedGitHubUrl): Promise<OpenPkg5
1581
1581
  * @param branch - Branch name (default: 'main')
1582
1582
  * @returns The OpenPkg spec, or null if not found
1583
1583
  */
1584
- declare function fetchSpec(owner: string, repo: string, branch?: string): Promise<OpenPkg5 | null>;
1585
- /**
1586
- * Scan types for CLI, API, and SDK consumers.
1587
- * Single source of truth for scan-related interfaces.
1588
- */
1589
- /**
1590
- * Result of scanning a repository for documentation coverage.
1591
- * Used by CLI scan command, API endpoints, and SDK consumers.
1592
- */
1593
- interface ScanResult {
1594
- /** GitHub repository owner */
1595
- owner: string;
1596
- /** GitHub repository name */
1597
- repo: string;
1598
- /** Git ref (branch/tag) that was scanned */
1599
- ref: string;
1600
- /** Package name if scanning a monorepo package */
1601
- packageName?: string;
1602
- /** Overall documentation coverage percentage (0-100) */
1603
- coverage: number;
1604
- /** Number of public exports analyzed */
1605
- exportCount: number;
1606
- /** Number of types analyzed */
1607
- typeCount: number;
1608
- /** Number of documentation drift issues found */
1609
- driftCount: number;
1610
- /** Names of exports missing documentation */
1611
- undocumented: string[];
1612
- /** Drift issues found during analysis */
1613
- drift: DriftIssue[];
1614
- }
1584
+ declare function fetchSpec(owner: string, repo: string, branch?: string): Promise<OpenPkg6 | null>;
1615
1585
  /**
1616
- * A documentation drift issue.
1586
+ * Progress event for installation status updates.
1617
1587
  */
1618
- interface DriftIssue {
1619
- /** Name of the with drift */
1620
- export: string;
1621
- /** Type of drift (e.g., 'param-mismatch', 'return-type') */
1622
- type: string;
1623
- /** Human-readable description of the issue */
1624
- issue: string;
1625
- /** Optional suggestion for fixing the issue */
1626
- suggestion?: string;
1627
- }
1628
- /**
1629
- * Options for running a scan.
1630
- */
1631
- interface ScanOptions {
1632
- /** GitHub URL or owner/repo shorthand */
1633
- url: string;
1634
- /** Git ref (branch/tag) to scan */
1635
- ref?: string;
1636
- /** Target package name for monorepos */
1637
- package?: string;
1638
- /** Skip dependency installation */
1639
- skipInstall?: boolean;
1640
- /** Skip external type resolution */
1641
- skipResolve?: boolean;
1642
- }
1643
- /**
1644
- * Stages of the scan pipeline.
1645
- */
1646
- type ProgressStage = "cloning" | "detecting" | "installing" | "building" | "analyzing" | "complete";
1647
- /**
1648
- * Progress event emitted during scan operations.
1649
- */
1650
- interface ProgressEvent {
1651
- /** Current stage of the scan */
1652
- stage: ProgressStage;
1588
+ interface InstallProgressEvent {
1589
+ /** Current stage */
1590
+ stage: "installing";
1653
1591
  /** Human-readable message */
1654
1592
  message: string;
1655
1593
  /** Progress percentage (0-100), if known */
1656
1594
  progress?: number;
1657
1595
  }
1658
1596
  /**
1659
- * Callback for receiving progress events.
1597
+ * Callback for receiving installation progress events.
1660
1598
  */
1661
- type ProgressCallback = (event: ProgressEvent) => void;
1599
+ type InstallProgressCallback = (event: InstallProgressEvent) => void;
1662
1600
  /**
1663
1601
  * Result of running a command.
1664
1602
  */
@@ -1702,7 +1640,7 @@ interface InstallOptions {
1702
1640
  /** Order of fallback package managers to try */
1703
1641
  fallbackOrder?: PackageManager[];
1704
1642
  /** Progress callback for status updates */
1705
- onProgress?: ProgressCallback;
1643
+ onProgress?: InstallProgressCallback;
1706
1644
  }
1707
1645
  /**
1708
1646
  * Install dependencies for a project.
@@ -1902,7 +1840,7 @@ declare function getDocumentedExports(markdownFiles: MarkdownDocFile[], exportNa
1902
1840
  * Get all exports that lack documentation
1903
1841
  */
1904
1842
  declare function getUndocumentedExports(markdownFiles: MarkdownDocFile[], exportNames: string[]): string[];
1905
- import { CategorizedBreaking, OpenPkg as OpenPkg7, SpecDiff as SpecDiff2 } from "@openpkg-ts/spec";
1843
+ import { CategorizedBreaking, OpenPkg as OpenPkg8, SpecDiff as SpecDiff2 } from "@openpkg-ts/spec";
1906
1844
  /**
1907
1845
  * Extended spec diff result with docs impact
1908
1846
  */
@@ -1948,7 +1886,7 @@ interface DiffWithDocsOptions {
1948
1886
  * }
1949
1887
  * ```
1950
1888
  */
1951
- declare function diffSpecWithDocs(oldSpec: OpenPkg7, newSpec: OpenPkg7, options?: DiffWithDocsOptions): SpecDiffWithDocs;
1889
+ declare function diffSpecWithDocs(oldSpec: OpenPkg8, newSpec: OpenPkg8, options?: DiffWithDocsOptions): SpecDiffWithDocs;
1952
1890
  /**
1953
1891
  * Check if a diff has any docs impact
1954
1892
  */
@@ -2004,7 +1942,29 @@ declare function findExportReferences(files: MarkdownDocFile[], exportNames: str
2004
1942
  * Check if a code block references any of the given names
2005
1943
  */
2006
1944
  declare function blockReferencesExport(block: MarkdownCodeBlock, exportName: string): boolean;
2007
- interface Diagnostic {
1945
+ import { EntryPointDetectionMethod } from "@openpkg-ts/spec";
1946
+ /**
1947
+ * Input for generation metadata that comes from the caller (CLI, API, etc.)
1948
+ */
1949
+ interface GenerationInput {
1950
+ /** Entry point file path (relative to package root) */
1951
+ entryPoint: string;
1952
+ /** How the entry point was detected */
1953
+ entryPointSource: EntryPointDetectionMethod;
1954
+ /** Whether this is a declaration-only analysis (.d.ts file) */
1955
+ isDeclarationOnly?: boolean;
1956
+ /** Generator tool name */
1957
+ generatorName: string;
1958
+ /** Generator tool version */
1959
+ generatorVersion: string;
1960
+ /** Detected package manager */
1961
+ packageManager?: string;
1962
+ /** Whether this is a monorepo */
1963
+ isMonorepo?: boolean;
1964
+ /** Target package name (for monorepos) */
1965
+ targetPackage?: string;
1966
+ }
1967
+ interface Diagnostic2 {
2008
1968
  message: string;
2009
1969
  severity: "error" | "warning" | "info";
2010
1970
  suggestion?: string;
@@ -2016,7 +1976,7 @@ interface Diagnostic {
2016
1976
  }
2017
1977
  interface AnalysisResult {
2018
1978
  spec: OpenPkgSpec;
2019
- diagnostics: Diagnostic[];
1979
+ diagnostics: Diagnostic2[];
2020
1980
  metadata: AnalysisMetadata;
2021
1981
  /** True if result came from cache (no fresh analysis) */
2022
1982
  fromCache?: boolean;
@@ -2034,6 +1994,8 @@ interface AnalysisMetadata {
2034
1994
  }
2035
1995
  interface AnalyzeOptions {
2036
1996
  filters?: FilterOptions;
1997
+ /** Generation metadata input (entry point info, tool version, etc.) */
1998
+ generationInput?: GenerationInput;
2037
1999
  }
2038
2000
  declare class DocCov {
2039
2001
  private readonly options;
@@ -2068,7 +2030,7 @@ declare class DocCov {
2068
2030
  declare function analyze(code: string, options?: AnalyzeOptions): Promise<OpenPkgSpec>;
2069
2031
  declare function analyzeFile(filePath: string, options?: AnalyzeOptions): Promise<OpenPkgSpec>;
2070
2032
  /** @deprecated Use DocCov instead */
2071
- declare const OpenPkg8: typeof DocCov;
2033
+ declare const OpenPkg9: typeof DocCov;
2072
2034
  import { SpecExport as SpecExport6 } from "@openpkg-ts/spec";
2073
2035
  import { SpecExportKind as SpecExportKind2 } from "@openpkg-ts/spec";
2074
2036
  /**
@@ -2179,127 +2141,18 @@ interface ResolvedTarget {
2179
2141
  * ```
2180
2142
  */
2181
2143
  declare function resolveTarget(fs: FileSystem, options: ResolveTargetOptions): Promise<ResolvedTarget>;
2182
- import { OpenPkg as OpenPkg9 } from "@openpkg-ts/spec";
2183
2144
  /**
2184
- * Options for creating a ScanOrchestrator.
2145
+ * A documentation drift issue in a spec summary.
2185
2146
  */
2186
- interface ScanOrchestratorOptions {
2187
- /** Progress callback for status updates */
2188
- onProgress?: ProgressCallback;
2189
- /** Command runner for executing shell commands */
2190
- commandRunner?: CommandRunner;
2191
- /** Skip external type resolution */
2192
- skipResolve?: boolean;
2193
- }
2194
- /**
2195
- * Context for the current scan operation.
2196
- */
2197
- interface ScanContext {
2198
- /** Parsed GitHub URL info */
2199
- parsed: ParsedGitHubUrl;
2200
- /** Target package name for monorepos */
2201
- packageName?: string;
2202
- /** Working directory for the scan */
2203
- workDir: string;
2204
- /** Entry point file path */
2205
- entryFile?: string;
2206
- }
2207
- /**
2208
- * Orchestrates the scan workflow.
2209
- *
2210
- * The orchestrator coordinates:
2211
- * 1. Repository cloning (for remote URLs)
2212
- * 2. Monorepo detection and package resolution
2213
- * 3. Entry point detection
2214
- * 4. Dependency installation
2215
- * 5. Build execution (if needed)
2216
- * 6. Documentation analysis
2217
- * 7. Summary extraction
2218
- *
2219
- * It's designed to be FileSystem-agnostic so it works with both:
2220
- * - NodeFileSystem (CLI - local execution)
2221
- * - SandboxFileSystem (API - isolated execution)
2222
- *
2223
- * @example
2224
- * ```typescript
2225
- * import { ScanOrchestrator, NodeFileSystem, createNodeCommandRunner } from '@doccov/sdk';
2226
- *
2227
- * const fs = new NodeFileSystem('/path/to/repo');
2228
- * const orchestrator = new ScanOrchestrator(fs, {
2229
- * commandRunner: createNodeCommandRunner(),
2230
- * onProgress: (event) => console.log(event.message),
2231
- * });
2232
- *
2233
- * const result = await orchestrator.scan({
2234
- * url: 'https://github.com/owner/repo',
2235
- * ref: 'main',
2236
- * });
2237
- *
2238
- * console.log(`Coverage: ${result.coverage}%`);
2239
- * ```
2240
- */
2241
- declare class ScanOrchestrator {
2242
- private readonly fs;
2243
- private readonly options;
2244
- constructor(fs: FileSystem, options?: ScanOrchestratorOptions);
2245
- /**
2246
- * Emit a progress event.
2247
- */
2248
- private emit;
2249
- /**
2250
- * Detect monorepo and resolve target package.
2251
- *
2252
- * @param packageName - Target package name (required for monorepos)
2253
- * @returns Target directory path (relative to workDir)
2254
- * @throws Error if monorepo requires --package flag
2255
- */
2256
- detectPackage(packageName?: string): Promise<{
2257
- targetPath: string;
2258
- resolvedPackage?: string;
2259
- }>;
2260
- /**
2261
- * Detect entry point for the package.
2262
- *
2263
- * @param targetPath - Path to the package directory
2264
- * @returns Entry point file path (relative to workDir)
2265
- */
2266
- detectEntry(targetPath: string): Promise<string>;
2267
- /**
2268
- * Install dependencies for the project.
2269
- *
2270
- * @param workDir - Working directory (absolute path)
2271
- * @returns Installation result
2272
- */
2273
- install(workDir: string): Promise<InstallResult>;
2274
- /**
2275
- * Run build if needed.
2276
- *
2277
- * @param workDir - Working directory (absolute path)
2278
- * @param targetPath - Target package path (relative)
2279
- */
2280
- build(workDir: string, targetPath: string): Promise<void>;
2281
- /**
2282
- * Run documentation analysis.
2283
- *
2284
- * @param entryFile - Path to entry file (absolute)
2285
- * @returns OpenPkg spec
2286
- */
2287
- analyze(entryFile: string): Promise<OpenPkg9>;
2288
- /**
2289
- * Run a complete scan workflow.
2290
- *
2291
- * @param options - Scan options
2292
- * @returns Scan result with coverage statistics
2293
- */
2294
- scan(options: ScanOptions): Promise<ScanResult>;
2295
- }
2296
- /**
2297
- * Error thrown when a monorepo is detected but no package is specified.
2298
- */
2299
- declare class MonorepoRequiresPackageError extends Error {
2300
- /** Available package names */
2301
- readonly availablePackages: string[];
2302
- constructor(availablePackages: string[]);
2147
+ interface SummaryDriftIssue {
2148
+ /** Name of the with drift */
2149
+ export: string;
2150
+ /** Type of drift (e.g., 'param-mismatch', 'return-type') */
2151
+ type: string;
2152
+ /** Human-readable description of the issue */
2153
+ issue: string;
2154
+ /** Optional suggestion for fixing the issue */
2155
+ suggestion?: string;
2303
2156
  }
2304
2157
  /**
2305
2158
  * Summary of a spec's documentation coverage.
@@ -2317,7 +2170,7 @@ interface SpecSummary {
2317
2170
  /** Names of undocumented or partially documented exports */
2318
2171
  undocumented: string[];
2319
2172
  /** Drift issues */
2320
- drift: DriftIssue[];
2173
+ drift: SummaryDriftIssue[];
2321
2174
  }
2322
2175
  /**
2323
2176
  * Extract a summary from an enriched OpenPkg spec.
@@ -2342,6 +2195,188 @@ interface SpecSummary {
2342
2195
  */
2343
2196
  declare function extractSpecSummary(spec: EnrichedOpenPkg): SpecSummary;
2344
2197
  /**
2198
+ * Build Plan types for AI-powered repository scanning.
2199
+ */
2200
+ /**
2201
+ * Target repository information for a build plan.
2202
+ */
2203
+ interface BuildPlanTarget {
2204
+ /** Target type (currently only GitHub is supported) */
2205
+ type: "github";
2206
+ /** Full GitHub repository URL */
2207
+ repoUrl: string;
2208
+ /** Git ref (branch, tag, or commit) */
2209
+ ref: string;
2210
+ /** Root path within the repository (for monorepos) */
2211
+ rootPath?: string;
2212
+ /** Entry point files to analyze */
2213
+ entryPoints: string[];
2214
+ }
2215
+ /**
2216
+ * Runtime environment configuration for executing a build plan.
2217
+ */
2218
+ interface BuildPlanEnvironment {
2219
+ /** Node.js or Bun runtime */
2220
+ runtime: "node20" | "node22" | "bun";
2221
+ /** Package manager to use */
2222
+ packageManager: "npm" | "yarn" | "pnpm" | "bun";
2223
+ /** Additional tools required (e.g., 'wasm-pack', 'cargo') */
2224
+ requiredTools?: string[];
2225
+ }
2226
+ /**
2227
+ * A single step in the build plan.
2228
+ */
2229
+ interface BuildPlanStep {
2230
+ /** Unique identifier for this step */
2231
+ id: string;
2232
+ /** Human-readable step name */
2233
+ name: string;
2234
+ /** Command to execute */
2235
+ command: string;
2236
+ /** Command arguments */
2237
+ args: string[];
2238
+ /** Working directory (relative to repo root) */
2239
+ cwd?: string;
2240
+ /** Timeout in milliseconds */
2241
+ timeout?: number;
2242
+ /** If true, failure won't stop the plan execution */
2243
+ optional?: boolean;
2244
+ }
2245
+ /**
2246
+ * AI-generated build plan for analyzing a repository.
2247
+ */
2248
+ interface BuildPlan {
2249
+ /** Build plan schema version */
2250
+ version: "1.0.0";
2251
+ /** When the plan was generated */
2252
+ generatedAt: string;
2253
+ /** Target repository information */
2254
+ target: BuildPlanTarget;
2255
+ /** Environment configuration */
2256
+ environment: BuildPlanEnvironment;
2257
+ /** Ordered list of steps to execute */
2258
+ steps: BuildPlanStep[];
2259
+ /** AI reasoning about the plan */
2260
+ reasoning: {
2261
+ /** Brief summary of the approach */
2262
+ summary: string;
2263
+ /** Why this approach was chosen */
2264
+ rationale: string;
2265
+ /** Potential issues or concerns */
2266
+ concerns: string[];
2267
+ };
2268
+ /** AI confidence in the plan */
2269
+ confidence: "high" | "medium" | "low";
2270
+ }
2271
+ /**
2272
+ * Result of executing a single build plan step.
2273
+ */
2274
+ interface BuildPlanStepResult {
2275
+ /** Step ID that was executed */
2276
+ stepId: string;
2277
+ /** Whether the step succeeded */
2278
+ success: boolean;
2279
+ /** Duration in milliseconds */
2280
+ duration: number;
2281
+ /** Command output (stdout) */
2282
+ output?: string;
2283
+ /** Error message if failed */
2284
+ error?: string;
2285
+ }
2286
+ /**
2287
+ * Result of executing a complete build plan.
2288
+ */
2289
+ interface BuildPlanExecutionResult {
2290
+ /** Whether all required steps succeeded */
2291
+ success: boolean;
2292
+ /** Generated OpenPkg spec (if successful) */
2293
+ spec?: import("@openpkg-ts/spec").OpenPkg;
2294
+ /** Results for each step */
2295
+ stepResults: BuildPlanStepResult[];
2296
+ /** Total execution time in milliseconds */
2297
+ totalDuration: number;
2298
+ /** Overall error message if failed */
2299
+ error?: string;
2300
+ }
2301
+ /**
2302
+ * GitHub context fetcher for AI-powered build plan generation.
2303
+ * Fetches project context via GitHub API without cloning the repository.
2304
+ */
2305
+ /**
2306
+ * Repository metadata from GitHub API.
2307
+ */
2308
+ interface GitHubRepoMetadata {
2309
+ owner: string;
2310
+ repo: string;
2311
+ defaultBranch: string;
2312
+ description: string | null;
2313
+ language: string | null;
2314
+ topics: string[];
2315
+ isPrivate: boolean;
2316
+ }
2317
+ /**
2318
+ * Detected package manager from lockfile.
2319
+ */
2320
+ type DetectedPackageManager = "npm" | "yarn" | "pnpm" | "bun" | "unknown";
2321
+ /**
2322
+ * Workspace/monorepo configuration.
2323
+ */
2324
+ interface WorkspaceConfig {
2325
+ isMonorepo: boolean;
2326
+ tool?: "npm" | "yarn" | "pnpm" | "lerna" | "turborepo" | "nx";
2327
+ packages?: string[];
2328
+ }
2329
+ /**
2330
+ * Build hints detected from project files.
2331
+ */
2332
+ interface BuildHints {
2333
+ hasTypeScript: boolean;
2334
+ hasWasm: boolean;
2335
+ hasNativeModules: boolean;
2336
+ hasBuildScript: boolean;
2337
+ buildScript?: string;
2338
+ frameworks: string[];
2339
+ }
2340
+ /**
2341
+ * Complete project context for build plan generation.
2342
+ */
2343
+ interface GitHubProjectContext {
2344
+ /** Repository metadata */
2345
+ metadata: GitHubRepoMetadata;
2346
+ /** Git ref being analyzed */
2347
+ ref: string;
2348
+ /** Detected package manager */
2349
+ packageManager: DetectedPackageManager;
2350
+ /** Workspace/monorepo configuration */
2351
+ workspace: WorkspaceConfig;
2352
+ /** Build hints from project files */
2353
+ buildHints: BuildHints;
2354
+ /** Raw file contents for AI analysis */
2355
+ files: {
2356
+ packageJson?: string;
2357
+ tsconfigJson?: string;
2358
+ lockfile?: {
2359
+ name: string;
2360
+ content: string;
2361
+ };
2362
+ };
2363
+ }
2364
+ /**
2365
+ * Parse GitHub URL into owner and repo.
2366
+ */
2367
+ declare function parseGitHubUrl2(url: string): {
2368
+ owner: string;
2369
+ repo: string;
2370
+ } | null;
2371
+ /**
2372
+ * Fetch complete project context from GitHub.
2373
+ */
2374
+ declare function fetchGitHubContext(repoUrl: string, ref?: string): Promise<GitHubProjectContext>;
2375
+ /**
2376
+ * List packages in a monorepo workspace.
2377
+ */
2378
+ declare function listWorkspacePackages(owner: string, repo: string, ref: string, patterns: string[]): Promise<string[]>;
2379
+ /**
2345
2380
  * Type-check a single example
2346
2381
  */
2347
2382
  declare function typecheckExample(example: string, packagePath: string, options?: TypecheckOptions): ExampleTypeError[];
@@ -2349,4 +2384,4 @@ declare function typecheckExample(example: string, packagePath: string, options?
2349
2384
  * Type-check multiple examples
2350
2385
  */
2351
2386
  declare function typecheckExamples(examples: string[], packagePath: string, options?: TypecheckOptions): TypecheckResult;
2352
- export { validateSpecCache, validateExamples, typecheckExamples, typecheckExample, shouldValidate, serializeJSDoc, saveSpecCache, saveReport, safeParseJson, runExamplesWithPackage, runExamples, runExample, resolveTarget, readPackageJson, parseMarkdownFiles, parseMarkdownFile, parseListFlag, parseJSDocToPatch, parseGitHubUrl, parseExamplesFlag, parseAssertions, mergeFixes, mergeFilters, mergeConfig, loadSpecCache, loadCachedReport, isFixableDrift, isExecutableLang, isCachedReportValid, installDependencies, hashString, hashFiles, hashFile, hasNonAssertionComments, hasDocsImpact, hasDocsForExport, groupDriftsByCategory, getUndocumentedExports, getSpecCachePath, getRunCommand, getRulesForKind, getRule, getReportPath, getPrimaryBuildScript, getInstallCommand, getDriftSummary, getDocumentedExports, getDocsImpactSummary, getDiffReportPath, getDefaultConfig, getCoverageRules, generateReportFromEnriched, generateReport, generateFixesForExport, generateFix, formatPackageList, formatDriftSummaryLine, findRemovedReferences, findPackageByName, findJSDocLocation, findExportReferences, findDeprecatedReferences, fetchSpecFromGitHub, fetchSpec, extractSpecSummary, extractPackageSpec, extractImports, extractFunctionCalls, evaluateQuality, evaluateExportQuality, ensureSpecCoverage, enrichSpec, diffSpecWithDocs, diffHashes, detectPackageManager, detectMonorepo, detectExampleRuntimeErrors, detectExampleAssertionFailures, detectEntryPoint, detectBuildInfo, defineConfig, createSourceFile, createNodeCommandRunner, computeExportDrift, computeDrift, clearSpecCache, categorizeDrifts, categorizeDrift, calculateAggregateCoverage, buildRawUrl, buildExportRegistry, buildDisplayUrl, buildCloneUrl, blockReferencesExport, applyPatchToJSDoc, applyEdits, analyzeProject2 as analyzeProject, analyzeFile, analyzeDocsImpact, analyze, WorkspacePackage, VALIDATION_INFO, TypecheckValidationResult, TypecheckResult, TypecheckOptions, SpecSummary, SpecDiffWithDocs, SpecCacheConfig, SpecCache, ScanResult, ScanOrchestratorOptions, ScanOrchestrator, ScanOptions, ScanContext, SandboxFileSystem, STYLE_RULES, SPEC_CACHE_FILE, RuntimeDrift, RunValidationResult, RunExamplesWithPackageResult, RunExamplesWithPackageOptions, RunExampleOptions, RuleContext, ResolvedTarget, ResolvedFilters, ResolveTargetOptions, REPORT_VERSION, REPORT_EXTENSIONS, QualityViolation, QualitySeverity2 as QualitySeverity, QualityRulesConfig, QualityRule, QualityResult, QualityConfig, ProjectInfo, ProgressStage, ProgressEvent, ProgressCallback, PresenceResult, ParsedGitHubUrl, PackageManagerInfo, PackageManager, PackageJson, PackageExports, OpenPkgSpec, OpenPkgOptions, OpenPkg8 as OpenPkg, NodeFileSystem, MonorepoType, MonorepoRequiresPackageError, MonorepoInfo, MemberChange, MarkdownDocFile, MarkdownCodeBlock, LLMAssertion, JSDocTag, JSDocReturn, JSDocPatch, JSDocParam, JSDocEdit, InstallResult, InstallOptions, FixType, FixSuggestion, FilterSource, FilterOptions, FileSystem, ExportReference, ExportDriftResult, ExportCoverageData, ExampleValidationTypeError, ExampleValidationResult, ExampleValidationOptions, ExampleValidationMode, ExampleValidation, ExampleTypeError, ExampleRunResult, EntryPointSource, EntryPointInfo, EnrichedOpenPkg, EnrichedExport, EnrichedDocsMetadata, EnrichOptions, DriftSummary, DriftResult, DriftReportSummary, DriftReport, DriftIssue, DocsImpactResult, DocsImpactReference, DocsImpact, DocsConfig, DocsChangeType, DocCovReport, DocCovOptions, DocCovConfig, DocCov, DiffWithDocsOptions, Diagnostic, DEFAULT_REPORT_PATH, DEFAULT_REPORT_DIR, CoverageSummary, CommandRunner, CommandResult, CheckConfig, CategorizedDrift, CacheValidationResult, CacheContext, CORE_RULES, CACHE_VERSION, BuildInfo, BUILTIN_RULES, ApplyEditsResult, AnalyzeProjectOptions, AnalyzeOptions, AnalysisResult, AggregateQualityResult, ALL_VALIDATIONS };
2387
+ export { validateSpecCache, validateExamples, typecheckExamples, typecheckExample, shouldValidate, serializeJSDoc, saveSpecCache, saveReport, safeParseJson, runExamplesWithPackage, runExamples, runExample, resolveTarget, readPackageJson, parseGitHubUrl2 as parseScanGitHubUrl, parseMarkdownFiles, parseMarkdownFile, parseListFlag, parseJSDocToPatch, parseGitHubUrl, parseExamplesFlag, parseAssertions, mergeFixes, mergeFilters, mergeConfig, loadSpecCache, loadCachedReport, listWorkspacePackages, isFixableDrift, isExecutableLang, isCachedReportValid, installDependencies, hashString, hashFiles, hashFile, hasNonAssertionComments, hasDocsImpact, hasDocsForExport, groupDriftsByCategory, getUndocumentedExports, getSpecCachePath, getRunCommand, getRulesForKind, getRule, getReportPath, getPrimaryBuildScript, getInstallCommand, getDriftSummary, getDocumentedExports, getDocsImpactSummary, getDiffReportPath, getDefaultConfig, getCoverageRules, generateReportFromEnriched, generateReport, generateFixesForExport, generateFix, formatPackageList, formatDriftSummaryLine, findRemovedReferences, findPackageByName, findJSDocLocation, findExportReferences, findDeprecatedReferences, fetchSpecFromGitHub, fetchSpec, fetchGitHubContext, extractSpecSummary, extractPackageSpec, extractImports, extractFunctionCalls, evaluateQuality, evaluateExportQuality, ensureSpecCoverage, enrichSpec, diffSpecWithDocs, diffHashes, detectPackageManager, detectMonorepo, detectExampleRuntimeErrors, detectExampleAssertionFailures, detectEntryPoint, detectBuildInfo, defineConfig, createSourceFile, createNodeCommandRunner, computeExportDrift, computeDrift, clearSpecCache, categorizeDrifts, categorizeDrift, calculateAggregateCoverage, buildRawUrl, buildExportRegistry, buildDisplayUrl, buildCloneUrl, blockReferencesExport, applyPatchToJSDoc, applyEdits, analyzeProject2 as analyzeProject, analyzeFile, analyzeDocsImpact, analyze, WorkspacePackage, WorkspaceConfig, VALIDATION_INFO, TypecheckValidationResult, TypecheckResult, TypecheckOptions, SummaryDriftIssue, SpecSummary, SpecDiffWithDocs, SpecCacheConfig, SpecCache, SandboxFileSystem, STYLE_RULES, SPEC_CACHE_FILE, RuntimeDrift, RunValidationResult, RunExamplesWithPackageResult, RunExamplesWithPackageOptions, RunExampleOptions, RuleContext, ResolvedTarget, ResolvedFilters, ResolveTargetOptions, REPORT_VERSION, REPORT_EXTENSIONS, QualityViolation, QualitySeverity2 as QualitySeverity, QualityRulesConfig, QualityRule, QualityResult, QualityConfig, ProjectInfo, PresenceResult, ParsedGitHubUrl, PackageManagerInfo, PackageManager, PackageJson, PackageExports, OpenPkgSpec, OpenPkgOptions, OpenPkg9 as OpenPkg, NodeFileSystem, MonorepoType, MonorepoInfo, MemberChange, MarkdownDocFile, MarkdownCodeBlock, LLMAssertion, JSDocTag, JSDocReturn, JSDocPatch, JSDocParam, JSDocEdit, InstallResult, InstallOptions, GitHubRepoMetadata, GitHubProjectContext, FixType, FixSuggestion, FilterSource, FilterOptions, FileSystem, ExportReference, ExportDriftResult, ExportCoverageData, ExampleValidationTypeError, ExampleValidationResult, ExampleValidationOptions, ExampleValidationMode, ExampleValidation, ExampleTypeError, ExampleRunResult, EntryPointSource, EntryPointInfo, EnrichedOpenPkg, EnrichedExport, EnrichedDocsMetadata, EnrichOptions, DriftSummary, DriftResult, DriftReportSummary, DriftReport, DocsImpactResult, DocsImpactReference, DocsImpact, DocsConfig, DocsChangeType, DocCovReport, DocCovOptions, DocCovConfig, DocCov, DiffWithDocsOptions, Diagnostic2 as Diagnostic, DetectedPackageManager, DEFAULT_REPORT_PATH, DEFAULT_REPORT_DIR, CoverageSummary, CommandRunner, CommandResult, CheckConfig, CategorizedDrift, CacheValidationResult, CacheContext, CORE_RULES, CACHE_VERSION, BuildPlanTarget, BuildPlanStepResult, BuildPlanStep, BuildPlanExecutionResult, BuildPlanEnvironment, BuildPlan, BuildInfo, BuildHints, BUILTIN_RULES, ApplyEditsResult, AnalyzeProjectOptions, AnalyzeOptions, AnalysisResult, AggregateQualityResult, ALL_VALIDATIONS };
package/dist/index.js CHANGED
@@ -6147,10 +6147,30 @@ class TypeRegistry {
6147
6147
  }
6148
6148
 
6149
6149
  // src/analysis/spec-builder.ts
6150
- function buildOpenPkgSpec(context, resolveExternalTypes) {
6151
- const { baseDir, checker: typeChecker, sourceFile, program } = context;
6150
+ function createDefaultGenerationInfo(entryFile) {
6151
+ return {
6152
+ timestamp: new Date().toISOString(),
6153
+ generator: {
6154
+ name: "@doccov/sdk",
6155
+ version: "0.0.0"
6156
+ },
6157
+ analysis: {
6158
+ entryPoint: entryFile,
6159
+ entryPointSource: "explicit",
6160
+ isDeclarationOnly: entryFile.endsWith(".d.ts"),
6161
+ resolvedExternalTypes: false
6162
+ },
6163
+ environment: {
6164
+ hasNodeModules: false
6165
+ },
6166
+ issues: []
6167
+ };
6168
+ }
6169
+ function buildOpenPkgSpec(context, resolveExternalTypes, generation) {
6170
+ const { baseDir, checker: typeChecker, sourceFile, program, entryFile } = context;
6152
6171
  const packageJsonPath = path9.join(baseDir, "package.json");
6153
6172
  const packageJson = fs8.existsSync(packageJsonPath) ? JSON.parse(fs8.readFileSync(packageJsonPath, "utf-8")) : {};
6173
+ const generationInfo = generation ?? createDefaultGenerationInfo(path9.relative(baseDir, entryFile));
6154
6174
  const spec = {
6155
6175
  $schema: SCHEMA_URL,
6156
6176
  openpkg: SCHEMA_VERSION,
@@ -6163,7 +6183,8 @@ function buildOpenPkgSpec(context, resolveExternalTypes) {
6163
6183
  ecosystem: "js/ts"
6164
6184
  },
6165
6185
  exports: [],
6166
- types: []
6186
+ types: [],
6187
+ generation: generationInfo
6167
6188
  };
6168
6189
  const typeRegistry = new TypeRegistry;
6169
6190
  const serializerContext = {
@@ -6480,7 +6501,7 @@ function hasExternalImports(sourceFile) {
6480
6501
  });
6481
6502
  return found;
6482
6503
  }
6483
- function runAnalysis(input) {
6504
+ function runAnalysis(input, generationInput) {
6484
6505
  const context = createAnalysisContext(input);
6485
6506
  const { baseDir, options, program } = context;
6486
6507
  const packageJsonPath = findNearestPackageJson(baseDir);
@@ -6493,30 +6514,65 @@ function runAnalysis(input) {
6493
6514
  `);
6494
6515
  return !/allowJs/i.test(msg);
6495
6516
  });
6496
- const spec = buildOpenPkgSpec(context, resolveExternalTypes);
6497
6517
  const specDiagnostics = [];
6518
+ const generationIssues = [];
6498
6519
  if (!hasNodeModules && hasExternalImports(context.sourceFile)) {
6499
- specDiagnostics.push({
6520
+ const issue = {
6521
+ code: "NO_NODE_MODULES",
6500
6522
  message: "External imports detected but node_modules not found.",
6501
6523
  severity: "info",
6502
6524
  suggestion: "Run npm install or bun install for complete type resolution."
6503
- });
6504
- }
6525
+ };
6526
+ specDiagnostics.push(issue);
6527
+ generationIssues.push(issue);
6528
+ }
6529
+ const generation = generationInput ? {
6530
+ timestamp: new Date().toISOString(),
6531
+ generator: {
6532
+ name: generationInput.generatorName,
6533
+ version: generationInput.generatorVersion
6534
+ },
6535
+ analysis: {
6536
+ entryPoint: generationInput.entryPoint,
6537
+ entryPointSource: generationInput.entryPointSource,
6538
+ isDeclarationOnly: generationInput.isDeclarationOnly ?? false,
6539
+ resolvedExternalTypes: resolveExternalTypes,
6540
+ maxTypeDepth: options.maxDepth
6541
+ },
6542
+ environment: {
6543
+ packageManager: generationInput.packageManager,
6544
+ hasNodeModules,
6545
+ isMonorepo: generationInput.isMonorepo,
6546
+ targetPackage: generationInput.targetPackage
6547
+ },
6548
+ issues: generationIssues
6549
+ } : undefined;
6550
+ const spec = buildOpenPkgSpec(context, resolveExternalTypes, generation);
6505
6551
  const danglingRefs = collectDanglingRefs(spec);
6506
6552
  for (const ref of danglingRefs) {
6507
- specDiagnostics.push({
6553
+ const issue = {
6554
+ code: "DANGLING_REF",
6508
6555
  message: `Type '${ref}' is referenced but not defined in types[].`,
6509
6556
  severity: "warning",
6510
6557
  suggestion: hasNodeModules ? "The type may be from an external package. Check import paths." : "Run npm/bun install to resolve external types."
6511
- });
6558
+ };
6559
+ specDiagnostics.push(issue);
6560
+ if (generation) {
6561
+ generation.issues.push(issue);
6562
+ }
6512
6563
  }
6513
6564
  const externalTypes = collectExternalTypes(spec);
6514
6565
  if (externalTypes.length > 0) {
6515
- specDiagnostics.push({
6566
+ const issue = {
6567
+ code: "EXTERNAL_TYPE_STUBS",
6516
6568
  message: `${externalTypes.length} external type(s) could not be fully resolved: ${externalTypes.slice(0, 5).join(", ")}${externalTypes.length > 5 ? "..." : ""}`,
6517
6569
  severity: "warning",
6518
6570
  suggestion: hasNodeModules ? "Types are from external packages. Full resolution requires type declarations." : "Run npm/bun install to resolve external type definitions."
6519
- });
6571
+ };
6572
+ specDiagnostics.push(issue);
6573
+ if (generation) {
6574
+ generation.issues.push(issue);
6575
+ }
6520
6576
  }
6521
6577
  const sourceFiles = program.getSourceFiles().filter((sf) => !sf.isDeclarationFile && sf.fileName.startsWith(baseDir)).map((sf) => sf.fileName);
6522
6578
  return {
@@ -8176,7 +8232,7 @@ class DocCov {
8176
8232
  packageDir,
8177
8233
  content: code,
8178
8234
  options: this.options
8179
- });
8235
+ }, analyzeOptions.generationInput);
8180
8236
  const filterOutcome = this.applySpecFilters(analysis.spec, analyzeOptions.filters);
8181
8237
  return {
8182
8238
  spec: filterOutcome.spec,
@@ -8211,7 +8267,7 @@ class DocCov {
8211
8267
  packageDir,
8212
8268
  content,
8213
8269
  options: this.options
8214
- });
8270
+ }, analyzeOptions.generationInput);
8215
8271
  const filterOutcome = this.applySpecFilters(analysis.spec, analyzeOptions.filters);
8216
8272
  const metadata = this.normalizeMetadata(analysis.metadata);
8217
8273
  const result = {
@@ -8486,130 +8542,204 @@ function extractSpecSummary(spec) {
8486
8542
  drift
8487
8543
  };
8488
8544
  }
8489
-
8490
- // src/scan/orchestrator.ts
8491
- class ScanOrchestrator {
8492
- fs;
8493
- options;
8494
- constructor(fs11, options = {}) {
8495
- this.fs = fs11;
8496
- this.options = options;
8497
- }
8498
- emit(event) {
8499
- this.options.onProgress?.(event);
8500
- }
8501
- async detectPackage(packageName) {
8502
- this.emit({ stage: "detecting", message: "Detecting project structure...", progress: 10 });
8503
- const mono = await detectMonorepo(this.fs);
8504
- if (mono.isMonorepo) {
8505
- if (!packageName) {
8506
- const publicPackages = mono.packages.filter((p) => !p.private);
8507
- throw new MonorepoRequiresPackageError(publicPackages.map((p) => p.name));
8508
- }
8509
- const pkg = findPackageByName(mono.packages, packageName);
8510
- if (!pkg) {
8511
- throw new Error(`Package "${packageName}" not found. Available: ${mono.packages.map((p) => p.name).join(", ")}`);
8512
- }
8513
- this.emit({ stage: "detecting", message: `Found package: ${pkg.name}`, progress: 15 });
8514
- return { targetPath: pkg.path, resolvedPackage: pkg.name };
8515
- }
8516
- return { targetPath: "." };
8517
- }
8518
- async detectEntry(targetPath) {
8519
- this.emit({ stage: "detecting", message: "Detecting entry point...", progress: 18 });
8520
- const entry = await detectEntryPoint(this.fs, targetPath);
8521
- const entryFile = targetPath === "." ? entry.path : `${targetPath}/${entry.path}`;
8522
- this.emit({
8523
- stage: "detecting",
8524
- message: `Entry point: ${entry.path} (from ${entry.source})`,
8525
- progress: 20
8526
- });
8527
- return entryFile;
8545
+ // src/scan/github-context.ts
8546
+ function parseGitHubUrl2(url) {
8547
+ const patterns = [
8548
+ /github\.com\/([^/]+)\/([^/]+?)(?:\.git)?(?:\/|$)/,
8549
+ /^([^/]+)\/([^/]+)$/
8550
+ ];
8551
+ for (const pattern of patterns) {
8552
+ const match = url.match(pattern);
8553
+ if (match) {
8554
+ return { owner: match[1], repo: match[2].replace(/\.git$/, "") };
8555
+ }
8528
8556
  }
8529
- async install(workDir) {
8530
- if (!this.options.commandRunner) {
8531
- return {
8532
- success: false,
8533
- packageManager: "npm",
8534
- error: "No command runner provided"
8535
- };
8557
+ return null;
8558
+ }
8559
+ async function fetchRawFile(owner, repo, ref, path13) {
8560
+ const url = `https://raw.githubusercontent.com/${owner}/${repo}/${ref}/${path13}`;
8561
+ try {
8562
+ const response = await fetch(url);
8563
+ if (response.ok) {
8564
+ return await response.text();
8536
8565
  }
8537
- this.emit({ stage: "installing", message: "Installing dependencies...", progress: 25 });
8538
- const result = await installDependencies(this.fs, workDir, this.options.commandRunner, {
8539
- onProgress: this.options.onProgress
8540
- });
8541
- if (result.success) {
8542
- this.emit({ stage: "installing", message: "Dependencies installed", progress: 45 });
8543
- } else {
8544
- this.emit({
8545
- stage: "installing",
8546
- message: "Install failed (continuing with limited analysis)",
8547
- progress: 45
8548
- });
8566
+ return null;
8567
+ } catch {
8568
+ return null;
8569
+ }
8570
+ }
8571
+ async function fetchRepoMetadata(owner, repo) {
8572
+ const url = `https://api.github.com/repos/${owner}/${repo}`;
8573
+ const response = await fetch(url, {
8574
+ headers: {
8575
+ Accept: "application/vnd.github.v3+json",
8576
+ "User-Agent": "DocCov-Scanner"
8549
8577
  }
8550
- return result;
8578
+ });
8579
+ if (!response.ok) {
8580
+ throw new Error(`Failed to fetch repository: ${response.status} ${response.statusText}`);
8551
8581
  }
8552
- async build(workDir, targetPath) {
8553
- if (!this.options.commandRunner)
8554
- return;
8555
- const buildInfo = await detectBuildInfo(this.fs, targetPath);
8556
- const buildScript = getPrimaryBuildScript(buildInfo);
8557
- if (!buildScript)
8558
- return;
8559
- this.emit({ stage: "building", message: "Running build...", progress: 50 });
8560
- const result = await this.options.commandRunner("npm", ["run", buildScript], {
8561
- cwd: workDir,
8562
- timeout: 300000
8563
- });
8564
- const buildMessage = result.exitCode === 0 ? "Build complete" : "Build failed (continuing)";
8565
- this.emit({ stage: "building", message: buildMessage, progress: 60 });
8566
- }
8567
- async analyze(entryFile) {
8568
- this.emit({ stage: "analyzing", message: "Analyzing documentation...", progress: 65 });
8569
- const doccov = new DocCov({ resolveExternalTypes: !this.options.skipResolve });
8570
- const result = await doccov.analyzeFileWithDiagnostics(entryFile);
8571
- this.emit({ stage: "analyzing", message: "Analysis complete", progress: 90 });
8572
- return result.spec;
8573
- }
8574
- async scan(options) {
8575
- const parsed = parseGitHubUrl(options.url, options.ref ?? "main");
8576
- this.emit({
8577
- stage: "detecting",
8578
- message: `Scanning ${parsed.owner}/${parsed.repo}...`,
8579
- progress: 5
8580
- });
8581
- const { targetPath, resolvedPackage } = await this.detectPackage(options.package);
8582
- const entryFile = await this.detectEntry(targetPath);
8583
- if (!options.skipInstall && this.options.commandRunner) {
8584
- await this.install(".");
8585
- await this.build(".", targetPath);
8586
- }
8587
- const spec = await this.analyze(entryFile);
8588
- this.emit({ stage: "complete", message: "Extracting results...", progress: 95 });
8589
- const summary = extractSpecSummary(spec);
8590
- this.emit({ stage: "complete", message: "Scan complete", progress: 100 });
8582
+ const data = await response.json();
8583
+ return {
8584
+ owner,
8585
+ repo,
8586
+ defaultBranch: data.default_branch,
8587
+ description: data.description,
8588
+ language: data.language,
8589
+ topics: data.topics ?? [],
8590
+ isPrivate: data.private
8591
+ };
8592
+ }
8593
+ async function detectPackageManager3(owner, repo, ref) {
8594
+ const lockfiles = [
8595
+ { name: "bun.lockb", manager: "bun" },
8596
+ { name: "pnpm-lock.yaml", manager: "pnpm" },
8597
+ { name: "yarn.lock", manager: "yarn" },
8598
+ { name: "package-lock.json", manager: "npm" }
8599
+ ];
8600
+ for (const { name, manager } of lockfiles) {
8601
+ const content = await fetchRawFile(owner, repo, ref, name);
8602
+ if (content !== null) {
8603
+ return { manager, lockfile: { name, content: content.slice(0, 1e4) } };
8604
+ }
8605
+ }
8606
+ return { manager: "unknown" };
8607
+ }
8608
+ async function detectWorkspace(packageJson, owner, repo, ref) {
8609
+ const pnpmWorkspace = await fetchRawFile(owner, repo, ref, "pnpm-workspace.yaml");
8610
+ if (pnpmWorkspace) {
8611
+ const packagesMatch = pnpmWorkspace.match(/packages:\s*\n((?:\s+-\s+['"]?[^\n]+['"]?\n?)+)/);
8612
+ const packages = packagesMatch ? packagesMatch[1].split(`
8613
+ `).map((line) => line.replace(/^\s+-\s+['"]?/, "").replace(/['"]?\s*$/, "")).filter(Boolean) : undefined;
8591
8614
  return {
8592
- owner: parsed.owner,
8593
- repo: parsed.repo,
8594
- ref: parsed.ref,
8595
- packageName: resolvedPackage ?? options.package,
8596
- coverage: summary.coverage,
8597
- exportCount: summary.exportCount,
8598
- typeCount: summary.typeCount,
8599
- driftCount: summary.driftCount,
8600
- undocumented: summary.undocumented,
8601
- drift: summary.drift
8615
+ isMonorepo: true,
8616
+ tool: "pnpm",
8617
+ packages
8602
8618
  };
8603
8619
  }
8620
+ const lernaJson = await fetchRawFile(owner, repo, ref, "lerna.json");
8621
+ if (lernaJson) {
8622
+ return { isMonorepo: true, tool: "lerna" };
8623
+ }
8624
+ if (packageJson && typeof packageJson === "object") {
8625
+ const pkg = packageJson;
8626
+ if (pkg.workspaces) {
8627
+ const workspaces = pkg.workspaces;
8628
+ const packages = Array.isArray(workspaces) ? workspaces : workspaces.packages;
8629
+ return {
8630
+ isMonorepo: true,
8631
+ tool: "npm",
8632
+ packages: packages?.filter((p) => typeof p === "string")
8633
+ };
8634
+ }
8635
+ }
8636
+ return { isMonorepo: false };
8604
8637
  }
8605
-
8606
- class MonorepoRequiresPackageError extends Error {
8607
- availablePackages;
8608
- constructor(availablePackages) {
8609
- super(`Monorepo detected with ${availablePackages.length} packages. ` + `Specify target with --package. Available: ${availablePackages.join(", ")}`);
8610
- this.name = "MonorepoRequiresPackageError";
8611
- this.availablePackages = availablePackages;
8638
+ function detectBuildHints(packageJson, tsconfigJson) {
8639
+ const hints = {
8640
+ hasTypeScript: false,
8641
+ hasWasm: false,
8642
+ hasNativeModules: false,
8643
+ hasBuildScript: false,
8644
+ frameworks: []
8645
+ };
8646
+ if (!packageJson || typeof packageJson !== "object") {
8647
+ return hints;
8648
+ }
8649
+ const pkg = packageJson;
8650
+ const deps = {
8651
+ ...typeof pkg.dependencies === "object" ? pkg.dependencies : {},
8652
+ ...typeof pkg.devDependencies === "object" ? pkg.devDependencies : {}
8653
+ };
8654
+ hints.hasTypeScript = "typescript" in deps || tsconfigJson !== null;
8655
+ hints.hasWasm = "wasm-pack" in deps || "@aspect-build/rules_esbuild" in deps;
8656
+ hints.hasNativeModules = "node-gyp" in deps || "prebuild" in deps || "napi-rs" in deps;
8657
+ const scripts = typeof pkg.scripts === "object" ? pkg.scripts : {};
8658
+ if (scripts.build) {
8659
+ hints.hasBuildScript = true;
8660
+ hints.buildScript = scripts.build;
8661
+ }
8662
+ const frameworkDeps = [
8663
+ { dep: "react", name: "React" },
8664
+ { dep: "vue", name: "Vue" },
8665
+ { dep: "svelte", name: "Svelte" },
8666
+ { dep: "next", name: "Next.js" },
8667
+ { dep: "nuxt", name: "Nuxt" },
8668
+ { dep: "astro", name: "Astro" },
8669
+ { dep: "express", name: "Express" },
8670
+ { dep: "fastify", name: "Fastify" },
8671
+ { dep: "hono", name: "Hono" }
8672
+ ];
8673
+ for (const { dep, name } of frameworkDeps) {
8674
+ if (dep in deps) {
8675
+ hints.frameworks.push(name);
8676
+ }
8677
+ }
8678
+ return hints;
8679
+ }
8680
+ async function fetchGitHubContext(repoUrl, ref) {
8681
+ const parsed = parseGitHubUrl2(repoUrl);
8682
+ if (!parsed) {
8683
+ throw new Error(`Invalid GitHub URL: ${repoUrl}`);
8684
+ }
8685
+ const { owner, repo } = parsed;
8686
+ const metadata = await fetchRepoMetadata(owner, repo);
8687
+ const targetRef = ref ?? metadata.defaultBranch;
8688
+ const [packageJsonRaw, tsconfigJsonRaw, pmResult] = await Promise.all([
8689
+ fetchRawFile(owner, repo, targetRef, "package.json"),
8690
+ fetchRawFile(owner, repo, targetRef, "tsconfig.json"),
8691
+ detectPackageManager3(owner, repo, targetRef)
8692
+ ]);
8693
+ let packageJson = null;
8694
+ let tsconfigJson = null;
8695
+ if (packageJsonRaw) {
8696
+ try {
8697
+ packageJson = JSON.parse(packageJsonRaw);
8698
+ } catch {}
8699
+ }
8700
+ if (tsconfigJsonRaw) {
8701
+ try {
8702
+ tsconfigJson = JSON.parse(tsconfigJsonRaw);
8703
+ } catch {}
8704
+ }
8705
+ const workspace = await detectWorkspace(packageJson, owner, repo, targetRef);
8706
+ const buildHints = detectBuildHints(packageJson, tsconfigJson);
8707
+ return {
8708
+ metadata,
8709
+ ref: targetRef,
8710
+ packageManager: pmResult.manager,
8711
+ workspace,
8712
+ buildHints,
8713
+ files: {
8714
+ packageJson: packageJsonRaw ?? undefined,
8715
+ tsconfigJson: tsconfigJsonRaw ?? undefined,
8716
+ lockfile: pmResult.lockfile
8717
+ }
8718
+ };
8719
+ }
8720
+ async function listWorkspacePackages(owner, repo, ref, patterns) {
8721
+ const packages = [];
8722
+ for (const pattern of patterns) {
8723
+ const baseDir = pattern.replace(/\/\*.*$/, "");
8724
+ try {
8725
+ const url = `https://api.github.com/repos/${owner}/${repo}/contents/${baseDir}?ref=${ref}`;
8726
+ const response = await fetch(url, {
8727
+ headers: {
8728
+ Accept: "application/vnd.github.v3+json",
8729
+ "User-Agent": "DocCov-Scanner"
8730
+ }
8731
+ });
8732
+ if (response.ok) {
8733
+ const contents = await response.json();
8734
+ for (const item of contents) {
8735
+ if (item.type === "dir") {
8736
+ packages.push(`${baseDir}/${item.name}`);
8737
+ }
8738
+ }
8739
+ }
8740
+ } catch {}
8612
8741
  }
8742
+ return packages;
8613
8743
  }
8614
8744
  export {
8615
8745
  validateSpecCache,
@@ -8626,6 +8756,7 @@ export {
8626
8756
  runExample,
8627
8757
  resolveTarget,
8628
8758
  readPackageJson,
8759
+ parseGitHubUrl2 as parseScanGitHubUrl,
8629
8760
  parseMarkdownFiles,
8630
8761
  parseMarkdownFile,
8631
8762
  parseListFlag,
@@ -8638,6 +8769,7 @@ export {
8638
8769
  mergeConfig,
8639
8770
  loadSpecCache,
8640
8771
  loadCachedReport,
8772
+ listWorkspacePackages,
8641
8773
  isFixableDrift,
8642
8774
  isExecutableLang,
8643
8775
  isCachedReportValid,
@@ -8676,6 +8808,7 @@ export {
8676
8808
  findDeprecatedReferences,
8677
8809
  fetchSpecFromGitHub,
8678
8810
  fetchSpec,
8811
+ fetchGitHubContext,
8679
8812
  extractSpecSummary,
8680
8813
  extractPackageSpec,
8681
8814
  extractImports,
@@ -8713,7 +8846,6 @@ export {
8713
8846
  analyzeDocsImpact,
8714
8847
  analyze,
8715
8848
  VALIDATION_INFO,
8716
- ScanOrchestrator,
8717
8849
  SandboxFileSystem,
8718
8850
  STYLE_RULES,
8719
8851
  SPEC_CACHE_FILE,
@@ -8721,7 +8853,6 @@ export {
8721
8853
  REPORT_EXTENSIONS,
8722
8854
  OpenPkg,
8723
8855
  NodeFileSystem,
8724
- MonorepoRequiresPackageError,
8725
8856
  DocCov,
8726
8857
  DEFAULT_REPORT_PATH,
8727
8858
  DEFAULT_REPORT_DIR,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@doccov/sdk",
3
- "version": "0.12.0",
3
+ "version": "0.13.0",
4
4
  "description": "DocCov SDK - Documentation coverage and drift detection for TypeScript",
5
5
  "keywords": [
6
6
  "typescript",
@@ -39,7 +39,7 @@
39
39
  "dist"
40
40
  ],
41
41
  "dependencies": {
42
- "@openpkg-ts/spec": "^0.8.0",
42
+ "@openpkg-ts/spec": "^0.9.0",
43
43
  "@vercel/sandbox": "^1.0.3",
44
44
  "mdast": "^3.0.0",
45
45
  "remark-mdx": "^3.1.0",