@lssm/bundle.contractspec-workspace 0.0.0-canary-20251217063201 → 0.0.0-canary-20251217073102
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/_virtual/rolldown_runtime.js +22 -1
- package/dist/adapters/ai.js +82 -1
- package/dist/adapters/factory.js +36 -1
- package/dist/adapters/fs.js +118 -1
- package/dist/adapters/git.js +54 -1
- package/dist/adapters/index.js +7 -1
- package/dist/adapters/logger.js +80 -1
- package/dist/adapters/watcher.js +69 -1
- package/dist/adapters/workspace.js +190 -2
- package/dist/ai/agents/claude-code-agent.js +146 -9
- package/dist/ai/agents/cursor-agent.js +286 -17
- package/dist/ai/agents/index.js +5 -1
- package/dist/ai/agents/openai-codex-agent.js +140 -8
- package/dist/ai/agents/orchestrator.js +142 -1
- package/dist/ai/agents/simple-agent.js +80 -4
- package/dist/ai/client.js +162 -1
- package/dist/ai/index.js +27 -1
- package/dist/ai/prompts/code-generation.js +55 -13
- package/dist/ai/prompts/index.js +12 -1
- package/dist/ai/prompts/spec-creation.js +61 -20
- package/dist/ai/providers.js +40 -1
- package/dist/formatters/index.js +18 -1
- package/dist/formatters/json.js +71 -1
- package/dist/formatters/sarif.js +163 -1
- package/dist/formatters/text.js +208 -2
- package/dist/index.js +81 -1
- package/dist/libs/ai-providers/dist/factory.js +154 -1
- package/dist/libs/ai-providers/dist/index.js +4 -1
- package/dist/libs/ai-providers/dist/legacy.js +72 -1
- package/dist/libs/ai-providers/dist/models.js +287 -1
- package/dist/libs/ai-providers/dist/validation.js +1 -1
- package/dist/libs/contracts/dist/capabilities/openbanking.js +88 -1
- package/dist/libs/contracts/dist/client/index.js +5 -1
- package/dist/libs/contracts/dist/client/react/feature-render.js +2 -1
- package/dist/libs/contracts/dist/client/react/form-render.js +4 -1
- package/dist/libs/contracts/dist/client/react/index.js +4 -1
- package/dist/libs/contracts/dist/contract-registry/index.js +1 -1
- package/dist/libs/contracts/dist/contract-registry/schemas.js +60 -1
- package/dist/libs/contracts/dist/docs/PUBLISHING.docblock.js +16 -76
- package/dist/libs/contracts/dist/docs/accessibility_wcag_compliance_specs.docblock.js +16 -350
- package/dist/libs/contracts/dist/docs/index.js +29 -1
- package/dist/libs/contracts/dist/docs/presentations.js +71 -1
- package/dist/libs/contracts/dist/docs/registry.js +44 -1
- package/dist/libs/contracts/dist/docs/tech/PHASE_1_QUICKSTART.docblock.js +16 -383
- package/dist/libs/contracts/dist/docs/tech/PHASE_2_AI_NATIVE_OPERATIONS.docblock.js +16 -68
- package/dist/libs/contracts/dist/docs/tech/PHASE_3_AUTO_EVOLUTION.docblock.js +16 -140
- package/dist/libs/contracts/dist/docs/tech/PHASE_4_PERSONALIZATION_ENGINE.docblock.js +16 -86
- package/dist/libs/contracts/dist/docs/tech/PHASE_5_ZERO_TOUCH_OPERATIONS.docblock.js +16 -1
- package/dist/libs/contracts/dist/docs/tech/auth/better-auth-nextjs.docblock.js +24 -2
- package/dist/libs/contracts/dist/docs/tech/contracts/openapi-export.docblock.js +21 -2
- package/dist/libs/contracts/dist/docs/tech/lifecycle-stage-system.docblock.js +16 -213
- package/dist/libs/contracts/dist/docs/tech/llm/llm-integration.docblock.js +73 -5
- package/dist/libs/contracts/dist/docs/tech/mcp-endpoints.docblock.js +37 -1
- package/dist/libs/contracts/dist/docs/tech/presentation-runtime.docblock.js +16 -1
- package/dist/libs/contracts/dist/docs/tech/schema/README.docblock.js +20 -262
- package/dist/libs/contracts/dist/docs/tech/studio/learning-events.docblock.js +48 -1
- package/dist/libs/contracts/dist/docs/tech/studio/learning-journeys.docblock.js +24 -2
- package/dist/libs/contracts/dist/docs/tech/studio/platform-admin-panel.docblock.js +23 -2
- package/dist/libs/contracts/dist/docs/tech/studio/project-access-teams.docblock.js +25 -16
- package/dist/libs/contracts/dist/docs/tech/studio/project-routing.docblock.js +67 -1
- package/dist/libs/contracts/dist/docs/tech/studio/sandbox-unlogged.docblock.js +22 -2
- package/dist/libs/contracts/dist/docs/tech/studio/team-invitations.docblock.js +40 -36
- package/dist/libs/contracts/dist/docs/tech/studio/workspace-ops.docblock.js +47 -1
- package/dist/libs/contracts/dist/docs/tech/studio/workspaces.docblock.js +23 -2
- package/dist/libs/contracts/dist/docs/tech/telemetry-ingest.docblock.js +36 -3
- package/dist/libs/contracts/dist/docs/tech/templates/runtime.docblock.js +20 -1
- package/dist/libs/contracts/dist/docs/tech/vscode-extension.docblock.js +36 -3
- package/dist/libs/contracts/dist/docs/tech/workflows/overview.docblock.js +20 -1
- package/dist/libs/contracts/dist/events.js +8 -1
- package/dist/libs/contracts/dist/experiments/evaluator.js +1 -1
- package/dist/libs/contracts/dist/index.js +72 -1
- package/dist/libs/contracts/dist/install.js +2 -1
- package/dist/libs/contracts/dist/integrations/contracts.js +377 -1
- package/dist/libs/contracts/dist/integrations/index.js +18 -1
- package/dist/libs/contracts/dist/integrations/openbanking/contracts/accounts.js +228 -1
- package/dist/libs/contracts/dist/integrations/openbanking/contracts/balances.js +159 -1
- package/dist/libs/contracts/dist/integrations/openbanking/contracts/index.js +3 -1
- package/dist/libs/contracts/dist/integrations/openbanking/contracts/transactions.js +210 -1
- package/dist/libs/contracts/dist/integrations/openbanking/models.js +242 -1
- package/dist/libs/contracts/dist/integrations/openbanking/telemetry.js +13 -1
- package/dist/libs/contracts/dist/integrations/providers/elevenlabs.js +52 -1
- package/dist/libs/contracts/dist/integrations/providers/gcs-storage.js +75 -1
- package/dist/libs/contracts/dist/integrations/providers/gmail.js +87 -1
- package/dist/libs/contracts/dist/integrations/providers/google-calendar.js +66 -1
- package/dist/libs/contracts/dist/integrations/providers/index.js +11 -1
- package/dist/libs/contracts/dist/integrations/providers/mistral.js +68 -1
- package/dist/libs/contracts/dist/integrations/providers/postmark.js +68 -1
- package/dist/libs/contracts/dist/integrations/providers/powens.js +116 -1
- package/dist/libs/contracts/dist/integrations/providers/qdrant.js +73 -1
- package/dist/libs/contracts/dist/integrations/providers/registry.js +10 -1
- package/dist/libs/contracts/dist/integrations/providers/stripe.js +83 -1
- package/dist/libs/contracts/dist/integrations/providers/twilio-sms.js +61 -1
- package/dist/libs/contracts/dist/jsonschema.js +24 -1
- package/dist/libs/contracts/dist/knowledge/contracts.js +306 -1
- package/dist/libs/contracts/dist/knowledge/index.js +7 -1
- package/dist/libs/contracts/dist/knowledge/spaces/email-threads.js +34 -1
- package/dist/libs/contracts/dist/knowledge/spaces/financial-docs.js +34 -1
- package/dist/libs/contracts/dist/knowledge/spaces/financial-overview.js +38 -1
- package/dist/libs/contracts/dist/knowledge/spaces/index.js +6 -1
- package/dist/libs/contracts/dist/knowledge/spaces/product-canon.js +34 -1
- package/dist/libs/contracts/dist/knowledge/spaces/support-faq.js +37 -1
- package/dist/libs/contracts/dist/knowledge/spaces/uploaded-docs.js +34 -1
- package/dist/libs/contracts/dist/llm/exporters.js +352 -4
- package/dist/libs/contracts/dist/llm/index.js +2 -1
- package/dist/libs/contracts/dist/llm/prompts.js +143 -7
- package/dist/libs/contracts/dist/onboarding-base.js +196 -1
- package/dist/libs/contracts/dist/openapi.js +75 -1
- package/dist/libs/contracts/dist/ownership.js +21 -1
- package/dist/libs/contracts/dist/presentations.js +1 -1
- package/dist/libs/contracts/dist/presentations.v2.js +11 -1
- package/dist/libs/contracts/dist/prompt.js +1 -1
- package/dist/libs/contracts/dist/promptRegistry.js +1 -1
- package/dist/libs/contracts/dist/regenerator/index.js +2 -1
- package/dist/libs/contracts/dist/regenerator/service.js +92 -1
- package/dist/libs/contracts/dist/regenerator/utils.js +51 -1
- package/dist/libs/contracts/dist/registry.js +208 -1
- package/dist/libs/contracts/dist/resources.js +1 -1
- package/dist/libs/contracts/dist/schema/dist/EnumType.js +2 -1
- package/dist/libs/contracts/dist/schema/dist/FieldType.js +49 -1
- package/dist/libs/contracts/dist/schema/dist/ScalarTypeEnum.js +236 -1
- package/dist/libs/contracts/dist/schema/dist/SchemaModel.js +34 -1
- package/dist/libs/contracts/dist/schema/dist/entity/defineEntity.js +1 -1
- package/dist/libs/contracts/dist/schema/dist/entity/index.js +2 -1
- package/dist/libs/contracts/dist/schema/dist/entity/types.js +1 -1
- package/dist/libs/contracts/dist/schema/dist/index.js +6 -1
- package/dist/libs/contracts/dist/server/graphql-pothos.js +6 -1
- package/dist/libs/contracts/dist/server/index.js +8 -1
- package/dist/libs/contracts/dist/server/mcp/createMcpServer.js +4 -1
- package/dist/libs/contracts/dist/server/mcp/registerPresentations.js +2 -1
- package/dist/libs/contracts/dist/server/mcp/registerPrompts.js +1 -1
- package/dist/libs/contracts/dist/server/mcp/registerResources.js +2 -1
- package/dist/libs/contracts/dist/server/mcp/registerTools.js +1 -1
- package/dist/libs/contracts/dist/server/provider-mcp.js +1 -1
- package/dist/libs/contracts/dist/server/rest-elysia.js +1 -1
- package/dist/libs/contracts/dist/server/rest-express.js +1 -1
- package/dist/libs/contracts/dist/server/rest-generic.js +1 -1
- package/dist/libs/contracts/dist/server/rest-next-app.js +1 -1
- package/dist/libs/contracts/dist/server/rest-next-pages.js +1 -1
- package/dist/libs/contracts/dist/spec.js +35 -1
- package/dist/libs/contracts/dist/telemetry/index.js +1 -1
- package/dist/libs/contracts/dist/telemetry/tracker.js +1 -1
- package/dist/libs/contracts/dist/tests/index.js +1 -1
- package/dist/libs/contracts/dist/tests/runner.js +150 -1
- package/dist/libs/contracts/dist/workflow/index.js +1 -1
- package/dist/libs/contracts/dist/workflow/runner.js +1 -1
- package/dist/libs/contracts-transformers/dist/common/utils.js +47 -1
- package/dist/libs/contracts-transformers/dist/openapi/exporter.js +1 -1
- package/dist/libs/contracts-transformers/dist/openapi/importer.js +255 -2
- package/dist/libs/contracts-transformers/dist/openapi/index.js +4 -1
- package/dist/libs/contracts-transformers/dist/openapi/parser.js +231 -1
- package/dist/libs/contracts-transformers/dist/openapi/schema-converter.js +201 -4
- package/dist/modules/contractspec-workspace/dist/ai/code-generation.js +50 -13
- package/dist/modules/contractspec-workspace/dist/ai/spec-creation.js +50 -18
- package/dist/modules/contractspec-workspace/dist/analysis/deps/graph.js +84 -2
- package/dist/modules/contractspec-workspace/dist/analysis/deps/parse-imports.js +30 -1
- package/dist/modules/contractspec-workspace/dist/analysis/diff/semantic.js +96 -1
- package/dist/modules/contractspec-workspace/dist/analysis/feature-scan.js +151 -1
- package/dist/modules/contractspec-workspace/dist/analysis/spec-scan.js +344 -1
- package/dist/modules/contractspec-workspace/dist/analysis/validate/spec-structure.js +122 -1
- package/dist/modules/contractspec-workspace/dist/templates/app-config.js +100 -28
- package/dist/modules/contractspec-workspace/dist/templates/data-view.js +41 -27
- package/dist/modules/contractspec-workspace/dist/templates/event.js +28 -14
- package/dist/modules/contractspec-workspace/dist/templates/experiment.js +76 -51
- package/dist/modules/contractspec-workspace/dist/templates/handler.js +49 -17
- package/dist/modules/contractspec-workspace/dist/templates/integration-utils.js +97 -26
- package/dist/modules/contractspec-workspace/dist/templates/integration.js +46 -23
- package/dist/modules/contractspec-workspace/dist/templates/knowledge.js +59 -19
- package/dist/modules/contractspec-workspace/dist/templates/migration.js +49 -26
- package/dist/modules/contractspec-workspace/dist/templates/operation.js +40 -28
- package/dist/modules/contractspec-workspace/dist/templates/presentation.js +45 -20
- package/dist/modules/contractspec-workspace/dist/templates/telemetry.js +73 -53
- package/dist/modules/contractspec-workspace/dist/templates/utils.js +38 -1
- package/dist/modules/contractspec-workspace/dist/templates/workflow-runner.js +12 -6
- package/dist/modules/contractspec-workspace/dist/templates/workflow.js +50 -24
- package/dist/modules/contractspec-workspace/dist/types/generation-types.js +20 -1
- package/dist/services/agent-guide/adapters/claude-code.js +144 -3
- package/dist/services/agent-guide/adapters/cursor-cli.js +135 -3
- package/dist/services/agent-guide/adapters/generic-mcp.js +159 -3
- package/dist/services/agent-guide/adapters/index.js +30 -1
- package/dist/services/agent-guide/agent-guide-service.js +148 -1
- package/dist/services/agent-guide/index.js +5 -1
- package/dist/services/build.js +140 -1
- package/dist/services/ci-check/ci-check-service.js +393 -1
- package/dist/services/ci-check/index.js +2 -1
- package/dist/services/ci-check/types.js +28 -1
- package/dist/services/clean.js +71 -1
- package/dist/services/config.js +76 -1
- package/dist/services/deps.js +62 -1
- package/dist/services/diff.js +33 -1
- package/dist/services/doctor/checks/ai.js +118 -2
- package/dist/services/doctor/checks/cli.js +146 -1
- package/dist/services/doctor/checks/config.js +170 -1
- package/dist/services/doctor/checks/deps.js +180 -1
- package/dist/services/doctor/checks/index.js +6 -1
- package/dist/services/doctor/checks/mcp.js +144 -1
- package/dist/services/doctor/checks/workspace.js +243 -1
- package/dist/services/doctor/doctor-service.js +115 -2
- package/dist/services/doctor/index.js +2 -1
- package/dist/services/doctor/types.js +26 -1
- package/dist/services/implementation/discovery.js +143 -2
- package/dist/services/implementation/index.js +2 -1
- package/dist/services/implementation/resolver.js +223 -1
- package/dist/services/index.js +53 -1
- package/dist/services/integrity-diagram.js +274 -6
- package/dist/services/integrity.js +272 -1
- package/dist/services/list.js +35 -1
- package/dist/services/openapi/export-service.js +51 -2
- package/dist/services/openapi/import-service.js +75 -1
- package/dist/services/openapi/index.js +4 -1
- package/dist/services/openapi/sync-service.js +121 -1
- package/dist/services/openapi/validate-service.js +130 -1
- package/dist/services/regenerator.js +23 -1
- package/dist/services/registry.js +73 -1
- package/dist/services/setup/config-generators.js +113 -26
- package/dist/services/setup/file-merger.js +60 -2
- package/dist/services/setup/index.js +4 -1
- package/dist/services/setup/setup-service.js +95 -1
- package/dist/services/setup/targets/agents-md.js +46 -1
- package/dist/services/setup/targets/cli-config.js +59 -1
- package/dist/services/setup/targets/cursor-rules.js +47 -1
- package/dist/services/setup/targets/mcp-claude.js +59 -1
- package/dist/services/setup/targets/mcp-cursor.js +58 -1
- package/dist/services/setup/targets/vscode-settings.js +62 -1
- package/dist/services/setup/types.js +26 -1
- package/dist/services/sync.js +62 -1
- package/dist/services/test.js +30 -1
- package/dist/services/validate-implementation.js +69 -1
- package/dist/services/validate.js +47 -1
- package/dist/services/verification-cache/adapters/filesystem.js +121 -1
- package/dist/services/verification-cache/adapters/in-memory.js +45 -1
- package/dist/services/verification-cache/adapters/index.js +3 -1
- package/dist/services/verification-cache/adapters/workspace-state.js +90 -1
- package/dist/services/verification-cache/cache-service.js +255 -1
- package/dist/services/verification-cache/index.js +6 -1
- package/dist/services/verification-cache/types.js +15 -1
- package/dist/services/verify/ai-verifier.js +336 -9
- package/dist/services/verify/behavior-verifier.js +185 -1
- package/dist/services/verify/index.js +4 -1
- package/dist/services/verify/structure-verifier.js +195 -2
- package/dist/services/verify/verify-service.js +203 -3
- package/dist/services/watch.js +31 -1
- package/dist/services/workspace-info.js +102 -2
- package/dist/templates/app-config.template.js +101 -28
- package/dist/templates/data-view.template.js +42 -27
- package/dist/templates/event.template.js +29 -14
- package/dist/templates/experiment.template.js +77 -51
- package/dist/templates/handler.template.js +53 -17
- package/dist/templates/index.js +36 -1
- package/dist/templates/integration.template.js +134 -50
- package/dist/templates/knowledge.template.js +62 -21
- package/dist/templates/migration.template.js +50 -26
- package/dist/templates/operation.template.js +44 -28
- package/dist/templates/presentation.template.js +46 -20
- package/dist/templates/telemetry.template.js +74 -53
- package/dist/templates/workflow-runner.template.js +12 -6
- package/dist/templates/workflow.template.js +51 -24
- package/package.json +13 -9
|
@@ -1,5 +1,60 @@
|
|
|
1
|
-
import{
|
|
2
|
-
|
|
1
|
+
import { generateVerificationPrompt } from "../../libs/contracts/dist/llm/prompts.js";
|
|
2
|
+
import "../../libs/contracts/dist/llm/index.js";
|
|
3
|
+
|
|
4
|
+
//#region src/services/verify/ai-verifier.ts
|
|
5
|
+
/**
|
|
6
|
+
* Parse AI response to structured result.
|
|
7
|
+
*/
|
|
8
|
+
function parseAIResponse(response) {
|
|
9
|
+
const jsonMatch = response.match(/```json\n?([\s\S]*?)\n?```/);
|
|
10
|
+
if (jsonMatch?.[1]) try {
|
|
11
|
+
const parsed = JSON.parse(jsonMatch[1]);
|
|
12
|
+
return {
|
|
13
|
+
compliant: parsed.passed ?? false,
|
|
14
|
+
confidence: (parsed.score ?? 0) / 100,
|
|
15
|
+
findings: (parsed.issues ?? []).map((issue) => ({
|
|
16
|
+
category: String(issue.category ?? "semantic"),
|
|
17
|
+
severity: String(issue.severity ?? "warning"),
|
|
18
|
+
message: String(issue.message ?? ""),
|
|
19
|
+
location: issue.location ? String(issue.location) : void 0,
|
|
20
|
+
suggestion: issue.suggestion ? String(issue.suggestion) : void 0
|
|
21
|
+
})),
|
|
22
|
+
rawResponse: response
|
|
23
|
+
};
|
|
24
|
+
} catch {}
|
|
25
|
+
const findings = [];
|
|
26
|
+
const lines = response.split("\n");
|
|
27
|
+
let currentSeverity = "info";
|
|
28
|
+
for (const line of lines) {
|
|
29
|
+
const lineLower = line.toLowerCase();
|
|
30
|
+
if (lineLower.includes("error") || lineLower.includes("critical")) currentSeverity = "error";
|
|
31
|
+
else if (lineLower.includes("warning") || lineLower.includes("should")) currentSeverity = "warning";
|
|
32
|
+
else if (lineLower.includes("info") || lineLower.includes("note")) currentSeverity = "info";
|
|
33
|
+
const bulletMatch = line.match(/^[-*•]\s*(.+)$/);
|
|
34
|
+
const numberedMatch = line.match(/^\d+\.\s*(.+)$/);
|
|
35
|
+
if (bulletMatch || numberedMatch) {
|
|
36
|
+
const content = bulletMatch?.[1] ?? numberedMatch?.[1] ?? "";
|
|
37
|
+
if (content.length > 10) findings.push({
|
|
38
|
+
category: "semantic",
|
|
39
|
+
severity: currentSeverity,
|
|
40
|
+
message: content
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
const hasErrors = findings.some((f) => f.severity === "error");
|
|
45
|
+
return {
|
|
46
|
+
compliant: !hasErrors,
|
|
47
|
+
confidence: hasErrors ? .3 : findings.length === 0 ? .9 : .7,
|
|
48
|
+
findings,
|
|
49
|
+
rawResponse: response
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Call AI provider for verification.
|
|
54
|
+
* This is a placeholder - actual implementation would use AI SDK.
|
|
55
|
+
*/
|
|
56
|
+
async function callAI(prompt, config) {
|
|
57
|
+
if (!config.aiApiKey) return `\`\`\`json
|
|
3
58
|
{
|
|
4
59
|
"passed": true,
|
|
5
60
|
"score": 50,
|
|
@@ -16,23 +71,154 @@ import{o as e}from"../../libs/contracts/dist/llm/prompts.js";import"../../libs/c
|
|
|
16
71
|
],
|
|
17
72
|
"summary": "AI verification skipped - no API key configured. Structure and behavior checks have been performed."
|
|
18
73
|
}
|
|
19
|
-
\`\`\``;
|
|
74
|
+
\`\`\``;
|
|
75
|
+
try {
|
|
76
|
+
const provider = config.aiProvider ?? "anthropic";
|
|
77
|
+
if (provider === "anthropic") {
|
|
78
|
+
const { anthropic } = await import("@ai-sdk/anthropic");
|
|
79
|
+
const { generateText } = await import("ai");
|
|
80
|
+
return (await generateText({
|
|
81
|
+
model: anthropic("claude-3-5-sonnet-20241022"),
|
|
82
|
+
prompt,
|
|
83
|
+
system: "You are an expert code reviewer analyzing implementation compliance with specifications. Respond with structured JSON."
|
|
84
|
+
})).text;
|
|
85
|
+
} else if (provider === "openai") {
|
|
86
|
+
const { openai } = await import("@ai-sdk/openai");
|
|
87
|
+
const { generateText } = await import("ai");
|
|
88
|
+
return (await generateText({
|
|
89
|
+
model: openai("gpt-4o"),
|
|
90
|
+
prompt,
|
|
91
|
+
system: "You are an expert code reviewer analyzing implementation compliance with specifications. Respond with structured JSON."
|
|
92
|
+
})).text;
|
|
93
|
+
}
|
|
94
|
+
throw new Error(`Unknown AI provider: ${provider}`);
|
|
95
|
+
} catch (error) {
|
|
96
|
+
return `\`\`\`json
|
|
20
97
|
{
|
|
21
98
|
"passed": false,
|
|
22
99
|
"score": 0,
|
|
23
100
|
"issues": [
|
|
24
|
-
{ "severity": "error", "category": "semantic", "message": "AI verification failed: ${
|
|
101
|
+
{ "severity": "error", "category": "semantic", "message": "AI verification failed: ${error instanceof Error ? error.message : "Unknown error"}" }
|
|
25
102
|
],
|
|
26
103
|
"summary": "AI verification encountered an error"
|
|
27
104
|
}
|
|
28
|
-
|
|
105
|
+
\`\`\``;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Run AI-powered verification.
|
|
110
|
+
*/
|
|
111
|
+
async function verifyWithAI(input, config = {}) {
|
|
112
|
+
const { spec, implementationCode, implementationPath } = input;
|
|
113
|
+
const startTime = Date.now();
|
|
114
|
+
const result = parseAIResponse(await callAI(generateVerificationPrompt(spec, implementationCode).taskPrompt, config));
|
|
115
|
+
const issues = result.findings.map((f) => ({
|
|
116
|
+
severity: f.severity,
|
|
117
|
+
category: "semantic",
|
|
118
|
+
message: f.message,
|
|
119
|
+
location: f.location ? { file: f.location } : implementationPath ? { file: implementationPath } : void 0,
|
|
120
|
+
suggestion: f.suggestion
|
|
121
|
+
}));
|
|
122
|
+
const score = Math.round(result.confidence * 100);
|
|
123
|
+
const passed = result.compliant;
|
|
124
|
+
return {
|
|
125
|
+
tier: "ai_review",
|
|
126
|
+
passed,
|
|
127
|
+
score,
|
|
128
|
+
issues,
|
|
129
|
+
suggestions: result.findings.filter((f) => f.suggestion).map((f) => f.suggestion),
|
|
130
|
+
coverage: {
|
|
131
|
+
scenarios: {
|
|
132
|
+
total: 0,
|
|
133
|
+
covered: 0
|
|
134
|
+
},
|
|
135
|
+
errors: {
|
|
136
|
+
total: 0,
|
|
137
|
+
handled: 0
|
|
138
|
+
},
|
|
139
|
+
fields: {
|
|
140
|
+
total: 1,
|
|
141
|
+
implemented: passed ? 1 : 0
|
|
142
|
+
}
|
|
143
|
+
},
|
|
144
|
+
meta: {
|
|
145
|
+
specName: spec.meta.name,
|
|
146
|
+
specVersion: spec.meta.version,
|
|
147
|
+
implementationPath: implementationPath ?? "unknown",
|
|
148
|
+
verifiedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
149
|
+
duration: Date.now() - startTime
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Create a simpler AI review without calling the API.
|
|
155
|
+
* Used as fallback or for quick checks.
|
|
156
|
+
*/
|
|
157
|
+
function createQuickAIReview(input) {
|
|
158
|
+
const { spec, implementationCode, implementationPath } = input;
|
|
159
|
+
const startTime = Date.now();
|
|
160
|
+
const issues = [];
|
|
161
|
+
if (implementationCode.includes("console.log")) issues.push({
|
|
162
|
+
severity: "warning",
|
|
163
|
+
category: "semantic",
|
|
164
|
+
message: "Console.log statements found - consider using proper logging",
|
|
165
|
+
suggestion: "Use a structured logger instead of console.log"
|
|
166
|
+
});
|
|
167
|
+
if (implementationCode.includes("// TODO") || implementationCode.includes("// FIXME")) issues.push({
|
|
168
|
+
severity: "info",
|
|
169
|
+
category: "semantic",
|
|
170
|
+
message: "TODO/FIXME comments found - implementation may be incomplete",
|
|
171
|
+
suggestion: "Address TODO items before finalizing implementation"
|
|
172
|
+
});
|
|
173
|
+
if (spec.policy.auth !== "anonymous" && !implementationCode.includes("auth")) issues.push({
|
|
174
|
+
severity: "warning",
|
|
175
|
+
category: "semantic",
|
|
176
|
+
message: `Spec requires ${spec.policy.auth} auth but no auth check found`,
|
|
177
|
+
suggestion: "Add authentication check at the handler entry point"
|
|
178
|
+
});
|
|
179
|
+
const score = issues.filter((i) => i.severity === "error").length === 0 ? 80 : 40;
|
|
180
|
+
const passed = issues.filter((i) => i.severity === "error").length === 0;
|
|
181
|
+
return {
|
|
182
|
+
tier: "ai_review",
|
|
183
|
+
passed,
|
|
184
|
+
score,
|
|
185
|
+
issues,
|
|
186
|
+
suggestions: issues.filter((i) => i.suggestion).map((i) => i.suggestion),
|
|
187
|
+
coverage: {
|
|
188
|
+
scenarios: {
|
|
189
|
+
total: 0,
|
|
190
|
+
covered: 0
|
|
191
|
+
},
|
|
192
|
+
errors: {
|
|
193
|
+
total: 0,
|
|
194
|
+
handled: 0
|
|
195
|
+
},
|
|
196
|
+
fields: {
|
|
197
|
+
total: 1,
|
|
198
|
+
implemented: passed ? 1 : 0
|
|
199
|
+
}
|
|
200
|
+
},
|
|
201
|
+
meta: {
|
|
202
|
+
specName: spec.meta.name,
|
|
203
|
+
specVersion: spec.meta.version,
|
|
204
|
+
implementationPath: implementationPath ?? "unknown",
|
|
205
|
+
verifiedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
206
|
+
duration: Date.now() - startTime
|
|
207
|
+
}
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Generate a prompt for semantic field verification.
|
|
212
|
+
*/
|
|
213
|
+
function generateSemanticFieldPrompt(specFields, implCode) {
|
|
214
|
+
return `You are analyzing a code implementation against its specification.
|
|
29
215
|
|
|
30
216
|
## Spec Schema Fields
|
|
31
|
-
${
|
|
217
|
+
${specFields}
|
|
32
218
|
|
|
33
219
|
## Implementation Code
|
|
34
220
|
\`\`\`typescript
|
|
35
|
-
${
|
|
221
|
+
${implCode}
|
|
36
222
|
\`\`\`
|
|
37
223
|
|
|
38
224
|
## Task
|
|
@@ -72,5 +258,146 @@ Match types:
|
|
|
72
258
|
- "compatible": Semantically similar (e.g., "email" vs "emailAddress")
|
|
73
259
|
- "mismatch": Different meaning despite similar naming
|
|
74
260
|
- "missing": Spec field not found in implementation
|
|
75
|
-
|
|
76
|
-
|
|
261
|
+
`;
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* Extract field definitions from spec schema.
|
|
265
|
+
*/
|
|
266
|
+
function extractSpecFields(spec) {
|
|
267
|
+
const fields = [];
|
|
268
|
+
/**
|
|
269
|
+
* Helper to safely extract fields from a schema.
|
|
270
|
+
*/
|
|
271
|
+
const extractFromSchema = (schema, direction) => {
|
|
272
|
+
try {
|
|
273
|
+
const shapeFn = schema?._def?.shape;
|
|
274
|
+
if (shapeFn && typeof shapeFn === "function") {
|
|
275
|
+
const shapeObj = shapeFn();
|
|
276
|
+
for (const [key, value] of Object.entries(shapeObj)) {
|
|
277
|
+
const typeName = value?._def?.typeName ?? "unknown";
|
|
278
|
+
fields.push(`- ${key}: ${String(typeName).replace("Zod", "").toLowerCase()} (${direction})`);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
} catch {
|
|
282
|
+
fields.push(`- [unable to extract ${direction} fields]`);
|
|
283
|
+
}
|
|
284
|
+
};
|
|
285
|
+
if (spec.io.input) extractFromSchema(spec.io.input, "input");
|
|
286
|
+
if (spec.io.output && !("resourceRef" in spec.io.output)) extractFromSchema(spec.io.output, "output");
|
|
287
|
+
if (fields.length === 0) return "- [no schema fields could be extracted]";
|
|
288
|
+
return fields.join("\n");
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* Parse semantic verification response from AI.
|
|
292
|
+
*/
|
|
293
|
+
function parseSemanticResponse(response) {
|
|
294
|
+
const jsonMatch = response.match(/```json\n?([\s\S]*?)\n?```/);
|
|
295
|
+
if (jsonMatch?.[1]) try {
|
|
296
|
+
const parsed = JSON.parse(jsonMatch[1]);
|
|
297
|
+
return {
|
|
298
|
+
fieldMappings: (parsed.fieldMappings ?? []).map((m) => ({
|
|
299
|
+
specField: String(m.specField ?? ""),
|
|
300
|
+
specType: String(m.specType ?? "unknown"),
|
|
301
|
+
implementationField: m.implementationField ? String(m.implementationField) : void 0,
|
|
302
|
+
implementationType: m.implementationType ? String(m.implementationType) : void 0,
|
|
303
|
+
match: m.match ?? "missing",
|
|
304
|
+
aiConfidence: typeof m.aiConfidence === "number" ? m.aiConfidence : .5,
|
|
305
|
+
suggestion: m.suggestion ? String(m.suggestion) : void 0
|
|
306
|
+
})),
|
|
307
|
+
intentAlignment: {
|
|
308
|
+
score: typeof parsed.intentAlignment?.score === "number" ? parsed.intentAlignment.score : 50,
|
|
309
|
+
issues: Array.isArray(parsed.intentAlignment?.issues) ? parsed.intentAlignment.issues : [],
|
|
310
|
+
suggestions: Array.isArray(parsed.intentAlignment?.suggestions) ? parsed.intentAlignment.suggestions : []
|
|
311
|
+
},
|
|
312
|
+
semanticIssues: (parsed.semanticIssues ?? []).map((i) => ({
|
|
313
|
+
category: String(i.category ?? "semantic"),
|
|
314
|
+
severity: i.severity ?? "warning",
|
|
315
|
+
message: String(i.message ?? ""),
|
|
316
|
+
suggestion: i.suggestion ? String(i.suggestion) : void 0
|
|
317
|
+
})),
|
|
318
|
+
rawResponse: response
|
|
319
|
+
};
|
|
320
|
+
} catch {}
|
|
321
|
+
return {
|
|
322
|
+
fieldMappings: [],
|
|
323
|
+
intentAlignment: {
|
|
324
|
+
score: 50,
|
|
325
|
+
issues: ["Unable to parse AI response for semantic analysis"],
|
|
326
|
+
suggestions: []
|
|
327
|
+
},
|
|
328
|
+
semanticIssues: [],
|
|
329
|
+
rawResponse: response
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* Run semantic field-level verification using AI.
|
|
334
|
+
*/
|
|
335
|
+
async function verifySemanticFields(input, config = {}) {
|
|
336
|
+
const { spec, implementationCode } = input;
|
|
337
|
+
return parseSemanticResponse(await callAI(generateSemanticFieldPrompt(extractSpecFields(spec), implementationCode), config));
|
|
338
|
+
}
|
|
339
|
+
/**
|
|
340
|
+
* Run enhanced AI verification with semantic field analysis.
|
|
341
|
+
*/
|
|
342
|
+
async function verifyWithAIEnhanced(input, config = {}) {
|
|
343
|
+
const { spec, implementationCode, implementationPath } = input;
|
|
344
|
+
const startTime = Date.now();
|
|
345
|
+
const baseReport = await verifyWithAI(input, config);
|
|
346
|
+
let semanticResult;
|
|
347
|
+
if (config.aiApiKey) try {
|
|
348
|
+
semanticResult = await verifySemanticFields(input, config);
|
|
349
|
+
} catch {}
|
|
350
|
+
if (semanticResult) {
|
|
351
|
+
const semanticIssues = [];
|
|
352
|
+
for (const mapping of semanticResult.fieldMappings) if (mapping.match === "missing") semanticIssues.push({
|
|
353
|
+
severity: "error",
|
|
354
|
+
category: "semantic",
|
|
355
|
+
message: `Missing field: '${mapping.specField}' (${mapping.specType}) not found in implementation`,
|
|
356
|
+
suggestion: mapping.suggestion ?? `Add field '${mapping.specField}' to implementation`
|
|
357
|
+
});
|
|
358
|
+
else if (mapping.match === "mismatch") semanticIssues.push({
|
|
359
|
+
severity: "warning",
|
|
360
|
+
category: "semantic",
|
|
361
|
+
message: `Field mismatch: '${mapping.specField}' has incorrect implementation as '${mapping.implementationField}'`,
|
|
362
|
+
suggestion: mapping.suggestion
|
|
363
|
+
});
|
|
364
|
+
else if (mapping.match === "compatible" && mapping.aiConfidence < .8) semanticIssues.push({
|
|
365
|
+
severity: "info",
|
|
366
|
+
category: "semantic",
|
|
367
|
+
message: `Field naming: '${mapping.specField}' implemented as '${mapping.implementationField}' (compatible but not exact)`,
|
|
368
|
+
suggestion: mapping.suggestion
|
|
369
|
+
});
|
|
370
|
+
for (const issue of semanticResult.intentAlignment.issues) semanticIssues.push({
|
|
371
|
+
severity: "warning",
|
|
372
|
+
category: "semantic",
|
|
373
|
+
message: issue
|
|
374
|
+
});
|
|
375
|
+
for (const issue of semanticResult.semanticIssues) semanticIssues.push({
|
|
376
|
+
severity: issue.severity,
|
|
377
|
+
category: "semantic",
|
|
378
|
+
message: issue.message,
|
|
379
|
+
suggestion: issue.suggestion
|
|
380
|
+
});
|
|
381
|
+
baseReport.issues = [...baseReport.issues, ...semanticIssues];
|
|
382
|
+
const totalFields = semanticResult.fieldMappings.length;
|
|
383
|
+
const implementedFields = semanticResult.fieldMappings.filter((m) => m.match === "exact" || m.match === "compatible").length;
|
|
384
|
+
if (totalFields > 0) {
|
|
385
|
+
const fieldScore = Math.round(implementedFields / totalFields * 100);
|
|
386
|
+
baseReport.score = Math.round((baseReport.score + fieldScore) / 2);
|
|
387
|
+
baseReport.coverage.fields = {
|
|
388
|
+
total: totalFields,
|
|
389
|
+
implemented: implementedFields
|
|
390
|
+
};
|
|
391
|
+
}
|
|
392
|
+
if (semanticIssues.some((i) => i.severity === "error")) baseReport.passed = false;
|
|
393
|
+
baseReport.suggestions = [...baseReport.suggestions, ...semanticResult.intentAlignment.suggestions];
|
|
394
|
+
}
|
|
395
|
+
baseReport.meta = {
|
|
396
|
+
...baseReport.meta,
|
|
397
|
+
duration: Date.now() - startTime
|
|
398
|
+
};
|
|
399
|
+
return baseReport;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
//#endregion
|
|
403
|
+
export { createQuickAIReview, verifySemanticFields, verifyWithAI, verifyWithAIEnhanced };
|
|
@@ -1 +1,185 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import { isEmitDeclRef } from "../../libs/contracts/dist/spec.js";
|
|
2
|
+
|
|
3
|
+
//#region src/services/verify/behavior-verifier.ts
|
|
4
|
+
/**
|
|
5
|
+
* Check if a scenario is likely covered by the implementation.
|
|
6
|
+
*/
|
|
7
|
+
function checkScenarioCoverage(code, scenario) {
|
|
8
|
+
const keywords = [
|
|
9
|
+
...scenario.given,
|
|
10
|
+
...scenario.when,
|
|
11
|
+
...scenario.then
|
|
12
|
+
].flatMap((s) => s.toLowerCase().split(/\s+/).filter((w) => w.length > 3));
|
|
13
|
+
const codeLower = code.toLowerCase();
|
|
14
|
+
const foundKeywords = keywords.filter((kw) => codeLower.includes(kw));
|
|
15
|
+
const coverage = keywords.length > 0 ? foundKeywords.length / keywords.length : 0;
|
|
16
|
+
const scenarioNameLower = scenario.name.toLowerCase().replace(/\s+/g, "");
|
|
17
|
+
const hasTestForScenario = codeLower.includes(scenarioNameLower) || codeLower.includes(`test('${scenario.name.toLowerCase()}'`) || codeLower.includes(`it('${scenario.name.toLowerCase()}'`) || codeLower.includes(`describe('${scenario.name.toLowerCase()}'`);
|
|
18
|
+
const passed = coverage >= .3 || hasTestForScenario;
|
|
19
|
+
return {
|
|
20
|
+
name: scenario.name,
|
|
21
|
+
type: "scenario",
|
|
22
|
+
passed,
|
|
23
|
+
expected: `Given: ${scenario.given.join("; ")}; When: ${scenario.when.join("; ")}; Then: ${scenario.then.join("; ")}`,
|
|
24
|
+
details: passed ? void 0 : `Scenario keywords not found in implementation (${Math.round(coverage * 100)}% coverage)`
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Check if an example is likely handled.
|
|
29
|
+
*/
|
|
30
|
+
function checkExampleCoverage(code, example) {
|
|
31
|
+
const inputStr = JSON.stringify(example.input);
|
|
32
|
+
const outputStr = JSON.stringify(example.output);
|
|
33
|
+
const inputValues = extractStringValues(example.input);
|
|
34
|
+
const outputValues = extractStringValues(example.output);
|
|
35
|
+
const codeLower = code.toLowerCase();
|
|
36
|
+
const foundInputValues = inputValues.filter((v) => codeLower.includes(v.toLowerCase()));
|
|
37
|
+
const foundOutputValues = outputValues.filter((v) => codeLower.includes(v.toLowerCase()));
|
|
38
|
+
const avgCoverage = ((inputValues.length > 0 ? foundInputValues.length / inputValues.length : 1) + (outputValues.length > 0 ? foundOutputValues.length / outputValues.length : 1)) / 2;
|
|
39
|
+
const passed = avgCoverage >= .2;
|
|
40
|
+
return {
|
|
41
|
+
name: example.name,
|
|
42
|
+
type: "example",
|
|
43
|
+
passed,
|
|
44
|
+
expected: `Input: ${inputStr.slice(0, 100)}...; Output: ${outputStr.slice(0, 100)}...`,
|
|
45
|
+
details: passed ? void 0 : `Example values not found in implementation (${Math.round(avgCoverage * 100)}% coverage)`
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Extract string values from an object for comparison.
|
|
50
|
+
*/
|
|
51
|
+
function extractStringValues(obj) {
|
|
52
|
+
const values = [];
|
|
53
|
+
function extract(value) {
|
|
54
|
+
if (typeof value === "string" && value.length > 2) values.push(value);
|
|
55
|
+
else if (Array.isArray(value)) value.forEach(extract);
|
|
56
|
+
else if (value && typeof value === "object") Object.values(value).forEach(extract);
|
|
57
|
+
}
|
|
58
|
+
extract(obj);
|
|
59
|
+
return values;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Check if an error case is handled.
|
|
63
|
+
*/
|
|
64
|
+
function checkErrorCaseCoverage(code, errorCode, errorDef) {
|
|
65
|
+
const hasErrorCode = code.includes(errorCode);
|
|
66
|
+
const hasHttpStatus = errorDef.http ? code.includes(String(errorDef.http)) : true;
|
|
67
|
+
const whenKeywords = errorDef.when.toLowerCase().split(/\s+/).filter((w) => w.length > 3);
|
|
68
|
+
const codeLower = code.toLowerCase();
|
|
69
|
+
const foundWhenKeywords = whenKeywords.filter((kw) => codeLower.includes(kw));
|
|
70
|
+
const whenCoverage = whenKeywords.length > 0 ? foundWhenKeywords.length / whenKeywords.length : 1;
|
|
71
|
+
const passed = hasErrorCode && (hasHttpStatus || whenCoverage >= .3);
|
|
72
|
+
return {
|
|
73
|
+
name: `Error: ${errorCode}`,
|
|
74
|
+
type: "error",
|
|
75
|
+
passed,
|
|
76
|
+
expected: `When: ${errorDef.when}; Return: ${errorCode} (HTTP ${errorDef.http ?? 400})`,
|
|
77
|
+
details: passed ? void 0 : !hasErrorCode ? `Error code '${errorCode}' not found in implementation` : `Error condition not properly implemented`
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Check if events are emitted in the right conditions.
|
|
82
|
+
*/
|
|
83
|
+
function checkEventConditions(code, spec) {
|
|
84
|
+
const events = spec.sideEffects?.emits ?? [];
|
|
85
|
+
const checks = [];
|
|
86
|
+
for (const event of events) {
|
|
87
|
+
const eventName = isEmitDeclRef(event) ? event.ref.name : event.name;
|
|
88
|
+
const when = event.when;
|
|
89
|
+
const whenKeywords = when.toLowerCase().split(/\s+/).filter((w) => w.length > 3);
|
|
90
|
+
const codeLower = code.toLowerCase();
|
|
91
|
+
const hasEvent = codeLower.includes(eventName.toLowerCase());
|
|
92
|
+
const foundKeywords = whenKeywords.filter((kw) => codeLower.includes(kw));
|
|
93
|
+
const conditionCoverage = whenKeywords.length > 0 ? foundKeywords.length / whenKeywords.length : 1;
|
|
94
|
+
checks.push({
|
|
95
|
+
name: `Event: ${eventName}`,
|
|
96
|
+
type: "scenario",
|
|
97
|
+
passed: hasEvent && conditionCoverage >= .3,
|
|
98
|
+
expected: `Emit ${eventName} when: ${when}`,
|
|
99
|
+
details: !hasEvent ? `Event '${eventName}' not found` : conditionCoverage < .3 ? `Event condition not properly implemented` : void 0
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
return checks;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Check if idempotency is properly handled.
|
|
106
|
+
*/
|
|
107
|
+
function checkIdempotency(code, spec) {
|
|
108
|
+
if (spec.policy.idempotent === void 0) return null;
|
|
109
|
+
if (!spec.policy.idempotent) return null;
|
|
110
|
+
const idempotentPatterns = [
|
|
111
|
+
"idempotency",
|
|
112
|
+
"idempotent",
|
|
113
|
+
"already exists",
|
|
114
|
+
"upsert",
|
|
115
|
+
"on conflict",
|
|
116
|
+
"if not exists",
|
|
117
|
+
"dedupe",
|
|
118
|
+
"duplicate"
|
|
119
|
+
];
|
|
120
|
+
const codeLower = code.toLowerCase();
|
|
121
|
+
const hasIdempotentPattern = idempotentPatterns.some((p) => codeLower.includes(p));
|
|
122
|
+
return {
|
|
123
|
+
name: "Idempotency",
|
|
124
|
+
type: "scenario",
|
|
125
|
+
passed: hasIdempotentPattern,
|
|
126
|
+
expected: "Operation should be idempotent (safe to retry)",
|
|
127
|
+
details: hasIdempotentPattern ? void 0 : "No idempotency pattern found for idempotent operation"
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Run all behavior checks and produce a verification report.
|
|
132
|
+
*/
|
|
133
|
+
function verifyBehavior(input) {
|
|
134
|
+
const { spec, implementationCode, implementationPath } = input;
|
|
135
|
+
const startTime = Date.now();
|
|
136
|
+
const checks = [];
|
|
137
|
+
for (const scenario of spec.acceptance?.scenarios ?? []) checks.push(checkScenarioCoverage(implementationCode, scenario));
|
|
138
|
+
for (const example of spec.acceptance?.examples ?? []) checks.push(checkExampleCoverage(implementationCode, example));
|
|
139
|
+
for (const [code, errorDef] of Object.entries(spec.io.errors ?? {})) checks.push(checkErrorCaseCoverage(implementationCode, code, errorDef));
|
|
140
|
+
checks.push(...checkEventConditions(implementationCode, spec));
|
|
141
|
+
const idempotencyCheck = checkIdempotency(implementationCode, spec);
|
|
142
|
+
if (idempotencyCheck) checks.push(idempotencyCheck);
|
|
143
|
+
const issues = checks.filter((c) => !c.passed).map((c) => ({
|
|
144
|
+
severity: c.type === "error" ? "error" : "warning",
|
|
145
|
+
category: c.type === "scenario" ? "scenario" : c.type === "example" ? "scenario" : "error_handling",
|
|
146
|
+
message: c.details ?? `${c.type} not covered: ${c.name}`,
|
|
147
|
+
location: implementationPath ? { file: implementationPath } : void 0,
|
|
148
|
+
suggestion: c.expected ? `Expected: ${c.expected}` : void 0
|
|
149
|
+
}));
|
|
150
|
+
const scenarioChecks = checks.filter((c) => c.type === "scenario");
|
|
151
|
+
const errorChecks = checks.filter((c) => c.type === "error");
|
|
152
|
+
const passedCount = checks.filter((c) => c.passed).length;
|
|
153
|
+
const score = checks.length > 0 ? Math.round(passedCount / checks.length * 100) : 100;
|
|
154
|
+
return {
|
|
155
|
+
tier: "behavior",
|
|
156
|
+
passed: issues.filter((i) => i.severity === "error").length === 0,
|
|
157
|
+
score,
|
|
158
|
+
issues,
|
|
159
|
+
suggestions: checks.filter((c) => !c.passed && c.expected).map((c) => `${c.name}: ${c.expected}`),
|
|
160
|
+
coverage: {
|
|
161
|
+
scenarios: {
|
|
162
|
+
total: scenarioChecks.length,
|
|
163
|
+
covered: scenarioChecks.filter((c) => c.passed).length
|
|
164
|
+
},
|
|
165
|
+
errors: {
|
|
166
|
+
total: errorChecks.length,
|
|
167
|
+
handled: errorChecks.filter((c) => c.passed).length
|
|
168
|
+
},
|
|
169
|
+
fields: {
|
|
170
|
+
total: checks.length,
|
|
171
|
+
implemented: passedCount
|
|
172
|
+
}
|
|
173
|
+
},
|
|
174
|
+
meta: {
|
|
175
|
+
specName: spec.meta.name,
|
|
176
|
+
specVersion: spec.meta.version,
|
|
177
|
+
implementationPath: implementationPath ?? "unknown",
|
|
178
|
+
verifiedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
179
|
+
duration: Date.now() - startTime
|
|
180
|
+
}
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
//#endregion
|
|
185
|
+
export { verifyBehavior };
|
|
@@ -1 +1,4 @@
|
|
|
1
|
-
import{verifyStructure
|
|
1
|
+
import { verifyStructure } from "./structure-verifier.js";
|
|
2
|
+
import { verifyBehavior } from "./behavior-verifier.js";
|
|
3
|
+
import { createQuickAIReview, verifySemanticFields, verifyWithAI, verifyWithAIEnhanced } from "./ai-verifier.js";
|
|
4
|
+
import { VerifyService, createVerifyService, verifyService } from "./verify-service.js";
|