@su-record/vibe 3.2.13 → 3.2.15
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/CLAUDE.md +15 -14
- package/README.en.md +1 -1
- package/README.md +1 -1
- package/dist/cli/setup/ProjectSetup.d.ts +6 -0
- package/dist/cli/setup/ProjectSetup.d.ts.map +1 -1
- package/dist/cli/setup/ProjectSetup.js +19 -13
- package/dist/cli/setup/ProjectSetup.js.map +1 -1
- package/dist/infra/lib/codex-proxy.d.ts +126 -0
- package/dist/infra/lib/codex-proxy.d.ts.map +1 -1
- package/dist/infra/lib/codex-proxy.js +16 -16
- package/dist/infra/lib/codex-proxy.js.map +1 -1
- package/dist/infra/lib/figma/audit.d.ts.map +1 -1
- package/dist/infra/lib/figma/audit.js +0 -2
- package/dist/infra/lib/figma/audit.js.map +1 -1
- package/dist/infra/lib/figma/extract.d.ts +6 -1
- package/dist/infra/lib/figma/extract.d.ts.map +1 -1
- package/dist/infra/lib/figma/extract.js +17 -15
- package/dist/infra/lib/figma/extract.js.map +1 -1
- package/dist/infra/lib/figma/types.d.ts +103 -0
- package/dist/infra/lib/figma/types.d.ts.map +1 -1
- package/dist/infra/lib/figma/types.js +8 -0
- package/dist/infra/lib/figma/types.js.map +1 -1
- package/hooks/hooks.json +1 -1
- package/hooks/scripts/clone-extract.js +16 -1
- package/hooks/scripts/code-check.js +72 -55
- package/hooks/scripts/lib/anchor.js +74 -0
- package/hooks/scripts/lib/console-allow.js +66 -0
- package/hooks/scripts/lib/dispatcher.js +71 -19
- package/hooks/scripts/lib/inbox.js +60 -0
- package/hooks/scripts/loop-ledger.js +24 -1
- package/hooks/scripts/post-edit-dispatcher.js +4 -3
- package/hooks/scripts/post-edit.js +2 -2
- package/package.json +13 -9
- package/skills/vibe/SKILL.md +2 -1
- package/skills/vibe.clone/references/verification-loops.md +6 -3
- package/skills/vibe.loop/SKILL.md +7 -4
- package/skills/vibe.review/SKILL.md +5 -1
- package/skills/vibe.run/references/e2e-and-autofix.md +1 -1
- package/skills/vibe.run/references/process-steps.md +1 -1
- package/vibe/constitution.md +1 -1
- package/vibe/rules/loop-contract.md +40 -3
- package/vibe/rules/quality/checklist.md +3 -3
- package/vibe/templates/constitution-template.md +1 -1
- package/dist/__tests__/agent-model-sync.test.d.ts +0 -2
- package/dist/__tests__/agent-model-sync.test.d.ts.map +0 -1
- package/dist/__tests__/agent-model-sync.test.js +0 -71
- package/dist/__tests__/agent-model-sync.test.js.map +0 -1
- package/dist/__tests__/architecture.test.d.ts +0 -2
- package/dist/__tests__/architecture.test.d.ts.map +0 -1
- package/dist/__tests__/architecture.test.js +0 -207
- package/dist/__tests__/architecture.test.js.map +0 -1
- package/dist/__tests__/skill-namespace.test.d.ts +0 -2
- package/dist/__tests__/skill-namespace.test.d.ts.map +0 -1
- package/dist/__tests__/skill-namespace.test.js +0 -60
- package/dist/__tests__/skill-namespace.test.js.map +0 -1
- package/dist/__tests__/stakes-contract.test.d.ts +0 -2
- package/dist/__tests__/stakes-contract.test.d.ts.map +0 -1
- package/dist/__tests__/stakes-contract.test.js +0 -166
- package/dist/__tests__/stakes-contract.test.js.map +0 -1
- package/dist/__tests__/stuck-semantics.test.d.ts +0 -2
- package/dist/__tests__/stuck-semantics.test.d.ts.map +0 -1
- package/dist/__tests__/stuck-semantics.test.js +0 -109
- package/dist/__tests__/stuck-semantics.test.js.map +0 -1
- package/dist/__tests__/wiring-integrity.test.d.ts +0 -2
- package/dist/__tests__/wiring-integrity.test.d.ts.map +0 -1
- package/dist/__tests__/wiring-integrity.test.js +0 -160
- package/dist/__tests__/wiring-integrity.test.js.map +0 -1
- package/dist/cli/commands/info.test.d.ts +0 -2
- package/dist/cli/commands/info.test.d.ts.map +0 -1
- package/dist/cli/commands/info.test.js +0 -74
- package/dist/cli/commands/info.test.js.map +0 -1
- package/dist/cli/commands/upgrade.test.d.ts +0 -2
- package/dist/cli/commands/upgrade.test.d.ts.map +0 -1
- package/dist/cli/commands/upgrade.test.js +0 -99
- package/dist/cli/commands/upgrade.test.js.map +0 -1
- package/dist/cli/design/design-md-parser.test.d.ts +0 -2
- package/dist/cli/design/design-md-parser.test.d.ts.map +0 -1
- package/dist/cli/design/design-md-parser.test.js +0 -149
- package/dist/cli/design/design-md-parser.test.js.map +0 -1
- package/dist/cli/detect.characterization.test.d.ts +0 -7
- package/dist/cli/detect.characterization.test.d.ts.map +0 -1
- package/dist/cli/detect.characterization.test.js +0 -294
- package/dist/cli/detect.characterization.test.js.map +0 -1
- package/dist/cli/postinstall/fs-utils.test.d.ts +0 -2
- package/dist/cli/postinstall/fs-utils.test.d.ts.map +0 -1
- package/dist/cli/postinstall/fs-utils.test.js +0 -259
- package/dist/cli/postinstall/fs-utils.test.js.map +0 -1
- package/dist/cli/setup/CodexHooks.test.d.ts +0 -2
- package/dist/cli/setup/CodexHooks.test.d.ts.map +0 -1
- package/dist/cli/setup/CodexHooks.test.js +0 -52
- package/dist/cli/setup/CodexHooks.test.js.map +0 -1
- package/dist/cli/setup/GlobalInstaller.test.d.ts +0 -2
- package/dist/cli/setup/GlobalInstaller.test.d.ts.map +0 -1
- package/dist/cli/setup/GlobalInstaller.test.js +0 -16
- package/dist/cli/setup/GlobalInstaller.test.js.map +0 -1
- package/dist/cli/utils/cli-detector.test.d.ts +0 -2
- package/dist/cli/utils/cli-detector.test.d.ts.map +0 -1
- package/dist/cli/utils/cli-detector.test.js +0 -52
- package/dist/cli/utils/cli-detector.test.js.map +0 -1
- package/dist/infra/lib/SkillFrontmatter.test.d.ts +0 -2
- package/dist/infra/lib/SkillFrontmatter.test.d.ts.map +0 -1
- package/dist/infra/lib/SkillFrontmatter.test.js +0 -60
- package/dist/infra/lib/SkillFrontmatter.test.js.map +0 -1
- package/dist/infra/lib/__tests__/AutomationLevel.test.d.ts +0 -2
- package/dist/infra/lib/__tests__/AutomationLevel.test.d.ts.map +0 -1
- package/dist/infra/lib/__tests__/AutomationLevel.test.js +0 -297
- package/dist/infra/lib/__tests__/AutomationLevel.test.js.map +0 -1
- package/dist/infra/lib/__tests__/ComponentRegistry.test.d.ts +0 -2
- package/dist/infra/lib/__tests__/ComponentRegistry.test.d.ts.map +0 -1
- package/dist/infra/lib/__tests__/ComponentRegistry.test.js +0 -99
- package/dist/infra/lib/__tests__/ComponentRegistry.test.js.map +0 -1
- package/dist/infra/lib/__tests__/DecisionTracer.test.d.ts +0 -2
- package/dist/infra/lib/__tests__/DecisionTracer.test.d.ts.map +0 -1
- package/dist/infra/lib/__tests__/DecisionTracer.test.js +0 -274
- package/dist/infra/lib/__tests__/DecisionTracer.test.js.map +0 -1
- package/dist/infra/lib/__tests__/InteractiveCheckpoint.test.d.ts +0 -2
- package/dist/infra/lib/__tests__/InteractiveCheckpoint.test.d.ts.map +0 -1
- package/dist/infra/lib/__tests__/InteractiveCheckpoint.test.js +0 -350
- package/dist/infra/lib/__tests__/InteractiveCheckpoint.test.js.map +0 -1
- package/dist/infra/lib/__tests__/LoopBreaker.test.d.ts +0 -2
- package/dist/infra/lib/__tests__/LoopBreaker.test.d.ts.map +0 -1
- package/dist/infra/lib/__tests__/LoopBreaker.test.js +0 -340
- package/dist/infra/lib/__tests__/LoopBreaker.test.js.map +0 -1
- package/dist/infra/lib/__tests__/VerificationLoop.test.d.ts +0 -2
- package/dist/infra/lib/__tests__/VerificationLoop.test.d.ts.map +0 -1
- package/dist/infra/lib/__tests__/VerificationLoop.test.js +0 -486
- package/dist/infra/lib/__tests__/VerificationLoop.test.js.map +0 -1
- package/dist/infra/lib/config/GlobalConfigManager.test.d.ts +0 -2
- package/dist/infra/lib/config/GlobalConfigManager.test.d.ts.map +0 -1
- package/dist/infra/lib/config/GlobalConfigManager.test.js +0 -9
- package/dist/infra/lib/config/GlobalConfigManager.test.js.map +0 -1
- package/dist/infra/lib/embedding/__tests__/EmbeddingProvider.test.d.ts +0 -2
- package/dist/infra/lib/embedding/__tests__/EmbeddingProvider.test.d.ts.map +0 -1
- package/dist/infra/lib/embedding/__tests__/EmbeddingProvider.test.js +0 -43
- package/dist/infra/lib/embedding/__tests__/EmbeddingProvider.test.js.map +0 -1
- package/dist/infra/lib/embedding/__tests__/VectorStore.test.d.ts +0 -2
- package/dist/infra/lib/embedding/__tests__/VectorStore.test.d.ts.map +0 -1
- package/dist/infra/lib/embedding/__tests__/VectorStore.test.js +0 -94
- package/dist/infra/lib/embedding/__tests__/VectorStore.test.js.map +0 -1
- package/dist/infra/lib/embedding/__tests__/cosine.test.d.ts +0 -2
- package/dist/infra/lib/embedding/__tests__/cosine.test.d.ts.map +0 -1
- package/dist/infra/lib/embedding/__tests__/cosine.test.js +0 -73
- package/dist/infra/lib/embedding/__tests__/cosine.test.js.map +0 -1
- package/dist/infra/lib/evolution/__tests__/deprecation.test.d.ts +0 -2
- package/dist/infra/lib/evolution/__tests__/deprecation.test.d.ts.map +0 -1
- package/dist/infra/lib/evolution/__tests__/deprecation.test.js +0 -251
- package/dist/infra/lib/evolution/__tests__/deprecation.test.js.map +0 -1
- package/dist/infra/lib/evolution/__tests__/eval.test.d.ts +0 -2
- package/dist/infra/lib/evolution/__tests__/eval.test.d.ts.map +0 -1
- package/dist/infra/lib/evolution/__tests__/eval.test.js +0 -603
- package/dist/infra/lib/evolution/__tests__/eval.test.js.map +0 -1
- package/dist/infra/lib/evolution/__tests__/generation.test.d.ts +0 -2
- package/dist/infra/lib/evolution/__tests__/generation.test.d.ts.map +0 -1
- package/dist/infra/lib/evolution/__tests__/generation.test.js +0 -396
- package/dist/infra/lib/evolution/__tests__/generation.test.js.map +0 -1
- package/dist/infra/lib/evolution/__tests__/insight.test.d.ts +0 -2
- package/dist/infra/lib/evolution/__tests__/insight.test.d.ts.map +0 -1
- package/dist/infra/lib/evolution/__tests__/insight.test.js +0 -204
- package/dist/infra/lib/evolution/__tests__/insight.test.js.map +0 -1
- package/dist/infra/lib/evolution/__tests__/integration.test.d.ts +0 -2
- package/dist/infra/lib/evolution/__tests__/integration.test.d.ts.map +0 -1
- package/dist/infra/lib/evolution/__tests__/integration.test.js +0 -206
- package/dist/infra/lib/evolution/__tests__/integration.test.js.map +0 -1
- package/dist/infra/lib/evolution/__tests__/lifecycle.test.d.ts +0 -2
- package/dist/infra/lib/evolution/__tests__/lifecycle.test.d.ts.map +0 -1
- package/dist/infra/lib/evolution/__tests__/lifecycle.test.js +0 -350
- package/dist/infra/lib/evolution/__tests__/lifecycle.test.js.map +0 -1
- package/dist/infra/lib/evolution/__tests__/parity.test.d.ts +0 -2
- package/dist/infra/lib/evolution/__tests__/parity.test.d.ts.map +0 -1
- package/dist/infra/lib/evolution/__tests__/parity.test.js +0 -319
- package/dist/infra/lib/evolution/__tests__/parity.test.js.map +0 -1
- package/dist/infra/lib/llm/auth/AuthProfileManager.test.d.ts +0 -5
- package/dist/infra/lib/llm/auth/AuthProfileManager.test.d.ts.map +0 -1
- package/dist/infra/lib/llm/auth/AuthProfileManager.test.js +0 -168
- package/dist/infra/lib/llm/auth/AuthProfileManager.test.js.map +0 -1
- package/dist/infra/lib/llm/auth/TokenRefresher.test.d.ts +0 -2
- package/dist/infra/lib/llm/auth/TokenRefresher.test.d.ts.map +0 -1
- package/dist/infra/lib/llm/auth/TokenRefresher.test.js +0 -120
- package/dist/infra/lib/llm/auth/TokenRefresher.test.js.map +0 -1
- package/dist/infra/lib/llm/timeout.test.d.ts +0 -2
- package/dist/infra/lib/llm/timeout.test.d.ts.map +0 -1
- package/dist/infra/lib/llm/timeout.test.js +0 -50
- package/dist/infra/lib/llm/timeout.test.js.map +0 -1
- package/dist/infra/lib/llm-availability.test.d.ts +0 -2
- package/dist/infra/lib/llm-availability.test.d.ts.map +0 -1
- package/dist/infra/lib/llm-availability.test.js +0 -37
- package/dist/infra/lib/llm-availability.test.js.map +0 -1
- package/dist/infra/lib/memory/KnowledgeGraph.test.d.ts +0 -2
- package/dist/infra/lib/memory/KnowledgeGraph.test.d.ts.map +0 -1
- package/dist/infra/lib/memory/KnowledgeGraph.test.js +0 -189
- package/dist/infra/lib/memory/KnowledgeGraph.test.js.map +0 -1
- package/dist/infra/lib/memory/MemorySearch.test.d.ts +0 -2
- package/dist/infra/lib/memory/MemorySearch.test.d.ts.map +0 -1
- package/dist/infra/lib/memory/MemorySearch.test.js +0 -149
- package/dist/infra/lib/memory/MemorySearch.test.js.map +0 -1
- package/dist/infra/lib/memory/MemoryStorage.test.d.ts +0 -2
- package/dist/infra/lib/memory/MemoryStorage.test.d.ts.map +0 -1
- package/dist/infra/lib/memory/MemoryStorage.test.js +0 -198
- package/dist/infra/lib/memory/MemoryStorage.test.js.map +0 -1
- package/dist/infra/lib/memory/SessionRAGRetriever.test.d.ts +0 -2
- package/dist/infra/lib/memory/SessionRAGRetriever.test.d.ts.map +0 -1
- package/dist/infra/lib/memory/SessionRAGRetriever.test.js +0 -180
- package/dist/infra/lib/memory/SessionRAGRetriever.test.js.map +0 -1
- package/dist/infra/lib/memory/SessionRAGStore.test.d.ts +0 -2
- package/dist/infra/lib/memory/SessionRAGStore.test.d.ts.map +0 -1
- package/dist/infra/lib/memory/SessionRAGStore.test.js +0 -326
- package/dist/infra/lib/memory/SessionRAGStore.test.js.map +0 -1
- package/dist/infra/lib/memory/__tests__/InMemoryStorage.test.d.ts +0 -2
- package/dist/infra/lib/memory/__tests__/InMemoryStorage.test.d.ts.map +0 -1
- package/dist/infra/lib/memory/__tests__/InMemoryStorage.test.js +0 -114
- package/dist/infra/lib/memory/__tests__/InMemoryStorage.test.js.map +0 -1
- package/dist/infra/lib/memory/__tests__/ReflectionStore.test.d.ts +0 -2
- package/dist/infra/lib/memory/__tests__/ReflectionStore.test.d.ts.map +0 -1
- package/dist/infra/lib/memory/__tests__/ReflectionStore.test.js +0 -196
- package/dist/infra/lib/memory/__tests__/ReflectionStore.test.js.map +0 -1
- package/dist/infra/lib/memory/index.test.d.ts +0 -2
- package/dist/infra/lib/memory/index.test.d.ts.map +0 -1
- package/dist/infra/lib/memory/index.test.js +0 -23
- package/dist/infra/lib/memory/index.test.js.map +0 -1
- package/dist/infra/lib/telemetry/SkillTelemetry.test.d.ts +0 -2
- package/dist/infra/lib/telemetry/SkillTelemetry.test.d.ts.map +0 -1
- package/dist/infra/lib/telemetry/SkillTelemetry.test.js +0 -124
- package/dist/infra/lib/telemetry/SkillTelemetry.test.js.map +0 -1
- package/dist/infra/lib/ui-ux/Bm25Engine.test.d.ts +0 -2
- package/dist/infra/lib/ui-ux/Bm25Engine.test.d.ts.map +0 -1
- package/dist/infra/lib/ui-ux/Bm25Engine.test.js +0 -159
- package/dist/infra/lib/ui-ux/Bm25Engine.test.js.map +0 -1
- package/dist/infra/lib/ui-ux/CsvDataLoader.test.d.ts +0 -2
- package/dist/infra/lib/ui-ux/CsvDataLoader.test.d.ts.map +0 -1
- package/dist/infra/lib/ui-ux/CsvDataLoader.test.js +0 -141
- package/dist/infra/lib/ui-ux/CsvDataLoader.test.js.map +0 -1
- package/dist/infra/lib/ui-ux/DesignSystemGenerator.test.d.ts +0 -2
- package/dist/infra/lib/ui-ux/DesignSystemGenerator.test.d.ts.map +0 -1
- package/dist/infra/lib/ui-ux/DesignSystemGenerator.test.js +0 -370
- package/dist/infra/lib/ui-ux/DesignSystemGenerator.test.js.map +0 -1
- package/dist/infra/lib/ui-ux/SearchService.test.d.ts +0 -2
- package/dist/infra/lib/ui-ux/SearchService.test.d.ts.map +0 -1
- package/dist/infra/lib/ui-ux/SearchService.test.js +0 -215
- package/dist/infra/lib/ui-ux/SearchService.test.js.map +0 -1
- package/dist/test-helpers/index.d.ts +0 -36
- package/dist/test-helpers/index.d.ts.map +0 -1
- package/dist/test-helpers/index.js +0 -85
- package/dist/test-helpers/index.js.map +0 -1
- package/dist/test-helpers/index.test.d.ts +0 -2
- package/dist/test-helpers/index.test.d.ts.map +0 -1
- package/dist/test-helpers/index.test.js +0 -92
- package/dist/test-helpers/index.test.js.map +0 -1
- package/dist/tests/curated-release-notes.test.d.ts +0 -2
- package/dist/tests/curated-release-notes.test.d.ts.map +0 -1
- package/dist/tests/curated-release-notes.test.js +0 -160
- package/dist/tests/curated-release-notes.test.js.map +0 -1
- package/dist/tools/convention/analyzeComplexity.test.d.ts +0 -2
- package/dist/tools/convention/analyzeComplexity.test.d.ts.map +0 -1
- package/dist/tools/convention/analyzeComplexity.test.js +0 -207
- package/dist/tools/convention/analyzeComplexity.test.js.map +0 -1
- package/dist/tools/convention/validateCodeQuality.test.d.ts +0 -2
- package/dist/tools/convention/validateCodeQuality.test.d.ts.map +0 -1
- package/dist/tools/convention/validateCodeQuality.test.js +0 -230
- package/dist/tools/convention/validateCodeQuality.test.js.map +0 -1
- package/dist/tools/loop/validateLoopDefinition.test.d.ts +0 -14
- package/dist/tools/loop/validateLoopDefinition.test.d.ts.map +0 -1
- package/dist/tools/loop/validateLoopDefinition.test.js +0 -229
- package/dist/tools/loop/validateLoopDefinition.test.js.map +0 -1
- package/dist/tools/spec/executionPacket.test.d.ts +0 -2
- package/dist/tools/spec/executionPacket.test.d.ts.map +0 -1
- package/dist/tools/spec/executionPacket.test.js +0 -374
- package/dist/tools/spec/executionPacket.test.js.map +0 -1
- package/dist/tools/spec/prdParser.test.d.ts +0 -6
- package/dist/tools/spec/prdParser.test.d.ts.map +0 -1
- package/dist/tools/spec/prdParser.test.js +0 -332
- package/dist/tools/spec/prdParser.test.js.map +0 -1
- package/dist/tools/spec/specGenerator.test.d.ts +0 -2
- package/dist/tools/spec/specGenerator.test.d.ts.map +0 -1
- package/dist/tools/spec/specGenerator.test.js +0 -130
- package/dist/tools/spec/specGenerator.test.js.map +0 -1
- package/dist/tools/spec/traceabilityMatrix.path-resolution.test.d.ts +0 -10
- package/dist/tools/spec/traceabilityMatrix.path-resolution.test.d.ts.map +0 -1
- package/dist/tools/spec/traceabilityMatrix.path-resolution.test.js +0 -120
- package/dist/tools/spec/traceabilityMatrix.path-resolution.test.js.map +0 -1
- package/dist/tools/spec/traceabilityMatrix.test.d.ts +0 -6
- package/dist/tools/spec/traceabilityMatrix.test.d.ts.map +0 -1
- package/dist/tools/spec/traceabilityMatrix.test.js +0 -359
- package/dist/tools/spec/traceabilityMatrix.test.js.map +0 -1
- package/hooks/scripts/__tests__/.vibe/command-log.txt +0 -3
- package/hooks/scripts/__tests__/auto-test-debounce.test.js +0 -145
- package/hooks/scripts/__tests__/clone-behaviors.test.js +0 -152
- package/hooks/scripts/__tests__/clone-merge-responsive.test.js +0 -106
- package/hooks/scripts/__tests__/code-check-detectors.test.js +0 -213
- package/hooks/scripts/__tests__/code-check-memory-write.test.js +0 -81
- package/hooks/scripts/__tests__/codex-hook-adapter.test.js +0 -64
- package/hooks/scripts/__tests__/curation-index.test.js +0 -157
- package/hooks/scripts/__tests__/dispatcher-inprocess.test.js +0 -99
- package/hooks/scripts/__tests__/figma-extract.test.js +0 -338
- package/hooks/scripts/__tests__/hook-payload.test.js +0 -29
- package/hooks/scripts/__tests__/llm-orchestrate-antigravity.test.js +0 -66
- package/hooks/scripts/__tests__/loop-ledger.test.js +0 -321
- package/hooks/scripts/__tests__/post-edit-dispatcher.test.js +0 -139
- package/hooks/scripts/__tests__/pre-tool-guard.test.js +0 -523
- package/hooks/scripts/__tests__/recipe-extractor.test.js +0 -244
- package/hooks/scripts/__tests__/run-ledger-verify-required.test.js +0 -151
- package/hooks/scripts/__tests__/run-ledger.test.js +0 -481
- package/hooks/scripts/__tests__/scope-from-spec.test.js +0 -215
- package/hooks/scripts/__tests__/sentinel-guard.test.js +0 -263
- package/hooks/scripts/__tests__/step-counter.test.js +0 -459
- package/hooks/scripts/__tests__/utils-npm-root.test.js +0 -99
|
@@ -1,603 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
2
|
-
import { join } from 'path';
|
|
3
|
-
import { tmpdir } from 'os';
|
|
4
|
-
import { rmSync } from 'fs';
|
|
5
|
-
import { MemoryStorage } from '../../memory/MemoryStorage.js';
|
|
6
|
-
import { SkillEvalRunner } from '../SkillEvalRunner.js';
|
|
7
|
-
import { SkillBenchmark } from '../SkillBenchmark.js';
|
|
8
|
-
import { SkillClassifier } from '../SkillClassifier.js';
|
|
9
|
-
import { DescriptionOptimizer } from '../DescriptionOptimizer.js';
|
|
10
|
-
// ─── SkillEvalRunner ─────────────────────────────────────────────────────────
|
|
11
|
-
describe('SkillEvalRunner', () => {
|
|
12
|
-
let storage;
|
|
13
|
-
let runner;
|
|
14
|
-
let testDir;
|
|
15
|
-
beforeEach(() => {
|
|
16
|
-
testDir = join(tmpdir(), `eval-runner-${Date.now()}-${Math.random().toString(36).slice(2)}`);
|
|
17
|
-
storage = new MemoryStorage(testDir);
|
|
18
|
-
runner = new SkillEvalRunner(storage);
|
|
19
|
-
});
|
|
20
|
-
afterEach(() => {
|
|
21
|
-
storage.close();
|
|
22
|
-
try {
|
|
23
|
-
rmSync(testDir, { recursive: true, force: true });
|
|
24
|
-
}
|
|
25
|
-
catch { /* ignore */ }
|
|
26
|
-
});
|
|
27
|
-
it('should create eval set and retrieve cases', () => {
|
|
28
|
-
const cases = runner.createEvalSet({
|
|
29
|
-
skillName: 'csv-analyzer',
|
|
30
|
-
evals: [
|
|
31
|
-
{
|
|
32
|
-
prompt: 'Analyze this CSV file and generate a summary',
|
|
33
|
-
expectedOutput: 'A statistical summary of the CSV data',
|
|
34
|
-
files: ['data.csv'],
|
|
35
|
-
assertions: [
|
|
36
|
-
{ description: 'Contains row count', type: 'contains', value: 'rows' },
|
|
37
|
-
{ description: 'Contains column info', type: 'contains', value: 'columns' },
|
|
38
|
-
],
|
|
39
|
-
},
|
|
40
|
-
{
|
|
41
|
-
prompt: 'Parse the CSV and find outliers',
|
|
42
|
-
expectedOutput: 'List of outlier values',
|
|
43
|
-
},
|
|
44
|
-
],
|
|
45
|
-
});
|
|
46
|
-
expect(cases).toHaveLength(2);
|
|
47
|
-
expect(cases[0].skillName).toBe('csv-analyzer');
|
|
48
|
-
expect(cases[0].assertions).toHaveLength(2);
|
|
49
|
-
expect(cases[0].files).toEqual(['data.csv']);
|
|
50
|
-
expect(cases[1].assertions).toHaveLength(0);
|
|
51
|
-
const retrieved = runner.getEvalCases('csv-analyzer');
|
|
52
|
-
expect(retrieved).toHaveLength(2);
|
|
53
|
-
});
|
|
54
|
-
it('should start and complete eval runs', () => {
|
|
55
|
-
const cases = runner.createEvalSet({
|
|
56
|
-
skillName: 'test-skill',
|
|
57
|
-
evals: [{ prompt: 'Test prompt', expectedOutput: 'Expected output' }],
|
|
58
|
-
});
|
|
59
|
-
const runId = runner.startRun(cases[0].id, 'test-skill', 'with_skill');
|
|
60
|
-
expect(runId).toBeTruthy();
|
|
61
|
-
runner.completeRun(runId, 'Generated output with rows and columns', [
|
|
62
|
-
{ assertionId: 'a1', description: 'Has content', passed: true, evidence: 'Output is non-empty' },
|
|
63
|
-
], 1500, 5000);
|
|
64
|
-
const runs = runner.getRunsForEval(cases[0].id);
|
|
65
|
-
expect(runs).toHaveLength(1);
|
|
66
|
-
expect(runs[0].status).toBe('passed');
|
|
67
|
-
expect(runs[0].durationMs).toBe(1500);
|
|
68
|
-
expect(runs[0].tokenCount).toBe(5000);
|
|
69
|
-
});
|
|
70
|
-
it('should mark run as failed when assertions fail', () => {
|
|
71
|
-
const cases = runner.createEvalSet({
|
|
72
|
-
skillName: 'test-skill',
|
|
73
|
-
evals: [{ prompt: 'Test', expectedOutput: 'Expected' }],
|
|
74
|
-
});
|
|
75
|
-
const runId = runner.startRun(cases[0].id, 'test-skill', 'with_skill');
|
|
76
|
-
runner.completeRun(runId, 'Bad output', [
|
|
77
|
-
{ assertionId: 'a1', description: 'Has rows', passed: false, evidence: 'Missing' },
|
|
78
|
-
{ assertionId: 'a2', description: 'Has cols', passed: true, evidence: 'Present' },
|
|
79
|
-
], 1000, 3000);
|
|
80
|
-
const runs = runner.getRunsForEval(cases[0].id);
|
|
81
|
-
expect(runs[0].status).toBe('failed');
|
|
82
|
-
});
|
|
83
|
-
it('should handle error runs', () => {
|
|
84
|
-
const cases = runner.createEvalSet({
|
|
85
|
-
skillName: 'test-skill',
|
|
86
|
-
evals: [{ prompt: 'Test', expectedOutput: 'Expected' }],
|
|
87
|
-
});
|
|
88
|
-
const runId = runner.startRun(cases[0].id, 'test-skill', 'baseline');
|
|
89
|
-
runner.failRun(runId, 'Connection timeout');
|
|
90
|
-
const runs = runner.getRunsForEval(cases[0].id);
|
|
91
|
-
expect(runs[0].status).toBe('error');
|
|
92
|
-
expect(runs[0].output).toBe('Connection timeout');
|
|
93
|
-
});
|
|
94
|
-
it('should grade output against assertions', () => {
|
|
95
|
-
const assertions = [
|
|
96
|
-
{ id: 'a1', description: 'Contains summary', type: 'contains', value: 'summary' },
|
|
97
|
-
{ id: 'a2', description: 'No errors', type: 'not_contains', value: 'error' },
|
|
98
|
-
{ id: 'a3', description: 'Has number', type: 'matches_regex', value: '\\d+' },
|
|
99
|
-
{ id: 'a4', description: 'Custom check', type: 'custom', value: 'quality > 8' },
|
|
100
|
-
];
|
|
101
|
-
const grades = runner.gradeOutput('Here is the summary: 42 items found', assertions);
|
|
102
|
-
expect(grades).toHaveLength(4);
|
|
103
|
-
expect(grades[0].passed).toBe(true); // contains 'summary'
|
|
104
|
-
expect(grades[1].passed).toBe(true); // not contains 'error'
|
|
105
|
-
expect(grades[2].passed).toBe(true); // matches \d+
|
|
106
|
-
expect(grades[3].passed).toBe(false); // custom always false without external grading
|
|
107
|
-
});
|
|
108
|
-
it('should grade failing contains assertion', () => {
|
|
109
|
-
const assertions = [
|
|
110
|
-
{ id: 'a1', description: 'Contains missing word', type: 'contains', value: 'nonexistent' },
|
|
111
|
-
];
|
|
112
|
-
const grades = runner.gradeOutput('Some output text', assertions);
|
|
113
|
-
expect(grades[0].passed).toBe(false);
|
|
114
|
-
expect(grades[0].evidence).toContain('does not contain');
|
|
115
|
-
});
|
|
116
|
-
it('should grade failing not_contains assertion', () => {
|
|
117
|
-
const assertions = [
|
|
118
|
-
{ id: 'a1', description: 'No errors', type: 'not_contains', value: 'error' },
|
|
119
|
-
];
|
|
120
|
-
const grades = runner.gradeOutput('An error occurred', assertions);
|
|
121
|
-
expect(grades[0].passed).toBe(false);
|
|
122
|
-
expect(grades[0].evidence).toContain('unexpectedly contains');
|
|
123
|
-
});
|
|
124
|
-
it('should handle invalid regex gracefully', () => {
|
|
125
|
-
const assertions = [
|
|
126
|
-
{ id: 'a1', description: 'Bad regex', type: 'matches_regex', value: '[invalid' },
|
|
127
|
-
];
|
|
128
|
-
const grades = runner.gradeOutput('test', assertions);
|
|
129
|
-
expect(grades[0].passed).toBe(false);
|
|
130
|
-
expect(grades[0].evidence).toContain('Invalid regex');
|
|
131
|
-
});
|
|
132
|
-
it('should get latest runs grouped by eval and variant', () => {
|
|
133
|
-
const cases = runner.createEvalSet({
|
|
134
|
-
skillName: 'grouped-skill',
|
|
135
|
-
evals: [
|
|
136
|
-
{ prompt: 'Eval 1', expectedOutput: 'Expected 1' },
|
|
137
|
-
{ prompt: 'Eval 2', expectedOutput: 'Expected 2' },
|
|
138
|
-
],
|
|
139
|
-
});
|
|
140
|
-
// Run both variants for eval 1
|
|
141
|
-
const wsRun = runner.startRun(cases[0].id, 'grouped-skill', 'with_skill');
|
|
142
|
-
runner.completeRun(wsRun, 'Output ws', [], 100, 500);
|
|
143
|
-
const blRun = runner.startRun(cases[0].id, 'grouped-skill', 'baseline');
|
|
144
|
-
runner.completeRun(blRun, 'Output bl', [], 200, 600);
|
|
145
|
-
// Only with_skill for eval 2
|
|
146
|
-
const wsRun2 = runner.startRun(cases[1].id, 'grouped-skill', 'with_skill');
|
|
147
|
-
runner.completeRun(wsRun2, 'Output ws2', [], 150, 550);
|
|
148
|
-
const grouped = runner.getLatestRuns('grouped-skill');
|
|
149
|
-
expect(grouped.size).toBe(2);
|
|
150
|
-
const eval1 = grouped.get(cases[0].id);
|
|
151
|
-
expect(eval1?.withSkill).not.toBeNull();
|
|
152
|
-
expect(eval1?.baseline).not.toBeNull();
|
|
153
|
-
const eval2 = grouped.get(cases[1].id);
|
|
154
|
-
expect(eval2?.withSkill).not.toBeNull();
|
|
155
|
-
expect(eval2?.baseline).toBeNull();
|
|
156
|
-
});
|
|
157
|
-
it('should delete eval set and associated runs', () => {
|
|
158
|
-
runner.createEvalSet({
|
|
159
|
-
skillName: 'to-delete',
|
|
160
|
-
evals: [{ prompt: 'Test', expectedOutput: 'Expected' }],
|
|
161
|
-
});
|
|
162
|
-
const cases = runner.getEvalCases('to-delete');
|
|
163
|
-
runner.startRun(cases[0].id, 'to-delete', 'with_skill');
|
|
164
|
-
const deleted = runner.deleteEvalSet('to-delete');
|
|
165
|
-
expect(deleted).toBe(1);
|
|
166
|
-
expect(runner.getEvalCases('to-delete')).toHaveLength(0);
|
|
167
|
-
});
|
|
168
|
-
it('should get eval case by ID', () => {
|
|
169
|
-
const cases = runner.createEvalSet({
|
|
170
|
-
skillName: 'by-id-test',
|
|
171
|
-
evals: [{ prompt: 'Specific prompt', expectedOutput: 'Specific output' }],
|
|
172
|
-
});
|
|
173
|
-
const found = runner.getEvalCase(cases[0].id);
|
|
174
|
-
expect(found).not.toBeNull();
|
|
175
|
-
expect(found.prompt).toBe('Specific prompt');
|
|
176
|
-
const notFound = runner.getEvalCase('nonexistent');
|
|
177
|
-
expect(notFound).toBeNull();
|
|
178
|
-
});
|
|
179
|
-
});
|
|
180
|
-
// ─── SkillBenchmark ──────────────────────────────────────────────────────────
|
|
181
|
-
describe('SkillBenchmark', () => {
|
|
182
|
-
let storage;
|
|
183
|
-
let runner;
|
|
184
|
-
let benchmark;
|
|
185
|
-
let testDir;
|
|
186
|
-
beforeEach(() => {
|
|
187
|
-
testDir = join(tmpdir(), `eval-bench-${Date.now()}-${Math.random().toString(36).slice(2)}`);
|
|
188
|
-
storage = new MemoryStorage(testDir);
|
|
189
|
-
runner = new SkillEvalRunner(storage);
|
|
190
|
-
benchmark = new SkillBenchmark(storage);
|
|
191
|
-
});
|
|
192
|
-
afterEach(() => {
|
|
193
|
-
storage.close();
|
|
194
|
-
try {
|
|
195
|
-
rmSync(testDir, { recursive: true, force: true });
|
|
196
|
-
}
|
|
197
|
-
catch { /* ignore */ }
|
|
198
|
-
});
|
|
199
|
-
function setupSkillWithRuns(skillName, wsPass, blPass) {
|
|
200
|
-
const cases = runner.createEvalSet({
|
|
201
|
-
skillName,
|
|
202
|
-
evals: [
|
|
203
|
-
{ prompt: 'Eval A', expectedOutput: 'Expected A', assertions: [{ description: 'Check A', type: 'contains', value: 'result' }] },
|
|
204
|
-
{ prompt: 'Eval B', expectedOutput: 'Expected B', assertions: [{ description: 'Check B', type: 'contains', value: 'data' }] },
|
|
205
|
-
],
|
|
206
|
-
});
|
|
207
|
-
for (const evalCase of cases) {
|
|
208
|
-
const wsId = runner.startRun(evalCase.id, skillName, 'with_skill');
|
|
209
|
-
const wsOutput = wsPass ? 'Here is the result with data' : 'Incomplete output';
|
|
210
|
-
const wsGrades = runner.gradeOutput(wsOutput, evalCase.assertions);
|
|
211
|
-
runner.completeRun(wsId, wsOutput, wsGrades, 1200, 4500);
|
|
212
|
-
const blId = runner.startRun(evalCase.id, skillName, 'baseline');
|
|
213
|
-
const blOutput = blPass ? 'Here is the result with data' : 'No useful output';
|
|
214
|
-
const blGrades = runner.gradeOutput(blOutput, evalCase.assertions);
|
|
215
|
-
runner.completeRun(blId, blOutput, blGrades, 1500, 5000);
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
it('should aggregate benchmark results', () => {
|
|
219
|
-
setupSkillWithRuns('bench-test', true, false);
|
|
220
|
-
const result = benchmark.aggregate('bench-test');
|
|
221
|
-
expect(result.skillName).toBe('bench-test');
|
|
222
|
-
expect(result.iteration).toBe(1);
|
|
223
|
-
expect(result.summary.totalEvals).toBe(2);
|
|
224
|
-
expect(result.summary.withSkill.passRate).toBe(1.0);
|
|
225
|
-
expect(result.summary.baseline.passRate).toBe(0);
|
|
226
|
-
expect(result.summary.delta.passRateDelta).toBe(1.0);
|
|
227
|
-
expect(result.evalBreakdowns).toHaveLength(2);
|
|
228
|
-
});
|
|
229
|
-
it('should track benchmark history across iterations', () => {
|
|
230
|
-
setupSkillWithRuns('history-test', true, false);
|
|
231
|
-
benchmark.aggregate('history-test');
|
|
232
|
-
// Second iteration with improved baseline
|
|
233
|
-
setupSkillWithRuns('history-test', true, true);
|
|
234
|
-
benchmark.aggregate('history-test');
|
|
235
|
-
const history = benchmark.getHistory('history-test');
|
|
236
|
-
expect(history).toHaveLength(2);
|
|
237
|
-
expect(history[0].iteration).toBe(1);
|
|
238
|
-
expect(history[1].iteration).toBe(2);
|
|
239
|
-
});
|
|
240
|
-
it('should get latest benchmark', () => {
|
|
241
|
-
setupSkillWithRuns('latest-test', true, false);
|
|
242
|
-
benchmark.aggregate('latest-test');
|
|
243
|
-
const latest = benchmark.getLatest('latest-test');
|
|
244
|
-
expect(latest).not.toBeNull();
|
|
245
|
-
expect(latest.iteration).toBe(1);
|
|
246
|
-
const none = benchmark.getLatest('nonexistent');
|
|
247
|
-
expect(none).toBeNull();
|
|
248
|
-
});
|
|
249
|
-
it('should compare two iterations', () => {
|
|
250
|
-
setupSkillWithRuns('compare-test', true, false);
|
|
251
|
-
benchmark.aggregate('compare-test');
|
|
252
|
-
setupSkillWithRuns('compare-test', true, true);
|
|
253
|
-
benchmark.aggregate('compare-test');
|
|
254
|
-
const comparison = benchmark.compare('compare-test', 1, 2);
|
|
255
|
-
expect(comparison.iterationA).not.toBeNull();
|
|
256
|
-
expect(comparison.iterationB).not.toBeNull();
|
|
257
|
-
expect(comparison.improvement).not.toBeNull();
|
|
258
|
-
});
|
|
259
|
-
it('should handle compare with missing iteration', () => {
|
|
260
|
-
const comparison = benchmark.compare('missing', 1, 2);
|
|
261
|
-
expect(comparison.iterationA).toBeNull();
|
|
262
|
-
expect(comparison.iterationB).toBeNull();
|
|
263
|
-
expect(comparison.improvement).toBeNull();
|
|
264
|
-
});
|
|
265
|
-
it('should format benchmark report as markdown', () => {
|
|
266
|
-
setupSkillWithRuns('report-test', true, false);
|
|
267
|
-
const result = benchmark.aggregate('report-test');
|
|
268
|
-
const report = benchmark.formatReport(result);
|
|
269
|
-
expect(report).toContain('# Benchmark: report-test');
|
|
270
|
-
expect(report).toContain('Pass Rate');
|
|
271
|
-
expect(report).toContain('Mean Duration');
|
|
272
|
-
expect(report).toContain('Per-Eval Breakdown');
|
|
273
|
-
});
|
|
274
|
-
it('should compute stddev for duration and tokens', () => {
|
|
275
|
-
const cases = runner.createEvalSet({
|
|
276
|
-
skillName: 'stddev-test',
|
|
277
|
-
evals: [
|
|
278
|
-
{ prompt: 'A', expectedOutput: 'A' },
|
|
279
|
-
{ prompt: 'B', expectedOutput: 'B' },
|
|
280
|
-
{ prompt: 'C', expectedOutput: 'C' },
|
|
281
|
-
],
|
|
282
|
-
});
|
|
283
|
-
// Varying durations and tokens
|
|
284
|
-
const durations = [1000, 2000, 3000];
|
|
285
|
-
const tokens = [4000, 5000, 6000];
|
|
286
|
-
for (let i = 0; i < cases.length; i++) {
|
|
287
|
-
const wsId = runner.startRun(cases[i].id, 'stddev-test', 'with_skill');
|
|
288
|
-
runner.completeRun(wsId, 'output', [], durations[i], tokens[i]);
|
|
289
|
-
const blId = runner.startRun(cases[i].id, 'stddev-test', 'baseline');
|
|
290
|
-
runner.completeRun(blId, 'output', [], durations[i] + 500, tokens[i] + 500);
|
|
291
|
-
}
|
|
292
|
-
const result = benchmark.aggregate('stddev-test');
|
|
293
|
-
expect(result.summary.withSkill.stddevDurationMs).toBeGreaterThan(0);
|
|
294
|
-
expect(result.summary.withSkill.stddevTokens).toBeGreaterThan(0);
|
|
295
|
-
});
|
|
296
|
-
});
|
|
297
|
-
// ─── SkillClassifier ─────────────────────────────────────────────────────────
|
|
298
|
-
describe('SkillClassifier', () => {
|
|
299
|
-
let storage;
|
|
300
|
-
let runner;
|
|
301
|
-
let benchmarkObj;
|
|
302
|
-
let classifier;
|
|
303
|
-
let testDir;
|
|
304
|
-
beforeEach(() => {
|
|
305
|
-
testDir = join(tmpdir(), `eval-class-${Date.now()}-${Math.random().toString(36).slice(2)}`);
|
|
306
|
-
storage = new MemoryStorage(testDir);
|
|
307
|
-
runner = new SkillEvalRunner(storage);
|
|
308
|
-
benchmarkObj = new SkillBenchmark(storage);
|
|
309
|
-
classifier = new SkillClassifier(storage);
|
|
310
|
-
});
|
|
311
|
-
afterEach(() => {
|
|
312
|
-
storage.close();
|
|
313
|
-
try {
|
|
314
|
-
rmSync(testDir, { recursive: true, force: true });
|
|
315
|
-
}
|
|
316
|
-
catch { /* ignore */ }
|
|
317
|
-
});
|
|
318
|
-
function createBenchmark(skillName, wsPassRate, blPassRate) {
|
|
319
|
-
const totalEvals = 10;
|
|
320
|
-
const wsPassCount = Math.round(wsPassRate * totalEvals);
|
|
321
|
-
const blPassCount = Math.round(blPassRate * totalEvals);
|
|
322
|
-
const evals = Array.from({ length: totalEvals }, (_, i) => ({
|
|
323
|
-
prompt: `Eval ${i}`,
|
|
324
|
-
expectedOutput: `Expected ${i}`,
|
|
325
|
-
assertions: [{ description: 'Check', type: 'contains', value: 'pass' }],
|
|
326
|
-
}));
|
|
327
|
-
const cases = runner.createEvalSet({ skillName, evals });
|
|
328
|
-
for (let i = 0; i < cases.length; i++) {
|
|
329
|
-
const wsId = runner.startRun(cases[i].id, skillName, 'with_skill');
|
|
330
|
-
const wsOutput = i < wsPassCount ? 'pass' : 'fail';
|
|
331
|
-
const wsGrades = runner.gradeOutput(wsOutput, cases[i].assertions);
|
|
332
|
-
runner.completeRun(wsId, wsOutput, wsGrades, 1000, 5000);
|
|
333
|
-
const blId = runner.startRun(cases[i].id, skillName, 'baseline');
|
|
334
|
-
const blOutput = i < blPassCount ? 'pass' : 'fail';
|
|
335
|
-
const blGrades = runner.gradeOutput(blOutput, cases[i].assertions);
|
|
336
|
-
runner.completeRun(blId, blOutput, blGrades, 1200, 5500);
|
|
337
|
-
}
|
|
338
|
-
benchmarkObj.aggregate(skillName);
|
|
339
|
-
}
|
|
340
|
-
it('should classify as unknown when no benchmarks exist', () => {
|
|
341
|
-
const result = classifier.classify('nonexistent');
|
|
342
|
-
expect(result.category).toBe('unknown');
|
|
343
|
-
expect(result.confidence).toBe(0);
|
|
344
|
-
expect(result.trend).toBe('insufficient_data');
|
|
345
|
-
});
|
|
346
|
-
it('should classify as capability_uplift when baseline is high', () => {
|
|
347
|
-
createBenchmark('cap-uplift', 0.9, 0.8);
|
|
348
|
-
const result = classifier.classify('cap-uplift');
|
|
349
|
-
expect(result.category).toBe('capability_uplift');
|
|
350
|
-
expect(result.baselinePassRate).toBeGreaterThanOrEqual(0.7);
|
|
351
|
-
});
|
|
352
|
-
it('should classify as encoded_preference when baseline is low and gap is large', () => {
|
|
353
|
-
createBenchmark('enc-pref', 0.9, 0.1);
|
|
354
|
-
const result = classifier.classify('enc-pref');
|
|
355
|
-
expect(result.category).toBe('encoded_preference');
|
|
356
|
-
expect(result.baselinePassRate).toBeLessThanOrEqual(0.3);
|
|
357
|
-
expect(result.withSkillPassRate).toBeGreaterThan(result.baselinePassRate);
|
|
358
|
-
});
|
|
359
|
-
it('should detect converging trend as capability_uplift', () => {
|
|
360
|
-
// First benchmark: large gap
|
|
361
|
-
createBenchmark('converge', 0.9, 0.2);
|
|
362
|
-
// Second benchmark: gap shrinks
|
|
363
|
-
createBenchmark('converge', 0.9, 0.7);
|
|
364
|
-
const result = classifier.classify('converge');
|
|
365
|
-
expect(result.trend).toBe('converging');
|
|
366
|
-
});
|
|
367
|
-
it('should detect stable trend as encoded_preference', () => {
|
|
368
|
-
// Both benchmarks: consistent gap
|
|
369
|
-
createBenchmark('stable', 0.9, 0.1);
|
|
370
|
-
createBenchmark('stable', 0.9, 0.1);
|
|
371
|
-
const result = classifier.classify('stable');
|
|
372
|
-
expect(result.trend).toBe('stable');
|
|
373
|
-
});
|
|
374
|
-
it('should classify from explicit rates', () => {
|
|
375
|
-
const result = classifier.classifyFromRates('test-skill', 0.95, 0.1);
|
|
376
|
-
expect(result.category).toBe('encoded_preference');
|
|
377
|
-
expect(result.skillName).toBe('test-skill');
|
|
378
|
-
});
|
|
379
|
-
it('should detect becoming obsolete', () => {
|
|
380
|
-
createBenchmark('obsolete', 0.9, 0.85);
|
|
381
|
-
const result = classifier.isBecomingObsolete('obsolete');
|
|
382
|
-
expect(result.obsolete).toBe(true);
|
|
383
|
-
expect(result.reason).toContain('well without the skill');
|
|
384
|
-
});
|
|
385
|
-
it('should not flag non-obsolete skills', () => {
|
|
386
|
-
createBenchmark('healthy', 0.9, 0.1);
|
|
387
|
-
const result = classifier.isBecomingObsolete('healthy');
|
|
388
|
-
expect(result.obsolete).toBe(false);
|
|
389
|
-
});
|
|
390
|
-
});
|
|
391
|
-
// ─── DescriptionOptimizer ────────────────────────────────────────────────────
|
|
392
|
-
describe('DescriptionOptimizer', () => {
|
|
393
|
-
let storage;
|
|
394
|
-
let optimizer;
|
|
395
|
-
let testDir;
|
|
396
|
-
beforeEach(() => {
|
|
397
|
-
testDir = join(tmpdir(), `eval-opt-${Date.now()}-${Math.random().toString(36).slice(2)}`);
|
|
398
|
-
storage = new MemoryStorage(testDir);
|
|
399
|
-
optimizer = new DescriptionOptimizer(storage);
|
|
400
|
-
});
|
|
401
|
-
afterEach(() => {
|
|
402
|
-
storage.close();
|
|
403
|
-
try {
|
|
404
|
-
rmSync(testDir, { recursive: true, force: true });
|
|
405
|
-
}
|
|
406
|
-
catch { /* ignore */ }
|
|
407
|
-
});
|
|
408
|
-
it('should split eval set into train/test with stratification', () => {
|
|
409
|
-
const queries = [
|
|
410
|
-
{ query: 'analyze this csv file', shouldTrigger: true },
|
|
411
|
-
{ query: 'parse my spreadsheet data', shouldTrigger: true },
|
|
412
|
-
{ query: 'generate a chart from data', shouldTrigger: true },
|
|
413
|
-
{ query: 'create csv summary', shouldTrigger: true },
|
|
414
|
-
{ query: 'write me an email', shouldTrigger: false },
|
|
415
|
-
{ query: 'fix this bug in the auth module', shouldTrigger: false },
|
|
416
|
-
{ query: 'deploy the application', shouldTrigger: false },
|
|
417
|
-
{ query: 'review my pull request', shouldTrigger: false },
|
|
418
|
-
];
|
|
419
|
-
const { train, test } = optimizer.splitEvalSet(queries);
|
|
420
|
-
// Both sets should have queries
|
|
421
|
-
expect(train.length).toBeGreaterThan(0);
|
|
422
|
-
expect(test.length).toBeGreaterThan(0);
|
|
423
|
-
// Combined should cover all queries
|
|
424
|
-
expect(train.length + test.length).toBe(queries.length);
|
|
425
|
-
// Both sets should have both types
|
|
426
|
-
expect(train.some(q => q.shouldTrigger)).toBe(true);
|
|
427
|
-
expect(train.some(q => !q.shouldTrigger)).toBe(true);
|
|
428
|
-
expect(test.some(q => q.shouldTrigger)).toBe(true);
|
|
429
|
-
expect(test.some(q => !q.shouldTrigger)).toBe(true);
|
|
430
|
-
});
|
|
431
|
-
it('should evaluate description against trigger queries', () => {
|
|
432
|
-
const description = 'Analyze CSV files, parse spreadsheet data, generate statistical summaries';
|
|
433
|
-
const queries = [
|
|
434
|
-
{ query: 'analyze this csv file and show me stats', shouldTrigger: true },
|
|
435
|
-
{ query: 'write a blog post about cooking', shouldTrigger: false },
|
|
436
|
-
];
|
|
437
|
-
const results = optimizer.evaluateDescription(description, queries);
|
|
438
|
-
expect(results).toHaveLength(2);
|
|
439
|
-
expect(results[0].shouldTrigger).toBe(true);
|
|
440
|
-
expect(results[1].shouldTrigger).toBe(false);
|
|
441
|
-
});
|
|
442
|
-
it('should score results correctly', () => {
|
|
443
|
-
const allCorrect = [
|
|
444
|
-
{ query: 'q1', shouldTrigger: true, didTrigger: true, triggerRate: 0.5, correct: true },
|
|
445
|
-
{ query: 'q2', shouldTrigger: false, didTrigger: false, triggerRate: 0.0, correct: true },
|
|
446
|
-
];
|
|
447
|
-
expect(optimizer.scoreResults(allCorrect)).toBe(1.0);
|
|
448
|
-
const halfCorrect = [
|
|
449
|
-
{ query: 'q1', shouldTrigger: true, didTrigger: true, triggerRate: 0.5, correct: true },
|
|
450
|
-
{ query: 'q2', shouldTrigger: false, didTrigger: true, triggerRate: 0.3, correct: false },
|
|
451
|
-
];
|
|
452
|
-
expect(optimizer.scoreResults(halfCorrect)).toBe(0.5);
|
|
453
|
-
expect(optimizer.scoreResults([])).toBe(0);
|
|
454
|
-
});
|
|
455
|
-
it('should suggest improvements for false negatives', () => {
|
|
456
|
-
const description = 'Process data files';
|
|
457
|
-
const failedResults = [
|
|
458
|
-
{ query: 'analyze csv spreadsheet', shouldTrigger: true, didTrigger: false, triggerRate: 0.05, correct: false },
|
|
459
|
-
];
|
|
460
|
-
const improved = optimizer.suggestImprovement(description, failedResults);
|
|
461
|
-
expect(improved).not.toBe(description);
|
|
462
|
-
expect(improved.length).toBeGreaterThan(description.length);
|
|
463
|
-
});
|
|
464
|
-
it('should suggest improvements for false positives', () => {
|
|
465
|
-
const description = 'Analyze data and generate reports from spreadsheets';
|
|
466
|
-
const failedResults = [
|
|
467
|
-
{ query: 'generate random passwords for security testing', shouldTrigger: false, didTrigger: true, triggerRate: 0.2, correct: false },
|
|
468
|
-
];
|
|
469
|
-
const improved = optimizer.suggestImprovement(description, failedResults);
|
|
470
|
-
expect(improved).not.toBe(description);
|
|
471
|
-
expect(improved).toContain('Does NOT');
|
|
472
|
-
});
|
|
473
|
-
it('should return original description when no failures', () => {
|
|
474
|
-
const description = 'Perfect description';
|
|
475
|
-
const improved = optimizer.suggestImprovement(description, []);
|
|
476
|
-
expect(improved).toBe(description);
|
|
477
|
-
});
|
|
478
|
-
it('should run full optimization loop', () => {
|
|
479
|
-
const queries = [
|
|
480
|
-
{ query: 'analyze this csv file and create a statistical report', shouldTrigger: true },
|
|
481
|
-
{ query: 'parse my data spreadsheet and find patterns', shouldTrigger: true },
|
|
482
|
-
{ query: 'summarize the csv columns with averages', shouldTrigger: true },
|
|
483
|
-
{ query: 'generate csv from database export', shouldTrigger: true },
|
|
484
|
-
{ query: 'help me write a novel', shouldTrigger: false },
|
|
485
|
-
{ query: 'fix the authentication bug', shouldTrigger: false },
|
|
486
|
-
{ query: 'deploy to production servers', shouldTrigger: false },
|
|
487
|
-
{ query: 'review this pull request code', shouldTrigger: false },
|
|
488
|
-
];
|
|
489
|
-
const result = optimizer.optimize('csv-analyzer', 'Analyze CSV files', queries, 3);
|
|
490
|
-
expect(result.skillName).toBe('csv-analyzer');
|
|
491
|
-
expect(result.originalDescription).toBe('Analyze CSV files');
|
|
492
|
-
expect(result.candidates.length).toBeGreaterThan(0);
|
|
493
|
-
expect(result.candidates.length).toBeLessThanOrEqual(3);
|
|
494
|
-
// Best description should be selected by test score
|
|
495
|
-
expect(result.bestDescription).toBeTruthy();
|
|
496
|
-
});
|
|
497
|
-
it('should persist and retrieve optimization history', () => {
|
|
498
|
-
const queries = [
|
|
499
|
-
{ query: 'analyze csv data', shouldTrigger: true },
|
|
500
|
-
{ query: 'write a poem', shouldTrigger: false },
|
|
501
|
-
{ query: 'parse spreadsheet', shouldTrigger: true },
|
|
502
|
-
{ query: 'cook dinner recipe', shouldTrigger: false },
|
|
503
|
-
];
|
|
504
|
-
optimizer.optimize('persist-test', 'Initial description', queries, 2);
|
|
505
|
-
const history = optimizer.getHistory('persist-test');
|
|
506
|
-
expect(history).toHaveLength(1);
|
|
507
|
-
const latest = optimizer.getLatest('persist-test');
|
|
508
|
-
expect(latest).not.toBeNull();
|
|
509
|
-
expect(latest.skillName).toBe('persist-test');
|
|
510
|
-
});
|
|
511
|
-
it('should evaluate candidate on both train and test sets', () => {
|
|
512
|
-
const train = [
|
|
513
|
-
{ query: 'analyze csv file', shouldTrigger: true },
|
|
514
|
-
{ query: 'write poetry', shouldTrigger: false },
|
|
515
|
-
];
|
|
516
|
-
const test = [
|
|
517
|
-
{ query: 'parse data spreadsheet', shouldTrigger: true },
|
|
518
|
-
{ query: 'fix security bug', shouldTrigger: false },
|
|
519
|
-
];
|
|
520
|
-
const candidate = optimizer.evaluateCandidate('Analyze CSV data files', train, test, 1);
|
|
521
|
-
expect(candidate.iteration).toBe(1);
|
|
522
|
-
expect(candidate.trainScore).toBeGreaterThanOrEqual(0);
|
|
523
|
-
expect(candidate.trainScore).toBeLessThanOrEqual(1);
|
|
524
|
-
expect(candidate.testScore).toBeGreaterThanOrEqual(0);
|
|
525
|
-
expect(candidate.testScore).toBeLessThanOrEqual(1);
|
|
526
|
-
expect(candidate.results).toHaveLength(4); // train + test
|
|
527
|
-
});
|
|
528
|
-
it('should generate 20-query trigger eval set', () => {
|
|
529
|
-
const queries = optimizer.generateTriggerEvalSet('csv-analyzer', 'Analyze CSV files, parse spreadsheet data, generate statistical summaries and charts');
|
|
530
|
-
expect(queries).toHaveLength(20);
|
|
531
|
-
const shouldTrigger = queries.filter(q => q.shouldTrigger);
|
|
532
|
-
const shouldNot = queries.filter(q => !q.shouldTrigger);
|
|
533
|
-
expect(shouldTrigger).toHaveLength(10);
|
|
534
|
-
expect(shouldNot).toHaveLength(10);
|
|
535
|
-
});
|
|
536
|
-
it('should generate near-miss queries from existing skills', () => {
|
|
537
|
-
const existingSkills = new Map([
|
|
538
|
-
['pdf-processor', 'Process PDF files, extract text and tables from PDF documents'],
|
|
539
|
-
['email-writer', 'Write professional emails, compose messages, draft correspondence'],
|
|
540
|
-
]);
|
|
541
|
-
const queries = optimizer.generateTriggerEvalSet('csv-analyzer', 'Analyze CSV files, parse spreadsheet data, generate statistical summaries', existingSkills);
|
|
542
|
-
expect(queries).toHaveLength(20);
|
|
543
|
-
// Should have near-miss queries from adjacent skills
|
|
544
|
-
const shouldNot = queries.filter(q => !q.shouldTrigger);
|
|
545
|
-
expect(shouldNot.length).toBe(10);
|
|
546
|
-
});
|
|
547
|
-
it('should validate trigger accuracy', () => {
|
|
548
|
-
const result = optimizer.validateTriggers('csv-analyzer', 'Analyze CSV files, parse spreadsheet data, generate statistical summaries', [
|
|
549
|
-
{ query: 'analyze this csv file and show statistics', shouldTrigger: true },
|
|
550
|
-
{ query: 'parse my data spreadsheet', shouldTrigger: true },
|
|
551
|
-
{ query: 'write a poem about nature', shouldTrigger: false },
|
|
552
|
-
{ query: 'deploy to production', shouldTrigger: false },
|
|
553
|
-
]);
|
|
554
|
-
expect(result.accuracy).toBeGreaterThanOrEqual(0);
|
|
555
|
-
expect(result.accuracy).toBeLessThanOrEqual(1);
|
|
556
|
-
expect(result.results).toHaveLength(4);
|
|
557
|
-
expect(Array.isArray(result.falsePositives)).toBe(true);
|
|
558
|
-
expect(Array.isArray(result.falseNegatives)).toBe(true);
|
|
559
|
-
});
|
|
560
|
-
it('should detect trigger collisions between skills', () => {
|
|
561
|
-
const existingSkills = new Map([
|
|
562
|
-
['data-analyzer', 'Analyze data files, parse CSV and JSON, generate reports'],
|
|
563
|
-
['email-writer', 'Write professional emails and compose messages'],
|
|
564
|
-
['pdf-processor', 'Process PDF documents, extract text and tables'],
|
|
565
|
-
]);
|
|
566
|
-
const collisions = optimizer.checkCollisions('csv-analyzer', 'Analyze CSV data files, parse spreadsheets, generate statistical reports', existingSkills);
|
|
567
|
-
// data-analyzer should collide (similar keywords)
|
|
568
|
-
expect(collisions.length).toBeGreaterThanOrEqual(1);
|
|
569
|
-
expect(collisions[0].collidingSkill).toBe('data-analyzer');
|
|
570
|
-
expect(collisions[0].overlapScore).toBeGreaterThan(0);
|
|
571
|
-
expect(collisions[0].sharedKeywords.length).toBeGreaterThan(0);
|
|
572
|
-
});
|
|
573
|
-
it('should batch validate multiple skills', () => {
|
|
574
|
-
const skills = new Map([
|
|
575
|
-
['csv-analyzer', 'Analyze CSV files, parse spreadsheet data, generate statistical summaries'],
|
|
576
|
-
['email-writer', 'Write professional emails, compose messages, draft correspondence'],
|
|
577
|
-
['pdf-processor', 'Process PDF files, extract text and tables from PDF documents'],
|
|
578
|
-
]);
|
|
579
|
-
const results = optimizer.batchValidate(skills, 0.7);
|
|
580
|
-
expect(results).toHaveLength(3);
|
|
581
|
-
for (const result of results) {
|
|
582
|
-
expect(result.skillName).toBeTruthy();
|
|
583
|
-
expect(result.accuracy).toBeGreaterThanOrEqual(0);
|
|
584
|
-
expect(result.accuracy).toBeLessThanOrEqual(1);
|
|
585
|
-
expect(typeof result.needsImprovement).toBe('boolean');
|
|
586
|
-
}
|
|
587
|
-
// Results should be sorted by accuracy (ascending)
|
|
588
|
-
for (let i = 1; i < results.length; i++) {
|
|
589
|
-
expect(results[i].accuracy).toBeGreaterThanOrEqual(results[i - 1].accuracy);
|
|
590
|
-
}
|
|
591
|
-
});
|
|
592
|
-
it('should stop optimization early on perfect score', () => {
|
|
593
|
-
// Simple case where description already matches perfectly
|
|
594
|
-
const queries = [
|
|
595
|
-
{ query: 'csv analysis report with statistics', shouldTrigger: true },
|
|
596
|
-
{ query: 'completely unrelated cooking recipe topic', shouldTrigger: false },
|
|
597
|
-
];
|
|
598
|
-
const result = optimizer.optimize('perfect-test', 'CSV analysis and statistics reporting tool', queries, 5);
|
|
599
|
-
// Should stop before max iterations if already perfect
|
|
600
|
-
expect(result.candidates.length).toBeLessThanOrEqual(5);
|
|
601
|
-
});
|
|
602
|
-
});
|
|
603
|
-
//# sourceMappingURL=eval.test.js.map
|