@codewalla_india/openspec 1.3.0 → 1.3.2
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/LICENSE +22 -22
- package/README.md +272 -230
- package/bin/openspec.js +5 -5
- package/dist/cli/index.js +99 -62
- package/dist/commands/change.d.ts +0 -2
- package/dist/commands/change.js +107 -86
- package/dist/commands/config.js +14 -16
- package/dist/commands/doctor.js +9 -4
- package/dist/commands/feedback.js +79 -30
- package/dist/commands/modify.d.ts +26 -0
- package/dist/commands/modify.js +147 -0
- package/dist/commands/schema.js +170 -91
- package/dist/commands/show.js +5 -2
- package/dist/commands/spec.js +49 -29
- package/dist/commands/store.js +15 -21
- package/dist/commands/validate.d.ts +8 -0
- package/dist/commands/validate.js +43 -20
- package/dist/commands/workflow/index.d.ts +2 -2
- package/dist/commands/workflow/index.js +1 -1
- package/dist/commands/workflow/instructions.d.ts +6 -26
- package/dist/commands/workflow/instructions.js +183 -376
- package/dist/commands/workflow/new-change.d.ts +0 -4
- package/dist/commands/workflow/new-change.js +10 -28
- package/dist/commands/workflow/shared.d.ts +34 -19
- package/dist/commands/workflow/shared.js +34 -4
- package/dist/commands/workflow/status.js +10 -32
- package/dist/commands/workflow/templates.js +15 -5
- package/dist/commands/workset.d.ts +2 -2
- package/dist/commands/workset.js +19 -22
- package/dist/comprehension-quiz/fingerprint.d.ts +39 -0
- package/dist/comprehension-quiz/fingerprint.js +84 -0
- package/dist/comprehension-quiz/index.d.ts +42 -0
- package/dist/comprehension-quiz/index.js +47 -0
- package/dist/comprehension-quiz/pass-record.d.ts +44 -0
- package/dist/comprehension-quiz/pass-record.js +98 -0
- package/dist/comprehension-quiz/providers/anthropic.d.ts +34 -0
- package/dist/comprehension-quiz/providers/anthropic.js +53 -0
- package/dist/comprehension-quiz/providers/factory.d.ts +44 -0
- package/dist/comprehension-quiz/providers/factory.js +174 -0
- package/dist/comprehension-quiz/providers/interface.d.ts +59 -0
- package/dist/comprehension-quiz/providers/interface.js +63 -0
- package/dist/comprehension-quiz/providers/local.d.ts +34 -0
- package/dist/comprehension-quiz/providers/local.js +53 -0
- package/dist/comprehension-quiz/providers/ollama.d.ts +34 -0
- package/dist/comprehension-quiz/providers/ollama.js +53 -0
- package/dist/comprehension-quiz/providers/openai.d.ts +34 -0
- package/dist/comprehension-quiz/providers/openai.js +53 -0
- package/dist/comprehension-quiz/question-generator.d.ts +69 -0
- package/dist/comprehension-quiz/question-generator.js +141 -0
- package/dist/comprehension-quiz/quiz-executor.d.ts +70 -0
- package/dist/comprehension-quiz/quiz-executor.js +165 -0
- package/dist/comprehension-quiz/types.d.ts +115 -0
- package/dist/comprehension-quiz/types.js +11 -0
- package/dist/core/archive.d.ts +14 -1
- package/dist/core/archive.js +1350 -190
- package/dist/core/artifact-graph/graph.d.ts +28 -9
- package/dist/core/artifact-graph/graph.js +94 -43
- package/dist/core/artifact-graph/index.d.ts +1 -1
- package/dist/core/artifact-graph/index.js +1 -1
- package/dist/core/artifact-graph/instruction-loader.d.ts +30 -3
- package/dist/core/artifact-graph/instruction-loader.js +70 -12
- package/dist/core/artifact-graph/outputs.d.ts +1 -0
- package/dist/core/artifact-graph/outputs.js +67 -5
- package/dist/core/artifact-graph/resolver.d.ts +14 -0
- package/dist/core/artifact-graph/resolver.js +69 -15
- package/dist/core/artifact-graph/types.js +21 -3
- package/dist/core/available-tools.d.ts +2 -2
- package/dist/core/available-tools.js +14 -3
- package/dist/core/change-metadata/schema.d.ts +2 -0
- package/dist/core/change-metadata/schema.js +13 -0
- package/dist/core/change-status-policy.d.ts +10 -1
- package/dist/core/change-status-policy.js +30 -2
- package/dist/core/command-generation/adapters/amazon-q.d.ts +4 -0
- package/dist/core/command-generation/adapters/amazon-q.js +11 -5
- package/dist/core/command-generation/adapters/antigravity.js +6 -5
- package/dist/core/command-generation/adapters/auggie.js +7 -6
- package/dist/core/command-generation/adapters/bob.d.ts +5 -1
- package/dist/core/command-generation/adapters/bob.js +11 -10
- package/dist/core/command-generation/adapters/claude.d.ts +1 -1
- package/dist/core/command-generation/adapters/claude.js +12 -17
- package/dist/core/command-generation/adapters/cline.js +5 -5
- package/dist/core/command-generation/adapters/codebuddy.js +8 -7
- package/dist/core/command-generation/adapters/continue.js +8 -7
- package/dist/core/command-generation/adapters/costrict.js +7 -6
- package/dist/core/command-generation/adapters/crush.js +9 -9
- package/dist/core/command-generation/adapters/cursor.js +8 -8
- package/dist/core/command-generation/adapters/devin.d.ts +19 -0
- package/dist/core/command-generation/adapters/devin.js +36 -0
- package/dist/core/command-generation/adapters/factory.js +7 -6
- package/dist/core/command-generation/adapters/gemini.js +40 -5
- package/dist/core/command-generation/adapters/github-copilot.js +6 -5
- package/dist/core/command-generation/adapters/iflow.js +9 -8
- package/dist/core/command-generation/adapters/index.d.ts +4 -2
- package/dist/core/command-generation/adapters/index.js +4 -2
- package/dist/core/command-generation/adapters/junie.js +6 -5
- package/dist/core/command-generation/adapters/kilocode.js +1 -1
- package/dist/core/command-generation/adapters/kiro.js +6 -5
- package/dist/core/command-generation/adapters/lingma.js +9 -9
- package/dist/core/command-generation/adapters/oh-my-pi.d.ts +21 -0
- package/dist/core/command-generation/adapters/oh-my-pi.js +42 -0
- package/dist/core/command-generation/adapters/opencode.js +6 -8
- package/dist/core/command-generation/adapters/pi.d.ts +2 -2
- package/dist/core/command-generation/adapters/pi.js +7 -10
- package/dist/core/command-generation/adapters/qoder.js +9 -9
- package/dist/core/command-generation/adapters/qwen.d.ts +7 -3
- package/dist/core/command-generation/adapters/qwen.js +14 -9
- package/dist/core/command-generation/adapters/roocode.d.ts +4 -4
- package/dist/core/command-generation/adapters/roocode.js +9 -9
- package/dist/core/command-generation/adapters/trae.d.ts +13 -0
- package/dist/core/command-generation/adapters/trae.js +28 -0
- package/dist/core/command-generation/adapters/zcode.d.ts +16 -0
- package/dist/core/command-generation/adapters/zcode.js +33 -0
- package/dist/core/command-generation/generator.d.ts +8 -0
- package/dist/core/command-generation/generator.js +15 -1
- package/dist/core/command-generation/index.d.ts +1 -1
- package/dist/core/command-generation/index.js +1 -1
- package/dist/core/command-generation/invocation.d.ts +73 -0
- package/dist/core/command-generation/invocation.js +77 -0
- package/dist/core/command-generation/registry.js +8 -4
- package/dist/core/command-generation/types.d.ts +9 -2
- package/dist/core/command-generation/yaml.d.ts +20 -6
- package/dist/core/command-generation/yaml.js +31 -21
- package/dist/core/command-surface.d.ts +15 -0
- package/dist/core/command-surface.js +33 -0
- package/dist/core/completions/command-registry.js +16 -61
- package/dist/core/completions/generators/bash-generator.js +41 -41
- package/dist/core/completions/generators/fish-generator.js +7 -7
- package/dist/core/completions/generators/powershell-generator.js +44 -37
- package/dist/core/completions/generators/zsh-generator.js +33 -33
- package/dist/core/completions/installers/zsh-installer.d.ts +9 -0
- package/dist/core/completions/installers/zsh-installer.js +20 -4
- package/dist/core/completions/templates/bash-templates.js +24 -24
- package/dist/core/completions/templates/fish-templates.js +38 -38
- package/dist/core/completions/templates/powershell-templates.js +28 -28
- package/dist/core/completions/templates/zsh-templates.js +39 -39
- package/dist/core/config-prompts.d.ts +1 -1
- package/dist/core/config-prompts.js +14 -1
- package/dist/core/config-schema.d.ts +10 -1
- package/dist/core/config-schema.js +67 -1
- package/dist/core/config.d.ts +15 -0
- package/dist/core/config.js +46 -5
- package/dist/core/file-state.js +56 -24
- package/dist/core/github-copilot/cloud-agent.d.ts +95 -0
- package/dist/core/github-copilot/cloud-agent.js +497 -0
- package/dist/core/global-config.d.ts +16 -0
- package/dist/core/init.d.ts +58 -0
- package/dist/core/init.js +474 -73
- package/dist/core/legacy-cleanup.d.ts +59 -0
- package/dist/core/legacy-cleanup.js +253 -24
- package/dist/core/list.js +23 -16
- package/dist/core/migration.d.ts +73 -1
- package/dist/core/migration.js +360 -11
- package/dist/core/modify/conflict-detector.d.ts +26 -0
- package/dist/core/modify/conflict-detector.js +62 -0
- package/dist/core/modify/dependency-propagator.d.ts +38 -0
- package/dist/core/modify/dependency-propagator.js +103 -0
- package/dist/core/modify/history-tracker.d.ts +34 -0
- package/dist/core/modify/history-tracker.js +114 -0
- package/dist/core/modify/index.d.ts +7 -0
- package/dist/core/modify/index.js +7 -0
- package/dist/core/onboarding-commands.d.ts +30 -0
- package/dist/core/onboarding-commands.js +38 -0
- package/dist/core/openspec-root.js +18 -15
- package/dist/core/parsers/change-parser.d.ts +17 -2
- package/dist/core/parsers/change-parser.js +35 -21
- package/dist/core/parsers/code-fence.d.ts +15 -0
- package/dist/core/parsers/code-fence.js +49 -0
- package/dist/core/parsers/markdown-parser.d.ts +0 -3
- package/dist/core/parsers/markdown-parser.js +7 -60
- package/dist/core/parsers/requirement-blocks.d.ts +29 -0
- package/dist/core/parsers/requirement-blocks.js +150 -31
- package/dist/core/parsers/requirement-text.d.ts +48 -0
- package/dist/core/parsers/requirement-text.js +98 -0
- package/dist/core/parsers/spec-structure.d.ts +1 -1
- package/dist/core/parsers/spec-structure.js +20 -30
- package/dist/core/profile-sync-drift.d.ts +0 -8
- package/dist/core/profile-sync-drift.js +49 -50
- package/dist/core/profiles.d.ts +2 -2
- package/dist/core/profiles.js +2 -2
- package/dist/core/project-config.d.ts +27 -18
- package/dist/core/project-config.js +101 -34
- package/dist/core/references.js +42 -4
- package/dist/core/relationship-health.d.ts +8 -0
- package/dist/core/relationship-health.js +13 -0
- package/dist/core/root-selection.d.ts +9 -6
- package/dist/core/root-selection.js +42 -5
- package/dist/core/schemas/base.schema.js +7 -2
- package/dist/core/shared/allowed-tools.d.ts +12 -0
- package/dist/core/shared/allowed-tools.js +12 -0
- package/dist/core/shared/index.d.ts +1 -0
- package/dist/core/shared/index.js +1 -0
- package/dist/core/shared/skill-content-equivalence.d.ts +7 -0
- package/dist/core/shared/skill-content-equivalence.js +41 -0
- package/dist/core/shared/skill-generation.js +17 -13
- package/dist/core/shared/skill-paths.d.ts +13 -0
- package/dist/core/shared/skill-paths.js +23 -0
- package/dist/core/shared/tool-detection.d.ts +27 -7
- package/dist/core/shared/tool-detection.js +167 -37
- package/dist/core/shared-skill-target.d.ts +16 -0
- package/dist/core/shared-skill-target.js +156 -0
- package/dist/core/specs-apply.d.ts +80 -33
- package/dist/core/specs-apply.js +667 -145
- package/dist/core/store/git.d.ts +13 -0
- package/dist/core/store/git.js +24 -0
- package/dist/core/store/operations.js +20 -0
- package/dist/core/templates/skill-templates.d.ts +3 -2
- package/dist/core/templates/skill-templates.js +3 -2
- package/dist/core/templates/workflows/apply-change.d.ts +10 -0
- package/dist/core/templates/workflows/apply-change.js +186 -323
- package/dist/core/templates/workflows/archive-change.js +387 -260
- package/dist/core/templates/workflows/bulk-archive-change.js +655 -475
- package/dist/core/templates/workflows/continue-change.js +210 -219
- package/dist/core/templates/workflows/explore.js +479 -443
- package/dist/core/templates/workflows/feedback.js +97 -97
- package/dist/core/templates/workflows/ff-change.js +200 -191
- package/dist/core/templates/workflows/modify-change.d.ts +4 -1
- package/dist/core/templates/workflows/modify-change.js +237 -115
- package/dist/core/templates/workflows/new-change.js +127 -134
- package/dist/core/templates/workflows/onboard.js +548 -542
- package/dist/core/templates/workflows/propose.js +273 -217
- package/dist/core/templates/workflows/store-selection.d.ts +1 -1
- package/dist/core/templates/workflows/store-selection.js +1 -1
- package/dist/core/templates/workflows/sync-specs.js +500 -273
- package/dist/core/templates/workflows/update-change.d.ts +10 -0
- package/dist/core/templates/workflows/update-change.js +177 -0
- package/dist/core/templates/workflows/verify-change.js +324 -326
- package/dist/core/update.d.ts +40 -5
- package/dist/core/update.js +411 -96
- package/dist/core/validation/constants.d.ts +4 -1
- package/dist/core/validation/constants.js +4 -1
- package/dist/core/validation/plan-validator.d.ts +8 -0
- package/dist/core/validation/plan-validator.js +45 -0
- package/dist/core/validation/task-numbering.d.ts +16 -0
- package/dist/core/validation/task-numbering.js +57 -0
- package/dist/core/validation/validator.d.ts +27 -3
- package/dist/core/validation/validator.js +337 -48
- package/dist/core/version-check.d.ts +152 -0
- package/dist/core/version-check.js +731 -0
- package/dist/core/view.js +13 -18
- package/dist/prompts/searchable-multi-select.js +1 -1
- package/dist/telemetry/caller-detection.d.ts +27 -0
- package/dist/telemetry/caller-detection.js +85 -0
- package/dist/telemetry/caller-detection.test.d.ts +5 -0
- package/dist/telemetry/config.d.ts +48 -2
- package/dist/telemetry/config.js +113 -11
- package/dist/telemetry/config.test.d.ts +5 -0
- package/dist/telemetry/deduplication.d.ts +35 -0
- package/dist/telemetry/deduplication.js +82 -0
- package/dist/telemetry/deduplication.test.d.ts +5 -0
- package/dist/telemetry/identity.d.ts +62 -22
- package/dist/telemetry/identity.js +147 -102
- package/dist/telemetry/index.d.ts +126 -15
- package/dist/telemetry/index.js +569 -37
- package/dist/telemetry/sanitization.d.ts +40 -0
- package/dist/telemetry/sanitization.js +114 -0
- package/dist/telemetry/sanitization.test.d.ts +5 -0
- package/dist/telemetry/throttling.d.ts +20 -0
- package/dist/telemetry/throttling.js +70 -0
- package/dist/ui/welcome-screen.d.ts +9 -1
- package/dist/ui/welcome-screen.js +91 -38
- package/dist/utils/change-metadata.d.ts +43 -0
- package/dist/utils/change-metadata.js +123 -7
- package/dist/utils/change-utils.d.ts +10 -4
- package/dist/utils/change-utils.js +20 -13
- package/dist/utils/ci.d.ts +12 -0
- package/dist/utils/ci.js +16 -0
- package/dist/utils/command-references.d.ts +92 -6
- package/dist/utils/command-references.js +180 -7
- package/dist/utils/date.d.ts +8 -0
- package/dist/utils/date.js +13 -0
- package/dist/utils/file-system.d.ts +10 -0
- package/dist/utils/file-system.js +70 -0
- package/dist/utils/index.d.ts +1 -1
- package/dist/utils/index.js +1 -1
- package/dist/utils/interactive.d.ts +23 -0
- package/dist/utils/interactive.js +32 -0
- package/dist/utils/item-discovery.d.ts +19 -0
- package/dist/utils/item-discovery.js +30 -48
- package/dist/utils/shell-detection.d.ts +1 -1
- package/dist/utils/shell-detection.js +64 -11
- package/dist/utils/spec-discovery.d.ts +40 -0
- package/dist/utils/spec-discovery.js +115 -0
- package/dist/utils/task-progress.d.ts +29 -1
- package/dist/utils/task-progress.js +109 -15
- package/package.json +96 -84
- package/schemas/spec-driven/schema.yaml +252 -184
- package/schemas/spec-driven/templates/design.md +19 -19
- package/schemas/spec-driven/templates/plan-template.md +91 -0
- package/schemas/spec-driven/templates/proposal.md +29 -24
- package/schemas/spec-driven/templates/spec.md +11 -8
- package/schemas/spec-driven/templates/tasks.md +9 -9
- package/scripts/postinstall.js +83 -83
- package/dist/core/command-generation/adapters/codex.d.ts +0 -16
- package/dist/core/command-generation/adapters/codex.js +0 -39
- package/dist/core/command-generation/adapters/windsurf.d.ts +0 -14
- package/dist/core/command-generation/adapters/windsurf.js +0 -38
- package/dist/core/comprehension/config.d.ts +0 -20
- package/dist/core/comprehension/config.js +0 -23
- package/dist/core/comprehension/fingerprint.d.ts +0 -14
- package/dist/core/comprehension/fingerprint.js +0 -33
- package/dist/core/comprehension/index.d.ts +0 -57
- package/dist/core/comprehension/index.js +0 -87
- package/dist/core/comprehension/pass-record.d.ts +0 -29
- package/dist/core/comprehension/pass-record.js +0 -64
- package/dist/core/comprehension/stats.d.ts +0 -35
- package/dist/core/comprehension/stats.js +0 -133
- package/dist/core/templates/workflows/comprehension-guidance.d.ts +0 -9
- package/dist/core/templates/workflows/comprehension-guidance.js +0 -71
- package/dist/core/templates/workflows/mcp-guidance.d.ts +0 -13
- package/dist/core/templates/workflows/mcp-guidance.js +0 -131
- package/dist/core/templates/workflows/user-prompt-guidance.d.ts +0 -16
- package/dist/core/templates/workflows/user-prompt-guidance.js +0 -48
- package/dist/telemetry/caller.d.ts +0 -5
- package/dist/telemetry/caller.js +0 -29
- package/dist/telemetry/client.d.ts +0 -27
- package/dist/telemetry/client.js +0 -127
- package/dist/telemetry/command-context.d.ts +0 -13
- package/dist/telemetry/command-context.js +0 -59
- package/dist/telemetry/comprehension.d.ts +0 -44
- package/dist/telemetry/comprehension.js +0 -105
- package/dist/telemetry/content.d.ts +0 -10
- package/dist/telemetry/content.js +0 -56
- package/dist/telemetry/git-stats.d.ts +0 -12
- package/dist/telemetry/git-stats.js +0 -69
- package/dist/telemetry/identify-cache.d.ts +0 -7
- package/dist/telemetry/identify-cache.js +0 -47
- package/dist/telemetry/input.d.ts +0 -17
- package/dist/telemetry/input.js +0 -68
- package/dist/telemetry/marker.d.ts +0 -37
- package/dist/telemetry/marker.js +0 -67
- package/dist/telemetry/workflow.d.ts +0 -85
- package/dist/telemetry/workflow.js +0 -318
- package/schemas/spec-driven/templates/plan.md +0 -19
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Local model provider implementation
|
|
3
|
+
*
|
|
4
|
+
* This module implements the local model LLM provider for question generation.
|
|
5
|
+
* It supports running local models for offline or private question generation.
|
|
6
|
+
*
|
|
7
|
+
* @module comprehension-quiz/providers/local
|
|
8
|
+
*/
|
|
9
|
+
import { BaseProvider } from './interface.js';
|
|
10
|
+
/**
|
|
11
|
+
* Local model provider for question generation
|
|
12
|
+
*
|
|
13
|
+
* Requires LOCAL_MODEL_PATH environment variable to be set.
|
|
14
|
+
*/
|
|
15
|
+
export class LocalProvider extends BaseProvider {
|
|
16
|
+
constructor(config) {
|
|
17
|
+
super(config);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Validate local model configuration
|
|
21
|
+
*
|
|
22
|
+
* @throws Error if model path is missing
|
|
23
|
+
*/
|
|
24
|
+
validateConfig() {
|
|
25
|
+
if (!this.config.model) {
|
|
26
|
+
throw new Error('LOCAL_MODEL_PATH environment variable is required for local provider');
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Generate quiz questions using local model
|
|
31
|
+
*
|
|
32
|
+
* @param artifactContent - The content of the artifact to generate questions from
|
|
33
|
+
* @param questionCount - Number of questions to generate
|
|
34
|
+
* @param artifactType - Type of artifact (proposal, design, specs, plan, tasks)
|
|
35
|
+
* @returns Array of generated questions
|
|
36
|
+
*/
|
|
37
|
+
async generateQuestions(artifactContent, questionCount, artifactType) {
|
|
38
|
+
// TODO: Implement local model inference
|
|
39
|
+
// For now, return placeholder questions
|
|
40
|
+
const questions = [];
|
|
41
|
+
for (let i = 0; i < questionCount; i++) {
|
|
42
|
+
questions.push({
|
|
43
|
+
text: `Sample question ${i + 1} for ${artifactType}`,
|
|
44
|
+
options: ['Option A', 'Option B', 'Option C'],
|
|
45
|
+
correctOption: 0,
|
|
46
|
+
artifactSource: artifactType,
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
this.validateQuestions(questions);
|
|
50
|
+
return questions;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=local.js.map
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ollama provider implementation
|
|
3
|
+
*
|
|
4
|
+
* This module implements the Ollama LLM provider for question generation.
|
|
5
|
+
* It uses the Ollama API to generate quiz questions from artifact content.
|
|
6
|
+
*
|
|
7
|
+
* @module comprehension-quiz/providers/ollama
|
|
8
|
+
*/
|
|
9
|
+
import { BaseProvider } from './interface.js';
|
|
10
|
+
import type { ProviderConfig, Question } from '../types.js';
|
|
11
|
+
/**
|
|
12
|
+
* Ollama provider for question generation
|
|
13
|
+
*
|
|
14
|
+
* Requires OLLAMA_BASE_URL environment variable to be set.
|
|
15
|
+
*/
|
|
16
|
+
export declare class OllamaProvider extends BaseProvider {
|
|
17
|
+
constructor(config: ProviderConfig);
|
|
18
|
+
/**
|
|
19
|
+
* Validate Ollama configuration
|
|
20
|
+
*
|
|
21
|
+
* @throws Error if endpoint is missing
|
|
22
|
+
*/
|
|
23
|
+
validateConfig(): void;
|
|
24
|
+
/**
|
|
25
|
+
* Generate quiz questions using Ollama API
|
|
26
|
+
*
|
|
27
|
+
* @param artifactContent - The content of the artifact to generate questions from
|
|
28
|
+
* @param questionCount - Number of questions to generate
|
|
29
|
+
* @param artifactType - Type of artifact (proposal, design, specs, plan, tasks)
|
|
30
|
+
* @returns Array of generated questions
|
|
31
|
+
*/
|
|
32
|
+
generateQuestions(artifactContent: string, questionCount: number, artifactType: 'proposal' | 'design' | 'specs' | 'plan' | 'tasks'): Promise<Question[]>;
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=ollama.d.ts.map
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ollama provider implementation
|
|
3
|
+
*
|
|
4
|
+
* This module implements the Ollama LLM provider for question generation.
|
|
5
|
+
* It uses the Ollama API to generate quiz questions from artifact content.
|
|
6
|
+
*
|
|
7
|
+
* @module comprehension-quiz/providers/ollama
|
|
8
|
+
*/
|
|
9
|
+
import { BaseProvider } from './interface.js';
|
|
10
|
+
/**
|
|
11
|
+
* Ollama provider for question generation
|
|
12
|
+
*
|
|
13
|
+
* Requires OLLAMA_BASE_URL environment variable to be set.
|
|
14
|
+
*/
|
|
15
|
+
export class OllamaProvider extends BaseProvider {
|
|
16
|
+
constructor(config) {
|
|
17
|
+
super(config);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Validate Ollama configuration
|
|
21
|
+
*
|
|
22
|
+
* @throws Error if endpoint is missing
|
|
23
|
+
*/
|
|
24
|
+
validateConfig() {
|
|
25
|
+
if (!this.config.endpoint) {
|
|
26
|
+
throw new Error('OLLAMA_BASE_URL environment variable is required for Ollama provider');
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Generate quiz questions using Ollama API
|
|
31
|
+
*
|
|
32
|
+
* @param artifactContent - The content of the artifact to generate questions from
|
|
33
|
+
* @param questionCount - Number of questions to generate
|
|
34
|
+
* @param artifactType - Type of artifact (proposal, design, specs, plan, tasks)
|
|
35
|
+
* @returns Array of generated questions
|
|
36
|
+
*/
|
|
37
|
+
async generateQuestions(artifactContent, questionCount, artifactType) {
|
|
38
|
+
// TODO: Implement Ollama API call
|
|
39
|
+
// For now, return placeholder questions
|
|
40
|
+
const questions = [];
|
|
41
|
+
for (let i = 0; i < questionCount; i++) {
|
|
42
|
+
questions.push({
|
|
43
|
+
text: `Sample question ${i + 1} for ${artifactType}`,
|
|
44
|
+
options: ['Option A', 'Option B', 'Option C'],
|
|
45
|
+
correctOption: 0,
|
|
46
|
+
artifactSource: artifactType,
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
this.validateQuestions(questions);
|
|
50
|
+
return questions;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=ollama.js.map
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenAI provider implementation
|
|
3
|
+
*
|
|
4
|
+
* This module implements the OpenAI LLM provider for question generation.
|
|
5
|
+
* It uses the OpenAI API to generate quiz questions from artifact content.
|
|
6
|
+
*
|
|
7
|
+
* @module comprehension-quiz/providers/openai
|
|
8
|
+
*/
|
|
9
|
+
import { BaseProvider } from './interface.js';
|
|
10
|
+
import type { ProviderConfig, Question } from '../types.js';
|
|
11
|
+
/**
|
|
12
|
+
* OpenAI provider for question generation
|
|
13
|
+
*
|
|
14
|
+
* Requires OPENAI_API_KEY environment variable to be set.
|
|
15
|
+
*/
|
|
16
|
+
export declare class OpenAIProvider extends BaseProvider {
|
|
17
|
+
constructor(config: ProviderConfig);
|
|
18
|
+
/**
|
|
19
|
+
* Validate OpenAI configuration
|
|
20
|
+
*
|
|
21
|
+
* @throws Error if API key is missing
|
|
22
|
+
*/
|
|
23
|
+
validateConfig(): void;
|
|
24
|
+
/**
|
|
25
|
+
* Generate quiz questions using OpenAI API
|
|
26
|
+
*
|
|
27
|
+
* @param artifactContent - The content of the artifact to generate questions from
|
|
28
|
+
* @param questionCount - Number of questions to generate
|
|
29
|
+
* @param artifactType - Type of artifact (proposal, design, specs, plan, tasks)
|
|
30
|
+
* @returns Array of generated questions
|
|
31
|
+
*/
|
|
32
|
+
generateQuestions(artifactContent: string, questionCount: number, artifactType: 'proposal' | 'design' | 'specs' | 'plan' | 'tasks'): Promise<Question[]>;
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=openai.d.ts.map
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenAI provider implementation
|
|
3
|
+
*
|
|
4
|
+
* This module implements the OpenAI LLM provider for question generation.
|
|
5
|
+
* It uses the OpenAI API to generate quiz questions from artifact content.
|
|
6
|
+
*
|
|
7
|
+
* @module comprehension-quiz/providers/openai
|
|
8
|
+
*/
|
|
9
|
+
import { BaseProvider } from './interface.js';
|
|
10
|
+
/**
|
|
11
|
+
* OpenAI provider for question generation
|
|
12
|
+
*
|
|
13
|
+
* Requires OPENAI_API_KEY environment variable to be set.
|
|
14
|
+
*/
|
|
15
|
+
export class OpenAIProvider extends BaseProvider {
|
|
16
|
+
constructor(config) {
|
|
17
|
+
super(config);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Validate OpenAI configuration
|
|
21
|
+
*
|
|
22
|
+
* @throws Error if API key is missing
|
|
23
|
+
*/
|
|
24
|
+
validateConfig() {
|
|
25
|
+
if (!this.config.apiKey) {
|
|
26
|
+
throw new Error('OPENAI_API_KEY environment variable is required for OpenAI provider');
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Generate quiz questions using OpenAI API
|
|
31
|
+
*
|
|
32
|
+
* @param artifactContent - The content of the artifact to generate questions from
|
|
33
|
+
* @param questionCount - Number of questions to generate
|
|
34
|
+
* @param artifactType - Type of artifact (proposal, design, specs, plan, tasks)
|
|
35
|
+
* @returns Array of generated questions
|
|
36
|
+
*/
|
|
37
|
+
async generateQuestions(artifactContent, questionCount, artifactType) {
|
|
38
|
+
// TODO: Implement OpenAI API call
|
|
39
|
+
// For now, return placeholder questions
|
|
40
|
+
const questions = [];
|
|
41
|
+
for (let i = 0; i < questionCount; i++) {
|
|
42
|
+
questions.push({
|
|
43
|
+
text: `Sample question ${i + 1} for ${artifactType}`,
|
|
44
|
+
options: ['Option A', 'Option B', 'Option C'],
|
|
45
|
+
correctOption: 0,
|
|
46
|
+
artifactSource: artifactType,
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
this.validateQuestions(questions);
|
|
50
|
+
return questions;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=openai.js.map
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Question generator for quiz questions
|
|
3
|
+
*
|
|
4
|
+
* This module handles reading artifact content and generating quiz questions
|
|
5
|
+
* using LLM providers. It includes logic for question count scaling based on
|
|
6
|
+
* artifact size and proportional question allocation across artifact types.
|
|
7
|
+
*
|
|
8
|
+
* @module comprehension-quiz/question-generator
|
|
9
|
+
*/
|
|
10
|
+
import type { Question, LLMProvider } from './types.js';
|
|
11
|
+
/**
|
|
12
|
+
* Determine question count based on artifact size
|
|
13
|
+
*
|
|
14
|
+
* @param totalSize - Total size of all artifacts in bytes
|
|
15
|
+
* @returns Number of questions to generate (5, 7, or 10)
|
|
16
|
+
*/
|
|
17
|
+
export declare function getQuestionCount(totalSize: number): number;
|
|
18
|
+
/**
|
|
19
|
+
* Calculate question allocation per artifact type
|
|
20
|
+
*
|
|
21
|
+
* Distributes questions proportionally to artifact size, ensuring at least
|
|
22
|
+
* one question per artifact type if it has content.
|
|
23
|
+
*
|
|
24
|
+
* @param totalQuestions - Total number of questions to generate
|
|
25
|
+
* @param artifactSizes - Size of each artifact type in bytes
|
|
26
|
+
* @returns Object with question count per artifact type
|
|
27
|
+
*/
|
|
28
|
+
export declare function calculateQuestionAllocation(totalQuestions: number, artifactSizes: {
|
|
29
|
+
proposal: number;
|
|
30
|
+
design: number;
|
|
31
|
+
specs: number;
|
|
32
|
+
plan: number;
|
|
33
|
+
tasks: number;
|
|
34
|
+
}): {
|
|
35
|
+
proposal: number;
|
|
36
|
+
design: number;
|
|
37
|
+
specs: number;
|
|
38
|
+
plan: number;
|
|
39
|
+
tasks: number;
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* Generate questions for a specific artifact type
|
|
43
|
+
*
|
|
44
|
+
* @param artifactContent - Content of the artifact
|
|
45
|
+
* @param artifactType - Type of artifact
|
|
46
|
+
* @param questionCount - Number of questions to generate
|
|
47
|
+
* @param provider - LLM provider to use
|
|
48
|
+
* @returns Array of generated questions
|
|
49
|
+
*/
|
|
50
|
+
export declare function generateQuestionsForArtifact(artifactContent: string, artifactType: 'proposal' | 'design' | 'specs' | 'plan' | 'tasks', questionCount: number, provider: LLMProvider): Promise<Question[]>;
|
|
51
|
+
/**
|
|
52
|
+
* Generate complete quiz question set for all artifacts
|
|
53
|
+
*
|
|
54
|
+
* Reads all artifact files, calculates question allocation, and generates
|
|
55
|
+
* questions for each artifact type using the provided or fallback LLM provider.
|
|
56
|
+
*
|
|
57
|
+
* @param artifactPaths - Object mapping artifact types to file paths
|
|
58
|
+
* @param totalQuestions - Total number of questions to generate
|
|
59
|
+
* @param provider - LLM provider to use (optional, uses fallback if not provided)
|
|
60
|
+
* @returns Array of all generated questions
|
|
61
|
+
*/
|
|
62
|
+
export declare function generateQuizQuestions(artifactPaths: {
|
|
63
|
+
proposal?: string;
|
|
64
|
+
design?: string;
|
|
65
|
+
specs?: string;
|
|
66
|
+
plan?: string;
|
|
67
|
+
tasks?: string;
|
|
68
|
+
}, totalQuestions: number, provider?: LLMProvider): Promise<Question[]>;
|
|
69
|
+
//# sourceMappingURL=question-generator.d.ts.map
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Question generator for quiz questions
|
|
3
|
+
*
|
|
4
|
+
* This module handles reading artifact content and generating quiz questions
|
|
5
|
+
* using LLM providers. It includes logic for question count scaling based on
|
|
6
|
+
* artifact size and proportional question allocation across artifact types.
|
|
7
|
+
*
|
|
8
|
+
* @module comprehension-quiz/question-generator
|
|
9
|
+
*/
|
|
10
|
+
import { createProviderWithFallback } from './providers/factory.js';
|
|
11
|
+
/**
|
|
12
|
+
* Read artifact content from file
|
|
13
|
+
*
|
|
14
|
+
* @param filePath - Path to the artifact file
|
|
15
|
+
* @returns File content as string
|
|
16
|
+
*/
|
|
17
|
+
async function readArtifactContent(filePath) {
|
|
18
|
+
const { promises: fs } = await import('fs');
|
|
19
|
+
try {
|
|
20
|
+
return await fs.readFile(filePath, 'utf-8');
|
|
21
|
+
}
|
|
22
|
+
catch (error) {
|
|
23
|
+
throw new Error(`Failed to read artifact file ${filePath}: ${error}`);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Determine question count based on artifact size
|
|
28
|
+
*
|
|
29
|
+
* @param totalSize - Total size of all artifacts in bytes
|
|
30
|
+
* @returns Number of questions to generate (5, 7, or 10)
|
|
31
|
+
*/
|
|
32
|
+
export function getQuestionCount(totalSize) {
|
|
33
|
+
if (totalSize < 2048) {
|
|
34
|
+
return 5; // < 2KB
|
|
35
|
+
}
|
|
36
|
+
else if (totalSize < 10240) {
|
|
37
|
+
return 7; // 2-10KB
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
return 10; // > 10KB
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Calculate question allocation per artifact type
|
|
45
|
+
*
|
|
46
|
+
* Distributes questions proportionally to artifact size, ensuring at least
|
|
47
|
+
* one question per artifact type if it has content.
|
|
48
|
+
*
|
|
49
|
+
* @param totalQuestions - Total number of questions to generate
|
|
50
|
+
* @param artifactSizes - Size of each artifact type in bytes
|
|
51
|
+
* @returns Object with question count per artifact type
|
|
52
|
+
*/
|
|
53
|
+
export function calculateQuestionAllocation(totalQuestions, artifactSizes) {
|
|
54
|
+
const totalSize = Object.values(artifactSizes).reduce((sum, size) => sum + size, 0);
|
|
55
|
+
const allocation = {
|
|
56
|
+
proposal: 0,
|
|
57
|
+
design: 0,
|
|
58
|
+
specs: 0,
|
|
59
|
+
plan: 0,
|
|
60
|
+
tasks: 0,
|
|
61
|
+
};
|
|
62
|
+
// Allocate questions proportionally to artifact size
|
|
63
|
+
let allocated = 0;
|
|
64
|
+
for (const [artifactType, size] of Object.entries(artifactSizes)) {
|
|
65
|
+
const proportion = size / totalSize;
|
|
66
|
+
const count = Math.round(proportion * totalQuestions);
|
|
67
|
+
allocation[artifactType] = count;
|
|
68
|
+
allocated += count;
|
|
69
|
+
}
|
|
70
|
+
// Ensure at least 1 question per artifact type if it has content
|
|
71
|
+
for (const [artifactType, size] of Object.entries(artifactSizes)) {
|
|
72
|
+
if (size > 0 && allocation[artifactType] === 0 && allocated < totalQuestions) {
|
|
73
|
+
allocation[artifactType] = 1;
|
|
74
|
+
allocated += 1;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
// Adjust to match totalQuestions exactly
|
|
78
|
+
const currentTotal = Object.values(allocation).reduce((sum, count) => sum + count, 0);
|
|
79
|
+
if (currentTotal !== totalQuestions) {
|
|
80
|
+
const diff = totalQuestions - currentTotal;
|
|
81
|
+
// Add remaining questions to the largest artifact
|
|
82
|
+
const largestArtifact = Object.entries(artifactSizes).sort((a, b) => b[1] - a[1])[0][0];
|
|
83
|
+
allocation[largestArtifact] += diff;
|
|
84
|
+
}
|
|
85
|
+
return allocation;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Generate questions for a specific artifact type
|
|
89
|
+
*
|
|
90
|
+
* @param artifactContent - Content of the artifact
|
|
91
|
+
* @param artifactType - Type of artifact
|
|
92
|
+
* @param questionCount - Number of questions to generate
|
|
93
|
+
* @param provider - LLM provider to use
|
|
94
|
+
* @returns Array of generated questions
|
|
95
|
+
*/
|
|
96
|
+
export async function generateQuestionsForArtifact(artifactContent, artifactType, questionCount, provider) {
|
|
97
|
+
return provider.generateQuestions(artifactContent, questionCount, artifactType);
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Generate complete quiz question set for all artifacts
|
|
101
|
+
*
|
|
102
|
+
* Reads all artifact files, calculates question allocation, and generates
|
|
103
|
+
* questions for each artifact type using the provided or fallback LLM provider.
|
|
104
|
+
*
|
|
105
|
+
* @param artifactPaths - Object mapping artifact types to file paths
|
|
106
|
+
* @param totalQuestions - Total number of questions to generate
|
|
107
|
+
* @param provider - LLM provider to use (optional, uses fallback if not provided)
|
|
108
|
+
* @returns Array of all generated questions
|
|
109
|
+
*/
|
|
110
|
+
export async function generateQuizQuestions(artifactPaths, totalQuestions, provider) {
|
|
111
|
+
// Use fallback provider if not provided
|
|
112
|
+
const llmProvider = provider || await createProviderWithFallback();
|
|
113
|
+
// Read all artifact contents and calculate sizes
|
|
114
|
+
const artifactContents = {};
|
|
115
|
+
const artifactSizes = {
|
|
116
|
+
proposal: 0,
|
|
117
|
+
design: 0,
|
|
118
|
+
specs: 0,
|
|
119
|
+
plan: 0,
|
|
120
|
+
tasks: 0,
|
|
121
|
+
};
|
|
122
|
+
for (const [artifactType, filePath] of Object.entries(artifactPaths)) {
|
|
123
|
+
if (filePath) {
|
|
124
|
+
const content = await readArtifactContent(filePath);
|
|
125
|
+
artifactContents[artifactType] = content;
|
|
126
|
+
artifactSizes[artifactType] = content.length;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
// Calculate question allocation
|
|
130
|
+
const allocation = calculateQuestionAllocation(totalQuestions, artifactSizes);
|
|
131
|
+
// Generate questions for each artifact type
|
|
132
|
+
const allQuestions = [];
|
|
133
|
+
for (const [artifactType, count] of Object.entries(allocation)) {
|
|
134
|
+
if (count > 0 && artifactContents[artifactType]) {
|
|
135
|
+
const questions = await generateQuestionsForArtifact(artifactContents[artifactType], artifactType, count, llmProvider);
|
|
136
|
+
allQuestions.push(...questions);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
return allQuestions;
|
|
140
|
+
}
|
|
141
|
+
//# sourceMappingURL=question-generator.js.map
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Quiz executor with state machine and CLI interaction
|
|
3
|
+
*
|
|
4
|
+
* This module implements the quiz execution engine with a strict state machine
|
|
5
|
+
* and timing constraints to enforce human-only participation. It handles question
|
|
6
|
+
* presentation, answer collection, timing validation, and feedback display.
|
|
7
|
+
*
|
|
8
|
+
* @module comprehension-quiz/quiz-executor
|
|
9
|
+
*/
|
|
10
|
+
import type { Question, QuizResult } from './types.js';
|
|
11
|
+
/**
|
|
12
|
+
* Quiz executor class
|
|
13
|
+
*
|
|
14
|
+
* Manages the quiz state machine and CLI interaction. Enforces timing
|
|
15
|
+
* constraints (4-second wait before accepting input, 2-second minimum answer time)
|
|
16
|
+
* to prevent AI agents from programmatically answering questions.
|
|
17
|
+
*/
|
|
18
|
+
export declare class QuizExecutor {
|
|
19
|
+
private state;
|
|
20
|
+
private currentQuestionIndex;
|
|
21
|
+
private questions;
|
|
22
|
+
private answers;
|
|
23
|
+
private questionDisplayedAt;
|
|
24
|
+
private answerReceivedAt;
|
|
25
|
+
private changeName;
|
|
26
|
+
private attemptNumber;
|
|
27
|
+
/**
|
|
28
|
+
* Execute quiz with given questions
|
|
29
|
+
*
|
|
30
|
+
* @param questions - Array of questions to ask
|
|
31
|
+
* @param changeName - Name of the change being tested
|
|
32
|
+
* @returns Quiz result with score and pass/fail status
|
|
33
|
+
*/
|
|
34
|
+
executeQuiz(questions: Question[], changeName: string): Promise<QuizResult>;
|
|
35
|
+
/**
|
|
36
|
+
* Transition to a new state
|
|
37
|
+
*
|
|
38
|
+
* @param newState - New state to transition to
|
|
39
|
+
*/
|
|
40
|
+
private transitionTo;
|
|
41
|
+
/**
|
|
42
|
+
* Ask a question to the user
|
|
43
|
+
*
|
|
44
|
+
* @param questionIndex - Index of the question to ask
|
|
45
|
+
*/
|
|
46
|
+
private askQuestion;
|
|
47
|
+
/**
|
|
48
|
+
* Wait for user answer with timing constraints
|
|
49
|
+
*
|
|
50
|
+
* Enforces a minimum 2-second wait time after question display before
|
|
51
|
+
* accepting input to prevent automated answering.
|
|
52
|
+
*
|
|
53
|
+
* @returns User's answer (1, 2, or 3), or -1 if invalid/too early
|
|
54
|
+
*/
|
|
55
|
+
private waitForAnswer;
|
|
56
|
+
/**
|
|
57
|
+
* Show feedback on the answer
|
|
58
|
+
*
|
|
59
|
+
* @param questionIndex - Index of the question
|
|
60
|
+
* @param answer - User's answer
|
|
61
|
+
*/
|
|
62
|
+
private showFeedback;
|
|
63
|
+
/**
|
|
64
|
+
* Calculate quiz result
|
|
65
|
+
*
|
|
66
|
+
* @returns Quiz result with score and pass/fail status
|
|
67
|
+
*/
|
|
68
|
+
private calculateResult;
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=quiz-executor.d.ts.map
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Quiz executor with state machine and CLI interaction
|
|
3
|
+
*
|
|
4
|
+
* This module implements the quiz execution engine with a strict state machine
|
|
5
|
+
* and timing constraints to enforce human-only participation. It handles question
|
|
6
|
+
* presentation, answer collection, timing validation, and feedback display.
|
|
7
|
+
*
|
|
8
|
+
* @module comprehension-quiz/quiz-executor
|
|
9
|
+
*/
|
|
10
|
+
import * as readline from 'readline';
|
|
11
|
+
import { trackComprehensionAttempt, trackComprehensionCompletion, trackApplyReady } from '../telemetry/index.js';
|
|
12
|
+
import { getPassRecord } from './pass-record.js';
|
|
13
|
+
/**
|
|
14
|
+
* Quiz executor class
|
|
15
|
+
*
|
|
16
|
+
* Manages the quiz state machine and CLI interaction. Enforces timing
|
|
17
|
+
* constraints (4-second wait before accepting input, 2-second minimum answer time)
|
|
18
|
+
* to prevent AI agents from programmatically answering questions.
|
|
19
|
+
*/
|
|
20
|
+
export class QuizExecutor {
|
|
21
|
+
state = 'START';
|
|
22
|
+
currentQuestionIndex = 0;
|
|
23
|
+
questions = [];
|
|
24
|
+
answers = [];
|
|
25
|
+
questionDisplayedAt = 0;
|
|
26
|
+
answerReceivedAt = 0;
|
|
27
|
+
changeName = '';
|
|
28
|
+
attemptNumber = 1;
|
|
29
|
+
/**
|
|
30
|
+
* Execute quiz with given questions
|
|
31
|
+
*
|
|
32
|
+
* @param questions - Array of questions to ask
|
|
33
|
+
* @param changeName - Name of the change being tested
|
|
34
|
+
* @returns Quiz result with score and pass/fail status
|
|
35
|
+
*/
|
|
36
|
+
async executeQuiz(questions, changeName) {
|
|
37
|
+
this.questions = questions;
|
|
38
|
+
this.changeName = changeName;
|
|
39
|
+
this.currentQuestionIndex = 0;
|
|
40
|
+
this.answers = [];
|
|
41
|
+
this.state = 'START';
|
|
42
|
+
// Track attempt number from existing pass record
|
|
43
|
+
const existingRecord = await getPassRecord(changeName);
|
|
44
|
+
this.attemptNumber = existingRecord ? existingRecord.attemptCount + 1 : 1;
|
|
45
|
+
// Track attempt start
|
|
46
|
+
await trackComprehensionAttempt(changeName, this.attemptNumber);
|
|
47
|
+
// Start the quiz
|
|
48
|
+
await this.transitionTo('WAITING_FOR_QUESTION_1');
|
|
49
|
+
for (let i = 0; i < questions.length; i++) {
|
|
50
|
+
await this.askQuestion(i);
|
|
51
|
+
const answer = await this.waitForAnswer();
|
|
52
|
+
this.answers.push(answer);
|
|
53
|
+
await this.showFeedback(i, answer);
|
|
54
|
+
if (i < questions.length - 1) {
|
|
55
|
+
await this.transitionTo(`WAITING_FOR_QUESTION_${i + 2}`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
await this.transitionTo('DONE');
|
|
59
|
+
const result = this.calculateResult();
|
|
60
|
+
// Track completion
|
|
61
|
+
await trackComprehensionCompletion(changeName, result.scorePercent, result.passed ? 'pass' : 'fail', this.attemptNumber);
|
|
62
|
+
// If passed, emit apply_ready milestone
|
|
63
|
+
if (result.passed) {
|
|
64
|
+
await trackApplyReady(changeName);
|
|
65
|
+
}
|
|
66
|
+
return result;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Transition to a new state
|
|
70
|
+
*
|
|
71
|
+
* @param newState - New state to transition to
|
|
72
|
+
*/
|
|
73
|
+
async transitionTo(newState) {
|
|
74
|
+
this.state = newState;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Ask a question to the user
|
|
78
|
+
*
|
|
79
|
+
* @param questionIndex - Index of the question to ask
|
|
80
|
+
*/
|
|
81
|
+
async askQuestion(questionIndex) {
|
|
82
|
+
const question = this.questions[questionIndex];
|
|
83
|
+
console.log(`\nQuestion ${questionIndex + 1}/${this.questions.length}:`);
|
|
84
|
+
console.log(question.text);
|
|
85
|
+
console.log('');
|
|
86
|
+
console.log('1)', question.options[0]);
|
|
87
|
+
console.log('2)', question.options[1]);
|
|
88
|
+
console.log('3)', question.options[2]);
|
|
89
|
+
console.log('');
|
|
90
|
+
this.questionDisplayedAt = Date.now();
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Wait for user answer with timing constraints
|
|
94
|
+
*
|
|
95
|
+
* Enforces a minimum 2-second wait time after question display before
|
|
96
|
+
* accepting input to prevent automated answering.
|
|
97
|
+
*
|
|
98
|
+
* @returns User's answer (1, 2, or 3), or -1 if invalid/too early
|
|
99
|
+
*/
|
|
100
|
+
async waitForAnswer() {
|
|
101
|
+
const rl = readline.createInterface({
|
|
102
|
+
input: process.stdin,
|
|
103
|
+
output: process.stdout,
|
|
104
|
+
});
|
|
105
|
+
const answer = await new Promise((resolve) => {
|
|
106
|
+
rl.question('', (answer) => {
|
|
107
|
+
rl.close();
|
|
108
|
+
const trimmed = answer.trim();
|
|
109
|
+
// Check if answer was submitted too early (less than 2 seconds after question display)
|
|
110
|
+
const timeSinceDisplay = Date.now() - this.questionDisplayedAt;
|
|
111
|
+
if (timeSinceDisplay < 2000) {
|
|
112
|
+
console.log('Answer submitted too early. Please wait at least 2 seconds before answering.');
|
|
113
|
+
resolve(-1);
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
// Validate input
|
|
117
|
+
if (trimmed === '1' || trimmed === '2' || trimmed === '3') {
|
|
118
|
+
resolve(parseInt(trimmed, 10));
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
console.log('Answer this question to continue.');
|
|
122
|
+
resolve(-1);
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
return answer;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Show feedback on the answer
|
|
130
|
+
*
|
|
131
|
+
* @param questionIndex - Index of the question
|
|
132
|
+
* @param answer - User's answer
|
|
133
|
+
*/
|
|
134
|
+
async showFeedback(questionIndex, answer) {
|
|
135
|
+
const question = this.questions[questionIndex];
|
|
136
|
+
const isCorrect = answer === question.correctOption + 1;
|
|
137
|
+
if (isCorrect) {
|
|
138
|
+
console.log('✓ Correct');
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
console.log('✗ Incorrect');
|
|
142
|
+
console.log(`The correct answer was ${question.correctOption + 1}`);
|
|
143
|
+
}
|
|
144
|
+
// Clear terminal screen
|
|
145
|
+
console.clear();
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Calculate quiz result
|
|
149
|
+
*
|
|
150
|
+
* @returns Quiz result with score and pass/fail status
|
|
151
|
+
*/
|
|
152
|
+
calculateResult() {
|
|
153
|
+
const correct = this.answers.filter((answer, index) => answer === this.questions[index].correctOption + 1).length;
|
|
154
|
+
const total = this.questions.length;
|
|
155
|
+
const scorePercent = Math.round((correct / total) * 100);
|
|
156
|
+
return {
|
|
157
|
+
correct,
|
|
158
|
+
total,
|
|
159
|
+
scorePercent,
|
|
160
|
+
passed: scorePercent >= 80,
|
|
161
|
+
attemptNumber: 1, // TODO: Track attempt count
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
//# sourceMappingURL=quiz-executor.js.map
|