vitek-plugin 0.2.0-beta → 0.2.2-beta
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/README.md +1 -1
- package/dist/adapters/dispatch/http-webhook.d.ts +10 -0
- package/dist/adapters/dispatch/http-webhook.d.ts.map +1 -0
- package/dist/adapters/dispatch/http-webhook.js +38 -0
- package/dist/adapters/node/console-structured-request-logger.d.ts +6 -0
- package/dist/adapters/node/console-structured-request-logger.d.ts.map +1 -0
- package/dist/adapters/node/console-structured-request-logger.js +31 -0
- package/dist/build/build-api-bundle.d.ts.map +1 -1
- package/dist/build/build-api-bundle.js +11 -0
- package/dist/build/build-sockets-bundle.d.ts.map +1 -1
- package/dist/build/build-sockets-bundle.js +11 -0
- package/dist/cli/contract.d.ts +11 -0
- package/dist/cli/contract.d.ts.map +1 -0
- package/dist/cli/contract.js +143 -0
- package/dist/cli/doctor.d.ts +2 -0
- package/dist/cli/doctor.d.ts.map +1 -0
- package/dist/cli/doctor.js +70 -0
- package/dist/cli/generate.d.ts +2 -0
- package/dist/cli/generate.d.ts.map +1 -0
- package/dist/cli/generate.js +56 -0
- package/dist/cli/mcp-docs.d.ts +2 -0
- package/dist/cli/mcp-docs.d.ts.map +1 -0
- package/dist/cli/mcp-docs.js +4 -0
- package/dist/cli/mcp-project-write-tools.d.ts +4 -0
- package/dist/cli/mcp-project-write-tools.d.ts.map +1 -0
- package/dist/cli/mcp-project-write-tools.js +64 -0
- package/dist/cli/schedule.d.ts +2 -0
- package/dist/cli/schedule.d.ts.map +1 -0
- package/dist/cli/schedule.js +66 -0
- package/dist/core/contract/compare-asyncapi.d.ts +3 -0
- package/dist/core/contract/compare-asyncapi.d.ts.map +1 -0
- package/dist/core/contract/compare-asyncapi.js +45 -0
- package/dist/core/contract/compare-openapi.d.ts +3 -0
- package/dist/core/contract/compare-openapi.d.ts.map +1 -0
- package/dist/core/contract/compare-openapi.js +116 -0
- package/dist/core/contract/http-methods.d.ts +2 -0
- package/dist/core/contract/http-methods.d.ts.map +1 -0
- package/dist/core/contract/http-methods.js +2 -0
- package/dist/core/contract/index.d.ts +9 -0
- package/dist/core/contract/index.d.ts.map +1 -0
- package/dist/core/contract/index.js +7 -0
- package/dist/core/contract/project-specs.d.ts +12 -0
- package/dist/core/contract/project-specs.d.ts.map +1 -0
- package/dist/core/contract/project-specs.js +27 -0
- package/dist/core/contract/sort-json.d.ts +2 -0
- package/dist/core/contract/sort-json.d.ts.map +1 -0
- package/dist/core/contract/sort-json.js +14 -0
- package/dist/core/contract/types.d.ts +7 -0
- package/dist/core/contract/types.d.ts.map +1 -0
- package/dist/core/contract/types.js +1 -0
- package/dist/core/dispatch/dispatchers.d.ts +4 -0
- package/dist/core/dispatch/dispatchers.d.ts.map +1 -0
- package/dist/core/dispatch/dispatchers.js +16 -0
- package/dist/core/dispatch/emit-safe.d.ts +3 -0
- package/dist/core/dispatch/emit-safe.d.ts.map +1 -0
- package/dist/core/dispatch/emit-safe.js +10 -0
- package/dist/core/dispatch/index.d.ts +4 -0
- package/dist/core/dispatch/index.d.ts.map +1 -0
- package/dist/core/dispatch/index.js +2 -0
- package/dist/core/dispatch/types.d.ts +22 -0
- package/dist/core/dispatch/types.d.ts.map +1 -0
- package/dist/core/dispatch/types.js +1 -0
- package/dist/core/doctor/index.d.ts +3 -0
- package/dist/core/doctor/index.d.ts.map +1 -0
- package/dist/core/doctor/index.js +1 -0
- package/dist/core/doctor/report.d.ts +4 -0
- package/dist/core/doctor/report.d.ts.map +1 -0
- package/dist/core/doctor/report.js +166 -0
- package/dist/core/doctor/scan.d.ts +3 -0
- package/dist/core/doctor/scan.d.ts.map +1 -0
- package/dist/core/doctor/scan.js +23 -0
- package/dist/core/doctor/types.d.ts +12 -0
- package/dist/core/doctor/types.d.ts.map +1 -0
- package/dist/core/doctor/types.js +1 -0
- package/dist/core/events/event-bus.d.ts +8 -0
- package/dist/core/events/event-bus.d.ts.map +1 -0
- package/dist/core/events/event-bus.js +26 -0
- package/dist/core/events/index.d.ts +3 -0
- package/dist/core/events/index.d.ts.map +1 -0
- package/dist/core/events/index.js +1 -0
- package/dist/core/generators/adapters/drizzle.d.ts +3 -0
- package/dist/core/generators/adapters/drizzle.d.ts.map +1 -0
- package/dist/core/generators/adapters/drizzle.js +26 -0
- package/dist/core/generators/adapters/prisma.d.ts +3 -0
- package/dist/core/generators/adapters/prisma.d.ts.map +1 -0
- package/dist/core/generators/adapters/prisma.js +136 -0
- package/dist/core/generators/adapters/sql.d.ts +3 -0
- package/dist/core/generators/adapters/sql.d.ts.map +1 -0
- package/dist/core/generators/adapters/sql.js +26 -0
- package/dist/core/generators/generate-crud.d.ts +8 -0
- package/dist/core/generators/generate-crud.d.ts.map +1 -0
- package/dist/core/generators/generate-crud.js +17 -0
- package/dist/core/generators/index.d.ts +3 -0
- package/dist/core/generators/index.d.ts.map +1 -0
- package/dist/core/generators/index.js +1 -0
- package/dist/core/generators/types.d.ts +16 -0
- package/dist/core/generators/types.d.ts.map +1 -0
- package/dist/core/generators/types.js +1 -0
- package/dist/core/generators/utils.d.ts +3 -0
- package/dist/core/generators/utils.d.ts.map +1 -0
- package/dist/core/generators/utils.js +10 -0
- package/dist/core/observability/with-span.d.ts +5 -0
- package/dist/core/observability/with-span.d.ts.map +1 -0
- package/dist/core/observability/with-span.js +7 -0
- package/dist/core/scheduler/define-schedule.d.ts +3 -0
- package/dist/core/scheduler/define-schedule.d.ts.map +1 -0
- package/dist/core/scheduler/define-schedule.js +3 -0
- package/dist/core/scheduler/in-memory-lock.d.ts +6 -0
- package/dist/core/scheduler/in-memory-lock.d.ts.map +1 -0
- package/dist/core/scheduler/in-memory-lock.js +12 -0
- package/dist/core/scheduler/index.d.ts +5 -0
- package/dist/core/scheduler/index.d.ts.map +1 -0
- package/dist/core/scheduler/index.js +3 -0
- package/dist/core/scheduler/runner.d.ts +6 -0
- package/dist/core/scheduler/runner.d.ts.map +1 -0
- package/dist/core/scheduler/runner.js +37 -0
- package/dist/core/scheduler/types.d.ts +21 -0
- package/dist/core/scheduler/types.d.ts.map +1 -0
- package/dist/core/scheduler/types.js +1 -0
- package/dist/core/server/request-log-meta.d.ts +5 -0
- package/dist/core/server/request-log-meta.d.ts.map +1 -0
- package/dist/core/server/request-log-meta.js +1 -0
- package/dist/mcp/write/apply-guard.d.ts +7 -0
- package/dist/mcp/write/apply-guard.d.ts.map +1 -0
- package/dist/mcp/write/apply-guard.js +22 -0
- package/dist/mcp/write/openapi-jsdoc.d.ts +2 -0
- package/dist/mcp/write/openapi-jsdoc.d.ts.map +1 -0
- package/dist/mcp/write/openapi-jsdoc.js +15 -0
- package/dist/mcp/write/project-write-handlers.d.ts +46 -0
- package/dist/mcp/write/project-write-handlers.d.ts.map +1 -0
- package/dist/mcp/write/project-write-handlers.js +304 -0
- package/dist/mcp/write/risks.d.ts +3 -0
- package/dist/mcp/write/risks.d.ts.map +1 -0
- package/dist/mcp/write/risks.js +20 -0
- package/dist/mcp/write/route-snippet.d.ts +5 -0
- package/dist/mcp/write/route-snippet.d.ts.map +1 -0
- package/dist/mcp/write/route-snippet.js +46 -0
- package/dist/mcp/write/safe-path.d.ts +3 -0
- package/dist/mcp/write/safe-path.d.ts.map +1 -0
- package/dist/mcp/write/safe-path.js +16 -0
- package/dist/mcp/write/test-file-content.d.ts +8 -0
- package/dist/mcp/write/test-file-content.d.ts.map +1 -0
- package/dist/mcp/write/test-file-content.js +31 -0
- package/dist/mcp/write/unified-diff.d.ts +2 -0
- package/dist/mcp/write/unified-diff.d.ts.map +1 -0
- package/dist/mcp/write/unified-diff.js +19 -0
- package/dist/mcp/write/validation-scaffold.d.ts +2 -0
- package/dist/mcp/write/validation-scaffold.d.ts.map +1 -0
- package/dist/mcp/write/validation-scaffold.js +31 -0
- package/dist/mcp-docs-server/resources/configuration.d.ts +3 -0
- package/dist/mcp-docs-server/resources/configuration.d.ts.map +1 -0
- package/dist/mcp-docs-server/resources/configuration.js +25 -0
- package/dist/mcp-docs-server/resources/context.d.ts +3 -0
- package/dist/mcp-docs-server/resources/context.d.ts.map +1 -0
- package/dist/mcp-docs-server/resources/context.js +34 -0
- package/dist/mcp-docs-server/resources/errors.d.ts +3 -0
- package/dist/mcp-docs-server/resources/errors.d.ts.map +1 -0
- package/dist/mcp-docs-server/resources/errors.js +27 -0
- package/dist/mcp-docs-server/resources/introspection.d.ts +3 -0
- package/dist/mcp-docs-server/resources/introspection.d.ts.map +1 -0
- package/dist/mcp-docs-server/resources/introspection.js +24 -0
- package/dist/mcp-docs-server/resources/middlewares.d.ts +3 -0
- package/dist/mcp-docs-server/resources/middlewares.d.ts.map +1 -0
- package/dist/mcp-docs-server/resources/middlewares.js +36 -0
- package/dist/mcp-docs-server/resources/plugin-api.d.ts +3 -0
- package/dist/mcp-docs-server/resources/plugin-api.d.ts.map +1 -0
- package/dist/mcp-docs-server/resources/plugin-api.js +32 -0
- package/dist/mcp-docs-server/resources/response.d.ts +3 -0
- package/dist/mcp-docs-server/resources/response.d.ts.map +1 -0
- package/dist/mcp-docs-server/resources/response.js +39 -0
- package/dist/mcp-docs-server/resources/routing.d.ts +3 -0
- package/dist/mcp-docs-server/resources/routing.d.ts.map +1 -0
- package/dist/mcp-docs-server/resources/routing.js +47 -0
- package/dist/mcp-docs-server/resources/validation.d.ts +3 -0
- package/dist/mcp-docs-server/resources/validation.d.ts.map +1 -0
- package/dist/mcp-docs-server/resources/validation.js +37 -0
- package/dist/mcp-docs-server/resources/websockets.d.ts +3 -0
- package/dist/mcp-docs-server/resources/websockets.d.ts.map +1 -0
- package/dist/mcp-docs-server/resources/websockets.js +42 -0
- package/dist/mcp-docs-server/start-mcp-docs-server.d.ts +2 -0
- package/dist/mcp-docs-server/start-mcp-docs-server.d.ts.map +1 -0
- package/dist/mcp-docs-server/start-mcp-docs-server.js +171 -0
- package/dist/mcp-docs-server/tools/create-middleware.d.ts +5 -0
- package/dist/mcp-docs-server/tools/create-middleware.d.ts.map +1 -0
- package/dist/mcp-docs-server/tools/create-middleware.js +29 -0
- package/dist/mcp-docs-server/tools/create-route.d.ts +5 -0
- package/dist/mcp-docs-server/tools/create-route.d.ts.map +1 -0
- package/dist/mcp-docs-server/tools/create-route.js +44 -0
- package/dist/mcp-docs-server/tools/create-socket.d.ts +5 -0
- package/dist/mcp-docs-server/tools/create-socket.d.ts.map +1 -0
- package/dist/mcp-docs-server/tools/create-socket.js +39 -0
- package/dist/mcp-docs-server/tools/suggest-vite-config.d.ts +11 -0
- package/dist/mcp-docs-server/tools/suggest-vite-config.d.ts.map +1 -0
- package/dist/mcp-docs-server/tools/suggest-vite-config.js +30 -0
- package/dist/mcp-docs-server/tools/validate-convention.d.ts +21 -0
- package/dist/mcp-docs-server/tools/validate-convention.d.ts.map +1 -0
- package/dist/mcp-docs-server/tools/validate-convention.js +48 -0
- package/dist/platform/config.d.ts +30 -0
- package/dist/platform/config.d.ts.map +1 -0
- package/dist/platform/config.js +85 -0
- package/dist/platform/correlation.d.ts +5 -0
- package/dist/platform/correlation.d.ts.map +1 -0
- package/dist/platform/correlation.js +19 -0
- package/dist/platform/index.d.ts +5 -0
- package/dist/platform/index.d.ts.map +1 -0
- package/dist/platform/index.js +3 -0
- package/dist/platform/redaction.d.ts +6 -0
- package/dist/platform/redaction.d.ts.map +1 -0
- package/dist/platform/redaction.js +40 -0
- package/dist/plugin/mode.d.ts +5 -0
- package/dist/plugin/mode.d.ts.map +1 -0
- package/dist/plugin/mode.js +7 -0
- package/dist/plugin/vitek-resolve.d.ts.map +1 -1
- package/dist/plugin/vitek-resolve.js +4 -3
- package/dist/plugin/vitek-transform.d.ts +1 -1
- package/dist/plugin/vitek-transform.d.ts.map +1 -1
- package/dist/plugin/vitek-transform.js +30 -5
- package/dist/public/dispatch.d.ts +3 -0
- package/dist/public/dispatch.d.ts.map +1 -0
- package/dist/public/dispatch.js +1 -0
- package/dist/public/doctor.d.ts +3 -0
- package/dist/public/doctor.d.ts.map +1 -0
- package/dist/public/doctor.js +1 -0
- package/dist/public/errors.d.ts +2 -0
- package/dist/public/errors.d.ts.map +1 -0
- package/dist/public/errors.js +1 -0
- package/dist/public/events.d.ts +3 -0
- package/dist/public/events.d.ts.map +1 -0
- package/dist/public/events.js +1 -0
- package/dist/public/generators.d.ts +3 -0
- package/dist/public/generators.d.ts.map +1 -0
- package/dist/public/generators.js +1 -0
- package/dist/public/introspection.d.ts +3 -0
- package/dist/public/introspection.d.ts.map +1 -0
- package/dist/public/introspection.js +1 -0
- package/dist/public/observability.d.ts +3 -0
- package/dist/public/observability.d.ts.map +1 -0
- package/dist/public/observability.js +1 -0
- package/dist/public/platform.d.ts +3 -0
- package/dist/public/platform.d.ts.map +1 -0
- package/dist/public/platform.js +1 -0
- package/dist/public/plugin.d.ts +3 -0
- package/dist/public/plugin.d.ts.map +1 -0
- package/dist/public/plugin.js +1 -0
- package/dist/public/response.d.ts +2 -0
- package/dist/public/response.d.ts.map +1 -0
- package/dist/public/response.js +1 -0
- package/dist/public/scheduler.d.ts +3 -0
- package/dist/public/scheduler.d.ts.map +1 -0
- package/dist/public/scheduler.js +1 -0
- package/dist/public/testing.d.ts +3 -0
- package/dist/public/testing.d.ts.map +1 -0
- package/dist/public/testing.js +1 -0
- package/dist/public/validation.d.ts +3 -0
- package/dist/public/validation.d.ts.map +1 -0
- package/dist/public/validation.js +1 -0
- package/dist/shared/mode.d.ts +5 -0
- package/dist/shared/mode.d.ts.map +1 -0
- package/dist/shared/mode.js +7 -0
- package/dist/testing/testing.d.ts +15 -0
- package/dist/testing/testing.d.ts.map +1 -0
- package/dist/testing/testing.js +51 -0
- package/package.json +23 -21
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compare-asyncapi.d.ts","sourceRoot":"","sources":["../../../src/core/contract/compare-asyncapi.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAkB7C,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,GAAG,UAAU,EAAE,CA+BtF"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { sortKeysDeep } from './sort-json.js';
|
|
2
|
+
function asRecord(value) {
|
|
3
|
+
if (value !== null && typeof value === 'object' && !Array.isArray(value)) {
|
|
4
|
+
return value;
|
|
5
|
+
}
|
|
6
|
+
return {};
|
|
7
|
+
}
|
|
8
|
+
function getChannels(spec) {
|
|
9
|
+
return asRecord(asRecord(spec).channels);
|
|
10
|
+
}
|
|
11
|
+
function channelFingerprint(channel) {
|
|
12
|
+
return JSON.stringify(sortKeysDeep(channel));
|
|
13
|
+
}
|
|
14
|
+
export function compareAsyncApiSpecs(baseline, current) {
|
|
15
|
+
const issues = [];
|
|
16
|
+
const baseCh = getChannels(baseline);
|
|
17
|
+
const curCh = getChannels(current);
|
|
18
|
+
const keys = new Set([...Object.keys(baseCh), ...Object.keys(curCh)]);
|
|
19
|
+
for (const k of [...keys].sort()) {
|
|
20
|
+
if (baseCh[k] != null && curCh[k] == null) {
|
|
21
|
+
issues.push({
|
|
22
|
+
severity: 'error',
|
|
23
|
+
code: 'asyncapi_missing_channel',
|
|
24
|
+
message: `WebSocket channel removed from contract: ${k}`,
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
else if (baseCh[k] == null && curCh[k] != null) {
|
|
28
|
+
issues.push({
|
|
29
|
+
severity: 'warning',
|
|
30
|
+
code: 'asyncapi_new_channel',
|
|
31
|
+
message: `WebSocket channel not in baseline: ${k}`,
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
else if (baseCh[k] != null && curCh[k] != null) {
|
|
35
|
+
if (channelFingerprint(baseCh[k]) !== channelFingerprint(curCh[k])) {
|
|
36
|
+
issues.push({
|
|
37
|
+
severity: 'error',
|
|
38
|
+
code: 'asyncapi_channel_mismatch',
|
|
39
|
+
message: `WebSocket channel definition drift: ${k}`,
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return issues;
|
|
45
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compare-openapi.d.ts","sourceRoot":"","sources":["../../../src/core/contract/compare-openapi.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAwC7C,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,GAAG,UAAU,EAAE,CAmFrF"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { OPENAPI_PATH_METHODS } from './http-methods.js';
|
|
2
|
+
import { sortKeysDeep } from './sort-json.js';
|
|
3
|
+
function asRecord(value) {
|
|
4
|
+
if (value !== null && typeof value === 'object' && !Array.isArray(value)) {
|
|
5
|
+
return value;
|
|
6
|
+
}
|
|
7
|
+
return {};
|
|
8
|
+
}
|
|
9
|
+
function getPaths(spec) {
|
|
10
|
+
return asRecord(asRecord(spec).paths);
|
|
11
|
+
}
|
|
12
|
+
function listOperations(paths) {
|
|
13
|
+
const out = [];
|
|
14
|
+
for (const openApiPath of Object.keys(paths).sort()) {
|
|
15
|
+
const item = asRecord(paths[openApiPath]);
|
|
16
|
+
for (const method of Object.keys(item).sort()) {
|
|
17
|
+
if (!OPENAPI_PATH_METHODS.has(method))
|
|
18
|
+
continue;
|
|
19
|
+
out.push({ openApiPath, method });
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return out;
|
|
23
|
+
}
|
|
24
|
+
function opKey(openApiPath, method) {
|
|
25
|
+
return `${method.toUpperCase()} ${openApiPath}`;
|
|
26
|
+
}
|
|
27
|
+
function getResponses(operation) {
|
|
28
|
+
const op = asRecord(operation);
|
|
29
|
+
return asRecord(op.responses);
|
|
30
|
+
}
|
|
31
|
+
function responseFingerprint(response) {
|
|
32
|
+
return JSON.stringify(sortKeysDeep(response));
|
|
33
|
+
}
|
|
34
|
+
export function compareOpenApiSpecs(baseline, current) {
|
|
35
|
+
const issues = [];
|
|
36
|
+
const basePaths = getPaths(baseline);
|
|
37
|
+
const curPaths = getPaths(current);
|
|
38
|
+
for (const openApiPath of Object.keys(basePaths).sort()) {
|
|
39
|
+
if (!curPaths[openApiPath]) {
|
|
40
|
+
issues.push({
|
|
41
|
+
severity: 'error',
|
|
42
|
+
code: 'missing_path',
|
|
43
|
+
message: `Path removed from contract: ${openApiPath}`,
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
for (const openApiPath of Object.keys(basePaths).sort()) {
|
|
48
|
+
if (!curPaths[openApiPath])
|
|
49
|
+
continue;
|
|
50
|
+
const baseItem = asRecord(basePaths[openApiPath]);
|
|
51
|
+
const curItem = asRecord(curPaths[openApiPath]);
|
|
52
|
+
for (const method of Object.keys(baseItem).sort()) {
|
|
53
|
+
if (!OPENAPI_PATH_METHODS.has(method))
|
|
54
|
+
continue;
|
|
55
|
+
if (curItem[method] == null) {
|
|
56
|
+
issues.push({
|
|
57
|
+
severity: 'error',
|
|
58
|
+
code: 'missing_method',
|
|
59
|
+
message: `Operation removed from contract: ${opKey(openApiPath, method)}`,
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
const baseOps = listOperations(basePaths);
|
|
65
|
+
const curOps = listOperations(curPaths);
|
|
66
|
+
const baseSet = new Set(baseOps.map((o) => opKey(o.openApiPath, o.method)));
|
|
67
|
+
for (const { openApiPath, method } of curOps) {
|
|
68
|
+
const key = opKey(openApiPath, method);
|
|
69
|
+
if (!baseSet.has(key)) {
|
|
70
|
+
issues.push({
|
|
71
|
+
severity: 'warning',
|
|
72
|
+
code: 'undocumented_operation',
|
|
73
|
+
message: `Operation not in baseline (new or undocumented in snapshot): ${key}`,
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
for (const { openApiPath, method } of baseOps) {
|
|
78
|
+
if (!curPaths[openApiPath])
|
|
79
|
+
continue;
|
|
80
|
+
const baseItem = asRecord(basePaths[openApiPath]);
|
|
81
|
+
const curItem = asRecord(curPaths[openApiPath]);
|
|
82
|
+
if (curItem[method] == null)
|
|
83
|
+
continue;
|
|
84
|
+
const baseOp = baseItem[method];
|
|
85
|
+
const curOp = curItem[method];
|
|
86
|
+
const baseResp = getResponses(baseOp);
|
|
87
|
+
const curResp = getResponses(curOp);
|
|
88
|
+
const statuses = new Set([...Object.keys(baseResp), ...Object.keys(curResp)]);
|
|
89
|
+
for (const status of [...statuses].sort()) {
|
|
90
|
+
if (baseResp[status] != null && curResp[status] == null) {
|
|
91
|
+
issues.push({
|
|
92
|
+
severity: 'error',
|
|
93
|
+
code: 'missing_response_status',
|
|
94
|
+
message: `Response ${status} missing for ${opKey(openApiPath, method)}`,
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
else if (baseResp[status] == null && curResp[status] != null) {
|
|
98
|
+
issues.push({
|
|
99
|
+
severity: 'warning',
|
|
100
|
+
code: 'new_response_status',
|
|
101
|
+
message: `New response status ${status} for ${opKey(openApiPath, method)}`,
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
else if (baseResp[status] != null && curResp[status] != null) {
|
|
105
|
+
if (responseFingerprint(baseResp[status]) !== responseFingerprint(curResp[status])) {
|
|
106
|
+
issues.push({
|
|
107
|
+
severity: 'error',
|
|
108
|
+
code: 'response_schema_mismatch',
|
|
109
|
+
message: `Response ${status} schema mismatch for ${opKey(openApiPath, method)}`,
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return issues;
|
|
116
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http-methods.d.ts","sourceRoot":"","sources":["../../../src/core/contract/http-methods.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,oBAAoB,aAAqC,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export type { DriftSeverity, DriftIssue } from './types.js';
|
|
2
|
+
export { sortKeysDeep } from './sort-json.js';
|
|
3
|
+
export { compareOpenApiSpecs } from './compare-openapi.js';
|
|
4
|
+
export { compareAsyncApiSpecs } from './compare-asyncapi.js';
|
|
5
|
+
export { loadProjectContractSpecs } from './project-specs.js';
|
|
6
|
+
export declare const CONTRACT_DIR = ".vitek/contract";
|
|
7
|
+
export declare const OPENAPI_SNAPSHOT_FILE = "openapi.snapshot.json";
|
|
8
|
+
export declare const ASYNCAPI_SNAPSHOT_FILE = "asyncapi.snapshot.json";
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/contract/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,EAAE,wBAAwB,EAAE,MAAM,oBAAoB,CAAC;AAE9D,eAAO,MAAM,YAAY,oBAAoB,CAAC;AAC9C,eAAO,MAAM,qBAAqB,0BAA0B,CAAC;AAC7D,eAAO,MAAM,sBAAsB,2BAA2B,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { sortKeysDeep } from './sort-json.js';
|
|
2
|
+
export { compareOpenApiSpecs } from './compare-openapi.js';
|
|
3
|
+
export { compareAsyncApiSpecs } from './compare-asyncapi.js';
|
|
4
|
+
export { loadProjectContractSpecs } from './project-specs.js';
|
|
5
|
+
export const CONTRACT_DIR = '.vitek/contract';
|
|
6
|
+
export const OPENAPI_SNAPSHOT_FILE = 'openapi.snapshot.json';
|
|
7
|
+
export const ASYNCAPI_SNAPSHOT_FILE = 'asyncapi.snapshot.json';
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export interface ProjectContractSpecsOptions {
|
|
2
|
+
root: string;
|
|
3
|
+
apiDir: string;
|
|
4
|
+
apiBasePath: string;
|
|
5
|
+
socketBasePath: string;
|
|
6
|
+
}
|
|
7
|
+
export interface ProjectContractSpecs {
|
|
8
|
+
openApi: object;
|
|
9
|
+
asyncApi: object | null;
|
|
10
|
+
}
|
|
11
|
+
export declare function loadProjectContractSpecs(opts: ProjectContractSpecsOptions): ProjectContractSpecs;
|
|
12
|
+
//# sourceMappingURL=project-specs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project-specs.d.ts","sourceRoot":"","sources":["../../../src/core/contract/project-specs.ts"],"names":[],"mappings":"AASA,MAAM,WAAW,2BAA2B;IAC1C,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB;AAeD,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,2BAA2B,GAAG,oBAAoB,CAehG"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import * as path from 'path';
|
|
2
|
+
import { scanApiDirectory } from '../file-system/scan-api-dir.js';
|
|
3
|
+
import { parsedRoutesToSchema } from '../generation/run-file-generation.js';
|
|
4
|
+
import { generateOpenApiSpec } from '../openapi/generate.js';
|
|
5
|
+
import { generateAsyncApiSpec } from '../asyncapi/generate.js';
|
|
6
|
+
const STABLE_ASYNCAPI_SERVER = 'ws://127.0.0.1';
|
|
7
|
+
function schemaToRouteForDocs(schema) {
|
|
8
|
+
return schema.map((s) => ({
|
|
9
|
+
pattern: s.pattern,
|
|
10
|
+
method: s.method,
|
|
11
|
+
params: s.params,
|
|
12
|
+
file: s.file,
|
|
13
|
+
bodyType: s.bodyType,
|
|
14
|
+
queryType: s.queryType,
|
|
15
|
+
}));
|
|
16
|
+
}
|
|
17
|
+
export function loadProjectContractSpecs(opts) {
|
|
18
|
+
const apiDirAbs = path.resolve(opts.root, opts.apiDir);
|
|
19
|
+
const scan = scanApiDirectory(apiDirAbs);
|
|
20
|
+
const schema = parsedRoutesToSchema(scan.routes);
|
|
21
|
+
const routesForDocs = schemaToRouteForDocs(schema);
|
|
22
|
+
const openApi = generateOpenApiSpec(routesForDocs, { apiBasePath: opts.apiBasePath });
|
|
23
|
+
const asyncApi = scan.sockets.length > 0
|
|
24
|
+
? generateAsyncApiSpec(scan.sockets.map((s) => ({ pattern: s.pattern })), opts.socketBasePath, { serverUrl: STABLE_ASYNCAPI_SERVER })
|
|
25
|
+
: null;
|
|
26
|
+
return { openApi, asyncApi };
|
|
27
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sort-json.d.ts","sourceRoot":"","sources":["../../../src/core/contract/sort-json.ts"],"names":[],"mappings":"AAAA,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAapD"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export function sortKeysDeep(value) {
|
|
2
|
+
if (value === null || typeof value !== 'object') {
|
|
3
|
+
return value;
|
|
4
|
+
}
|
|
5
|
+
if (Array.isArray(value)) {
|
|
6
|
+
return value.map(sortKeysDeep);
|
|
7
|
+
}
|
|
8
|
+
const obj = value;
|
|
9
|
+
const sorted = {};
|
|
10
|
+
for (const k of Object.keys(obj).sort()) {
|
|
11
|
+
sorted[k] = sortKeysDeep(obj[k]);
|
|
12
|
+
}
|
|
13
|
+
return sorted;
|
|
14
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/core/contract/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,SAAS,CAAC;AAEhD,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,aAAa,CAAC;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dispatchers.d.ts","sourceRoot":"","sources":["../../../src/core/dispatch/dispatchers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAc,MAAM,YAAY,CAAC;AAE9D,wBAAgB,yBAAyB,IAAI,eAAe,CAI3D;AAED,wBAAgB,4BAA4B,IAAI,eAAe,CAY9D"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export function createNoopIssueDispatcher() {
|
|
2
|
+
return {
|
|
3
|
+
dispatch(_event) { },
|
|
4
|
+
};
|
|
5
|
+
}
|
|
6
|
+
export function createConsoleIssueDispatcher() {
|
|
7
|
+
return {
|
|
8
|
+
dispatch(event) {
|
|
9
|
+
console.log(JSON.stringify({
|
|
10
|
+
component: 'vitek',
|
|
11
|
+
event: 'issue.dispatch',
|
|
12
|
+
...event,
|
|
13
|
+
}));
|
|
14
|
+
},
|
|
15
|
+
};
|
|
16
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { IssueDispatcher, IssueEvent } from './types.js';
|
|
2
|
+
export declare function emitIssueSafe(dispatcher: IssueDispatcher | undefined, event: IssueEvent, onError?: (message: string, data?: Record<string, unknown>) => void): void;
|
|
3
|
+
//# sourceMappingURL=emit-safe.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"emit-safe.d.ts","sourceRoot":"","sources":["../../../src/core/dispatch/emit-safe.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE9D,wBAAgB,aAAa,CAC3B,UAAU,EAAE,eAAe,GAAG,SAAS,EACvC,KAAK,EAAE,UAAU,EACjB,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,GAClE,IAAI,CAON"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export function emitIssueSafe(dispatcher, event, onError) {
|
|
2
|
+
if (!dispatcher)
|
|
3
|
+
return;
|
|
4
|
+
Promise.resolve(dispatcher.dispatch(event)).catch((err) => {
|
|
5
|
+
if (!onError)
|
|
6
|
+
return;
|
|
7
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
8
|
+
onError('Issue dispatch failed', { message });
|
|
9
|
+
});
|
|
10
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export type { IssueSeverity, IssueSource, IssueSuggestion, IssueEvent, IssueDispatcher, } from './types.js';
|
|
2
|
+
export { createNoopIssueDispatcher, createConsoleIssueDispatcher } from './dispatchers.js';
|
|
3
|
+
export { emitIssueSafe } from './emit-safe.js';
|
|
4
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/dispatch/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,aAAa,EACb,WAAW,EACX,eAAe,EACf,UAAU,EACV,eAAe,GAChB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,yBAAyB,EAAE,4BAA4B,EAAE,MAAM,kBAAkB,CAAC;AAC3F,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export type IssueSeverity = 'error' | 'warning' | 'info';
|
|
2
|
+
export type IssueSource = 'runtime.http' | 'runtime.hook' | 'contract.check' | 'doctor' | 'manual';
|
|
3
|
+
export interface IssueSuggestion {
|
|
4
|
+
title: string;
|
|
5
|
+
detail?: string;
|
|
6
|
+
}
|
|
7
|
+
export interface IssueEvent {
|
|
8
|
+
id: string;
|
|
9
|
+
timestamp: string;
|
|
10
|
+
severity: IssueSeverity;
|
|
11
|
+
source: IssueSource;
|
|
12
|
+
title: string;
|
|
13
|
+
message: string;
|
|
14
|
+
route?: string;
|
|
15
|
+
requestId?: string;
|
|
16
|
+
metadata?: Record<string, unknown>;
|
|
17
|
+
suggestions?: IssueSuggestion[];
|
|
18
|
+
}
|
|
19
|
+
export interface IssueDispatcher {
|
|
20
|
+
dispatch(event: IssueEvent): void | Promise<void>;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/core/dispatch/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC;AAEzD,MAAM,MAAM,WAAW,GACnB,cAAc,GACd,cAAc,GACd,gBAAgB,GAChB,QAAQ,GACR,QAAQ,CAAC;AAEb,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,aAAa,CAAC;IACxB,MAAM,EAAE,WAAW,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC,WAAW,CAAC,EAAE,eAAe,EAAE,CAAC;CACjC;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACnD"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/doctor/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,qBAAqB,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AACtE,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { buildDoctorReport } from './report.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"report.d.ts","sourceRoot":"","sources":["../../../src/core/doctor/report.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,KAAK,EAAyB,YAAY,EAAE,MAAM,YAAY,CAAC;AAsHtE,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,cAAc,GAAG,YAAY,CAkBpF"}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import { DEFAULT_PLATFORM_CONFIG } from '../../platform/config.js';
|
|
2
|
+
import { countTests, listProjectFiles } from './scan.js';
|
|
3
|
+
function exists(files, rel) {
|
|
4
|
+
return files.includes(rel);
|
|
5
|
+
}
|
|
6
|
+
function startsWithAny(files, prefix) {
|
|
7
|
+
return files.some((f) => f.startsWith(prefix));
|
|
8
|
+
}
|
|
9
|
+
function contractsDimension(files) {
|
|
10
|
+
let score = 0;
|
|
11
|
+
const notes = [];
|
|
12
|
+
if (exists(files, '.vitek/contract/openapi.snapshot.json')) {
|
|
13
|
+
score += 10;
|
|
14
|
+
}
|
|
15
|
+
else {
|
|
16
|
+
notes.push('Add contract snapshot: vitek contract snapshot');
|
|
17
|
+
}
|
|
18
|
+
if (exists(files, '.vitek/contract/asyncapi.snapshot.json')) {
|
|
19
|
+
score += 5;
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
notes.push('Add AsyncAPI snapshot when socket routes exist');
|
|
23
|
+
}
|
|
24
|
+
if (exists(files, 'docs/guide/contract.md')) {
|
|
25
|
+
score += 5;
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
notes.push('Document contract checks');
|
|
29
|
+
}
|
|
30
|
+
return { name: 'Contracts', score, max: 20, notes };
|
|
31
|
+
}
|
|
32
|
+
function testsDimension(files) {
|
|
33
|
+
const tests = countTests(files);
|
|
34
|
+
let score = 0;
|
|
35
|
+
const notes = [];
|
|
36
|
+
if (tests >= 40)
|
|
37
|
+
score += 12;
|
|
38
|
+
else if (tests >= 20)
|
|
39
|
+
score += 8;
|
|
40
|
+
else if (tests >= 10)
|
|
41
|
+
score += 5;
|
|
42
|
+
else
|
|
43
|
+
notes.push('Increase automated test coverage');
|
|
44
|
+
if (startsWithAny(files, 'examples/') && files.some((f) => f.startsWith('examples/') && /\.(test|spec)\./.test(f))) {
|
|
45
|
+
score += 8;
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
notes.push('Add example-level tests');
|
|
49
|
+
}
|
|
50
|
+
return { name: 'Tests', score, max: 20, notes };
|
|
51
|
+
}
|
|
52
|
+
function securityDimension(files) {
|
|
53
|
+
let score = 0;
|
|
54
|
+
const notes = [];
|
|
55
|
+
if (exists(files, 'docs/guide/security.md'))
|
|
56
|
+
score += 6;
|
|
57
|
+
else
|
|
58
|
+
notes.push('Add security guide');
|
|
59
|
+
if (exists(files, 'src/platform/redaction.ts'))
|
|
60
|
+
score += 5;
|
|
61
|
+
else
|
|
62
|
+
notes.push('Add/redesign redaction utilities');
|
|
63
|
+
if (DEFAULT_PLATFORM_CONFIG.ai.redaction.stripHeaders.length > 0 &&
|
|
64
|
+
DEFAULT_PLATFORM_CONFIG.ai.redaction.stripFields.length > 0) {
|
|
65
|
+
score += 4;
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
notes.push('Define default redaction policy');
|
|
69
|
+
}
|
|
70
|
+
return { name: 'Security', score, max: 15, notes };
|
|
71
|
+
}
|
|
72
|
+
function observabilityDimension(files, config) {
|
|
73
|
+
let score = 0;
|
|
74
|
+
const notes = [];
|
|
75
|
+
if (exists(files, 'src/platform/correlation.ts'))
|
|
76
|
+
score += 4;
|
|
77
|
+
else
|
|
78
|
+
notes.push('Add request correlation layer');
|
|
79
|
+
if (exists(files, 'src/adapters/vite/logger.ts'))
|
|
80
|
+
score += 3;
|
|
81
|
+
else
|
|
82
|
+
notes.push('Add structured request logging');
|
|
83
|
+
if (config.features.observability)
|
|
84
|
+
score += 3;
|
|
85
|
+
else
|
|
86
|
+
notes.push('Enable features.observability when ready');
|
|
87
|
+
return { name: 'Observability', score, max: 10, notes };
|
|
88
|
+
}
|
|
89
|
+
function reliabilityDimension(files, config) {
|
|
90
|
+
let score = 0;
|
|
91
|
+
const notes = [];
|
|
92
|
+
if (exists(files, 'src/core/dispatch/types.ts'))
|
|
93
|
+
score += 4;
|
|
94
|
+
else
|
|
95
|
+
notes.push('Add issue/event dispatch contracts');
|
|
96
|
+
if (exists(files, 'src/core/events/event-bus.ts'))
|
|
97
|
+
score += 4;
|
|
98
|
+
else
|
|
99
|
+
notes.push('Add event bus');
|
|
100
|
+
if (exists(files, 'src/core/scheduler/runner.ts'))
|
|
101
|
+
score += 4;
|
|
102
|
+
else
|
|
103
|
+
notes.push('Add scheduler runner');
|
|
104
|
+
if (config.features.issueDispatch)
|
|
105
|
+
score += 3;
|
|
106
|
+
else
|
|
107
|
+
notes.push('Enable features.issueDispatch when sink is ready');
|
|
108
|
+
return { name: 'Reliability', score, max: 15, notes };
|
|
109
|
+
}
|
|
110
|
+
function docsDimension(files) {
|
|
111
|
+
let score = 0;
|
|
112
|
+
const notes = [];
|
|
113
|
+
if (exists(files, 'docs/ROADMAP-AI-PLATFORM.md'))
|
|
114
|
+
score += 4;
|
|
115
|
+
else
|
|
116
|
+
notes.push('Keep roadmap updated');
|
|
117
|
+
if (exists(files, 'docs/guide/ai-platform-config.md'))
|
|
118
|
+
score += 3;
|
|
119
|
+
else
|
|
120
|
+
notes.push('Document platform config');
|
|
121
|
+
if (exists(files, 'docs/guide/mcp-project.md'))
|
|
122
|
+
score += 3;
|
|
123
|
+
else
|
|
124
|
+
notes.push('Document MCP project flows');
|
|
125
|
+
return { name: 'Docs', score, max: 10, notes };
|
|
126
|
+
}
|
|
127
|
+
function architectureDimension(files) {
|
|
128
|
+
let score = 0;
|
|
129
|
+
const notes = [];
|
|
130
|
+
if (startsWithAny(files, 'src/core/contract/'))
|
|
131
|
+
score += 3;
|
|
132
|
+
else
|
|
133
|
+
notes.push('Missing contract module split');
|
|
134
|
+
if (startsWithAny(files, 'src/core/dispatch/'))
|
|
135
|
+
score += 3;
|
|
136
|
+
else
|
|
137
|
+
notes.push('Missing dispatch module split');
|
|
138
|
+
if (startsWithAny(files, 'src/core/events/'))
|
|
139
|
+
score += 2;
|
|
140
|
+
else
|
|
141
|
+
notes.push('Missing events module split');
|
|
142
|
+
if (startsWithAny(files, 'src/core/scheduler/'))
|
|
143
|
+
score += 2;
|
|
144
|
+
else
|
|
145
|
+
notes.push('Missing scheduler module split');
|
|
146
|
+
return { name: 'Architecture', score, max: 10, notes };
|
|
147
|
+
}
|
|
148
|
+
export function buildDoctorReport(root, config) {
|
|
149
|
+
const files = listProjectFiles(root);
|
|
150
|
+
const dimensions = [
|
|
151
|
+
contractsDimension(files),
|
|
152
|
+
testsDimension(files),
|
|
153
|
+
securityDimension(files),
|
|
154
|
+
observabilityDimension(files, config),
|
|
155
|
+
reliabilityDimension(files, config),
|
|
156
|
+
docsDimension(files),
|
|
157
|
+
architectureDimension(files),
|
|
158
|
+
];
|
|
159
|
+
const score = dimensions.reduce((sum, d) => sum + d.score, 0);
|
|
160
|
+
const topActions = dimensions
|
|
161
|
+
.filter((d) => d.score < d.max)
|
|
162
|
+
.sort((a, b) => a.score / a.max - b.score / b.max)
|
|
163
|
+
.flatMap((d) => d.notes.map((n) => `${d.name}: ${n}`))
|
|
164
|
+
.slice(0, 5);
|
|
165
|
+
return { score, dimensions, topActions };
|
|
166
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scan.d.ts","sourceRoot":"","sources":["../../../src/core/doctor/scan.ts"],"names":[],"mappings":"AAeA,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAIvD;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,CAElD"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import * as fs from 'fs';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
function walk(dir, out) {
|
|
4
|
+
if (!fs.existsSync(dir))
|
|
5
|
+
return;
|
|
6
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
7
|
+
const full = path.join(dir, entry.name);
|
|
8
|
+
if (entry.isDirectory()) {
|
|
9
|
+
walk(full, out);
|
|
10
|
+
}
|
|
11
|
+
else if (entry.isFile()) {
|
|
12
|
+
out.push(full);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
export function listProjectFiles(root) {
|
|
17
|
+
const out = [];
|
|
18
|
+
walk(root, out);
|
|
19
|
+
return out.map((f) => path.relative(root, f).replace(/\\/g, '/'));
|
|
20
|
+
}
|
|
21
|
+
export function countTests(files) {
|
|
22
|
+
return files.filter((f) => /\.(test|spec)\.(ts|js|tsx|jsx|mjs|cjs)$/.test(f)).length;
|
|
23
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export interface DoctorDimensionResult {
|
|
2
|
+
name: string;
|
|
3
|
+
score: number;
|
|
4
|
+
max: number;
|
|
5
|
+
notes: string[];
|
|
6
|
+
}
|
|
7
|
+
export interface DoctorReport {
|
|
8
|
+
score: number;
|
|
9
|
+
dimensions: DoctorDimensionResult[];
|
|
10
|
+
topActions: string[];
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/core/doctor/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,qBAAqB,EAAE,CAAC;IACpC,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export type EventMap = Record<string, unknown>;
|
|
2
|
+
export type EventHandler<TPayload> = (payload: TPayload) => void | Promise<void>;
|
|
3
|
+
export interface EventBus<TEvents extends EventMap> {
|
|
4
|
+
on<TKey extends keyof TEvents>(event: TKey, handler: EventHandler<TEvents[TKey]>): () => void;
|
|
5
|
+
emit<TKey extends keyof TEvents>(event: TKey, payload: TEvents[TKey]): Promise<void>;
|
|
6
|
+
}
|
|
7
|
+
export declare function createEventBus<TEvents extends EventMap>(): EventBus<TEvents>;
|
|
8
|
+
//# sourceMappingURL=event-bus.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-bus.d.ts","sourceRoot":"","sources":["../../../src/core/events/event-bus.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAE/C,MAAM,MAAM,YAAY,CAAC,QAAQ,IAAI,CAAC,OAAO,EAAE,QAAQ,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAEjF,MAAM,WAAW,QAAQ,CAAC,OAAO,SAAS,QAAQ;IAChD,EAAE,CAAC,IAAI,SAAS,MAAM,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,YAAY,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,GAAG,MAAM,IAAI,CAAC;IAC9F,IAAI,CAAC,IAAI,SAAS,MAAM,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACtF;AAED,wBAAgB,cAAc,CAAC,OAAO,SAAS,QAAQ,KAAK,QAAQ,CAAC,OAAO,CAAC,CAuB5E"}
|