@contractspec/bundle.workspace 1.52.0 → 1.53.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/adapters/ai.d.mts +2 -2
- package/dist/adapters/ai.d.mts.map +1 -1
- package/dist/adapters/ai.mjs.map +1 -1
- package/dist/adapters/factory.d.mts +2 -2
- package/dist/adapters/factory.d.mts.map +1 -1
- package/dist/adapters/factory.mjs +3 -14
- package/dist/adapters/factory.mjs.map +1 -1
- package/dist/adapters/fs.bun.d.mts +11 -0
- package/dist/adapters/fs.bun.d.mts.map +1 -0
- package/dist/adapters/fs.bun.mjs +81 -0
- package/dist/adapters/fs.bun.mjs.map +1 -0
- package/dist/adapters/fs.d.mts +2 -8
- package/dist/adapters/fs.d.mts.map +1 -1
- package/dist/adapters/fs.mjs +4 -88
- package/dist/adapters/fs.mjs.map +1 -1
- package/dist/adapters/fs.node.d.mts +11 -0
- package/dist/adapters/fs.node.d.mts.map +1 -0
- package/dist/adapters/fs.node.mjs +84 -0
- package/dist/adapters/fs.node.mjs.map +1 -0
- package/dist/adapters/index.d.mts +3 -1
- package/dist/adapters/index.mjs +3 -1
- package/dist/ai/agents/index.d.mts +6 -0
- package/dist/ai/agents/orchestrator.d.mts +4 -4
- package/dist/ai/agents/orchestrator.d.mts.map +1 -1
- package/dist/ai/agents/orchestrator.mjs +5 -0
- package/dist/ai/agents/orchestrator.mjs.map +1 -1
- package/dist/ai/agents/simple-agent.d.mts +2 -2
- package/dist/ai/agents/simple-agent.d.mts.map +1 -1
- package/dist/ai/agents/simple-agent.mjs.map +1 -1
- package/dist/ai/agents/types.d.mts +4 -5
- package/dist/ai/agents/types.d.mts.map +1 -1
- package/dist/ai/agents/unified-adapter.mjs +70 -0
- package/dist/ai/agents/unified-adapter.mjs.map +1 -0
- package/dist/ai/index.d.mts +3 -3
- package/dist/ai/index.mjs +1 -2
- package/dist/ai/prompts/spec-creation.mjs +1 -1
- package/dist/ai/providers.d.mts +3 -18
- package/dist/ai/providers.d.mts.map +1 -1
- package/dist/ai/providers.mjs +2 -22
- package/dist/ai/providers.mjs.map +1 -1
- package/dist/index.d.mts +13 -8
- package/dist/index.mjs +11 -7
- package/dist/ports/ai.d.mts +7 -3
- package/dist/ports/ai.d.mts.map +1 -1
- package/dist/ports/index.d.mts +1 -1
- package/dist/registry.d.mts +15 -0
- package/dist/registry.d.mts.map +1 -0
- package/dist/registry.mjs +19 -0
- package/dist/registry.mjs.map +1 -0
- package/dist/services/action-drift/service.d.mts +11 -0
- package/dist/services/action-drift/service.d.mts.map +1 -0
- package/dist/services/action-drift/service.mjs +43 -0
- package/dist/services/action-drift/service.mjs.map +1 -0
- package/dist/services/action-drift/types.d.mts +23 -0
- package/dist/services/action-drift/types.d.mts.map +1 -0
- package/dist/services/action-pr/service.d.mts +17 -0
- package/dist/services/action-pr/service.d.mts.map +1 -0
- package/dist/services/action-pr/service.mjs +205 -0
- package/dist/services/action-pr/service.mjs.map +1 -0
- package/dist/services/action-pr/types.d.mts +67 -0
- package/dist/services/action-pr/types.d.mts.map +1 -0
- package/dist/services/build.d.mts +3 -2
- package/dist/services/build.d.mts.map +1 -1
- package/dist/services/build.mjs.map +1 -1
- package/dist/services/ci-check/checks/coverage.mjs +30 -41
- package/dist/services/ci-check/checks/coverage.mjs.map +1 -1
- package/dist/services/ci-check/checks/handlers.mjs +3 -3
- package/dist/services/ci-check/checks/handlers.mjs.map +1 -1
- package/dist/services/ci-check/checks/implementation.mjs +1 -1
- package/dist/services/ci-check/checks/implementation.mjs.map +1 -1
- package/dist/services/ci-check/checks/structure.mjs +5 -6
- package/dist/services/ci-check/checks/structure.mjs.map +1 -1
- package/dist/services/ci-check/checks/test-refs.mjs +19 -29
- package/dist/services/ci-check/checks/test-refs.mjs.map +1 -1
- package/dist/services/ci-check/checks/tests.mjs +3 -3
- package/dist/services/ci-check/checks/tests.mjs.map +1 -1
- package/dist/services/ci-check/ci-check-service.d.mts.map +1 -1
- package/dist/services/ci-check/ci-check-service.mjs +7 -12
- package/dist/services/ci-check/ci-check-service.mjs.map +1 -1
- package/dist/services/config.d.mts +3 -3
- package/dist/services/config.d.mts.map +1 -1
- package/dist/services/config.mjs +12 -34
- package/dist/services/config.mjs.map +1 -1
- package/dist/services/create/ai-generator.d.mts +3 -3
- package/dist/services/create/ai-generator.d.mts.map +1 -1
- package/dist/services/create/ai-generator.mjs +1 -1
- package/dist/services/create/ai-generator.mjs.map +1 -1
- package/dist/services/create/index.d.mts +4 -4
- package/dist/services/create/index.d.mts.map +1 -1
- package/dist/services/create/index.mjs.map +1 -1
- package/dist/services/docs/docs-service.mjs +16 -13
- package/dist/services/docs/docs-service.mjs.map +1 -1
- package/dist/services/extract.mjs +2 -10
- package/dist/services/extract.mjs.map +1 -1
- package/dist/services/implementation/discovery.d.mts.map +1 -1
- package/dist/services/implementation/discovery.mjs +6 -14
- package/dist/services/implementation/discovery.mjs.map +1 -1
- package/dist/services/implementation/index.d.mts +1 -1
- package/dist/services/implementation/index.mjs +1 -1
- package/dist/services/implementation/resolver/index.d.mts +8 -6
- package/dist/services/implementation/resolver/index.d.mts.map +1 -1
- package/dist/services/implementation/resolver/index.mjs +33 -31
- package/dist/services/implementation/resolver/index.mjs.map +1 -1
- package/dist/services/implementation/resolver/parsers.d.mts +1 -5
- package/dist/services/implementation/resolver/parsers.d.mts.map +1 -1
- package/dist/services/implementation/resolver/parsers.mjs +1 -19
- package/dist/services/implementation/resolver/parsers.mjs.map +1 -1
- package/dist/services/implementation/types.d.mts +3 -1
- package/dist/services/implementation/types.d.mts.map +1 -1
- package/dist/services/index.d.mts +5 -1
- package/dist/services/index.mjs +4 -2
- package/dist/services/list.d.mts +4 -3
- package/dist/services/list.d.mts.map +1 -1
- package/dist/services/list.mjs +4 -2
- package/dist/services/list.mjs.map +1 -1
- package/dist/services/sync.d.mts +2 -2
- package/dist/services/sync.d.mts.map +1 -1
- package/dist/services/sync.mjs.map +1 -1
- package/dist/services/test/test-generator-service.d.mts +1 -1
- package/dist/services/test/test-service.mjs +1 -1
- package/dist/services/validate/blueprint-validator.mjs +1 -1
- package/dist/services/validate/implementation-agent-validator.d.mts +2 -2
- package/dist/services/validate/implementation-agent-validator.d.mts.map +1 -1
- package/dist/services/validate/implementation-agent-validator.mjs.map +1 -1
- package/dist/services/validate/implementation-validator.d.mts +4 -3
- package/dist/services/validate/implementation-validator.d.mts.map +1 -1
- package/dist/services/validate/implementation-validator.mjs +4 -13
- package/dist/services/validate/implementation-validator.mjs.map +1 -1
- package/dist/services/validate/spec-validator.d.mts +1 -1
- package/dist/services/validate/spec-validator.d.mts.map +1 -1
- package/dist/services/validate/spec-validator.mjs +11 -7
- package/dist/services/validate/spec-validator.mjs.map +1 -1
- package/dist/services/validate/tenant-validator.mjs +1 -1
- package/dist/services/watch.d.mts +2 -2
- package/dist/services/watch.d.mts.map +1 -1
- package/dist/services/watch.mjs.map +1 -1
- package/dist/utils/filter.d.mts +10 -1
- package/dist/utils/filter.d.mts.map +1 -1
- package/dist/utils/filter.mjs +28 -1
- package/dist/utils/filter.mjs.map +1 -1
- package/dist/utils/index.d.mts +2 -2
- package/dist/utils/index.mjs +2 -1
- package/package.json +11 -9
- package/dist/ai/client.d.mts +0 -97
- package/dist/ai/client.d.mts.map +0 -1
- package/dist/ai/client.mjs +0 -189
- package/dist/ai/client.mjs.map +0 -1
- package/dist/types/config.d.mts +0 -34
- package/dist/types/config.d.mts.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"implementation.mjs","names":[],"sources":["../../../../src/services/ci-check/checks/implementation.ts"],"sourcesContent":["/**\n * Implementation verification checks.\n */\n\nimport type { FsAdapter } from '../../../ports/fs';\nimport type { LoggerAdapter } from '../../../ports/logger';\nimport { loadWorkspaceConfig } from '../../config';\nimport { resolveAllImplementations } from '../../implementation/resolver';\nimport type { CICheckOptions, CIIssue } from '../types';\n\n/**\n * Run implementation verification checks.\n */\nexport async function runImplementationChecks(\n adapters: { fs: FsAdapter; logger: LoggerAdapter },\n specFiles:
|
|
1
|
+
{"version":3,"file":"implementation.mjs","names":[],"sources":["../../../../src/services/ci-check/checks/implementation.ts"],"sourcesContent":["/**\n * Implementation verification checks.\n */\n\nimport type { SpecScanResult } from '@contractspec/module.workspace';\nimport type { FsAdapter } from '../../../ports/fs';\nimport type { LoggerAdapter } from '../../../ports/logger';\nimport { loadWorkspaceConfig } from '../../config';\nimport { resolveAllImplementations } from '../../implementation/resolver';\nimport type { CICheckOptions, CIIssue } from '../types';\n\n/**\n * Run implementation verification checks.\n */\nexport async function runImplementationChecks(\n adapters: { fs: FsAdapter; logger: LoggerAdapter },\n specFiles: SpecScanResult[],\n options: CICheckOptions\n): Promise<CIIssue[]> {\n const { fs } = adapters;\n const issues: CIIssue[] = [];\n\n const config = await loadWorkspaceConfig(fs);\n const implOptions = options.implementation ?? {};\n\n // Only check operation specs by default\n const operationSpecs = specFiles.filter((f) => f.specType === 'operation');\n\n // Resolve implementations for all specs\n const results = await resolveAllImplementations(\n operationSpecs,\n { fs },\n config,\n {\n computeHashes: implOptions.useCache ?? true,\n }\n );\n\n for (const result of results) {\n // Check if implementation is required\n if (implOptions.requireImplemented && result.status === 'missing') {\n issues.push({\n ruleId: 'impl-missing',\n severity: 'error',\n message: `Spec ${result.specKey} has no implementation`,\n category: 'implementation',\n file: result.specPath,\n context: {\n specKey: result.specKey,\n specVersion: result.specVersion,\n status: result.status,\n },\n });\n } else if (result.status === 'missing') {\n issues.push({\n ruleId: 'impl-missing',\n severity: 'warning',\n message: `Spec ${result.specKey} has no implementation`,\n category: 'implementation',\n file: result.specPath,\n context: {\n specKey: result.specKey,\n specVersion: result.specVersion,\n status: result.status,\n },\n });\n }\n\n // Check for partial implementations\n if (!implOptions.allowPartial && result.status === 'partial') {\n const missingImpls = result.implementations\n .filter((i) => !i.exists && i.type !== 'test')\n .map((i) => i.path);\n\n issues.push({\n ruleId: 'impl-partial',\n severity: 'warning',\n message: `Spec ${result.specKey} has partial implementation: missing ${missingImpls.join(', ')}`,\n category: 'implementation',\n file: result.specPath,\n context: {\n specKey: result.specKey,\n specVersion: result.specVersion,\n status: result.status,\n missingFiles: missingImpls,\n },\n });\n }\n\n // Report missing tests\n const missingTests = result.implementations.filter(\n (i) => !i.exists && i.type === 'test'\n );\n if (missingTests.length > 0) {\n issues.push({\n ruleId: 'impl-missing-tests',\n severity: 'note',\n message: `Spec ${result.specKey} missing test files: ${missingTests.map((t) => t.path).join(', ')}`,\n category: 'implementation',\n file: result.specPath,\n context: {\n specKey: result.specKey,\n missingTests: missingTests.map((t) => t.path),\n },\n });\n }\n }\n\n return issues;\n}\n"],"mappings":";;;;;;;AAcA,eAAsB,wBACpB,UACA,WACA,SACoB;CACpB,MAAM,EAAE,OAAO;CACf,MAAM,SAAoB,EAAE;CAE5B,MAAM,SAAS,MAAM,oBAAoB,GAAG;CAC5C,MAAM,cAAc,QAAQ,kBAAkB,EAAE;CAMhD,MAAM,UAAU,MAAM,0BAHC,UAAU,QAAQ,MAAM,EAAE,aAAa,YAAY,EAKxE,EAAE,IAAI,EACN,QACA,EACE,eAAe,YAAY,YAAY,MACxC,CACF;AAED,MAAK,MAAM,UAAU,SAAS;AAE5B,MAAI,YAAY,sBAAsB,OAAO,WAAW,UACtD,QAAO,KAAK;GACV,QAAQ;GACR,UAAU;GACV,SAAS,QAAQ,OAAO,QAAQ;GAChC,UAAU;GACV,MAAM,OAAO;GACb,SAAS;IACP,SAAS,OAAO;IAChB,aAAa,OAAO;IACpB,QAAQ,OAAO;IAChB;GACF,CAAC;WACO,OAAO,WAAW,UAC3B,QAAO,KAAK;GACV,QAAQ;GACR,UAAU;GACV,SAAS,QAAQ,OAAO,QAAQ;GAChC,UAAU;GACV,MAAM,OAAO;GACb,SAAS;IACP,SAAS,OAAO;IAChB,aAAa,OAAO;IACpB,QAAQ,OAAO;IAChB;GACF,CAAC;AAIJ,MAAI,CAAC,YAAY,gBAAgB,OAAO,WAAW,WAAW;GAC5D,MAAM,eAAe,OAAO,gBACzB,QAAQ,MAAM,CAAC,EAAE,UAAU,EAAE,SAAS,OAAO,CAC7C,KAAK,MAAM,EAAE,KAAK;AAErB,UAAO,KAAK;IACV,QAAQ;IACR,UAAU;IACV,SAAS,QAAQ,OAAO,QAAQ,uCAAuC,aAAa,KAAK,KAAK;IAC9F,UAAU;IACV,MAAM,OAAO;IACb,SAAS;KACP,SAAS,OAAO;KAChB,aAAa,OAAO;KACpB,QAAQ,OAAO;KACf,cAAc;KACf;IACF,CAAC;;EAIJ,MAAM,eAAe,OAAO,gBAAgB,QACzC,MAAM,CAAC,EAAE,UAAU,EAAE,SAAS,OAChC;AACD,MAAI,aAAa,SAAS,EACxB,QAAO,KAAK;GACV,QAAQ;GACR,UAAU;GACV,SAAS,QAAQ,OAAO,QAAQ,uBAAuB,aAAa,KAAK,MAAM,EAAE,KAAK,CAAC,KAAK,KAAK;GACjG,UAAU;GACV,MAAM,OAAO;GACb,SAAS;IACP,SAAS,OAAO;IAChB,cAAc,aAAa,KAAK,MAAM,EAAE,KAAK;IAC9C;GACF,CAAC;;AAIN,QAAO"}
|
|
@@ -7,24 +7,23 @@ import { validateSpecStructure } from "@contractspec/module.workspace";
|
|
|
7
7
|
/**
|
|
8
8
|
* Run spec structure validation checks.
|
|
9
9
|
*/
|
|
10
|
-
async function runStructureChecks(
|
|
11
|
-
const { fs } = adapters;
|
|
10
|
+
async function runStructureChecks(specFiles) {
|
|
12
11
|
const issues = [];
|
|
13
|
-
for (const
|
|
14
|
-
const result = validateSpecStructure(
|
|
12
|
+
for (const specFile of specFiles) {
|
|
13
|
+
const result = validateSpecStructure(specFile);
|
|
15
14
|
for (const error of result.errors) issues.push({
|
|
16
15
|
ruleId: "spec-structure-error",
|
|
17
16
|
severity: "error",
|
|
18
17
|
message: error,
|
|
19
18
|
category: "structure",
|
|
20
|
-
file
|
|
19
|
+
file: specFile.filePath
|
|
21
20
|
});
|
|
22
21
|
for (const warning of result.warnings) issues.push({
|
|
23
22
|
ruleId: "spec-structure-warning",
|
|
24
23
|
severity: "warning",
|
|
25
24
|
message: warning,
|
|
26
25
|
category: "structure",
|
|
27
|
-
file
|
|
26
|
+
file: specFile.filePath
|
|
28
27
|
});
|
|
29
28
|
}
|
|
30
29
|
return issues;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"structure.mjs","names":[],"sources":["../../../../src/services/ci-check/checks/structure.ts"],"sourcesContent":["/**\n * Structure validation checks.\n */\n\nimport { validateSpecStructure
|
|
1
|
+
{"version":3,"file":"structure.mjs","names":[],"sources":["../../../../src/services/ci-check/checks/structure.ts"],"sourcesContent":["/**\n * Structure validation checks.\n */\n\nimport {\n type SpecScanResult,\n validateSpecStructure,\n} from '@contractspec/module.workspace';\nimport type { CIIssue } from '../types';\n\n/**\n * Run spec structure validation checks.\n */\nexport async function runStructureChecks(\n specFiles: SpecScanResult[]\n): Promise<CIIssue[]> {\n const issues: CIIssue[] = [];\n\n for (const specFile of specFiles) {\n const result = validateSpecStructure(specFile);\n\n for (const error of result.errors) {\n issues.push({\n ruleId: 'spec-structure-error',\n severity: 'error',\n message: error,\n category: 'structure',\n file: specFile.filePath,\n });\n }\n\n for (const warning of result.warnings) {\n issues.push({\n ruleId: 'spec-structure-warning',\n severity: 'warning',\n message: warning,\n category: 'structure',\n file: specFile.filePath,\n });\n }\n }\n\n return issues;\n}\n"],"mappings":";;;;;;;;;AAaA,eAAsB,mBACpB,WACoB;CACpB,MAAM,SAAoB,EAAE;AAE5B,MAAK,MAAM,YAAY,WAAW;EAChC,MAAM,SAAS,sBAAsB,SAAS;AAE9C,OAAK,MAAM,SAAS,OAAO,OACzB,QAAO,KAAK;GACV,QAAQ;GACR,UAAU;GACV,SAAS;GACT,UAAU;GACV,MAAM,SAAS;GAChB,CAAC;AAGJ,OAAK,MAAM,WAAW,OAAO,SAC3B,QAAO,KAAK;GACV,QAAQ;GACR,UAAU;GACV,SAAS;GACT,UAAU;GACV,MAAM,SAAS;GAChB,CAAC;;AAIN,QAAO"}
|
|
@@ -1,42 +1,32 @@
|
|
|
1
1
|
import { validateTestRefs } from "../../test-link/test-ref-validator.mjs";
|
|
2
|
-
import
|
|
2
|
+
import "@contractspec/module.workspace";
|
|
3
3
|
|
|
4
4
|
//#region src/services/ci-check/checks/test-refs.ts
|
|
5
5
|
/**
|
|
6
|
-
* Test reference validation checks.
|
|
7
|
-
*
|
|
8
|
-
* Validates that all tests referenced in OperationSpec.tests actually exist.
|
|
9
|
-
* Missing references are reported as ERRORS (blocking CI) to enforce contract integrity.
|
|
10
|
-
*/
|
|
11
|
-
/**
|
|
12
6
|
* Run test reference validation checks.
|
|
13
7
|
*/
|
|
14
|
-
async function runTestRefsChecks(
|
|
15
|
-
const { fs } = adapters;
|
|
8
|
+
async function runTestRefsChecks(specFiles) {
|
|
16
9
|
const issues = [];
|
|
17
10
|
const testSpecIndex = /* @__PURE__ */ new Map();
|
|
18
11
|
const specsByFile = /* @__PURE__ */ new Map();
|
|
19
12
|
for (const specFile of specFiles) {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
testRefs: scan.testRefs
|
|
38
|
-
});
|
|
39
|
-
}
|
|
13
|
+
if (!specFile.key || !specFile.version) continue;
|
|
14
|
+
if (specFile.specType === "test-spec") {
|
|
15
|
+
const testKey = `${specFile.key}.v${specFile.version}`;
|
|
16
|
+
testSpecIndex.set(testKey, {
|
|
17
|
+
key: specFile.key,
|
|
18
|
+
version: specFile.version,
|
|
19
|
+
file: specFile.filePath,
|
|
20
|
+
type: "test-spec"
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
if (specFile.testRefs && specFile.testRefs.length > 0) {
|
|
24
|
+
if (!specsByFile.has(specFile.filePath)) specsByFile.set(specFile.filePath, []);
|
|
25
|
+
specsByFile.get(specFile.filePath)?.push({
|
|
26
|
+
key: specFile.key,
|
|
27
|
+
version: specFile.version,
|
|
28
|
+
testRefs: specFile.testRefs
|
|
29
|
+
});
|
|
40
30
|
}
|
|
41
31
|
}
|
|
42
32
|
for (const [specFile, specs] of specsByFile) for (const spec of specs) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"test-refs.mjs","names":[],"sources":["../../../../src/services/ci-check/checks/test-refs.ts"],"sourcesContent":["/**\n * Test reference validation checks.\n *\n * Validates that all tests referenced in OperationSpec.tests actually exist.\n * Missing references are reported as ERRORS (blocking CI) to enforce contract integrity.\n */\n\nimport {
|
|
1
|
+
{"version":3,"file":"test-refs.mjs","names":[],"sources":["../../../../src/services/ci-check/checks/test-refs.ts"],"sourcesContent":["/**\n * Test reference validation checks.\n *\n * Validates that all tests referenced in OperationSpec.tests actually exist.\n * Missing references are reported as ERRORS (blocking CI) to enforce contract integrity.\n */\n\nimport { type SpecScanResult } from '@contractspec/module.workspace';\nimport type { SpecLocation } from '../../integrity';\nimport { validateTestRefs } from '../../test-link';\nimport type { CIIssue } from '../types';\n\n/**\n * Run test reference validation checks.\n */\nexport async function runTestRefsChecks(\n specFiles: SpecScanResult[]\n): Promise<CIIssue[]> {\n const issues: CIIssue[] = [];\n\n // Build inventory of test specs\n const testSpecIndex = new Map<string, SpecLocation>();\n const specsByFile = new Map<\n string,\n {\n key: string;\n version: string;\n testRefs?: { key: string; version: string }[];\n }[]\n >();\n\n // Scan all spec files to build inventory\n for (const specFile of specFiles) {\n if (!specFile.key || !specFile.version) continue;\n\n // Build test spec index\n if (specFile.specType === 'test-spec') {\n const testKey = `${specFile.key}.v${specFile.version}`;\n testSpecIndex.set(testKey, {\n key: specFile.key,\n version: specFile.version,\n file: specFile.filePath,\n type: 'test-spec',\n });\n }\n\n // Track specs with test refs for validation\n if (specFile.testRefs && specFile.testRefs.length > 0) {\n if (!specsByFile.has(specFile.filePath)) {\n specsByFile.set(specFile.filePath, []);\n }\n specsByFile.get(specFile.filePath)?.push({\n key: specFile.key,\n version: specFile.version,\n testRefs: specFile.testRefs,\n });\n }\n }\n\n // Validate test references for each spec\n for (const [specFile, specs] of specsByFile) {\n for (const spec of specs) {\n if (!spec.testRefs) continue;\n\n const result = validateTestRefs(\n specFile,\n spec.key,\n spec.version,\n spec.testRefs,\n testSpecIndex,\n { treatMissingAsError: true }\n );\n\n // Report errors for missing test references\n for (const error of result.errors) {\n issues.push({\n ruleId: 'test-ref-missing',\n severity: 'error', // ERRORS - block CI for contract integrity\n message: error,\n category: 'test-refs',\n file: specFile,\n context: {\n specKey: spec.key,\n specVersion: spec.version,\n missingTests: result.missingTests,\n },\n });\n }\n }\n }\n\n return issues;\n}\n"],"mappings":";;;;;;;AAeA,eAAsB,kBACpB,WACoB;CACpB,MAAM,SAAoB,EAAE;CAG5B,MAAM,gCAAgB,IAAI,KAA2B;CACrD,MAAM,8BAAc,IAAI,KAOrB;AAGH,MAAK,MAAM,YAAY,WAAW;AAChC,MAAI,CAAC,SAAS,OAAO,CAAC,SAAS,QAAS;AAGxC,MAAI,SAAS,aAAa,aAAa;GACrC,MAAM,UAAU,GAAG,SAAS,IAAI,IAAI,SAAS;AAC7C,iBAAc,IAAI,SAAS;IACzB,KAAK,SAAS;IACd,SAAS,SAAS;IAClB,MAAM,SAAS;IACf,MAAM;IACP,CAAC;;AAIJ,MAAI,SAAS,YAAY,SAAS,SAAS,SAAS,GAAG;AACrD,OAAI,CAAC,YAAY,IAAI,SAAS,SAAS,CACrC,aAAY,IAAI,SAAS,UAAU,EAAE,CAAC;AAExC,eAAY,IAAI,SAAS,SAAS,EAAE,KAAK;IACvC,KAAK,SAAS;IACd,SAAS,SAAS;IAClB,UAAU,SAAS;IACpB,CAAC;;;AAKN,MAAK,MAAM,CAAC,UAAU,UAAU,YAC9B,MAAK,MAAM,QAAQ,OAAO;AACxB,MAAI,CAAC,KAAK,SAAU;EAEpB,MAAM,SAAS,iBACb,UACA,KAAK,KACL,KAAK,SACL,KAAK,UACL,eACA,EAAE,qBAAqB,MAAM,CAC9B;AAGD,OAAK,MAAM,SAAS,OAAO,OACzB,QAAO,KAAK;GACV,QAAQ;GACR,UAAU;GACV,SAAS;GACT,UAAU;GACV,MAAM;GACN,SAAS;IACP,SAAS,KAAK;IACd,aAAa,KAAK;IAClB,cAAc,OAAO;IACtB;GACF,CAAC;;AAKR,QAAO"}
|
|
@@ -10,7 +10,7 @@ async function runTestChecks(adapters, specFiles) {
|
|
|
10
10
|
const issues = [];
|
|
11
11
|
const config = await loadWorkspaceConfig(fs);
|
|
12
12
|
for (const specFile of specFiles) {
|
|
13
|
-
if (
|
|
13
|
+
if (specFile.specType !== "operation") continue;
|
|
14
14
|
const result = await validateImplementationFiles(specFile, { fs }, config, {
|
|
15
15
|
checkTests: true,
|
|
16
16
|
outputDir: config.outputDir
|
|
@@ -20,14 +20,14 @@ async function runTestChecks(adapters, specFiles) {
|
|
|
20
20
|
severity: "warning",
|
|
21
21
|
message: error,
|
|
22
22
|
category: "tests",
|
|
23
|
-
file: specFile
|
|
23
|
+
file: specFile.filePath
|
|
24
24
|
});
|
|
25
25
|
for (const warning of result.warnings) issues.push({
|
|
26
26
|
ruleId: "test-warning",
|
|
27
27
|
severity: "warning",
|
|
28
28
|
message: warning,
|
|
29
29
|
category: "tests",
|
|
30
|
-
file: specFile
|
|
30
|
+
file: specFile.filePath
|
|
31
31
|
});
|
|
32
32
|
}
|
|
33
33
|
return issues;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tests.mjs","names":[],"sources":["../../../../src/services/ci-check/checks/tests.ts"],"sourcesContent":["/**\n * Test coverage checks.\n */\n\nimport type { FsAdapter } from '../../../ports/fs';\nimport type { LoggerAdapter } from '../../../ports/logger';\nimport { loadWorkspaceConfig } from '../../config';\nimport { validateImplementationFiles } from '../../validate/implementation-validator';\nimport type { CIIssue } from '../types';\n\n/**\n * Run test coverage checks.\n */\nexport async function runTestChecks(\n adapters: { fs: FsAdapter; logger: LoggerAdapter },\n specFiles:
|
|
1
|
+
{"version":3,"file":"tests.mjs","names":[],"sources":["../../../../src/services/ci-check/checks/tests.ts"],"sourcesContent":["/**\n * Test coverage checks.\n */\n\nimport type { FsAdapter } from '../../../ports/fs';\nimport type { LoggerAdapter } from '../../../ports/logger';\nimport { loadWorkspaceConfig } from '../../config';\nimport { validateImplementationFiles } from '../../validate/implementation-validator';\nimport type { CIIssue } from '../types';\nimport type { SpecScanResult } from '@contractspec/module.workspace';\n\n/**\n * Run test coverage checks.\n */\nexport async function runTestChecks(\n adapters: { fs: FsAdapter; logger: LoggerAdapter },\n specFiles: SpecScanResult[]\n): Promise<CIIssue[]> {\n const { fs } = adapters;\n const issues: CIIssue[] = [];\n\n const config = await loadWorkspaceConfig(fs);\n\n for (const specFile of specFiles) {\n // Only check operation specs\n if (specFile.specType !== 'operation') continue;\n\n const result = await validateImplementationFiles(specFile, { fs }, config, {\n checkTests: true,\n outputDir: config.outputDir,\n });\n\n for (const error of result.errors) {\n issues.push({\n ruleId: 'test-missing',\n severity: 'warning', // Test missing is a warning, not error\n message: error,\n category: 'tests',\n file: specFile.filePath,\n });\n }\n\n for (const warning of result.warnings) {\n issues.push({\n ruleId: 'test-warning',\n severity: 'warning',\n message: warning,\n category: 'tests',\n file: specFile.filePath,\n });\n }\n }\n\n return issues;\n}\n"],"mappings":";;;;;;;AAcA,eAAsB,cACpB,UACA,WACoB;CACpB,MAAM,EAAE,OAAO;CACf,MAAM,SAAoB,EAAE;CAE5B,MAAM,SAAS,MAAM,oBAAoB,GAAG;AAE5C,MAAK,MAAM,YAAY,WAAW;AAEhC,MAAI,SAAS,aAAa,YAAa;EAEvC,MAAM,SAAS,MAAM,4BAA4B,UAAU,EAAE,IAAI,EAAE,QAAQ;GACzE,YAAY;GACZ,WAAW,OAAO;GACnB,CAAC;AAEF,OAAK,MAAM,SAAS,OAAO,OACzB,QAAO,KAAK;GACV,QAAQ;GACR,UAAU;GACV,SAAS;GACT,UAAU;GACV,MAAM,SAAS;GAChB,CAAC;AAGJ,OAAK,MAAM,WAAW,OAAO,SAC3B,QAAO,KAAK;GACV,QAAQ;GACR,UAAU;GACV,SAAS;GACT,UAAU;GACV,MAAM,SAAS;GAChB,CAAC;;AAIN,QAAO"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ci-check-service.d.mts","names":[],"sources":["../../../src/services/ci-check/ci-check-service.ts"],"sourcesContent":[],"mappings":";;;;;;;;;
|
|
1
|
+
{"version":3,"file":"ci-check-service.d.mts","names":[],"sources":["../../../src/services/ci-check/ci-check-service.ts"],"sourcesContent":[],"mappings":";;;;;;;;;iBAqCsB,WAAA;MACJ;UAAmB;aAC1B,iBACR,QAAQ"}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import "../../utils/index.mjs";
|
|
1
|
+
import { listSpecs } from "../list.mjs";
|
|
3
2
|
import { runStructureChecks } from "./checks/structure.mjs";
|
|
4
3
|
import { runIntegrityChecks } from "./checks/integrity.mjs";
|
|
5
4
|
import { runDepsChecks } from "./checks/deps.mjs";
|
|
@@ -13,16 +12,9 @@ import { runLayerChecks } from "./checks/layers.mjs";
|
|
|
13
12
|
import { runDriftChecks } from "./checks/drift.mjs";
|
|
14
13
|
import "./checks/index.mjs";
|
|
15
14
|
import { createCategorySummary, getChecksToRun, getGitInfo } from "./utils.mjs";
|
|
16
|
-
import { isFeatureFile } from "@contractspec/module.workspace";
|
|
17
15
|
|
|
18
16
|
//#region src/services/ci-check/ci-check-service.ts
|
|
19
17
|
/**
|
|
20
|
-
* CI Check service.
|
|
21
|
-
*
|
|
22
|
-
* Orchestrates all validation checks for CI/CD pipelines.
|
|
23
|
-
* Returns structured results suitable for multiple output formats.
|
|
24
|
-
*/
|
|
25
|
-
/**
|
|
26
18
|
* Run all CI checks and return structured results.
|
|
27
19
|
*/
|
|
28
20
|
async function runCIChecks(adapters, options = {}) {
|
|
@@ -32,10 +24,13 @@ async function runCIChecks(adapters, options = {}) {
|
|
|
32
24
|
const categorySummaries = [];
|
|
33
25
|
const checksToRun = getChecksToRun(options);
|
|
34
26
|
logger.info("Starting CI checks...", { checks: checksToRun });
|
|
35
|
-
const specFiles =
|
|
27
|
+
const specFiles = await listSpecs(adapters, {
|
|
28
|
+
pattern: options.pattern,
|
|
29
|
+
type: ["feature", "test-spec"]
|
|
30
|
+
});
|
|
36
31
|
if (checksToRun.includes("structure")) {
|
|
37
32
|
const categoryStart = Date.now();
|
|
38
|
-
const structureIssues = await runStructureChecks(
|
|
33
|
+
const structureIssues = await runStructureChecks(specFiles);
|
|
39
34
|
issues.push(...structureIssues);
|
|
40
35
|
categorySummaries.push(createCategorySummary("structure", structureIssues, Date.now() - categoryStart));
|
|
41
36
|
}
|
|
@@ -71,7 +66,7 @@ async function runCIChecks(adapters, options = {}) {
|
|
|
71
66
|
}
|
|
72
67
|
if (checksToRun.includes("test-refs")) {
|
|
73
68
|
const categoryStart = Date.now();
|
|
74
|
-
const testRefIssues = await runTestRefsChecks(
|
|
69
|
+
const testRefIssues = await runTestRefsChecks(specFiles);
|
|
75
70
|
issues.push(...testRefIssues);
|
|
76
71
|
categorySummaries.push(createCategorySummary("test-refs", testRefIssues, Date.now() - categoryStart));
|
|
77
72
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ci-check-service.mjs","names":[],"sources":["../../../src/services/ci-check/ci-check-service.ts"],"sourcesContent":["/**\n * CI Check service.\n *\n * Orchestrates all validation checks for CI/CD pipelines.\n * Returns structured results suitable for multiple output formats.\n */\n\nimport
|
|
1
|
+
{"version":3,"file":"ci-check-service.mjs","names":[],"sources":["../../../src/services/ci-check/ci-check-service.ts"],"sourcesContent":["/**\n * CI Check service.\n *\n * Orchestrates all validation checks for CI/CD pipelines.\n * Returns structured results suitable for multiple output formats.\n */\n\nimport type { FsAdapter } from '../../ports/fs';\nimport type { LoggerAdapter } from '../../ports/logger';\n\nimport type {\n CICheckCategorySummary,\n CICheckOptions,\n CICheckResult,\n CIIssue,\n} from './types';\n\nimport {\n runCoverageChecks,\n runDepsChecks,\n runDoctorChecks,\n runDriftChecks,\n runHandlerChecks,\n runImplementationChecks,\n runIntegrityChecks,\n runLayerChecks,\n runStructureChecks,\n runTestChecks,\n runTestRefsChecks,\n} from './checks';\n\nimport { createCategorySummary, getChecksToRun, getGitInfo } from './utils';\nimport { listSpecs } from '../list';\n\n/**\n * Run all CI checks and return structured results.\n */\nexport async function runCIChecks(\n adapters: { fs: FsAdapter; logger: LoggerAdapter },\n options: CICheckOptions = {}\n): Promise<CICheckResult> {\n const startTime = Date.now();\n const { fs, logger } = adapters;\n\n const issues: CIIssue[] = [];\n const categorySummaries: CICheckCategorySummary[] = [];\n\n // Determine which checks to run\n const checksToRun = getChecksToRun(options);\n\n logger.info('Starting CI checks...', { checks: checksToRun });\n\n // Discover spec files\n const specFiles = await listSpecs(adapters, {\n pattern: options.pattern as string | undefined,\n type: ['feature', 'test-spec'],\n });\n\n // Run spec structure validation\n if (checksToRun.includes('structure')) {\n const categoryStart = Date.now();\n const structureIssues = await runStructureChecks(specFiles);\n issues.push(...structureIssues);\n categorySummaries.push(\n createCategorySummary(\n 'structure',\n structureIssues,\n Date.now() - categoryStart\n )\n );\n }\n\n // Run integrity analysis\n if (checksToRun.includes('integrity')) {\n const categoryStart = Date.now();\n const integrityIssues = await runIntegrityChecks(adapters, options);\n issues.push(...integrityIssues);\n categorySummaries.push(\n createCategorySummary(\n 'integrity',\n integrityIssues,\n Date.now() - categoryStart\n )\n );\n }\n\n // Run dependency analysis\n if (checksToRun.includes('deps')) {\n const categoryStart = Date.now();\n const depsIssues = await runDepsChecks(adapters, options);\n issues.push(...depsIssues);\n categorySummaries.push(\n createCategorySummary('deps', depsIssues, Date.now() - categoryStart)\n );\n }\n\n // Run doctor checks (skip AI in CI)\n if (checksToRun.includes('doctor')) {\n const categoryStart = Date.now();\n const doctorIssues = await runDoctorChecks(adapters, options);\n issues.push(...doctorIssues);\n categorySummaries.push(\n createCategorySummary('doctor', doctorIssues, Date.now() - categoryStart)\n );\n }\n\n // Run handler checks\n if (checksToRun.includes('handlers') || options.checkHandlers) {\n const categoryStart = Date.now();\n const handlerIssues = await runHandlerChecks(adapters, specFiles);\n issues.push(...handlerIssues);\n categorySummaries.push(\n createCategorySummary(\n 'handlers',\n handlerIssues,\n Date.now() - categoryStart\n )\n );\n }\n\n // Run test checks\n if (checksToRun.includes('tests') || options.checkTests) {\n const categoryStart = Date.now();\n const testIssues = await runTestChecks(adapters, specFiles);\n issues.push(...testIssues);\n categorySummaries.push(\n createCategorySummary('tests', testIssues, Date.now() - categoryStart)\n );\n }\n\n // Run test-refs checks (validate OperationSpec.tests references)\n if (checksToRun.includes('test-refs')) {\n const categoryStart = Date.now();\n const testRefIssues = await runTestRefsChecks(specFiles);\n issues.push(...testRefIssues);\n categorySummaries.push(\n createCategorySummary(\n 'test-refs',\n testRefIssues,\n Date.now() - categoryStart\n )\n );\n }\n\n // Run coverage checks (validate TestSpec.coverage requirements)\n if (checksToRun.includes('coverage')) {\n const categoryStart = Date.now();\n const coverageIssues = await runCoverageChecks(\n adapters,\n specFiles,\n options\n );\n issues.push(...coverageIssues);\n categorySummaries.push(\n createCategorySummary(\n 'coverage',\n coverageIssues,\n Date.now() - categoryStart\n )\n );\n }\n\n // Run implementation checks\n if (checksToRun.includes('implementation')) {\n const categoryStart = Date.now();\n const implIssues = await runImplementationChecks(\n adapters,\n specFiles,\n options\n );\n issues.push(...implIssues);\n categorySummaries.push(\n createCategorySummary(\n 'implementation',\n implIssues,\n Date.now() - categoryStart\n )\n );\n }\n\n // Run layers checks\n if (checksToRun.includes('layers')) {\n const categoryStart = Date.now();\n const layerIssues = await runLayerChecks(adapters, options);\n issues.push(...layerIssues);\n categorySummaries.push(\n createCategorySummary('layers', layerIssues, Date.now() - categoryStart)\n );\n }\n\n // Run drift checks\n if (checksToRun.includes('drift')) {\n const categoryStart = Date.now();\n const driftIssues = await runDriftChecks(adapters, options);\n issues.push(...driftIssues);\n categorySummaries.push(\n createCategorySummary('drift', driftIssues, Date.now() - categoryStart)\n );\n }\n\n // Calculate totals\n const totalErrors = issues.filter((i) => i.severity === 'error').length;\n const totalWarnings = issues.filter((i) => i.severity === 'warning').length;\n const totalNotes = issues.filter((i) => i.severity === 'note').length;\n\n // Determine success (no errors, or no warnings if failOnWarnings)\n const success = options.failOnWarnings\n ? totalErrors === 0 && totalWarnings === 0\n : totalErrors === 0;\n\n // Try to get git info\n const gitInfo = await getGitInfo(fs);\n\n const result: CICheckResult = {\n success,\n totalErrors,\n totalWarnings,\n totalNotes,\n issues,\n categories: categorySummaries,\n durationMs: Date.now() - startTime,\n timestamp: new Date().toISOString(),\n ...gitInfo,\n };\n\n logger.info('CI checks complete', {\n success,\n errors: totalErrors,\n warnings: totalWarnings,\n durationMs: result.durationMs,\n });\n\n return result;\n}\n"],"mappings":"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"}
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import { FsAdapter } from "../ports/fs.mjs";
|
|
2
|
-
import {
|
|
2
|
+
import { ResolvedContractsrcConfig } from "@contractspec/lib.contracts";
|
|
3
3
|
|
|
4
4
|
//#region src/services/config.d.ts
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Load workspace configuration from .contractsrc.json.
|
|
8
8
|
*/
|
|
9
|
-
declare function loadWorkspaceConfig(fs: FsAdapter, cwd?: string): Promise<
|
|
9
|
+
declare function loadWorkspaceConfig(fs: FsAdapter, cwd?: string): Promise<ResolvedContractsrcConfig>;
|
|
10
10
|
/**
|
|
11
11
|
* Get API key for the configured provider.
|
|
12
12
|
*/
|
|
13
|
-
declare function getApiKey(provider:
|
|
13
|
+
declare function getApiKey(provider: ResolvedContractsrcConfig['aiProvider']): string | undefined;
|
|
14
14
|
//#endregion
|
|
15
15
|
export { getApiKey, loadWorkspaceConfig };
|
|
16
16
|
//# sourceMappingURL=config.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.mts","names":[],"sources":["../../src/services/config.ts"],"sourcesContent":[],"mappings":";;;;;;;;
|
|
1
|
+
{"version":3,"file":"config.d.mts","names":[],"sources":["../../src/services/config.ts"],"sourcesContent":[],"mappings":";;;;;;;;AAiBU,iBAHY,mBAAA,CAGZ,EAAA,EAFJ,SAEI,EAAA,GAAA,CAAA,EAAA,MAAA,CAAA,EAAP,OAAO,CAAC,yBAAD,CAAA;AA6BV;;;iBAAgB,SAAA,WACJ"}
|
package/dist/services/config.mjs
CHANGED
|
@@ -1,48 +1,26 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import * as z$1 from "zod";
|
|
1
|
+
import { ContractsrcSchema, DEFAULT_CONTRACTSRC } from "@contractspec/lib.contracts";
|
|
3
2
|
|
|
4
3
|
//#region src/services/config.ts
|
|
5
4
|
/**
|
|
6
|
-
* Workspace configuration service.
|
|
7
|
-
*/
|
|
8
|
-
const ConfigSchema = z$1.object({
|
|
9
|
-
aiProvider: z$1.enum([
|
|
10
|
-
"claude",
|
|
11
|
-
"openai",
|
|
12
|
-
"ollama",
|
|
13
|
-
"custom"
|
|
14
|
-
]).default("claude"),
|
|
15
|
-
aiModel: z$1.string().optional(),
|
|
16
|
-
agentMode: z$1.enum([
|
|
17
|
-
"simple",
|
|
18
|
-
"cursor",
|
|
19
|
-
"claude-code",
|
|
20
|
-
"openai-codex"
|
|
21
|
-
]).default("simple"),
|
|
22
|
-
customEndpoint: z$1.url().nullable().optional(),
|
|
23
|
-
customApiKey: z$1.string().nullable().optional(),
|
|
24
|
-
outputDir: z$1.string().default("./src"),
|
|
25
|
-
conventions: z$1.object({
|
|
26
|
-
operations: z$1.string().default("interactions/commands|queries"),
|
|
27
|
-
events: z$1.string().default("events"),
|
|
28
|
-
presentations: z$1.string().default("presentations"),
|
|
29
|
-
forms: z$1.string().default("forms")
|
|
30
|
-
}),
|
|
31
|
-
defaultOwners: z$1.array(z$1.string()).default([]),
|
|
32
|
-
defaultTags: z$1.array(z$1.string()).default([])
|
|
33
|
-
});
|
|
34
|
-
/**
|
|
35
5
|
* Load workspace configuration from .contractsrc.json.
|
|
36
6
|
*/
|
|
37
7
|
async function loadWorkspaceConfig(fs, cwd) {
|
|
38
8
|
const configPath = fs.join(cwd ?? ".", ".contractsrc.json");
|
|
39
|
-
if (!await fs.exists(configPath)) return
|
|
9
|
+
if (!await fs.exists(configPath)) return DEFAULT_CONTRACTSRC;
|
|
40
10
|
try {
|
|
41
11
|
const content = await fs.readFile(configPath);
|
|
42
12
|
const parsed = JSON.parse(content);
|
|
43
|
-
|
|
13
|
+
const resolved = ContractsrcSchema.safeParse(parsed);
|
|
14
|
+
return {
|
|
15
|
+
...DEFAULT_CONTRACTSRC,
|
|
16
|
+
...resolved.data,
|
|
17
|
+
conventions: {
|
|
18
|
+
...DEFAULT_CONTRACTSRC.conventions,
|
|
19
|
+
...resolved.data?.conventions || {}
|
|
20
|
+
}
|
|
21
|
+
};
|
|
44
22
|
} catch {
|
|
45
|
-
return
|
|
23
|
+
return DEFAULT_CONTRACTSRC;
|
|
46
24
|
}
|
|
47
25
|
}
|
|
48
26
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.mjs","names":[
|
|
1
|
+
{"version":3,"file":"config.mjs","names":[],"sources":["../../src/services/config.ts"],"sourcesContent":["/**\n * Workspace configuration service.\n */\n\nimport type { FsAdapter } from '../ports/fs';\nimport {\n ContractsrcSchema,\n DEFAULT_CONTRACTSRC,\n type ResolvedContractsrcConfig,\n} from '@contractspec/lib.contracts';\n\n/**\n * Load workspace configuration from .contractsrc.json.\n */\nexport async function loadWorkspaceConfig(\n fs: FsAdapter,\n cwd?: string\n): Promise<ResolvedContractsrcConfig> {\n const configPath = fs.join(cwd ?? '.', '.contractsrc.json');\n\n const exists = await fs.exists(configPath);\n if (!exists) {\n return DEFAULT_CONTRACTSRC;\n }\n\n try {\n const content = await fs.readFile(configPath);\n const parsed = JSON.parse(content);\n const resolved = ContractsrcSchema.safeParse(parsed);\n\n return {\n ...DEFAULT_CONTRACTSRC,\n ...resolved.data,\n conventions: {\n ...DEFAULT_CONTRACTSRC.conventions,\n ...(resolved.data?.conventions || {}),\n },\n };\n } catch {\n return DEFAULT_CONTRACTSRC;\n }\n}\n\n/**\n * Get API key for the configured provider.\n */\nexport function getApiKey(\n provider: ResolvedContractsrcConfig['aiProvider']\n): string | undefined {\n switch (provider) {\n case 'claude':\n return process.env['ANTHROPIC_API_KEY'];\n case 'openai':\n return process.env['OPENAI_API_KEY'];\n case 'custom':\n return process.env['CONTRACTSPEC_LLM_API_KEY'];\n case 'ollama':\n return undefined; // Ollama doesn't need API key for local\n default:\n return undefined;\n }\n}\n"],"mappings":";;;;;;AAcA,eAAsB,oBACpB,IACA,KACoC;CACpC,MAAM,aAAa,GAAG,KAAK,OAAO,KAAK,oBAAoB;AAG3D,KAAI,CADW,MAAM,GAAG,OAAO,WAAW,CAExC,QAAO;AAGT,KAAI;EACF,MAAM,UAAU,MAAM,GAAG,SAAS,WAAW;EAC7C,MAAM,SAAS,KAAK,MAAM,QAAQ;EAClC,MAAM,WAAW,kBAAkB,UAAU,OAAO;AAEpD,SAAO;GACL,GAAG;GACH,GAAG,SAAS;GACZ,aAAa;IACX,GAAG,oBAAoB;IACvB,GAAI,SAAS,MAAM,eAAe,EAAE;IACrC;GACF;SACK;AACN,SAAO;;;;;;AAOX,SAAgB,UACd,UACoB;AACpB,SAAQ,UAAR;EACE,KAAK,SACH,QAAO,QAAQ,IAAI;EACrB,KAAK,SACH,QAAO,QAAQ,IAAI;EACrB,KAAK,SACH,QAAO,QAAQ,IAAI;EACrB,KAAK,SACH;EACF,QACE"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { PresentationKind
|
|
2
|
-
import { OpKind } from "@contractspec/lib.contracts";
|
|
1
|
+
import { PresentationKind } from "@contractspec/module.workspace";
|
|
2
|
+
import { OpKind, ResolvedContractsrcConfig } from "@contractspec/lib.contracts";
|
|
3
3
|
|
|
4
4
|
//#region src/services/create/ai-generator.d.ts
|
|
5
5
|
|
|
@@ -8,7 +8,7 @@ import { OpKind } from "@contractspec/lib.contracts";
|
|
|
8
8
|
*/
|
|
9
9
|
declare class AIGenerator {
|
|
10
10
|
private config;
|
|
11
|
-
constructor(config:
|
|
11
|
+
constructor(config: ResolvedContractsrcConfig);
|
|
12
12
|
private getModel;
|
|
13
13
|
/**
|
|
14
14
|
* Generate operation spec from natural language description
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ai-generator.d.mts","names":[],"sources":["../../../src/services/create/ai-generator.ts"],"sourcesContent":[],"mappings":";;;;;;;;AAsI4E,cApG/D,WAAA,CAoG+D;EAkCjC,QAAA,MAAA;EAeE,WAAA,CAAA,MAAA,EApJf,
|
|
1
|
+
{"version":3,"file":"ai-generator.d.mts","names":[],"sources":["../../../src/services/create/ai-generator.ts"],"sourcesContent":[],"mappings":";;;;;;;;AAsI4E,cApG/D,WAAA,CAoG+D;EAkCjC,QAAA,MAAA;EAeE,WAAA,CAAA,MAAA,EApJf,yBAoJe;EAeL,QAAA,QAAA;EAmBnC;;;mDA/JoD,SAAM;;;;;;;;;;;;;;;;;;;0CA6ClB;;;;;;;;;;;;;sDA+Be,mBAAgB;;;;;;;;;;;;;;;;qCAkCjC;;;;uCAeE;;;;kCAeL;;;;kGAmBnC;;;;yEAkBA"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { getApiKey } from "../config.mjs";
|
|
2
2
|
import { buildComponentPrompt, buildEventSpecPrompt, buildFormPrompt, buildHandlerPrompt, buildOperationSpecPrompt, buildPresentationSpecPrompt, buildTestPrompt, getCodeGenSystemPrompt, getSystemPrompt } from "@contractspec/module.workspace";
|
|
3
3
|
import { generateObject, generateText, streamText } from "ai";
|
|
4
|
-
import { createProvider } from "@contractspec/lib.ai-providers";
|
|
5
4
|
import * as z$1 from "zod";
|
|
5
|
+
import { createProvider } from "@contractspec/lib.ai-providers";
|
|
6
6
|
|
|
7
7
|
//#region src/services/create/ai-generator.ts
|
|
8
8
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ai-generator.mjs","names":["z"],"sources":["../../../src/services/create/ai-generator.ts"],"sourcesContent":["/**\n * AI Generator Service\n *\n * Generates specs and code using AI models.\n */\n\nimport { generateObject, generateText, streamText } from 'ai';\nimport * as z from 'zod';\nimport {\n createProvider,\n type ProviderConfig,\n type ProviderName,\n} from '@contractspec/lib.ai-providers';\nimport {\n type WorkspaceConfig,\n type PresentationKind,\n} from '@contractspec/module.workspace';\nimport type { OpKind } from '@contractspec/lib.contracts';\nimport {\n buildOperationSpecPrompt,\n buildEventSpecPrompt,\n buildPresentationSpecPrompt,\n getSystemPrompt,\n buildHandlerPrompt,\n buildComponentPrompt,\n buildFormPrompt,\n buildTestPrompt,\n getCodeGenSystemPrompt,\n} from '@contractspec/module.workspace';\nimport { getApiKey } from '../config';\n\n/**\n * AI Generator Service\n */\nexport class AIGenerator {\n constructor(private config: WorkspaceConfig) {}\n\n private getModel() {\n const providerName = this.config.aiProvider as ProviderName;\n const apiKey =\n this.config.customApiKey || getApiKey(this.config.aiProvider);\n\n // Map WorkspaceConfig to ProviderConfig\n const providerConfig: ProviderConfig = {\n provider: (providerName as string) === 'custom' ? 'openai' : providerName, // Fallback custom to openai compatible\n\n model: this.config.aiModel,\n apiKey: apiKey,\n baseUrl: this.config.customEndpoint || undefined,\n };\n\n const provider = createProvider(providerConfig);\n return provider.getModel();\n }\n\n /**\n * Generate operation spec from natural language description\n */\n async generateOperationSpec(description: string, kind: OpKind) {\n const model = this.getModel();\n\n const schema = z.object({\n name: z.string().describe('Dot notation name like \"domain.operation\"'),\n version: z.number().int().positive().default(1),\n description: z.string().describe('Clear, concise summary'),\n goal: z.string().describe('Business purpose'),\n context: z.string().describe('Background and constraints'),\n stability: z\n .enum(['experimental', 'beta', 'stable', 'deprecated'])\n .default('beta'),\n owners: z.array(z.string()).describe('Team/person owners with @ prefix'),\n tags: z.array(z.string()).describe('Categorization tags'),\n auth: z\n .enum(['anonymous', 'user', 'admin'])\n .describe('Required auth level'),\n inputShape: z.string().describe('Description of input structure'),\n outputShape: z.string().describe('Description of output structure'),\n flags: z.array(z.string()).describe('Feature flags').default([]),\n possibleEvents: z\n .array(z.string())\n .describe('Events this may emit')\n .default([]),\n analytics: z\n .array(z.string())\n .describe('Analytics events to track')\n .default([]),\n });\n\n const prompt = buildOperationSpecPrompt(description, kind);\n\n const result = await generateObject({\n model,\n schema,\n prompt,\n system: getSystemPrompt(),\n });\n\n return result.object;\n }\n\n /**\n * Generate event spec from description\n */\n async generateEventSpec(description: string) {\n const model = this.getModel();\n\n const schema = z.object({\n name: z.string().describe('Dot notation name like \"domain.event_name\"'),\n version: z.number().int().positive().default(1),\n description: z.string().describe('When this event is emitted'),\n stability: z\n .enum(['experimental', 'beta', 'stable', 'deprecated'])\n .default('beta'),\n owners: z.array(z.string()).default([]),\n tags: z.array(z.string()).default([]),\n payloadShape: z.string().describe('Description of event payload'),\n piiFields: z.array(z.string()).describe('PII field paths').default([]),\n });\n\n const prompt = buildEventSpecPrompt(description);\n\n const result = await generateObject({\n model,\n schema,\n prompt,\n system: getSystemPrompt(),\n });\n\n return result.object;\n }\n\n /**\n * Generate presentation spec from description\n */\n async generatePresentationSpec(description: string, kind: PresentationKind) {\n const model = this.getModel();\n\n const schema = z.object({\n name: z.string(),\n version: z.number().int().positive().default(1),\n description: z.string(),\n stability: z\n .enum(['experimental', 'beta', 'stable', 'deprecated'])\n .default('beta'),\n owners: z.array(z.string()).default([]),\n tags: z.array(z.string()).default([]),\n componentKey: z.string().optional(),\n propsShape: z.string().optional(),\n content: z.string().optional(),\n mimeType: z.string().optional(),\n dataShape: z.string().optional(),\n });\n\n const prompt = buildPresentationSpecPrompt(description, kind);\n\n const result = await generateObject({\n model,\n schema,\n prompt,\n system: getSystemPrompt(),\n });\n\n return result.object;\n }\n\n /**\n * Generate handler implementation from spec\n */\n async generateHandler(specCode: string): Promise<string> {\n const model = this.getModel();\n\n const result = await generateText({\n model,\n prompt: buildHandlerPrompt(specCode),\n system: getCodeGenSystemPrompt(),\n });\n\n return result.text;\n }\n\n /**\n * Generate React component from presentation spec\n */\n async generateComponent(specCode: string): Promise<string> {\n const model = this.getModel();\n\n const result = await generateText({\n model,\n prompt: buildComponentPrompt(specCode),\n system: getCodeGenSystemPrompt(),\n });\n\n return result.text;\n }\n\n /**\n * Generate form component from form spec\n */\n async generateForm(specCode: string): Promise<string> {\n const model = this.getModel();\n\n const result = await generateText({\n model,\n prompt: buildFormPrompt(specCode),\n system: getCodeGenSystemPrompt(),\n });\n\n return result.text;\n }\n\n /**\n * Generate tests for implementation\n */\n async generateTests(\n specCode: string,\n implementationCode: string,\n testType: 'handler' | 'component'\n ): Promise<string> {\n const model = this.getModel();\n\n const result = await generateText({\n model,\n prompt: buildTestPrompt(specCode, implementationCode, testType),\n system: getCodeGenSystemPrompt(),\n });\n\n return result.text;\n }\n\n /**\n * Stream code generation for better UX\n */\n async streamCodeGeneration(\n prompt: string,\n onChunk: (text: string) => void\n ): Promise<string> {\n const model = this.getModel();\n\n const result = await streamText({\n model,\n prompt,\n system: getCodeGenSystemPrompt(),\n });\n\n let fullText = '';\n\n for await (const chunk of result.textStream) {\n fullText += chunk;\n onChunk(chunk);\n }\n\n return fullText;\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ai-generator.mjs","names":["z"],"sources":["../../../src/services/create/ai-generator.ts"],"sourcesContent":["/**\n * AI Generator Service\n *\n * Generates specs and code using AI models.\n */\n\nimport { generateObject, generateText, streamText } from 'ai';\nimport * as z from 'zod';\nimport {\n createProvider,\n type ProviderConfig,\n type ProviderName,\n} from '@contractspec/lib.ai-providers';\nimport {\n buildComponentPrompt,\n buildEventSpecPrompt,\n buildFormPrompt,\n buildHandlerPrompt,\n buildOperationSpecPrompt,\n buildPresentationSpecPrompt,\n buildTestPrompt,\n getCodeGenSystemPrompt,\n getSystemPrompt,\n type PresentationKind,\n} from '@contractspec/module.workspace';\nimport type {\n OpKind,\n ResolvedContractsrcConfig,\n} from '@contractspec/lib.contracts';\nimport { getApiKey } from '../config';\n\n/**\n * AI Generator Service\n */\nexport class AIGenerator {\n constructor(private config: ResolvedContractsrcConfig) {}\n\n private getModel() {\n const providerName = this.config.aiProvider as ProviderName;\n const apiKey =\n this.config.customApiKey || getApiKey(this.config.aiProvider);\n\n // Map WorkspaceConfig to ProviderConfig\n const providerConfig: ProviderConfig = {\n provider: (providerName as string) === 'custom' ? 'openai' : providerName, // Fallback custom to openai compatible\n\n model: this.config.aiModel,\n apiKey: apiKey,\n baseUrl: this.config.customEndpoint || undefined,\n };\n\n const provider = createProvider(providerConfig);\n return provider.getModel();\n }\n\n /**\n * Generate operation spec from natural language description\n */\n async generateOperationSpec(description: string, kind: OpKind) {\n const model = this.getModel();\n\n const schema = z.object({\n name: z.string().describe('Dot notation name like \"domain.operation\"'),\n version: z.number().int().positive().default(1),\n description: z.string().describe('Clear, concise summary'),\n goal: z.string().describe('Business purpose'),\n context: z.string().describe('Background and constraints'),\n stability: z\n .enum(['experimental', 'beta', 'stable', 'deprecated'])\n .default('beta'),\n owners: z.array(z.string()).describe('Team/person owners with @ prefix'),\n tags: z.array(z.string()).describe('Categorization tags'),\n auth: z\n .enum(['anonymous', 'user', 'admin'])\n .describe('Required auth level'),\n inputShape: z.string().describe('Description of input structure'),\n outputShape: z.string().describe('Description of output structure'),\n flags: z.array(z.string()).describe('Feature flags').default([]),\n possibleEvents: z\n .array(z.string())\n .describe('Events this may emit')\n .default([]),\n analytics: z\n .array(z.string())\n .describe('Analytics events to track')\n .default([]),\n });\n\n const prompt = buildOperationSpecPrompt(description, kind);\n\n const result = await generateObject({\n model,\n schema,\n prompt,\n system: getSystemPrompt(),\n });\n\n return result.object;\n }\n\n /**\n * Generate event spec from description\n */\n async generateEventSpec(description: string) {\n const model = this.getModel();\n\n const schema = z.object({\n name: z.string().describe('Dot notation name like \"domain.event_name\"'),\n version: z.number().int().positive().default(1),\n description: z.string().describe('When this event is emitted'),\n stability: z\n .enum(['experimental', 'beta', 'stable', 'deprecated'])\n .default('beta'),\n owners: z.array(z.string()).default([]),\n tags: z.array(z.string()).default([]),\n payloadShape: z.string().describe('Description of event payload'),\n piiFields: z.array(z.string()).describe('PII field paths').default([]),\n });\n\n const prompt = buildEventSpecPrompt(description);\n\n const result = await generateObject({\n model,\n schema,\n prompt,\n system: getSystemPrompt(),\n });\n\n return result.object;\n }\n\n /**\n * Generate presentation spec from description\n */\n async generatePresentationSpec(description: string, kind: PresentationKind) {\n const model = this.getModel();\n\n const schema = z.object({\n name: z.string(),\n version: z.number().int().positive().default(1),\n description: z.string(),\n stability: z\n .enum(['experimental', 'beta', 'stable', 'deprecated'])\n .default('beta'),\n owners: z.array(z.string()).default([]),\n tags: z.array(z.string()).default([]),\n componentKey: z.string().optional(),\n propsShape: z.string().optional(),\n content: z.string().optional(),\n mimeType: z.string().optional(),\n dataShape: z.string().optional(),\n });\n\n const prompt = buildPresentationSpecPrompt(description, kind);\n\n const result = await generateObject({\n model,\n schema,\n prompt,\n system: getSystemPrompt(),\n });\n\n return result.object;\n }\n\n /**\n * Generate handler implementation from spec\n */\n async generateHandler(specCode: string): Promise<string> {\n const model = this.getModel();\n\n const result = await generateText({\n model,\n prompt: buildHandlerPrompt(specCode),\n system: getCodeGenSystemPrompt(),\n });\n\n return result.text;\n }\n\n /**\n * Generate React component from presentation spec\n */\n async generateComponent(specCode: string): Promise<string> {\n const model = this.getModel();\n\n const result = await generateText({\n model,\n prompt: buildComponentPrompt(specCode),\n system: getCodeGenSystemPrompt(),\n });\n\n return result.text;\n }\n\n /**\n * Generate form component from form spec\n */\n async generateForm(specCode: string): Promise<string> {\n const model = this.getModel();\n\n const result = await generateText({\n model,\n prompt: buildFormPrompt(specCode),\n system: getCodeGenSystemPrompt(),\n });\n\n return result.text;\n }\n\n /**\n * Generate tests for implementation\n */\n async generateTests(\n specCode: string,\n implementationCode: string,\n testType: 'handler' | 'component'\n ): Promise<string> {\n const model = this.getModel();\n\n const result = await generateText({\n model,\n prompt: buildTestPrompt(specCode, implementationCode, testType),\n system: getCodeGenSystemPrompt(),\n });\n\n return result.text;\n }\n\n /**\n * Stream code generation for better UX\n */\n async streamCodeGeneration(\n prompt: string,\n onChunk: (text: string) => void\n ): Promise<string> {\n const model = this.getModel();\n\n const result = await streamText({\n model,\n prompt,\n system: getCodeGenSystemPrompt(),\n });\n\n let fullText = '';\n\n for await (const chunk of result.textStream) {\n fullText += chunk;\n onChunk(chunk);\n }\n\n return fullText;\n }\n}\n"],"mappings":"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"}
|
|
@@ -10,19 +10,19 @@ import { generateAppBlueprintSpec } from "../../templates/app-config.template.mj
|
|
|
10
10
|
import { generateDataViewSpec } from "../../templates/data-view.template.mjs";
|
|
11
11
|
import { generateIntegrationSpec } from "../../templates/integration.template.mjs";
|
|
12
12
|
import { generateKnowledgeSpaceSpec } from "../../templates/knowledge.template.mjs";
|
|
13
|
-
import { generateComponentTemplate
|
|
13
|
+
import { generateComponentTemplate, generateHandlerTemplate, generateTestTemplate } from "../../templates/handler.template.mjs";
|
|
14
14
|
import { generateWorkflowRunnerTemplate } from "../../templates/workflow-runner.template.mjs";
|
|
15
15
|
import { FeatureSpecParams, generateFeatureSpec } from "../../templates/feature.template.mjs";
|
|
16
16
|
import { templates_d_exports } from "./templates.mjs";
|
|
17
|
-
import {
|
|
17
|
+
import { ResolvedContractsrcConfig } from "@contractspec/lib.contracts";
|
|
18
18
|
|
|
19
19
|
//#region src/services/create/index.d.ts
|
|
20
20
|
declare class SpecCreatorService {
|
|
21
21
|
readonly ai: AIGenerator;
|
|
22
22
|
readonly templates: typeof templates_d_exports;
|
|
23
|
-
constructor(config:
|
|
23
|
+
constructor(config: ResolvedContractsrcConfig);
|
|
24
24
|
}
|
|
25
|
-
declare function createSpecCreator(config:
|
|
25
|
+
declare function createSpecCreator(config: ResolvedContractsrcConfig): SpecCreatorService;
|
|
26
26
|
//#endregion
|
|
27
27
|
export { SpecCreatorService, createSpecCreator };
|
|
28
28
|
//# sourceMappingURL=index.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../../../src/services/create/index.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;;;;;;;;;;cAUa,kBAAA;eACS;6BACK;sBAEL;;iBAQN,iBAAA,
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../../../src/services/create/index.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;;;;;;;;;;cAUa,kBAAA;eACS;6BACK;sBAEL;;iBAQN,iBAAA,SACN,4BACP"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["templates"],"sources":["../../../src/services/create/index.ts"],"sourcesContent":["/**\n * Spec Creation Service\n *\n * Unifies manual and AI-assisted spec creation.\n */\n\nimport { AIGenerator } from './ai-generator';\nimport * as templates from './templates';\nimport type {
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["templates"],"sources":["../../../src/services/create/index.ts"],"sourcesContent":["/**\n * Spec Creation Service\n *\n * Unifies manual and AI-assisted spec creation.\n */\n\nimport { AIGenerator } from './ai-generator';\nimport * as templates from './templates';\nimport type { ResolvedContractsrcConfig } from '@contractspec/lib.contracts';\n\nexport class SpecCreatorService {\n public readonly ai: AIGenerator;\n public readonly templates = templates;\n\n constructor(config: ResolvedContractsrcConfig) {\n this.ai = new AIGenerator(config);\n }\n}\n\nexport * from './ai-generator';\nexport * from './templates';\n\nexport function createSpecCreator(\n config: ResolvedContractsrcConfig\n): SpecCreatorService {\n return new SpecCreatorService(config);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAUA,IAAa,qBAAb,MAAgC;CAC9B,AAAgB;CAChB,AAAgB,YAAYA;CAE5B,YAAY,QAAmC;AAC7C,OAAK,KAAK,IAAI,YAAY,OAAO;;;AAOrC,SAAgB,kBACd,QACoB;AACpB,QAAO,IAAI,mBAAmB,OAAO"}
|
|
@@ -16,6 +16,7 @@ async function generateDocsFromSpecs(specFiles, options, adapters) {
|
|
|
16
16
|
const scanResults = [];
|
|
17
17
|
for (const file of specFiles) try {
|
|
18
18
|
const content = await fs.readFile(file);
|
|
19
|
+
if (file.endsWith("packages/libs/contracts/src/app-config/spec.ts")) console.log("coupable", file);
|
|
19
20
|
const results = scanAllSpecsFromSource(content, file);
|
|
20
21
|
if (results.length > 0) scanResults.push(...results);
|
|
21
22
|
else {
|
|
@@ -26,24 +27,26 @@ async function generateDocsFromSpecs(specFiles, options, adapters) {
|
|
|
26
27
|
resolver.initialize(scanResults);
|
|
27
28
|
for (const file of specFiles) try {
|
|
28
29
|
const parsedList = await loadSpecFromSource(file);
|
|
29
|
-
if (parsedList
|
|
30
|
+
if (!parsedList?.length) {
|
|
31
|
+
logger.warn(`Could not parse spec from ${file}`);
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
for (const parsed of parsedList) {
|
|
30
35
|
const block = convertSpecToDocBlock(parsed, { rootPath: options.rootPath });
|
|
31
36
|
defaultDocRegistry.register(block);
|
|
32
37
|
blocks.push(block);
|
|
33
38
|
logger.debug(`Generated doc for ${block.id}`);
|
|
34
|
-
if (options.outputDir)
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
}
|
|
39
|
+
if (!options.outputDir) continue;
|
|
40
|
+
const moduleDef = resolver.resolve(file);
|
|
41
|
+
let targetDir = options.outputDir;
|
|
42
|
+
if (moduleDef) targetDir = path.join(options.outputDir, moduleDef.key);
|
|
43
|
+
else targetDir = path.join(options.outputDir, "_common");
|
|
44
|
+
await fs.mkdir(targetDir);
|
|
45
|
+
const filename = `${block.id}.md`;
|
|
46
|
+
const filePath = path.join(targetDir, filename);
|
|
47
|
+
const generatedContent = `<!-- @generated - This file was generated by ContractSpec. Do not edit manually. -->\n\n${block.body}`;
|
|
48
|
+
await fs.writeFile(filePath, generatedContent);
|
|
45
49
|
}
|
|
46
|
-
else logger.warn(`Could not parse spec from ${file}`);
|
|
47
50
|
} catch (error) {
|
|
48
51
|
logger.error(`Error processing ${file}: ${error instanceof Error ? error.message : String(error)}`);
|
|
49
52
|
}
|