@contractspec/bundle.workspace 4.0.0 → 4.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/dist/ai/agents/unified-adapter.d.ts +1 -1
- package/dist/index.js +261 -23
- package/dist/node/index.js +261 -23
- package/dist/services/ci-check/checks/docs.d.ts +7 -0
- package/dist/services/ci-check/checks/docs.test.d.ts +1 -0
- package/dist/services/ci-check/checks/index.d.ts +1 -0
- package/dist/services/ci-check/types.d.ts +1 -1
- package/dist/services/docs/docblock-audit.d.ts +8 -0
- package/dist/services/docs/docs-service.d.ts +2 -0
- package/dist/services/docs/docs-service.test.d.ts +1 -0
- package/dist/services/docs/index.d.ts +1 -0
- package/dist/services/doctor/checks/docs.d.ts +3 -0
- package/dist/services/doctor/checks/docs.test.d.ts +1 -0
- package/dist/services/doctor/checks/index.d.ts +1 -0
- package/dist/services/doctor/doctor-service.d.ts +2 -1
- package/dist/services/doctor/types.d.ts +1 -1
- package/dist/services/impact/impact-detection-service.d.ts +9 -6
- package/dist/services/impact/index.d.ts +9 -3
- package/package.json +12 -12
- package/dist/services/impact/impact.docblock.d.ts +0 -9
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
* Adapter for UnifiedAgent to work with Workspace AgentOrchestrator.
|
|
3
3
|
*/
|
|
4
4
|
import { type UnifiedAgentConfig } from '@contractspec/lib.ai-agent/agent/unified-agent';
|
|
5
|
-
import type { AgentSpec } from '@contractspec/lib.ai-agent/spec';
|
|
6
5
|
import type { AgentMode } from '@contractspec/lib.contracts-spec';
|
|
6
|
+
import type { AgentSpec } from '@contractspec/lib.contracts-spec/agent';
|
|
7
7
|
import type { AgentProvider, AgentResult, AgentTask } from './types';
|
|
8
8
|
export declare class UnifiedAgentAdapter implements AgentProvider {
|
|
9
9
|
readonly name: AgentMode;
|
package/dist/index.js
CHANGED
|
@@ -397,7 +397,6 @@ var DEFAULT_FS_IGNORES = [
|
|
|
397
397
|
"**/*.d.ts",
|
|
398
398
|
"**/importer/**",
|
|
399
399
|
"**/exporter/**",
|
|
400
|
-
"**/docs/**/*.docblock.ts",
|
|
401
400
|
"**/docs/presentations.ts"
|
|
402
401
|
];
|
|
403
402
|
|
|
@@ -4349,6 +4348,93 @@ async function runDepsChecks(adapters, options) {
|
|
|
4349
4348
|
}
|
|
4350
4349
|
return issues;
|
|
4351
4350
|
}
|
|
4351
|
+
// src/services/docs/docblock-audit.ts
|
|
4352
|
+
import {
|
|
4353
|
+
analyzePackageDocBlocks
|
|
4354
|
+
} from "@contractspec/module.workspace";
|
|
4355
|
+
var PACKAGE_GLOB_IGNORES = [
|
|
4356
|
+
"**/node_modules/**",
|
|
4357
|
+
"**/dist/**",
|
|
4358
|
+
"**/.turbo/**",
|
|
4359
|
+
"**/.next/**"
|
|
4360
|
+
];
|
|
4361
|
+
async function discoverWorkspaceDocPackages(fs5, workspaceRoot) {
|
|
4362
|
+
const packageJsonFiles = await fs5.glob({
|
|
4363
|
+
pattern: "packages/**/package.json",
|
|
4364
|
+
cwd: workspaceRoot,
|
|
4365
|
+
ignore: PACKAGE_GLOB_IGNORES
|
|
4366
|
+
});
|
|
4367
|
+
const discovered = new Map;
|
|
4368
|
+
for (const packageJsonFile of packageJsonFiles) {
|
|
4369
|
+
const packageRoot = fs5.dirname(packageJsonFile);
|
|
4370
|
+
const srcRoot = fs5.join(packageRoot, "src");
|
|
4371
|
+
if (!await fs5.exists(srcRoot)) {
|
|
4372
|
+
continue;
|
|
4373
|
+
}
|
|
4374
|
+
try {
|
|
4375
|
+
const packageJson = JSON.parse(await fs5.readFile(packageJsonFile));
|
|
4376
|
+
discovered.set(packageRoot, {
|
|
4377
|
+
packageName: packageJson.name ?? fs5.relative(workspaceRoot, packageRoot),
|
|
4378
|
+
packageRoot,
|
|
4379
|
+
srcRoot
|
|
4380
|
+
});
|
|
4381
|
+
} catch {
|
|
4382
|
+
continue;
|
|
4383
|
+
}
|
|
4384
|
+
}
|
|
4385
|
+
const rootPackageJson = fs5.join(workspaceRoot, "package.json");
|
|
4386
|
+
const rootSrc = fs5.join(workspaceRoot, "src");
|
|
4387
|
+
if (await fs5.exists(rootPackageJson) && await fs5.exists(rootSrc)) {
|
|
4388
|
+
try {
|
|
4389
|
+
const packageJson = JSON.parse(await fs5.readFile(rootPackageJson));
|
|
4390
|
+
discovered.set(workspaceRoot, {
|
|
4391
|
+
packageName: packageJson.name ?? workspaceRoot,
|
|
4392
|
+
packageRoot: workspaceRoot,
|
|
4393
|
+
srcRoot: rootSrc
|
|
4394
|
+
});
|
|
4395
|
+
} catch {}
|
|
4396
|
+
}
|
|
4397
|
+
return [...discovered.values()].sort((left, right) => left.packageRoot.localeCompare(right.packageRoot));
|
|
4398
|
+
}
|
|
4399
|
+
async function analyzeWorkspaceDocBlocks(fs5, workspaceRoot) {
|
|
4400
|
+
const diagnostics = [];
|
|
4401
|
+
const packages = await discoverWorkspaceDocPackages(fs5, workspaceRoot);
|
|
4402
|
+
for (const pkg of packages) {
|
|
4403
|
+
const result = analyzePackageDocBlocks({
|
|
4404
|
+
packageName: pkg.packageName,
|
|
4405
|
+
srcRoot: pkg.srcRoot
|
|
4406
|
+
});
|
|
4407
|
+
for (const diagnostic of result.diagnostics) {
|
|
4408
|
+
diagnostics.push({
|
|
4409
|
+
...diagnostic,
|
|
4410
|
+
packageName: pkg.packageName,
|
|
4411
|
+
packageRoot: pkg.packageRoot,
|
|
4412
|
+
srcRoot: pkg.srcRoot
|
|
4413
|
+
});
|
|
4414
|
+
}
|
|
4415
|
+
}
|
|
4416
|
+
return diagnostics;
|
|
4417
|
+
}
|
|
4418
|
+
|
|
4419
|
+
// src/services/ci-check/checks/docs.ts
|
|
4420
|
+
async function runDocsChecks(adapters, options) {
|
|
4421
|
+
const workspaceRoot = options.workspaceRoot ?? process.cwd();
|
|
4422
|
+
const diagnostics = await analyzeWorkspaceDocBlocks(adapters.fs, workspaceRoot);
|
|
4423
|
+
return diagnostics.map((diagnostic) => ({
|
|
4424
|
+
ruleId: diagnostic.ruleId,
|
|
4425
|
+
severity: diagnostic.severity === "warning" ? "warning" : "error",
|
|
4426
|
+
message: diagnostic.message,
|
|
4427
|
+
category: "docs",
|
|
4428
|
+
file: diagnostic.file,
|
|
4429
|
+
line: diagnostic.line,
|
|
4430
|
+
column: diagnostic.column,
|
|
4431
|
+
context: {
|
|
4432
|
+
packageName: diagnostic.packageName,
|
|
4433
|
+
packageRoot: diagnostic.packageRoot,
|
|
4434
|
+
...diagnostic.context
|
|
4435
|
+
}
|
|
4436
|
+
}));
|
|
4437
|
+
}
|
|
4352
4438
|
// src/services/doctor/checks/ai.ts
|
|
4353
4439
|
async function runAiChecks(fs5, ctx, prompts) {
|
|
4354
4440
|
const results = [];
|
|
@@ -4627,7 +4713,7 @@ function generateContractsrcConfig(options) {
|
|
|
4627
4713
|
type: "biome"
|
|
4628
4714
|
},
|
|
4629
4715
|
ci: {
|
|
4630
|
-
checks: ["structure", "integrity", "deps", "doctor", "policy"],
|
|
4716
|
+
checks: ["structure", "integrity", "deps", "doctor", "docs", "policy"],
|
|
4631
4717
|
failOnWarnings: false,
|
|
4632
4718
|
uploadSarif: true
|
|
4633
4719
|
},
|
|
@@ -5437,6 +5523,34 @@ async function checkContractsLibrary(fs5, ctx) {
|
|
|
5437
5523
|
};
|
|
5438
5524
|
}
|
|
5439
5525
|
}
|
|
5526
|
+
// src/services/doctor/checks/docs.ts
|
|
5527
|
+
async function runDocChecks(fs5, ctx) {
|
|
5528
|
+
const diagnostics = await analyzeWorkspaceDocBlocks(fs5, ctx.workspaceRoot);
|
|
5529
|
+
if (diagnostics.length === 0) {
|
|
5530
|
+
return [
|
|
5531
|
+
{
|
|
5532
|
+
category: "docs",
|
|
5533
|
+
name: "Same-File DocBlocks",
|
|
5534
|
+
status: "pass",
|
|
5535
|
+
message: "All analyzed packages follow the same-file DocBlock rules."
|
|
5536
|
+
}
|
|
5537
|
+
];
|
|
5538
|
+
}
|
|
5539
|
+
return diagnostics.map((diagnostic) => ({
|
|
5540
|
+
category: "docs",
|
|
5541
|
+
name: `Same-File DocBlocks (${diagnostic.packageName})`,
|
|
5542
|
+
status: diagnostic.severity === "warning" ? "warn" : "fail",
|
|
5543
|
+
message: diagnostic.message,
|
|
5544
|
+
details: fs5.relative(ctx.workspaceRoot, diagnostic.file),
|
|
5545
|
+
context: {
|
|
5546
|
+
ruleId: diagnostic.ruleId,
|
|
5547
|
+
file: diagnostic.file,
|
|
5548
|
+
line: diagnostic.line,
|
|
5549
|
+
column: diagnostic.column,
|
|
5550
|
+
packageName: diagnostic.packageName
|
|
5551
|
+
}
|
|
5552
|
+
}));
|
|
5553
|
+
}
|
|
5440
5554
|
// src/services/layer-discovery.ts
|
|
5441
5555
|
import {
|
|
5442
5556
|
isExampleFile,
|
|
@@ -6346,6 +6460,7 @@ var ALL_CHECK_CATEGORIES = [
|
|
|
6346
6460
|
"config",
|
|
6347
6461
|
"mcp",
|
|
6348
6462
|
"deps",
|
|
6463
|
+
"docs",
|
|
6349
6464
|
"workspace",
|
|
6350
6465
|
"ai",
|
|
6351
6466
|
"layers"
|
|
@@ -6355,6 +6470,7 @@ var CHECK_CATEGORY_LABELS = {
|
|
|
6355
6470
|
config: "Configuration Files",
|
|
6356
6471
|
mcp: "MCP Server",
|
|
6357
6472
|
deps: "Dependencies",
|
|
6473
|
+
docs: "DocBlock Ownership",
|
|
6358
6474
|
workspace: "Workspace Structure",
|
|
6359
6475
|
ai: "AI Provider",
|
|
6360
6476
|
layers: "Contract Layers"
|
|
@@ -6367,6 +6483,7 @@ var defaultDoctorDependencies = {
|
|
|
6367
6483
|
runConfigChecks,
|
|
6368
6484
|
runMcpChecks,
|
|
6369
6485
|
runDepsChecks: runDepsChecks2,
|
|
6486
|
+
runDocChecks,
|
|
6370
6487
|
runWorkspaceChecks,
|
|
6371
6488
|
runAiChecks,
|
|
6372
6489
|
runLayerChecks
|
|
@@ -6450,6 +6567,8 @@ async function runCategoryChecks(category, fs5, ctx, prompts, checks) {
|
|
|
6450
6567
|
return checks.runMcpChecks(fs5, ctx);
|
|
6451
6568
|
case "deps":
|
|
6452
6569
|
return checks.runDepsChecks(fs5, ctx);
|
|
6570
|
+
case "docs":
|
|
6571
|
+
return checks.runDocChecks(fs5, ctx);
|
|
6453
6572
|
case "workspace":
|
|
6454
6573
|
return checks.runWorkspaceChecks(fs5, ctx);
|
|
6455
6574
|
case "ai":
|
|
@@ -6532,13 +6651,14 @@ import path3 from "path";
|
|
|
6532
6651
|
|
|
6533
6652
|
// src/services/generate-artifacts.ts
|
|
6534
6653
|
import path2 from "path";
|
|
6535
|
-
|
|
6536
6654
|
// src/services/docs/docs-service.ts
|
|
6537
6655
|
import {
|
|
6538
|
-
|
|
6656
|
+
packageDocBlocks
|
|
6539
6657
|
} from "@contractspec/lib.contracts-spec/docs";
|
|
6540
6658
|
import {
|
|
6659
|
+
buildPackageDocManifest,
|
|
6541
6660
|
convertSpecToDocBlock,
|
|
6661
|
+
extractModuleDocData,
|
|
6542
6662
|
loadSpecFromSource,
|
|
6543
6663
|
scanAllSpecsFromSource as scanAllSpecsFromSource2,
|
|
6544
6664
|
scanSpecSource as scanSpecSource3
|
|
@@ -6628,6 +6748,14 @@ async function generateDocsFromSpecs(specFiles, options, adapters) {
|
|
|
6628
6748
|
} catch (_err) {}
|
|
6629
6749
|
}
|
|
6630
6750
|
resolver.initialize(scanResults);
|
|
6751
|
+
const authoredEntries = await loadAuthoredDocEntriesFromSourceFiles(specFiles, adapters);
|
|
6752
|
+
for (const authoredEntry of authoredEntries) {
|
|
6753
|
+
blocks.push(authoredEntry.entry.block);
|
|
6754
|
+
logger3.debug(`Loaded authored doc ${authoredEntry.entry.id}`);
|
|
6755
|
+
if (options.outputDir) {
|
|
6756
|
+
await writeDocBlockFile(authoredEntry.entry.block, authoredEntry.filePath, options.outputDir, resolver, fs5);
|
|
6757
|
+
}
|
|
6758
|
+
}
|
|
6631
6759
|
for (const file of specFiles) {
|
|
6632
6760
|
try {
|
|
6633
6761
|
const parsedList = await loadSpecFromSource(file);
|
|
@@ -6639,26 +6767,12 @@ async function generateDocsFromSpecs(specFiles, options, adapters) {
|
|
|
6639
6767
|
const block = convertSpecToDocBlock(parsed, {
|
|
6640
6768
|
rootPath: options.rootPath
|
|
6641
6769
|
});
|
|
6642
|
-
defaultDocRegistry.register(block);
|
|
6643
6770
|
blocks.push(block);
|
|
6644
6771
|
logger3.debug(`Generated doc for ${block.id}`);
|
|
6645
6772
|
if (!options.outputDir) {
|
|
6646
6773
|
continue;
|
|
6647
6774
|
}
|
|
6648
|
-
|
|
6649
|
-
let targetDir = options.outputDir;
|
|
6650
|
-
if (moduleDef) {
|
|
6651
|
-
targetDir = path.join(options.outputDir, moduleDef.key);
|
|
6652
|
-
} else {
|
|
6653
|
-
targetDir = path.join(options.outputDir, "_common");
|
|
6654
|
-
}
|
|
6655
|
-
await fs5.mkdir(targetDir);
|
|
6656
|
-
const filename = `${block.id}.md`;
|
|
6657
|
-
const filePath = path.join(targetDir, filename);
|
|
6658
|
-
const generatedContent = `<!-- @generated - This file was generated by ContractSpec. Do not edit manually. -->
|
|
6659
|
-
|
|
6660
|
-
${block.body}`;
|
|
6661
|
-
await fs5.writeFile(filePath, generatedContent);
|
|
6775
|
+
await writeDocBlockFile(block, file, options.outputDir, resolver, fs5);
|
|
6662
6776
|
}
|
|
6663
6777
|
} catch (error) {
|
|
6664
6778
|
logger3.error(`Error processing ${file}: ${error instanceof Error ? error.message : String(error)}`);
|
|
@@ -6669,6 +6783,36 @@ ${block.body}`;
|
|
|
6669
6783
|
}
|
|
6670
6784
|
return { blocks, count: blocks.length };
|
|
6671
6785
|
}
|
|
6786
|
+
async function loadAuthoredDocBlocksFromSourceFiles(sourceFiles, adapters) {
|
|
6787
|
+
const entries = await loadAuthoredDocEntriesFromSourceFiles(sourceFiles, adapters);
|
|
6788
|
+
return entries.map(({ entry }) => entry.block);
|
|
6789
|
+
}
|
|
6790
|
+
function loadPackageAuthoredDocBlocks(packageName, srcRoot) {
|
|
6791
|
+
return packageDocBlocks(buildPackageDocManifest({ packageName, srcRoot }));
|
|
6792
|
+
}
|
|
6793
|
+
async function loadAuthoredDocEntriesFromSourceFiles(sourceFiles, adapters) {
|
|
6794
|
+
const uniqueFiles = [...new Set(sourceFiles)].sort((left, right) => left.localeCompare(right));
|
|
6795
|
+
const entries = [];
|
|
6796
|
+
for (const filePath of uniqueFiles) {
|
|
6797
|
+
const sourceText = await adapters.fs.readFile(filePath);
|
|
6798
|
+
const sourceModule = filePath.replace(/\\/g, "/").replace(/\.[cm]?[jt]sx?$/, "");
|
|
6799
|
+
const moduleData = extractModuleDocData(sourceText, filePath, sourceModule);
|
|
6800
|
+
for (const entry of moduleData.entries) {
|
|
6801
|
+
entries.push({ entry, filePath });
|
|
6802
|
+
}
|
|
6803
|
+
}
|
|
6804
|
+
return entries;
|
|
6805
|
+
}
|
|
6806
|
+
async function writeDocBlockFile(block, file, outputDir, resolver, fs5) {
|
|
6807
|
+
const moduleDef = resolver.resolve(file);
|
|
6808
|
+
const targetDir = moduleDef ? path.join(outputDir, moduleDef.key) : path.join(outputDir, "_common");
|
|
6809
|
+
await fs5.mkdir(targetDir);
|
|
6810
|
+
const filePath = path.join(targetDir, `${block.id}.md`);
|
|
6811
|
+
const generatedContent = `<!-- @generated - This file was generated by ContractSpec. Do not edit manually. -->
|
|
6812
|
+
|
|
6813
|
+
${block.body}`;
|
|
6814
|
+
await fs5.writeFile(filePath, generatedContent);
|
|
6815
|
+
}
|
|
6672
6816
|
// src/services/generate-artifacts.ts
|
|
6673
6817
|
async function generateArtifacts(adapters, contractsDir, generatedDir, rootPath) {
|
|
6674
6818
|
if (!await adapters.fs.exists(contractsDir)) {}
|
|
@@ -7925,7 +8069,12 @@ import {
|
|
|
7925
8069
|
DEFAULT_CONTRACTSRC as DEFAULT_CONTRACTSRC3
|
|
7926
8070
|
} from "@contractspec/lib.contracts-spec/workspace-config";
|
|
7927
8071
|
var IMPLEMENTATION_PATH_PATTERN = /(^|\/)(handlers?|routes?|controllers?|api)(\/|$)|\.(handler|handlers|route|routes|controller)\.(ts|tsx)$/i;
|
|
7928
|
-
var CONTRACT_REFERENCE_PATTERN = /@contractspec\/lib\.contracts(?:-spec|-integrations)?|define(Command|Query|Event|Feature|Presentation|Capability|Form|DataView|Integration)|OperationSpecRegistry|ContractHandler|installOp|contracts
|
|
8072
|
+
var CONTRACT_REFERENCE_PATTERN = /@contractspec\/lib\.contracts(?:-spec|-integrations)?|define(Command|Query|Event|Feature|Presentation|Capability|Form|DataView|Integration)|OperationSpecRegistry|ContractHandler|installOp|contracts\b|['"][^'"]+\.(operation|event|presentation|feature|capability|form|test-spec)(?:\.[tj]sx?)?['"]/;
|
|
8073
|
+
var CONTRACT_CONTEXT_PATTERN = /@contractspec\/(?:lib\.contracts(?:-spec|-integrations)?|module\.ai-chat|bundle\.library\/application\/mcp|example\.)|['"][^'"]+\.(operation|event|presentation|feature|capability|form|test-spec)(?:\.[tj]sx?)?['"]/;
|
|
8074
|
+
var SUPPORT_FILE_PATTERN = /(^|\/)(index|types)\.ts$|\.types\.ts$|\.storage\.ts$|(?:^|\/)[^/]*\.(resolver|scheduler)\.ts$|(?:^|\/)[^/]*(factory|resources|mock-data)\.ts$/i;
|
|
8075
|
+
var FIXTURE_PATH_PATTERN = /(^|\/)(__fixtures__|fixtures)(\/|$)/i;
|
|
8076
|
+
var WORKSPACE_PACKAGE_ROOT_PATTERN = /^(.*\/packages\/(?:apps|apps-registry|bundles|examples|integrations|libs|modules|tools)\/[^/]+)(?:\/|$)/i;
|
|
8077
|
+
var PACKAGE_ROOT_POLICY_CONTEXT_PATTERN = /\/packages\/(?:apps|apps-registry|bundles|modules)\//i;
|
|
7929
8078
|
function splitConventionPath(value) {
|
|
7930
8079
|
if (!value) {
|
|
7931
8080
|
return [];
|
|
@@ -7949,7 +8098,7 @@ function isPolicyCandidate(filePath, specFiles, config) {
|
|
|
7949
8098
|
if (!/\.(ts|tsx)$/.test(normalized)) {
|
|
7950
8099
|
return false;
|
|
7951
8100
|
}
|
|
7952
|
-
if (normalized.includes("/node_modules/") || normalized.includes("/dist/") || normalized.endsWith(".d.ts") || normalized.endsWith(".test.ts") || normalized.endsWith(".spec.ts")) {
|
|
8101
|
+
if (normalized.includes("/node_modules/") || normalized.includes("/dist/") || FIXTURE_PATH_PATTERN.test(normalized) || SUPPORT_FILE_PATTERN.test(normalized) || normalized.endsWith(".d.ts") || normalized.endsWith(".test.ts") || normalized.endsWith(".spec.ts")) {
|
|
7953
8102
|
return false;
|
|
7954
8103
|
}
|
|
7955
8104
|
if (specFiles.has(normalized)) {
|
|
@@ -7960,6 +8109,16 @@ function isPolicyCandidate(filePath, specFiles, config) {
|
|
|
7960
8109
|
}
|
|
7961
8110
|
return IMPLEMENTATION_PATH_PATTERN.test(normalized);
|
|
7962
8111
|
}
|
|
8112
|
+
function getWorkspacePackageRoot(filePath) {
|
|
8113
|
+
const normalized = filePath.replaceAll("\\", "/");
|
|
8114
|
+
const match = normalized.match(WORKSPACE_PACKAGE_ROOT_PATTERN);
|
|
8115
|
+
return match?.[1] ?? null;
|
|
8116
|
+
}
|
|
8117
|
+
function isBarrelFile(content) {
|
|
8118
|
+
const meaningfulLines = content.split(`
|
|
8119
|
+
`).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("//") && !line.startsWith("/*") && !line.startsWith("*") && !line.startsWith("*/"));
|
|
8120
|
+
return meaningfulLines.length > 0 && meaningfulLines.every((line) => line.startsWith("import ") || line.startsWith("export *") || line.startsWith("export {") || line.startsWith("export type {") || line === "'use client';" || line === '"use client";' || line === "'use server';" || line === '"use server";');
|
|
8121
|
+
}
|
|
7963
8122
|
function resolvePolicyConfig(config) {
|
|
7964
8123
|
if (!config) {
|
|
7965
8124
|
return DEFAULT_CONTRACTSRC3;
|
|
@@ -7985,6 +8144,7 @@ async function runPolicyChecks(adapters, options) {
|
|
|
7985
8144
|
const config = options.config ? resolvePolicyConfig(options.config) : await loadWorkspaceConfig(fs5);
|
|
7986
8145
|
const scannedSpecs = await listSpecs({ fs: fs5 }, { config });
|
|
7987
8146
|
const specFiles = new Set(scannedSpecs.map((spec) => spec.filePath.replaceAll("\\", "/")));
|
|
8147
|
+
const packageRootsWithSpecs = new Set(scannedSpecs.map((spec) => getWorkspacePackageRoot(spec.filePath)).filter((root) => Boolean(root)));
|
|
7988
8148
|
const sourceFiles = await fs5.glob({ pattern: "**/*.{ts,tsx}" });
|
|
7989
8149
|
for (const file of sourceFiles) {
|
|
7990
8150
|
if (!isPolicyCandidate(file, specFiles, config)) {
|
|
@@ -7992,6 +8152,14 @@ async function runPolicyChecks(adapters, options) {
|
|
|
7992
8152
|
}
|
|
7993
8153
|
try {
|
|
7994
8154
|
const content = await fs5.readFile(file);
|
|
8155
|
+
if (isBarrelFile(content)) {
|
|
8156
|
+
continue;
|
|
8157
|
+
}
|
|
8158
|
+
const packageRoot = getWorkspacePackageRoot(file);
|
|
8159
|
+
const hasLocalSpecContext = packageRoot !== null && PACKAGE_ROOT_POLICY_CONTEXT_PATTERN.test(packageRoot) && packageRootsWithSpecs.has(packageRoot);
|
|
8160
|
+
if (!hasLocalSpecContext && !CONTRACT_CONTEXT_PATTERN.test(content)) {
|
|
8161
|
+
continue;
|
|
8162
|
+
}
|
|
7995
8163
|
if (CONTRACT_REFERENCE_PATTERN.test(content)) {
|
|
7996
8164
|
continue;
|
|
7997
8165
|
}
|
|
@@ -8132,6 +8300,7 @@ function createCategorySummary(category, issues, durationMs) {
|
|
|
8132
8300
|
integrity: "Contract Integrity Analysis",
|
|
8133
8301
|
deps: "Dependency Analysis",
|
|
8134
8302
|
doctor: "Installation Health",
|
|
8303
|
+
docs: "DocBlock Ownership",
|
|
8135
8304
|
policy: "Contract Policy Enforcement",
|
|
8136
8305
|
handlers: "Handler Implementation",
|
|
8137
8306
|
tests: "Test Coverage",
|
|
@@ -8179,7 +8348,7 @@ async function getGitInfo(fs5) {
|
|
|
8179
8348
|
}
|
|
8180
8349
|
function getChecksToRun(options) {
|
|
8181
8350
|
const configuredChecks = options.config?.ci?.checks;
|
|
8182
|
-
const allCategories = configuredChecks && configuredChecks.length > 0 ? [...configuredChecks] : ["structure", "integrity", "deps", "doctor"];
|
|
8351
|
+
const allCategories = configuredChecks && configuredChecks.length > 0 ? [...configuredChecks] : ["structure", "integrity", "deps", "doctor", "docs"];
|
|
8183
8352
|
if (options.checkHandlers) {
|
|
8184
8353
|
allCategories.push("handlers");
|
|
8185
8354
|
}
|
|
@@ -8237,6 +8406,12 @@ async function runCIChecks(adapters, options = {}) {
|
|
|
8237
8406
|
issues.push(...doctorIssues);
|
|
8238
8407
|
categorySummaries.push(createCategorySummary("doctor", doctorIssues, Date.now() - categoryStart));
|
|
8239
8408
|
}
|
|
8409
|
+
if (checksToRun.includes("docs")) {
|
|
8410
|
+
const categoryStart = Date.now();
|
|
8411
|
+
const docsIssues = await runDocsChecks(adapters, options);
|
|
8412
|
+
issues.push(...docsIssues);
|
|
8413
|
+
categorySummaries.push(createCategorySummary("docs", docsIssues, Date.now() - categoryStart));
|
|
8414
|
+
}
|
|
8240
8415
|
if (checksToRun.includes("policy")) {
|
|
8241
8416
|
const categoryStart = Date.now();
|
|
8242
8417
|
const policyIssues = await runPolicyChecks(adapters, options);
|
|
@@ -8315,6 +8490,7 @@ var ALL_CI_CHECK_CATEGORIES = [
|
|
|
8315
8490
|
"integrity",
|
|
8316
8491
|
"deps",
|
|
8317
8492
|
"doctor",
|
|
8493
|
+
"docs",
|
|
8318
8494
|
"policy",
|
|
8319
8495
|
"handlers",
|
|
8320
8496
|
"tests",
|
|
@@ -8329,6 +8505,7 @@ var CI_CHECK_CATEGORY_LABELS = {
|
|
|
8329
8505
|
integrity: "Contract Integrity Analysis",
|
|
8330
8506
|
deps: "Dependency Analysis",
|
|
8331
8507
|
doctor: "Installation Health",
|
|
8508
|
+
docs: "DocBlock Ownership",
|
|
8332
8509
|
policy: "Contract Policy Enforcement",
|
|
8333
8510
|
handlers: "Handler Implementation",
|
|
8334
8511
|
tests: "Test Coverage",
|
|
@@ -11619,7 +11796,8 @@ __export(exports_impact, {
|
|
|
11619
11796
|
formatMinimalComment: () => formatMinimalComment,
|
|
11620
11797
|
formatJson: () => formatJson2,
|
|
11621
11798
|
formatCheckRun: () => formatCheckRun,
|
|
11622
|
-
detectImpact: () => detectImpact
|
|
11799
|
+
detectImpact: () => detectImpact,
|
|
11800
|
+
ImpactDetectionOverviewDocBlock: () => ImpactDetectionOverviewDocBlock
|
|
11623
11801
|
});
|
|
11624
11802
|
|
|
11625
11803
|
// src/services/impact/formatters.ts
|
|
@@ -11846,6 +12024,63 @@ function computeSnapshotDiffs(baseSpecs, headSpecs) {
|
|
|
11846
12024
|
}
|
|
11847
12025
|
return diffs;
|
|
11848
12026
|
}
|
|
12027
|
+
|
|
12028
|
+
// src/services/impact/index.ts
|
|
12029
|
+
var ImpactDetectionOverviewDocBlock = {
|
|
12030
|
+
id: "feature.impact-detection.overview",
|
|
12031
|
+
title: "Contract Impact Detection",
|
|
12032
|
+
kind: "goal",
|
|
12033
|
+
visibility: "public",
|
|
12034
|
+
route: "/docs/features/impact-detection",
|
|
12035
|
+
body: `
|
|
12036
|
+
# Contract Impact Detection
|
|
12037
|
+
|
|
12038
|
+
Automated detection and classification of breaking changes in ContractSpec APIs.
|
|
12039
|
+
|
|
12040
|
+
## Features
|
|
12041
|
+
|
|
12042
|
+
- **Snapshot Generation**: Creates canonical, deterministic representations of contracts
|
|
12043
|
+
- **Deep Diff Engine**: Field-level comparison of input/output schemas
|
|
12044
|
+
- **Breaking Change Classification**: Automatic classification using 16 rules
|
|
12045
|
+
- **Multiple Output Formats**: JSON, Markdown, Text, GitHub Check Run
|
|
12046
|
+
- **GitHub Integration**: PR comments and check runs
|
|
12047
|
+
- **CLI Tool**: \`contractspec impact\` command
|
|
12048
|
+
|
|
12049
|
+
## Quick Start
|
|
12050
|
+
|
|
12051
|
+
### CLI Usage
|
|
12052
|
+
|
|
12053
|
+
\`\`\`bash
|
|
12054
|
+
# Basic usage
|
|
12055
|
+
contractspec impact
|
|
12056
|
+
|
|
12057
|
+
# Compare against specific baseline
|
|
12058
|
+
contractspec impact --baseline origin/main
|
|
12059
|
+
|
|
12060
|
+
# Get JSON output
|
|
12061
|
+
contractspec impact --format json
|
|
12062
|
+
\`\`\`
|
|
12063
|
+
|
|
12064
|
+
### GitHub Action
|
|
12065
|
+
|
|
12066
|
+
\`\`\`yaml
|
|
12067
|
+
- uses: lssm-tech/contractspec-action@v1
|
|
12068
|
+
with:
|
|
12069
|
+
mode: impact
|
|
12070
|
+
pr-comment: true
|
|
12071
|
+
fail-on-breaking: true
|
|
12072
|
+
\`\`\`
|
|
12073
|
+
|
|
12074
|
+
## Architecture
|
|
12075
|
+
|
|
12076
|
+
The system consists of three layers:
|
|
12077
|
+
|
|
12078
|
+
1. **Analysis Modules** (module package): Snapshot, Deep Diff, Classifier
|
|
12079
|
+
2. **Impact Service** (bundle package): Orchestration + Formatters
|
|
12080
|
+
3. **Integrations**: CLI command + GitHub Action
|
|
12081
|
+
`,
|
|
12082
|
+
tags: ["impact-detection", "breaking-changes", "ci-cd"]
|
|
12083
|
+
};
|
|
11849
12084
|
// src/services/import/import-service.ts
|
|
11850
12085
|
import {
|
|
11851
12086
|
detectFramework,
|
|
@@ -17691,6 +17926,8 @@ export {
|
|
|
17691
17926
|
module,
|
|
17692
17927
|
mergeMonorepoConfigs,
|
|
17693
17928
|
loadWorkspaceConfig,
|
|
17929
|
+
loadPackageAuthoredDocBlocks,
|
|
17930
|
+
loadAuthoredDocBlocksFromSourceFiles,
|
|
17694
17931
|
listTests,
|
|
17695
17932
|
listSpecsForView,
|
|
17696
17933
|
listSpecs,
|
|
@@ -17814,6 +18051,7 @@ export {
|
|
|
17814
18051
|
claudeCodeAdapter,
|
|
17815
18052
|
cacheKeyToString,
|
|
17816
18053
|
buildSpec,
|
|
18054
|
+
analyzeWorkspaceDocBlocks,
|
|
17817
18055
|
analyzeIntegrity,
|
|
17818
18056
|
analyzeGap,
|
|
17819
18057
|
analyzeDeps,
|
package/dist/node/index.js
CHANGED
|
@@ -397,7 +397,6 @@ var DEFAULT_FS_IGNORES = [
|
|
|
397
397
|
"**/*.d.ts",
|
|
398
398
|
"**/importer/**",
|
|
399
399
|
"**/exporter/**",
|
|
400
|
-
"**/docs/**/*.docblock.ts",
|
|
401
400
|
"**/docs/presentations.ts"
|
|
402
401
|
];
|
|
403
402
|
|
|
@@ -4349,6 +4348,93 @@ async function runDepsChecks(adapters, options) {
|
|
|
4349
4348
|
}
|
|
4350
4349
|
return issues;
|
|
4351
4350
|
}
|
|
4351
|
+
// src/services/docs/docblock-audit.ts
|
|
4352
|
+
import {
|
|
4353
|
+
analyzePackageDocBlocks
|
|
4354
|
+
} from "@contractspec/module.workspace";
|
|
4355
|
+
var PACKAGE_GLOB_IGNORES = [
|
|
4356
|
+
"**/node_modules/**",
|
|
4357
|
+
"**/dist/**",
|
|
4358
|
+
"**/.turbo/**",
|
|
4359
|
+
"**/.next/**"
|
|
4360
|
+
];
|
|
4361
|
+
async function discoverWorkspaceDocPackages(fs5, workspaceRoot) {
|
|
4362
|
+
const packageJsonFiles = await fs5.glob({
|
|
4363
|
+
pattern: "packages/**/package.json",
|
|
4364
|
+
cwd: workspaceRoot,
|
|
4365
|
+
ignore: PACKAGE_GLOB_IGNORES
|
|
4366
|
+
});
|
|
4367
|
+
const discovered = new Map;
|
|
4368
|
+
for (const packageJsonFile of packageJsonFiles) {
|
|
4369
|
+
const packageRoot = fs5.dirname(packageJsonFile);
|
|
4370
|
+
const srcRoot = fs5.join(packageRoot, "src");
|
|
4371
|
+
if (!await fs5.exists(srcRoot)) {
|
|
4372
|
+
continue;
|
|
4373
|
+
}
|
|
4374
|
+
try {
|
|
4375
|
+
const packageJson = JSON.parse(await fs5.readFile(packageJsonFile));
|
|
4376
|
+
discovered.set(packageRoot, {
|
|
4377
|
+
packageName: packageJson.name ?? fs5.relative(workspaceRoot, packageRoot),
|
|
4378
|
+
packageRoot,
|
|
4379
|
+
srcRoot
|
|
4380
|
+
});
|
|
4381
|
+
} catch {
|
|
4382
|
+
continue;
|
|
4383
|
+
}
|
|
4384
|
+
}
|
|
4385
|
+
const rootPackageJson = fs5.join(workspaceRoot, "package.json");
|
|
4386
|
+
const rootSrc = fs5.join(workspaceRoot, "src");
|
|
4387
|
+
if (await fs5.exists(rootPackageJson) && await fs5.exists(rootSrc)) {
|
|
4388
|
+
try {
|
|
4389
|
+
const packageJson = JSON.parse(await fs5.readFile(rootPackageJson));
|
|
4390
|
+
discovered.set(workspaceRoot, {
|
|
4391
|
+
packageName: packageJson.name ?? workspaceRoot,
|
|
4392
|
+
packageRoot: workspaceRoot,
|
|
4393
|
+
srcRoot: rootSrc
|
|
4394
|
+
});
|
|
4395
|
+
} catch {}
|
|
4396
|
+
}
|
|
4397
|
+
return [...discovered.values()].sort((left, right) => left.packageRoot.localeCompare(right.packageRoot));
|
|
4398
|
+
}
|
|
4399
|
+
async function analyzeWorkspaceDocBlocks(fs5, workspaceRoot) {
|
|
4400
|
+
const diagnostics = [];
|
|
4401
|
+
const packages = await discoverWorkspaceDocPackages(fs5, workspaceRoot);
|
|
4402
|
+
for (const pkg of packages) {
|
|
4403
|
+
const result = analyzePackageDocBlocks({
|
|
4404
|
+
packageName: pkg.packageName,
|
|
4405
|
+
srcRoot: pkg.srcRoot
|
|
4406
|
+
});
|
|
4407
|
+
for (const diagnostic of result.diagnostics) {
|
|
4408
|
+
diagnostics.push({
|
|
4409
|
+
...diagnostic,
|
|
4410
|
+
packageName: pkg.packageName,
|
|
4411
|
+
packageRoot: pkg.packageRoot,
|
|
4412
|
+
srcRoot: pkg.srcRoot
|
|
4413
|
+
});
|
|
4414
|
+
}
|
|
4415
|
+
}
|
|
4416
|
+
return diagnostics;
|
|
4417
|
+
}
|
|
4418
|
+
|
|
4419
|
+
// src/services/ci-check/checks/docs.ts
|
|
4420
|
+
async function runDocsChecks(adapters, options) {
|
|
4421
|
+
const workspaceRoot = options.workspaceRoot ?? process.cwd();
|
|
4422
|
+
const diagnostics = await analyzeWorkspaceDocBlocks(adapters.fs, workspaceRoot);
|
|
4423
|
+
return diagnostics.map((diagnostic) => ({
|
|
4424
|
+
ruleId: diagnostic.ruleId,
|
|
4425
|
+
severity: diagnostic.severity === "warning" ? "warning" : "error",
|
|
4426
|
+
message: diagnostic.message,
|
|
4427
|
+
category: "docs",
|
|
4428
|
+
file: diagnostic.file,
|
|
4429
|
+
line: diagnostic.line,
|
|
4430
|
+
column: diagnostic.column,
|
|
4431
|
+
context: {
|
|
4432
|
+
packageName: diagnostic.packageName,
|
|
4433
|
+
packageRoot: diagnostic.packageRoot,
|
|
4434
|
+
...diagnostic.context
|
|
4435
|
+
}
|
|
4436
|
+
}));
|
|
4437
|
+
}
|
|
4352
4438
|
// src/services/doctor/checks/ai.ts
|
|
4353
4439
|
async function runAiChecks(fs5, ctx, prompts) {
|
|
4354
4440
|
const results = [];
|
|
@@ -4627,7 +4713,7 @@ function generateContractsrcConfig(options) {
|
|
|
4627
4713
|
type: "biome"
|
|
4628
4714
|
},
|
|
4629
4715
|
ci: {
|
|
4630
|
-
checks: ["structure", "integrity", "deps", "doctor", "policy"],
|
|
4716
|
+
checks: ["structure", "integrity", "deps", "doctor", "docs", "policy"],
|
|
4631
4717
|
failOnWarnings: false,
|
|
4632
4718
|
uploadSarif: true
|
|
4633
4719
|
},
|
|
@@ -5437,6 +5523,34 @@ async function checkContractsLibrary(fs5, ctx) {
|
|
|
5437
5523
|
};
|
|
5438
5524
|
}
|
|
5439
5525
|
}
|
|
5526
|
+
// src/services/doctor/checks/docs.ts
|
|
5527
|
+
async function runDocChecks(fs5, ctx) {
|
|
5528
|
+
const diagnostics = await analyzeWorkspaceDocBlocks(fs5, ctx.workspaceRoot);
|
|
5529
|
+
if (diagnostics.length === 0) {
|
|
5530
|
+
return [
|
|
5531
|
+
{
|
|
5532
|
+
category: "docs",
|
|
5533
|
+
name: "Same-File DocBlocks",
|
|
5534
|
+
status: "pass",
|
|
5535
|
+
message: "All analyzed packages follow the same-file DocBlock rules."
|
|
5536
|
+
}
|
|
5537
|
+
];
|
|
5538
|
+
}
|
|
5539
|
+
return diagnostics.map((diagnostic) => ({
|
|
5540
|
+
category: "docs",
|
|
5541
|
+
name: `Same-File DocBlocks (${diagnostic.packageName})`,
|
|
5542
|
+
status: diagnostic.severity === "warning" ? "warn" : "fail",
|
|
5543
|
+
message: diagnostic.message,
|
|
5544
|
+
details: fs5.relative(ctx.workspaceRoot, diagnostic.file),
|
|
5545
|
+
context: {
|
|
5546
|
+
ruleId: diagnostic.ruleId,
|
|
5547
|
+
file: diagnostic.file,
|
|
5548
|
+
line: diagnostic.line,
|
|
5549
|
+
column: diagnostic.column,
|
|
5550
|
+
packageName: diagnostic.packageName
|
|
5551
|
+
}
|
|
5552
|
+
}));
|
|
5553
|
+
}
|
|
5440
5554
|
// src/services/layer-discovery.ts
|
|
5441
5555
|
import {
|
|
5442
5556
|
isExampleFile,
|
|
@@ -6346,6 +6460,7 @@ var ALL_CHECK_CATEGORIES = [
|
|
|
6346
6460
|
"config",
|
|
6347
6461
|
"mcp",
|
|
6348
6462
|
"deps",
|
|
6463
|
+
"docs",
|
|
6349
6464
|
"workspace",
|
|
6350
6465
|
"ai",
|
|
6351
6466
|
"layers"
|
|
@@ -6355,6 +6470,7 @@ var CHECK_CATEGORY_LABELS = {
|
|
|
6355
6470
|
config: "Configuration Files",
|
|
6356
6471
|
mcp: "MCP Server",
|
|
6357
6472
|
deps: "Dependencies",
|
|
6473
|
+
docs: "DocBlock Ownership",
|
|
6358
6474
|
workspace: "Workspace Structure",
|
|
6359
6475
|
ai: "AI Provider",
|
|
6360
6476
|
layers: "Contract Layers"
|
|
@@ -6367,6 +6483,7 @@ var defaultDoctorDependencies = {
|
|
|
6367
6483
|
runConfigChecks,
|
|
6368
6484
|
runMcpChecks,
|
|
6369
6485
|
runDepsChecks: runDepsChecks2,
|
|
6486
|
+
runDocChecks,
|
|
6370
6487
|
runWorkspaceChecks,
|
|
6371
6488
|
runAiChecks,
|
|
6372
6489
|
runLayerChecks
|
|
@@ -6450,6 +6567,8 @@ async function runCategoryChecks(category, fs5, ctx, prompts, checks) {
|
|
|
6450
6567
|
return checks.runMcpChecks(fs5, ctx);
|
|
6451
6568
|
case "deps":
|
|
6452
6569
|
return checks.runDepsChecks(fs5, ctx);
|
|
6570
|
+
case "docs":
|
|
6571
|
+
return checks.runDocChecks(fs5, ctx);
|
|
6453
6572
|
case "workspace":
|
|
6454
6573
|
return checks.runWorkspaceChecks(fs5, ctx);
|
|
6455
6574
|
case "ai":
|
|
@@ -6532,13 +6651,14 @@ import path3 from "path";
|
|
|
6532
6651
|
|
|
6533
6652
|
// src/services/generate-artifacts.ts
|
|
6534
6653
|
import path2 from "path";
|
|
6535
|
-
|
|
6536
6654
|
// src/services/docs/docs-service.ts
|
|
6537
6655
|
import {
|
|
6538
|
-
|
|
6656
|
+
packageDocBlocks
|
|
6539
6657
|
} from "@contractspec/lib.contracts-spec/docs";
|
|
6540
6658
|
import {
|
|
6659
|
+
buildPackageDocManifest,
|
|
6541
6660
|
convertSpecToDocBlock,
|
|
6661
|
+
extractModuleDocData,
|
|
6542
6662
|
loadSpecFromSource,
|
|
6543
6663
|
scanAllSpecsFromSource as scanAllSpecsFromSource2,
|
|
6544
6664
|
scanSpecSource as scanSpecSource3
|
|
@@ -6628,6 +6748,14 @@ async function generateDocsFromSpecs(specFiles, options, adapters) {
|
|
|
6628
6748
|
} catch (_err) {}
|
|
6629
6749
|
}
|
|
6630
6750
|
resolver.initialize(scanResults);
|
|
6751
|
+
const authoredEntries = await loadAuthoredDocEntriesFromSourceFiles(specFiles, adapters);
|
|
6752
|
+
for (const authoredEntry of authoredEntries) {
|
|
6753
|
+
blocks.push(authoredEntry.entry.block);
|
|
6754
|
+
logger3.debug(`Loaded authored doc ${authoredEntry.entry.id}`);
|
|
6755
|
+
if (options.outputDir) {
|
|
6756
|
+
await writeDocBlockFile(authoredEntry.entry.block, authoredEntry.filePath, options.outputDir, resolver, fs5);
|
|
6757
|
+
}
|
|
6758
|
+
}
|
|
6631
6759
|
for (const file of specFiles) {
|
|
6632
6760
|
try {
|
|
6633
6761
|
const parsedList = await loadSpecFromSource(file);
|
|
@@ -6639,26 +6767,12 @@ async function generateDocsFromSpecs(specFiles, options, adapters) {
|
|
|
6639
6767
|
const block = convertSpecToDocBlock(parsed, {
|
|
6640
6768
|
rootPath: options.rootPath
|
|
6641
6769
|
});
|
|
6642
|
-
defaultDocRegistry.register(block);
|
|
6643
6770
|
blocks.push(block);
|
|
6644
6771
|
logger3.debug(`Generated doc for ${block.id}`);
|
|
6645
6772
|
if (!options.outputDir) {
|
|
6646
6773
|
continue;
|
|
6647
6774
|
}
|
|
6648
|
-
|
|
6649
|
-
let targetDir = options.outputDir;
|
|
6650
|
-
if (moduleDef) {
|
|
6651
|
-
targetDir = path.join(options.outputDir, moduleDef.key);
|
|
6652
|
-
} else {
|
|
6653
|
-
targetDir = path.join(options.outputDir, "_common");
|
|
6654
|
-
}
|
|
6655
|
-
await fs5.mkdir(targetDir);
|
|
6656
|
-
const filename = `${block.id}.md`;
|
|
6657
|
-
const filePath = path.join(targetDir, filename);
|
|
6658
|
-
const generatedContent = `<!-- @generated - This file was generated by ContractSpec. Do not edit manually. -->
|
|
6659
|
-
|
|
6660
|
-
${block.body}`;
|
|
6661
|
-
await fs5.writeFile(filePath, generatedContent);
|
|
6775
|
+
await writeDocBlockFile(block, file, options.outputDir, resolver, fs5);
|
|
6662
6776
|
}
|
|
6663
6777
|
} catch (error) {
|
|
6664
6778
|
logger3.error(`Error processing ${file}: ${error instanceof Error ? error.message : String(error)}`);
|
|
@@ -6669,6 +6783,36 @@ ${block.body}`;
|
|
|
6669
6783
|
}
|
|
6670
6784
|
return { blocks, count: blocks.length };
|
|
6671
6785
|
}
|
|
6786
|
+
async function loadAuthoredDocBlocksFromSourceFiles(sourceFiles, adapters) {
|
|
6787
|
+
const entries = await loadAuthoredDocEntriesFromSourceFiles(sourceFiles, adapters);
|
|
6788
|
+
return entries.map(({ entry }) => entry.block);
|
|
6789
|
+
}
|
|
6790
|
+
function loadPackageAuthoredDocBlocks(packageName, srcRoot) {
|
|
6791
|
+
return packageDocBlocks(buildPackageDocManifest({ packageName, srcRoot }));
|
|
6792
|
+
}
|
|
6793
|
+
async function loadAuthoredDocEntriesFromSourceFiles(sourceFiles, adapters) {
|
|
6794
|
+
const uniqueFiles = [...new Set(sourceFiles)].sort((left, right) => left.localeCompare(right));
|
|
6795
|
+
const entries = [];
|
|
6796
|
+
for (const filePath of uniqueFiles) {
|
|
6797
|
+
const sourceText = await adapters.fs.readFile(filePath);
|
|
6798
|
+
const sourceModule = filePath.replace(/\\/g, "/").replace(/\.[cm]?[jt]sx?$/, "");
|
|
6799
|
+
const moduleData = extractModuleDocData(sourceText, filePath, sourceModule);
|
|
6800
|
+
for (const entry of moduleData.entries) {
|
|
6801
|
+
entries.push({ entry, filePath });
|
|
6802
|
+
}
|
|
6803
|
+
}
|
|
6804
|
+
return entries;
|
|
6805
|
+
}
|
|
6806
|
+
async function writeDocBlockFile(block, file, outputDir, resolver, fs5) {
|
|
6807
|
+
const moduleDef = resolver.resolve(file);
|
|
6808
|
+
const targetDir = moduleDef ? path.join(outputDir, moduleDef.key) : path.join(outputDir, "_common");
|
|
6809
|
+
await fs5.mkdir(targetDir);
|
|
6810
|
+
const filePath = path.join(targetDir, `${block.id}.md`);
|
|
6811
|
+
const generatedContent = `<!-- @generated - This file was generated by ContractSpec. Do not edit manually. -->
|
|
6812
|
+
|
|
6813
|
+
${block.body}`;
|
|
6814
|
+
await fs5.writeFile(filePath, generatedContent);
|
|
6815
|
+
}
|
|
6672
6816
|
// src/services/generate-artifacts.ts
|
|
6673
6817
|
async function generateArtifacts(adapters, contractsDir, generatedDir, rootPath) {
|
|
6674
6818
|
if (!await adapters.fs.exists(contractsDir)) {}
|
|
@@ -7925,7 +8069,12 @@ import {
|
|
|
7925
8069
|
DEFAULT_CONTRACTSRC as DEFAULT_CONTRACTSRC3
|
|
7926
8070
|
} from "@contractspec/lib.contracts-spec/workspace-config";
|
|
7927
8071
|
var IMPLEMENTATION_PATH_PATTERN = /(^|\/)(handlers?|routes?|controllers?|api)(\/|$)|\.(handler|handlers|route|routes|controller)\.(ts|tsx)$/i;
|
|
7928
|
-
var CONTRACT_REFERENCE_PATTERN = /@contractspec\/lib\.contracts(?:-spec|-integrations)?|define(Command|Query|Event|Feature|Presentation|Capability|Form|DataView|Integration)|OperationSpecRegistry|ContractHandler|installOp|contracts
|
|
8072
|
+
var CONTRACT_REFERENCE_PATTERN = /@contractspec\/lib\.contracts(?:-spec|-integrations)?|define(Command|Query|Event|Feature|Presentation|Capability|Form|DataView|Integration)|OperationSpecRegistry|ContractHandler|installOp|contracts\b|['"][^'"]+\.(operation|event|presentation|feature|capability|form|test-spec)(?:\.[tj]sx?)?['"]/;
|
|
8073
|
+
var CONTRACT_CONTEXT_PATTERN = /@contractspec\/(?:lib\.contracts(?:-spec|-integrations)?|module\.ai-chat|bundle\.library\/application\/mcp|example\.)|['"][^'"]+\.(operation|event|presentation|feature|capability|form|test-spec)(?:\.[tj]sx?)?['"]/;
|
|
8074
|
+
var SUPPORT_FILE_PATTERN = /(^|\/)(index|types)\.ts$|\.types\.ts$|\.storage\.ts$|(?:^|\/)[^/]*\.(resolver|scheduler)\.ts$|(?:^|\/)[^/]*(factory|resources|mock-data)\.ts$/i;
|
|
8075
|
+
var FIXTURE_PATH_PATTERN = /(^|\/)(__fixtures__|fixtures)(\/|$)/i;
|
|
8076
|
+
var WORKSPACE_PACKAGE_ROOT_PATTERN = /^(.*\/packages\/(?:apps|apps-registry|bundles|examples|integrations|libs|modules|tools)\/[^/]+)(?:\/|$)/i;
|
|
8077
|
+
var PACKAGE_ROOT_POLICY_CONTEXT_PATTERN = /\/packages\/(?:apps|apps-registry|bundles|modules)\//i;
|
|
7929
8078
|
function splitConventionPath(value) {
|
|
7930
8079
|
if (!value) {
|
|
7931
8080
|
return [];
|
|
@@ -7949,7 +8098,7 @@ function isPolicyCandidate(filePath, specFiles, config) {
|
|
|
7949
8098
|
if (!/\.(ts|tsx)$/.test(normalized)) {
|
|
7950
8099
|
return false;
|
|
7951
8100
|
}
|
|
7952
|
-
if (normalized.includes("/node_modules/") || normalized.includes("/dist/") || normalized.endsWith(".d.ts") || normalized.endsWith(".test.ts") || normalized.endsWith(".spec.ts")) {
|
|
8101
|
+
if (normalized.includes("/node_modules/") || normalized.includes("/dist/") || FIXTURE_PATH_PATTERN.test(normalized) || SUPPORT_FILE_PATTERN.test(normalized) || normalized.endsWith(".d.ts") || normalized.endsWith(".test.ts") || normalized.endsWith(".spec.ts")) {
|
|
7953
8102
|
return false;
|
|
7954
8103
|
}
|
|
7955
8104
|
if (specFiles.has(normalized)) {
|
|
@@ -7960,6 +8109,16 @@ function isPolicyCandidate(filePath, specFiles, config) {
|
|
|
7960
8109
|
}
|
|
7961
8110
|
return IMPLEMENTATION_PATH_PATTERN.test(normalized);
|
|
7962
8111
|
}
|
|
8112
|
+
function getWorkspacePackageRoot(filePath) {
|
|
8113
|
+
const normalized = filePath.replaceAll("\\", "/");
|
|
8114
|
+
const match = normalized.match(WORKSPACE_PACKAGE_ROOT_PATTERN);
|
|
8115
|
+
return match?.[1] ?? null;
|
|
8116
|
+
}
|
|
8117
|
+
function isBarrelFile(content) {
|
|
8118
|
+
const meaningfulLines = content.split(`
|
|
8119
|
+
`).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("//") && !line.startsWith("/*") && !line.startsWith("*") && !line.startsWith("*/"));
|
|
8120
|
+
return meaningfulLines.length > 0 && meaningfulLines.every((line) => line.startsWith("import ") || line.startsWith("export *") || line.startsWith("export {") || line.startsWith("export type {") || line === "'use client';" || line === '"use client";' || line === "'use server';" || line === '"use server";');
|
|
8121
|
+
}
|
|
7963
8122
|
function resolvePolicyConfig(config) {
|
|
7964
8123
|
if (!config) {
|
|
7965
8124
|
return DEFAULT_CONTRACTSRC3;
|
|
@@ -7985,6 +8144,7 @@ async function runPolicyChecks(adapters, options) {
|
|
|
7985
8144
|
const config = options.config ? resolvePolicyConfig(options.config) : await loadWorkspaceConfig(fs5);
|
|
7986
8145
|
const scannedSpecs = await listSpecs({ fs: fs5 }, { config });
|
|
7987
8146
|
const specFiles = new Set(scannedSpecs.map((spec) => spec.filePath.replaceAll("\\", "/")));
|
|
8147
|
+
const packageRootsWithSpecs = new Set(scannedSpecs.map((spec) => getWorkspacePackageRoot(spec.filePath)).filter((root) => Boolean(root)));
|
|
7988
8148
|
const sourceFiles = await fs5.glob({ pattern: "**/*.{ts,tsx}" });
|
|
7989
8149
|
for (const file of sourceFiles) {
|
|
7990
8150
|
if (!isPolicyCandidate(file, specFiles, config)) {
|
|
@@ -7992,6 +8152,14 @@ async function runPolicyChecks(adapters, options) {
|
|
|
7992
8152
|
}
|
|
7993
8153
|
try {
|
|
7994
8154
|
const content = await fs5.readFile(file);
|
|
8155
|
+
if (isBarrelFile(content)) {
|
|
8156
|
+
continue;
|
|
8157
|
+
}
|
|
8158
|
+
const packageRoot = getWorkspacePackageRoot(file);
|
|
8159
|
+
const hasLocalSpecContext = packageRoot !== null && PACKAGE_ROOT_POLICY_CONTEXT_PATTERN.test(packageRoot) && packageRootsWithSpecs.has(packageRoot);
|
|
8160
|
+
if (!hasLocalSpecContext && !CONTRACT_CONTEXT_PATTERN.test(content)) {
|
|
8161
|
+
continue;
|
|
8162
|
+
}
|
|
7995
8163
|
if (CONTRACT_REFERENCE_PATTERN.test(content)) {
|
|
7996
8164
|
continue;
|
|
7997
8165
|
}
|
|
@@ -8132,6 +8300,7 @@ function createCategorySummary(category, issues, durationMs) {
|
|
|
8132
8300
|
integrity: "Contract Integrity Analysis",
|
|
8133
8301
|
deps: "Dependency Analysis",
|
|
8134
8302
|
doctor: "Installation Health",
|
|
8303
|
+
docs: "DocBlock Ownership",
|
|
8135
8304
|
policy: "Contract Policy Enforcement",
|
|
8136
8305
|
handlers: "Handler Implementation",
|
|
8137
8306
|
tests: "Test Coverage",
|
|
@@ -8179,7 +8348,7 @@ async function getGitInfo(fs5) {
|
|
|
8179
8348
|
}
|
|
8180
8349
|
function getChecksToRun(options) {
|
|
8181
8350
|
const configuredChecks = options.config?.ci?.checks;
|
|
8182
|
-
const allCategories = configuredChecks && configuredChecks.length > 0 ? [...configuredChecks] : ["structure", "integrity", "deps", "doctor"];
|
|
8351
|
+
const allCategories = configuredChecks && configuredChecks.length > 0 ? [...configuredChecks] : ["structure", "integrity", "deps", "doctor", "docs"];
|
|
8183
8352
|
if (options.checkHandlers) {
|
|
8184
8353
|
allCategories.push("handlers");
|
|
8185
8354
|
}
|
|
@@ -8237,6 +8406,12 @@ async function runCIChecks(adapters, options = {}) {
|
|
|
8237
8406
|
issues.push(...doctorIssues);
|
|
8238
8407
|
categorySummaries.push(createCategorySummary("doctor", doctorIssues, Date.now() - categoryStart));
|
|
8239
8408
|
}
|
|
8409
|
+
if (checksToRun.includes("docs")) {
|
|
8410
|
+
const categoryStart = Date.now();
|
|
8411
|
+
const docsIssues = await runDocsChecks(adapters, options);
|
|
8412
|
+
issues.push(...docsIssues);
|
|
8413
|
+
categorySummaries.push(createCategorySummary("docs", docsIssues, Date.now() - categoryStart));
|
|
8414
|
+
}
|
|
8240
8415
|
if (checksToRun.includes("policy")) {
|
|
8241
8416
|
const categoryStart = Date.now();
|
|
8242
8417
|
const policyIssues = await runPolicyChecks(adapters, options);
|
|
@@ -8315,6 +8490,7 @@ var ALL_CI_CHECK_CATEGORIES = [
|
|
|
8315
8490
|
"integrity",
|
|
8316
8491
|
"deps",
|
|
8317
8492
|
"doctor",
|
|
8493
|
+
"docs",
|
|
8318
8494
|
"policy",
|
|
8319
8495
|
"handlers",
|
|
8320
8496
|
"tests",
|
|
@@ -8329,6 +8505,7 @@ var CI_CHECK_CATEGORY_LABELS = {
|
|
|
8329
8505
|
integrity: "Contract Integrity Analysis",
|
|
8330
8506
|
deps: "Dependency Analysis",
|
|
8331
8507
|
doctor: "Installation Health",
|
|
8508
|
+
docs: "DocBlock Ownership",
|
|
8332
8509
|
policy: "Contract Policy Enforcement",
|
|
8333
8510
|
handlers: "Handler Implementation",
|
|
8334
8511
|
tests: "Test Coverage",
|
|
@@ -11619,7 +11796,8 @@ __export(exports_impact, {
|
|
|
11619
11796
|
formatMinimalComment: () => formatMinimalComment,
|
|
11620
11797
|
formatJson: () => formatJson2,
|
|
11621
11798
|
formatCheckRun: () => formatCheckRun,
|
|
11622
|
-
detectImpact: () => detectImpact
|
|
11799
|
+
detectImpact: () => detectImpact,
|
|
11800
|
+
ImpactDetectionOverviewDocBlock: () => ImpactDetectionOverviewDocBlock
|
|
11623
11801
|
});
|
|
11624
11802
|
|
|
11625
11803
|
// src/services/impact/formatters.ts
|
|
@@ -11846,6 +12024,63 @@ function computeSnapshotDiffs(baseSpecs, headSpecs) {
|
|
|
11846
12024
|
}
|
|
11847
12025
|
return diffs;
|
|
11848
12026
|
}
|
|
12027
|
+
|
|
12028
|
+
// src/services/impact/index.ts
|
|
12029
|
+
var ImpactDetectionOverviewDocBlock = {
|
|
12030
|
+
id: "feature.impact-detection.overview",
|
|
12031
|
+
title: "Contract Impact Detection",
|
|
12032
|
+
kind: "goal",
|
|
12033
|
+
visibility: "public",
|
|
12034
|
+
route: "/docs/features/impact-detection",
|
|
12035
|
+
body: `
|
|
12036
|
+
# Contract Impact Detection
|
|
12037
|
+
|
|
12038
|
+
Automated detection and classification of breaking changes in ContractSpec APIs.
|
|
12039
|
+
|
|
12040
|
+
## Features
|
|
12041
|
+
|
|
12042
|
+
- **Snapshot Generation**: Creates canonical, deterministic representations of contracts
|
|
12043
|
+
- **Deep Diff Engine**: Field-level comparison of input/output schemas
|
|
12044
|
+
- **Breaking Change Classification**: Automatic classification using 16 rules
|
|
12045
|
+
- **Multiple Output Formats**: JSON, Markdown, Text, GitHub Check Run
|
|
12046
|
+
- **GitHub Integration**: PR comments and check runs
|
|
12047
|
+
- **CLI Tool**: \`contractspec impact\` command
|
|
12048
|
+
|
|
12049
|
+
## Quick Start
|
|
12050
|
+
|
|
12051
|
+
### CLI Usage
|
|
12052
|
+
|
|
12053
|
+
\`\`\`bash
|
|
12054
|
+
# Basic usage
|
|
12055
|
+
contractspec impact
|
|
12056
|
+
|
|
12057
|
+
# Compare against specific baseline
|
|
12058
|
+
contractspec impact --baseline origin/main
|
|
12059
|
+
|
|
12060
|
+
# Get JSON output
|
|
12061
|
+
contractspec impact --format json
|
|
12062
|
+
\`\`\`
|
|
12063
|
+
|
|
12064
|
+
### GitHub Action
|
|
12065
|
+
|
|
12066
|
+
\`\`\`yaml
|
|
12067
|
+
- uses: lssm-tech/contractspec-action@v1
|
|
12068
|
+
with:
|
|
12069
|
+
mode: impact
|
|
12070
|
+
pr-comment: true
|
|
12071
|
+
fail-on-breaking: true
|
|
12072
|
+
\`\`\`
|
|
12073
|
+
|
|
12074
|
+
## Architecture
|
|
12075
|
+
|
|
12076
|
+
The system consists of three layers:
|
|
12077
|
+
|
|
12078
|
+
1. **Analysis Modules** (module package): Snapshot, Deep Diff, Classifier
|
|
12079
|
+
2. **Impact Service** (bundle package): Orchestration + Formatters
|
|
12080
|
+
3. **Integrations**: CLI command + GitHub Action
|
|
12081
|
+
`,
|
|
12082
|
+
tags: ["impact-detection", "breaking-changes", "ci-cd"]
|
|
12083
|
+
};
|
|
11849
12084
|
// src/services/import/import-service.ts
|
|
11850
12085
|
import {
|
|
11851
12086
|
detectFramework,
|
|
@@ -17691,6 +17926,8 @@ export {
|
|
|
17691
17926
|
module,
|
|
17692
17927
|
mergeMonorepoConfigs,
|
|
17693
17928
|
loadWorkspaceConfig,
|
|
17929
|
+
loadPackageAuthoredDocBlocks,
|
|
17930
|
+
loadAuthoredDocBlocksFromSourceFiles,
|
|
17694
17931
|
listTests,
|
|
17695
17932
|
listSpecsForView,
|
|
17696
17933
|
listSpecs,
|
|
@@ -17814,6 +18051,7 @@ export {
|
|
|
17814
18051
|
claudeCodeAdapter,
|
|
17815
18052
|
cacheKeyToString,
|
|
17816
18053
|
buildSpec,
|
|
18054
|
+
analyzeWorkspaceDocBlocks,
|
|
17817
18055
|
analyzeIntegrity,
|
|
17818
18056
|
analyzeGap,
|
|
17819
18057
|
analyzeDeps,
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { FsAdapter } from '../../../ports/fs';
|
|
2
|
+
import type { LoggerAdapter } from '../../../ports/logger';
|
|
3
|
+
import type { CICheckOptions, CIIssue } from '../types';
|
|
4
|
+
export declare function runDocsChecks(adapters: {
|
|
5
|
+
fs: FsAdapter;
|
|
6
|
+
logger: LoggerAdapter;
|
|
7
|
+
}, options: CICheckOptions): Promise<CIIssue[]>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export { runCoverageChecks } from './coverage';
|
|
5
5
|
export { runDepsChecks } from './deps';
|
|
6
|
+
export { runDocsChecks } from './docs';
|
|
6
7
|
export { runDoctorChecks } from './doctor';
|
|
7
8
|
export { runDriftChecks } from './drift';
|
|
8
9
|
export { runHandlerChecks } from './handlers';
|
|
@@ -7,7 +7,7 @@ import type { ContractsrcConfig, ResolvedContractsrcConfig } from '@contractspec
|
|
|
7
7
|
/**
|
|
8
8
|
* Categories of CI checks.
|
|
9
9
|
*/
|
|
10
|
-
export type CICheckCategory = 'structure' | 'integrity' | 'deps' | 'doctor' | 'policy' | 'handlers' | 'tests' | 'test-refs' | 'coverage' | 'implementation' | 'layers' | 'drift';
|
|
10
|
+
export type CICheckCategory = 'structure' | 'integrity' | 'deps' | 'doctor' | 'docs' | 'policy' | 'handlers' | 'tests' | 'test-refs' | 'coverage' | 'implementation' | 'layers' | 'drift';
|
|
11
11
|
/**
|
|
12
12
|
* All available CI check categories.
|
|
13
13
|
*/
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type DocBlockDiagnostic } from '@contractspec/module.workspace';
|
|
2
|
+
import type { FsAdapter } from '../../ports/fs';
|
|
3
|
+
export interface WorkspaceDocBlockDiagnostic extends DocBlockDiagnostic {
|
|
4
|
+
packageName: string;
|
|
5
|
+
packageRoot: string;
|
|
6
|
+
srcRoot: string;
|
|
7
|
+
}
|
|
8
|
+
export declare function analyzeWorkspaceDocBlocks(fs: FsAdapter, workspaceRoot: string): Promise<WorkspaceDocBlockDiagnostic[]>;
|
|
@@ -13,3 +13,5 @@ export interface DocsServiceResult {
|
|
|
13
13
|
* Generate documentation from spec files.
|
|
14
14
|
*/
|
|
15
15
|
export declare function generateDocsFromSpecs(specFiles: string[], options: DocsServiceOptions, adapters: WorkspaceAdapters): Promise<DocsServiceResult>;
|
|
16
|
+
export declare function loadAuthoredDocBlocksFromSourceFiles(sourceFiles: string[], adapters: Pick<WorkspaceAdapters, 'fs'>): Promise<DocBlock[]>;
|
|
17
|
+
export declare function loadPackageAuthoredDocBlocks(packageName: string, srcRoot: string): DocBlock[];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -5,6 +5,7 @@ export { runAiChecks } from './ai';
|
|
|
5
5
|
export { runCliChecks } from './cli';
|
|
6
6
|
export { runConfigChecks } from './config';
|
|
7
7
|
export { runDepsChecks } from './deps';
|
|
8
|
+
export { runDocChecks } from './docs';
|
|
8
9
|
export { runLayerChecks } from './layers';
|
|
9
10
|
export { runMcpChecks } from './mcp';
|
|
10
11
|
export { runWorkspaceChecks } from './workspace';
|
|
@@ -6,13 +6,14 @@
|
|
|
6
6
|
import { findPackageRoot, findWorkspaceRoot, getPackageName, isMonorepo } from '../../adapters/workspace';
|
|
7
7
|
import type { FsAdapter } from '../../ports/fs';
|
|
8
8
|
import type { LoggerAdapter } from '../../ports/logger';
|
|
9
|
-
import { runAiChecks, runCliChecks, runConfigChecks, runDepsChecks, runLayerChecks, runMcpChecks, runWorkspaceChecks } from './checks/index';
|
|
9
|
+
import { runAiChecks, runCliChecks, runConfigChecks, runDepsChecks, runDocChecks, runLayerChecks, runMcpChecks, runWorkspaceChecks } from './checks/index';
|
|
10
10
|
import type { CheckResult, DoctorOptions, DoctorPromptCallbacks, DoctorResult } from './types';
|
|
11
11
|
interface DoctorCheckRunners {
|
|
12
12
|
runCliChecks: typeof runCliChecks;
|
|
13
13
|
runConfigChecks: typeof runConfigChecks;
|
|
14
14
|
runMcpChecks: typeof runMcpChecks;
|
|
15
15
|
runDepsChecks: typeof runDepsChecks;
|
|
16
|
+
runDocChecks: typeof runDocChecks;
|
|
16
17
|
runWorkspaceChecks: typeof runWorkspaceChecks;
|
|
17
18
|
runAiChecks: typeof runAiChecks;
|
|
18
19
|
runLayerChecks: typeof runLayerChecks;
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
/**
|
|
7
7
|
* Categories of health checks.
|
|
8
8
|
*/
|
|
9
|
-
export type CheckCategory = 'cli' | 'config' | 'mcp' | 'deps' | 'workspace' | 'ai' | 'layers';
|
|
9
|
+
export type CheckCategory = 'cli' | 'config' | 'mcp' | 'deps' | 'docs' | 'workspace' | 'ai' | 'layers';
|
|
10
10
|
/**
|
|
11
11
|
* All available check categories.
|
|
12
12
|
*/
|
|
@@ -1,13 +1,16 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Impact detection service.
|
|
3
|
-
*
|
|
4
|
-
* Orchestrates contract snapshot generation, diff computation,
|
|
5
|
-
* and impact classification for CI/CD pipelines.
|
|
6
|
-
*/
|
|
7
1
|
import type { FsAdapter } from '../../ports/fs';
|
|
8
2
|
import type { GitAdapter } from '../../ports/git';
|
|
9
3
|
import type { LoggerAdapter } from '../../ports/logger';
|
|
10
4
|
import type { ImpactDetectionOptions, ImpactDetectionResult } from './types';
|
|
5
|
+
export declare const ImpactDetectionRulesDocBlock: {
|
|
6
|
+
id: string;
|
|
7
|
+
title: string;
|
|
8
|
+
kind: "reference";
|
|
9
|
+
visibility: "public";
|
|
10
|
+
route: string;
|
|
11
|
+
body: string;
|
|
12
|
+
tags: string[];
|
|
13
|
+
};
|
|
11
14
|
/**
|
|
12
15
|
* Detect the impact of contract changes between baseline and current state.
|
|
13
16
|
*
|
|
@@ -1,6 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
export declare const ImpactDetectionOverviewDocBlock: {
|
|
2
|
+
id: string;
|
|
3
|
+
title: string;
|
|
4
|
+
kind: "goal";
|
|
5
|
+
visibility: "public";
|
|
6
|
+
route: string;
|
|
7
|
+
body: string;
|
|
8
|
+
tags: string[];
|
|
9
|
+
};
|
|
4
10
|
export { formatCheckRun, formatJson, formatMinimalComment, formatPrComment, } from './formatters';
|
|
5
11
|
export { detectImpact } from './impact-detection-service';
|
|
6
12
|
export * from './types';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@contractspec/bundle.workspace",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.1.0",
|
|
4
4
|
"description": "Workspace utilities for monorepo development",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"contractspec",
|
|
@@ -33,15 +33,15 @@
|
|
|
33
33
|
"dependencies": {
|
|
34
34
|
"@ai-sdk/anthropic": "3.0.58",
|
|
35
35
|
"@ai-sdk/openai": "3.0.41",
|
|
36
|
-
"@contractspec/biome-config": "3.8.
|
|
37
|
-
"@contractspec/lib.ai-agent": "
|
|
38
|
-
"@contractspec/lib.ai-providers": "3.7.
|
|
39
|
-
"@contractspec/lib.contracts-spec": "
|
|
40
|
-
"@contractspec/lib.contracts-integrations": "3.
|
|
41
|
-
"@contractspec/lib.contracts-transformers": "3.7.
|
|
42
|
-
"@contractspec/lib.source-extractors": "2.7.
|
|
43
|
-
"@contractspec/module.workspace": "4.
|
|
44
|
-
"@contractspec/lib.utils-typescript": "3.7.
|
|
36
|
+
"@contractspec/biome-config": "3.8.3",
|
|
37
|
+
"@contractspec/lib.ai-agent": "8.0.0",
|
|
38
|
+
"@contractspec/lib.ai-providers": "3.7.9",
|
|
39
|
+
"@contractspec/lib.contracts-spec": "5.0.0",
|
|
40
|
+
"@contractspec/lib.contracts-integrations": "3.8.4",
|
|
41
|
+
"@contractspec/lib.contracts-transformers": "3.7.12",
|
|
42
|
+
"@contractspec/lib.source-extractors": "2.7.12",
|
|
43
|
+
"@contractspec/module.workspace": "4.1.0",
|
|
44
|
+
"@contractspec/lib.utils-typescript": "3.7.9",
|
|
45
45
|
"ai": "6.0.116",
|
|
46
46
|
"chalk": "^5.6.2",
|
|
47
47
|
"chokidar": "^5.0.0",
|
|
@@ -54,12 +54,12 @@
|
|
|
54
54
|
"zod": "^4.3.5"
|
|
55
55
|
},
|
|
56
56
|
"devDependencies": {
|
|
57
|
-
"@contractspec/tool.typescript": "3.7.
|
|
57
|
+
"@contractspec/tool.typescript": "3.7.9",
|
|
58
58
|
"@types/bun": "^1.3.11",
|
|
59
59
|
"@types/micromatch": "^4.0.10",
|
|
60
60
|
"@types/node": "^25.3.5",
|
|
61
61
|
"typescript": "^5.9.3",
|
|
62
|
-
"@contractspec/tool.bun": "3.7.
|
|
62
|
+
"@contractspec/tool.bun": "3.7.9"
|
|
63
63
|
},
|
|
64
64
|
"exports": {
|
|
65
65
|
".": {
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* DocBlock for Contract Impact Detection feature.
|
|
3
|
-
*
|
|
4
|
-
* Colocated documentation following the DocBlock pattern.
|
|
5
|
-
*/
|
|
6
|
-
import type { DocBlock } from '@contractspec/lib.contracts-spec/docs/types';
|
|
7
|
-
export declare const ImpactDetectionOverviewDoc: DocBlock;
|
|
8
|
-
export declare const ImpactDetectionRulesDoc: DocBlock;
|
|
9
|
-
export declare const ImpactDetectionUsageDoc: DocBlock;
|