@codewalla_india/openspec 1.3.1 → 1.3.3

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.
Files changed (333) hide show
  1. package/LICENSE +22 -22
  2. package/README.md +214 -133
  3. package/bin/openspec.js +5 -5
  4. package/dist/cli/index.js +99 -62
  5. package/dist/commands/change.d.ts +0 -2
  6. package/dist/commands/change.js +107 -86
  7. package/dist/commands/config.js +14 -16
  8. package/dist/commands/doctor.js +9 -4
  9. package/dist/commands/feedback.js +79 -30
  10. package/dist/commands/modify.d.ts +26 -0
  11. package/dist/commands/modify.js +147 -0
  12. package/dist/commands/schema.js +170 -91
  13. package/dist/commands/show.js +5 -2
  14. package/dist/commands/spec.js +49 -29
  15. package/dist/commands/store.js +15 -21
  16. package/dist/commands/validate.d.ts +8 -0
  17. package/dist/commands/validate.js +43 -20
  18. package/dist/commands/workflow/index.d.ts +2 -2
  19. package/dist/commands/workflow/index.js +1 -1
  20. package/dist/commands/workflow/instructions.d.ts +6 -26
  21. package/dist/commands/workflow/instructions.js +183 -376
  22. package/dist/commands/workflow/new-change.d.ts +0 -4
  23. package/dist/commands/workflow/new-change.js +10 -28
  24. package/dist/commands/workflow/shared.d.ts +34 -19
  25. package/dist/commands/workflow/shared.js +34 -4
  26. package/dist/commands/workflow/status.js +10 -32
  27. package/dist/commands/workflow/templates.js +15 -5
  28. package/dist/commands/workset.d.ts +2 -2
  29. package/dist/commands/workset.js +19 -22
  30. package/dist/comprehension-quiz/fingerprint.d.ts +39 -0
  31. package/dist/comprehension-quiz/fingerprint.js +84 -0
  32. package/dist/comprehension-quiz/index.d.ts +42 -0
  33. package/dist/comprehension-quiz/index.js +47 -0
  34. package/dist/comprehension-quiz/pass-record.d.ts +44 -0
  35. package/dist/comprehension-quiz/pass-record.js +98 -0
  36. package/dist/comprehension-quiz/providers/anthropic.d.ts +35 -0
  37. package/dist/comprehension-quiz/providers/anthropic.js +69 -0
  38. package/dist/comprehension-quiz/providers/factory.d.ts +44 -0
  39. package/dist/comprehension-quiz/providers/factory.js +174 -0
  40. package/dist/comprehension-quiz/providers/interface.d.ts +98 -0
  41. package/dist/comprehension-quiz/providers/interface.js +150 -0
  42. package/dist/comprehension-quiz/providers/local.d.ts +35 -0
  43. package/dist/comprehension-quiz/providers/local.js +69 -0
  44. package/dist/comprehension-quiz/providers/ollama.d.ts +35 -0
  45. package/dist/comprehension-quiz/providers/ollama.js +69 -0
  46. package/dist/comprehension-quiz/providers/openai.d.ts +35 -0
  47. package/dist/comprehension-quiz/providers/openai.js +72 -0
  48. package/dist/comprehension-quiz/question-generator.d.ts +117 -0
  49. package/dist/comprehension-quiz/question-generator.js +203 -0
  50. package/dist/comprehension-quiz/quiz-executor.d.ts +75 -0
  51. package/dist/comprehension-quiz/quiz-executor.js +181 -0
  52. package/dist/comprehension-quiz/types.d.ts +137 -0
  53. package/dist/comprehension-quiz/types.js +11 -0
  54. package/dist/core/archive.d.ts +14 -1
  55. package/dist/core/archive.js +1350 -190
  56. package/dist/core/artifact-graph/graph.d.ts +28 -9
  57. package/dist/core/artifact-graph/graph.js +94 -43
  58. package/dist/core/artifact-graph/index.d.ts +1 -1
  59. package/dist/core/artifact-graph/index.js +1 -1
  60. package/dist/core/artifact-graph/instruction-loader.d.ts +30 -3
  61. package/dist/core/artifact-graph/instruction-loader.js +70 -12
  62. package/dist/core/artifact-graph/outputs.d.ts +1 -0
  63. package/dist/core/artifact-graph/outputs.js +67 -5
  64. package/dist/core/artifact-graph/resolver.d.ts +14 -0
  65. package/dist/core/artifact-graph/resolver.js +69 -15
  66. package/dist/core/artifact-graph/types.js +21 -3
  67. package/dist/core/available-tools.d.ts +2 -2
  68. package/dist/core/available-tools.js +14 -3
  69. package/dist/core/change-metadata/schema.d.ts +2 -0
  70. package/dist/core/change-metadata/schema.js +13 -0
  71. package/dist/core/change-status-policy.d.ts +10 -1
  72. package/dist/core/change-status-policy.js +30 -2
  73. package/dist/core/command-generation/adapters/amazon-q.d.ts +4 -0
  74. package/dist/core/command-generation/adapters/amazon-q.js +11 -5
  75. package/dist/core/command-generation/adapters/antigravity.js +6 -5
  76. package/dist/core/command-generation/adapters/auggie.js +7 -6
  77. package/dist/core/command-generation/adapters/bob.d.ts +5 -1
  78. package/dist/core/command-generation/adapters/bob.js +11 -10
  79. package/dist/core/command-generation/adapters/claude.d.ts +1 -1
  80. package/dist/core/command-generation/adapters/claude.js +12 -17
  81. package/dist/core/command-generation/adapters/cline.js +5 -5
  82. package/dist/core/command-generation/adapters/codebuddy.js +8 -7
  83. package/dist/core/command-generation/adapters/continue.js +8 -7
  84. package/dist/core/command-generation/adapters/costrict.js +7 -6
  85. package/dist/core/command-generation/adapters/crush.js +9 -9
  86. package/dist/core/command-generation/adapters/cursor.js +8 -8
  87. package/dist/core/command-generation/adapters/devin.d.ts +19 -0
  88. package/dist/core/command-generation/adapters/devin.js +36 -0
  89. package/dist/core/command-generation/adapters/factory.js +7 -6
  90. package/dist/core/command-generation/adapters/gemini.js +40 -5
  91. package/dist/core/command-generation/adapters/github-copilot.js +6 -5
  92. package/dist/core/command-generation/adapters/iflow.js +9 -8
  93. package/dist/core/command-generation/adapters/index.d.ts +4 -2
  94. package/dist/core/command-generation/adapters/index.js +4 -2
  95. package/dist/core/command-generation/adapters/junie.js +6 -5
  96. package/dist/core/command-generation/adapters/kilocode.js +1 -1
  97. package/dist/core/command-generation/adapters/kiro.js +6 -5
  98. package/dist/core/command-generation/adapters/lingma.js +9 -9
  99. package/dist/core/command-generation/adapters/oh-my-pi.d.ts +21 -0
  100. package/dist/core/command-generation/adapters/oh-my-pi.js +42 -0
  101. package/dist/core/command-generation/adapters/opencode.js +6 -8
  102. package/dist/core/command-generation/adapters/pi.d.ts +2 -2
  103. package/dist/core/command-generation/adapters/pi.js +7 -10
  104. package/dist/core/command-generation/adapters/qoder.js +9 -9
  105. package/dist/core/command-generation/adapters/qwen.d.ts +7 -3
  106. package/dist/core/command-generation/adapters/qwen.js +14 -9
  107. package/dist/core/command-generation/adapters/roocode.d.ts +4 -4
  108. package/dist/core/command-generation/adapters/roocode.js +9 -9
  109. package/dist/core/command-generation/adapters/trae.d.ts +13 -0
  110. package/dist/core/command-generation/adapters/trae.js +28 -0
  111. package/dist/core/command-generation/adapters/zcode.d.ts +16 -0
  112. package/dist/core/command-generation/adapters/zcode.js +33 -0
  113. package/dist/core/command-generation/generator.d.ts +8 -0
  114. package/dist/core/command-generation/generator.js +15 -1
  115. package/dist/core/command-generation/index.d.ts +1 -1
  116. package/dist/core/command-generation/index.js +1 -1
  117. package/dist/core/command-generation/invocation.d.ts +73 -0
  118. package/dist/core/command-generation/invocation.js +77 -0
  119. package/dist/core/command-generation/registry.js +8 -4
  120. package/dist/core/command-generation/types.d.ts +9 -2
  121. package/dist/core/command-generation/yaml.d.ts +20 -6
  122. package/dist/core/command-generation/yaml.js +31 -21
  123. package/dist/core/command-surface.d.ts +15 -0
  124. package/dist/core/command-surface.js +33 -0
  125. package/dist/core/completions/command-registry.js +16 -61
  126. package/dist/core/completions/generators/bash-generator.js +41 -41
  127. package/dist/core/completions/generators/fish-generator.js +7 -7
  128. package/dist/core/completions/generators/powershell-generator.js +44 -37
  129. package/dist/core/completions/generators/zsh-generator.js +33 -33
  130. package/dist/core/completions/installers/zsh-installer.d.ts +9 -0
  131. package/dist/core/completions/installers/zsh-installer.js +20 -4
  132. package/dist/core/completions/templates/bash-templates.js +24 -24
  133. package/dist/core/completions/templates/fish-templates.js +38 -38
  134. package/dist/core/completions/templates/powershell-templates.js +28 -28
  135. package/dist/core/completions/templates/zsh-templates.js +39 -39
  136. package/dist/core/config-prompts.d.ts +1 -1
  137. package/dist/core/config-prompts.js +14 -1
  138. package/dist/core/config-schema.d.ts +10 -1
  139. package/dist/core/config-schema.js +67 -1
  140. package/dist/core/config.d.ts +15 -0
  141. package/dist/core/config.js +46 -5
  142. package/dist/core/file-state.js +56 -24
  143. package/dist/core/github-copilot/cloud-agent.d.ts +95 -0
  144. package/dist/core/github-copilot/cloud-agent.js +497 -0
  145. package/dist/core/global-config.d.ts +16 -0
  146. package/dist/core/init.d.ts +58 -0
  147. package/dist/core/init.js +474 -73
  148. package/dist/core/legacy-cleanup.d.ts +59 -0
  149. package/dist/core/legacy-cleanup.js +253 -24
  150. package/dist/core/list.js +23 -16
  151. package/dist/core/migration.d.ts +73 -1
  152. package/dist/core/migration.js +360 -11
  153. package/dist/core/modify/conflict-detector.d.ts +26 -0
  154. package/dist/core/modify/conflict-detector.js +62 -0
  155. package/dist/core/modify/dependency-propagator.d.ts +38 -0
  156. package/dist/core/modify/dependency-propagator.js +103 -0
  157. package/dist/core/modify/history-tracker.d.ts +34 -0
  158. package/dist/core/modify/history-tracker.js +114 -0
  159. package/dist/core/modify/index.d.ts +7 -0
  160. package/dist/core/modify/index.js +7 -0
  161. package/dist/core/onboarding-commands.d.ts +30 -0
  162. package/dist/core/onboarding-commands.js +38 -0
  163. package/dist/core/openspec-root.js +18 -15
  164. package/dist/core/parsers/change-parser.d.ts +17 -2
  165. package/dist/core/parsers/change-parser.js +35 -21
  166. package/dist/core/parsers/code-fence.d.ts +15 -0
  167. package/dist/core/parsers/code-fence.js +49 -0
  168. package/dist/core/parsers/markdown-parser.d.ts +0 -3
  169. package/dist/core/parsers/markdown-parser.js +7 -60
  170. package/dist/core/parsers/requirement-blocks.d.ts +29 -0
  171. package/dist/core/parsers/requirement-blocks.js +150 -31
  172. package/dist/core/parsers/requirement-text.d.ts +48 -0
  173. package/dist/core/parsers/requirement-text.js +98 -0
  174. package/dist/core/parsers/spec-structure.d.ts +1 -1
  175. package/dist/core/parsers/spec-structure.js +20 -30
  176. package/dist/core/profile-sync-drift.d.ts +0 -8
  177. package/dist/core/profile-sync-drift.js +49 -50
  178. package/dist/core/profiles.d.ts +2 -2
  179. package/dist/core/profiles.js +2 -2
  180. package/dist/core/project-config.d.ts +27 -18
  181. package/dist/core/project-config.js +101 -34
  182. package/dist/core/references.js +42 -4
  183. package/dist/core/relationship-health.d.ts +8 -0
  184. package/dist/core/relationship-health.js +13 -0
  185. package/dist/core/root-selection.d.ts +9 -6
  186. package/dist/core/root-selection.js +42 -5
  187. package/dist/core/schemas/base.schema.js +7 -2
  188. package/dist/core/shared/allowed-tools.d.ts +12 -0
  189. package/dist/core/shared/allowed-tools.js +12 -0
  190. package/dist/core/shared/index.d.ts +1 -0
  191. package/dist/core/shared/index.js +1 -0
  192. package/dist/core/shared/skill-content-equivalence.d.ts +7 -0
  193. package/dist/core/shared/skill-content-equivalence.js +41 -0
  194. package/dist/core/shared/skill-generation.js +17 -13
  195. package/dist/core/shared/skill-paths.d.ts +13 -0
  196. package/dist/core/shared/skill-paths.js +23 -0
  197. package/dist/core/shared/tool-detection.d.ts +27 -7
  198. package/dist/core/shared/tool-detection.js +167 -37
  199. package/dist/core/shared-skill-target.d.ts +16 -0
  200. package/dist/core/shared-skill-target.js +156 -0
  201. package/dist/core/specs-apply.d.ts +80 -33
  202. package/dist/core/specs-apply.js +667 -145
  203. package/dist/core/store/git.d.ts +13 -0
  204. package/dist/core/store/git.js +24 -0
  205. package/dist/core/store/operations.js +20 -0
  206. package/dist/core/templates/skill-templates.d.ts +3 -2
  207. package/dist/core/templates/skill-templates.js +3 -2
  208. package/dist/core/templates/workflows/apply-change.d.ts +10 -0
  209. package/dist/core/templates/workflows/apply-change.js +186 -224
  210. package/dist/core/templates/workflows/archive-change.js +387 -260
  211. package/dist/core/templates/workflows/bulk-archive-change.js +655 -475
  212. package/dist/core/templates/workflows/continue-change.js +210 -219
  213. package/dist/core/templates/workflows/explore.js +479 -443
  214. package/dist/core/templates/workflows/feedback.js +97 -97
  215. package/dist/core/templates/workflows/ff-change.js +200 -191
  216. package/dist/core/templates/workflows/modify-change.d.ts +4 -1
  217. package/dist/core/templates/workflows/modify-change.js +193 -71
  218. package/dist/core/templates/workflows/new-change.js +127 -134
  219. package/dist/core/templates/workflows/onboard.js +548 -542
  220. package/dist/core/templates/workflows/propose.js +273 -217
  221. package/dist/core/templates/workflows/store-selection.d.ts +1 -1
  222. package/dist/core/templates/workflows/store-selection.js +1 -1
  223. package/dist/core/templates/workflows/sync-specs.js +500 -273
  224. package/dist/core/templates/workflows/update-change.d.ts +10 -0
  225. package/dist/core/templates/workflows/update-change.js +177 -0
  226. package/dist/core/templates/workflows/verify-change.js +324 -326
  227. package/dist/core/update.d.ts +40 -5
  228. package/dist/core/update.js +411 -96
  229. package/dist/core/validation/constants.d.ts +4 -1
  230. package/dist/core/validation/constants.js +4 -1
  231. package/dist/core/validation/plan-validator.d.ts +8 -0
  232. package/dist/core/validation/plan-validator.js +45 -0
  233. package/dist/core/validation/task-numbering.d.ts +16 -0
  234. package/dist/core/validation/task-numbering.js +57 -0
  235. package/dist/core/validation/validator.d.ts +27 -3
  236. package/dist/core/validation/validator.js +337 -48
  237. package/dist/core/version-check.d.ts +152 -0
  238. package/dist/core/version-check.js +731 -0
  239. package/dist/core/view.js +13 -18
  240. package/dist/prompts/searchable-multi-select.js +1 -1
  241. package/dist/telemetry/caller-detection.d.ts +27 -0
  242. package/dist/telemetry/caller-detection.js +85 -0
  243. package/dist/telemetry/caller-detection.test.d.ts +5 -0
  244. package/dist/telemetry/config.d.ts +48 -2
  245. package/dist/telemetry/config.js +113 -11
  246. package/dist/telemetry/config.test.d.ts +5 -0
  247. package/dist/telemetry/deduplication.d.ts +35 -0
  248. package/dist/telemetry/deduplication.js +82 -0
  249. package/dist/telemetry/deduplication.test.d.ts +5 -0
  250. package/dist/telemetry/identity.d.ts +62 -22
  251. package/dist/telemetry/identity.js +147 -102
  252. package/dist/telemetry/index.d.ts +126 -15
  253. package/dist/telemetry/index.js +569 -37
  254. package/dist/telemetry/sanitization.d.ts +40 -0
  255. package/dist/telemetry/sanitization.js +114 -0
  256. package/dist/telemetry/sanitization.test.d.ts +5 -0
  257. package/dist/telemetry/throttling.d.ts +20 -0
  258. package/dist/telemetry/throttling.js +70 -0
  259. package/dist/ui/welcome-screen.d.ts +9 -1
  260. package/dist/ui/welcome-screen.js +91 -38
  261. package/dist/utils/change-metadata.d.ts +43 -0
  262. package/dist/utils/change-metadata.js +123 -7
  263. package/dist/utils/change-utils.d.ts +10 -4
  264. package/dist/utils/change-utils.js +20 -13
  265. package/dist/utils/ci.d.ts +12 -0
  266. package/dist/utils/ci.js +16 -0
  267. package/dist/utils/command-references.d.ts +92 -6
  268. package/dist/utils/command-references.js +180 -7
  269. package/dist/utils/date.d.ts +8 -0
  270. package/dist/utils/date.js +13 -0
  271. package/dist/utils/file-system.d.ts +10 -0
  272. package/dist/utils/file-system.js +70 -0
  273. package/dist/utils/index.d.ts +1 -1
  274. package/dist/utils/index.js +1 -1
  275. package/dist/utils/interactive.d.ts +23 -0
  276. package/dist/utils/interactive.js +32 -0
  277. package/dist/utils/item-discovery.d.ts +19 -0
  278. package/dist/utils/item-discovery.js +30 -48
  279. package/dist/utils/shell-detection.d.ts +1 -1
  280. package/dist/utils/shell-detection.js +64 -11
  281. package/dist/utils/spec-discovery.d.ts +40 -0
  282. package/dist/utils/spec-discovery.js +115 -0
  283. package/dist/utils/task-progress.d.ts +29 -1
  284. package/dist/utils/task-progress.js +109 -15
  285. package/package.json +96 -84
  286. package/schemas/spec-driven/schema.yaml +252 -184
  287. package/schemas/spec-driven/templates/design.md +19 -19
  288. package/schemas/spec-driven/templates/plan-template.md +91 -0
  289. package/schemas/spec-driven/templates/proposal.md +29 -24
  290. package/schemas/spec-driven/templates/spec.md +11 -8
  291. package/schemas/spec-driven/templates/tasks.md +9 -9
  292. package/scripts/postinstall.js +83 -83
  293. package/dist/core/command-generation/adapters/codex.d.ts +0 -16
  294. package/dist/core/command-generation/adapters/codex.js +0 -39
  295. package/dist/core/command-generation/adapters/windsurf.d.ts +0 -14
  296. package/dist/core/command-generation/adapters/windsurf.js +0 -38
  297. package/dist/core/comprehension/config.d.ts +0 -20
  298. package/dist/core/comprehension/config.js +0 -23
  299. package/dist/core/comprehension/fingerprint.d.ts +0 -14
  300. package/dist/core/comprehension/fingerprint.js +0 -33
  301. package/dist/core/comprehension/index.d.ts +0 -57
  302. package/dist/core/comprehension/index.js +0 -87
  303. package/dist/core/comprehension/pass-record.d.ts +0 -29
  304. package/dist/core/comprehension/pass-record.js +0 -64
  305. package/dist/core/comprehension/stats.d.ts +0 -35
  306. package/dist/core/comprehension/stats.js +0 -133
  307. package/dist/core/templates/workflows/comprehension-guidance.d.ts +0 -9
  308. package/dist/core/templates/workflows/comprehension-guidance.js +0 -73
  309. package/dist/core/templates/workflows/mcp-guidance.d.ts +0 -13
  310. package/dist/core/templates/workflows/mcp-guidance.js +0 -131
  311. package/dist/core/templates/workflows/user-prompt-guidance.d.ts +0 -16
  312. package/dist/core/templates/workflows/user-prompt-guidance.js +0 -48
  313. package/dist/telemetry/caller.d.ts +0 -5
  314. package/dist/telemetry/caller.js +0 -29
  315. package/dist/telemetry/client.d.ts +0 -27
  316. package/dist/telemetry/client.js +0 -127
  317. package/dist/telemetry/command-context.d.ts +0 -13
  318. package/dist/telemetry/command-context.js +0 -59
  319. package/dist/telemetry/comprehension.d.ts +0 -44
  320. package/dist/telemetry/comprehension.js +0 -105
  321. package/dist/telemetry/content.d.ts +0 -10
  322. package/dist/telemetry/content.js +0 -56
  323. package/dist/telemetry/git-stats.d.ts +0 -12
  324. package/dist/telemetry/git-stats.js +0 -69
  325. package/dist/telemetry/identify-cache.d.ts +0 -7
  326. package/dist/telemetry/identify-cache.js +0 -47
  327. package/dist/telemetry/input.d.ts +0 -17
  328. package/dist/telemetry/input.js +0 -68
  329. package/dist/telemetry/marker.d.ts +0 -37
  330. package/dist/telemetry/marker.js +0 -67
  331. package/dist/telemetry/workflow.d.ts +0 -85
  332. package/dist/telemetry/workflow.js +0 -318
  333. package/schemas/spec-driven/templates/plan.md +0 -19
@@ -0,0 +1,150 @@
1
+ /**
2
+ * LLM provider interface for question generation
3
+ *
4
+ * This module defines the abstract base class that all LLM providers must implement.
5
+ * The interface ensures consistent question generation across different backends (OpenAI,
6
+ * Anthropic, Ollama, local models) with validation of generated questions.
7
+ *
8
+ * @module comprehension-quiz/providers/interface
9
+ */
10
+ /**
11
+ * Abstract base class for LLM providers
12
+ *
13
+ * All providers must extend this class and implement the abstract methods.
14
+ * Provides common validation logic for generated questions.
15
+ *
16
+ * @example
17
+ * ```ts
18
+ * class MyProvider extends BaseProvider {
19
+ * async generateQuestions(content, count, type) {
20
+ * // Generate questions using your LLM
21
+ * }
22
+ * validateConfig() {
23
+ * // Check your configuration
24
+ * }
25
+ * }
26
+ * ```
27
+ */
28
+ export class BaseProvider {
29
+ config;
30
+ constructor(config) {
31
+ this.config = config;
32
+ this.validateConfig();
33
+ }
34
+ /**
35
+ * Build the system + user messages for single-question generation.
36
+ *
37
+ * Contract:
38
+ * - System message explicitly forbids listing multiple questions.
39
+ * - User message asks for exactly one question (question N of total).
40
+ * - Response format is strict JSON only — no prose, no explanation, no answer label.
41
+ * - The correct answer index (correctOption) is returned as a number 0-2; its
42
+ * meaning is never explained in the response so the LLM cannot read it back.
43
+ *
44
+ * @returns { system, user } message pair ready to send to the LLM API
45
+ */
46
+ buildSingleQuestionPrompt(artifactContent, artifactType, questionIndex, totalQuestions, previousQuestionTexts) {
47
+ const previousBlock = previousQuestionTexts.length > 0
48
+ ? `\n\nAlready asked questions (do NOT repeat these):\n${previousQuestionTexts.map((t, i) => `${i + 1}. ${t}`).join('\n')}`
49
+ : '';
50
+ const system = [
51
+ 'You are a quiz question generator for a software change review system.',
52
+ 'STRICT RULES — violating any rule causes system failure:',
53
+ ' 1. Output EXACTLY ONE question. Never output a list, array, or multiple questions.',
54
+ ' 2. Output ONLY valid JSON matching the schema below. No prose before or after.',
55
+ ' 3. Do NOT include the word "Answer", "Correct", or any hint about which option is right.',
56
+ ' 4. Do NOT explain the options. Do NOT add notes, caveats, or additional text.',
57
+ ' 5. The "correctOption" field is an opaque integer (0, 1, or 2). Do not label it.',
58
+ '',
59
+ 'Response schema (output this JSON and nothing else):',
60
+ '{',
61
+ ' "text": "<question text>",',
62
+ ' "options": ["<option 1>", "<option 2>", "<option 3>"],',
63
+ ' "correctOption": <0|1|2>,',
64
+ ' "artifactSource": "<proposal|design|specs|plan|tasks>"',
65
+ '}',
66
+ ].join('\n');
67
+ const user = [
68
+ `Generate question ${questionIndex + 1} of ${totalQuestions} for the "${artifactType}" artifact.`,
69
+ 'The question must require reading the artifact to answer correctly.',
70
+ 'Distractors must be plausible but wrong based on artifact content.',
71
+ previousBlock,
72
+ '',
73
+ `Artifact content:\n---\n${artifactContent}\n---`,
74
+ ].join('\n');
75
+ return { system, user };
76
+ }
77
+ /**
78
+ * Parse the raw LLM text response into a Question object.
79
+ * Strips markdown fences if present, then JSON-parses and validates.
80
+ *
81
+ * @param rawResponse - Raw text returned by the LLM API
82
+ * @param artifactType - Expected artifact source (used as fallback)
83
+ * @returns Validated Question object
84
+ * @throws Error if the response cannot be parsed or fails validation
85
+ */
86
+ parseSingleQuestionResponse(rawResponse, artifactType) {
87
+ let text = rawResponse.trim();
88
+ // Strip markdown code fences if present
89
+ text = text.replace(/^```(?:json)?\s*/i, '').replace(/\s*```$/, '').trim();
90
+ let parsed;
91
+ try {
92
+ parsed = JSON.parse(text);
93
+ }
94
+ catch {
95
+ throw new Error(`LLM returned invalid JSON for single question: ${rawResponse.slice(0, 200)}`);
96
+ }
97
+ const q = parsed;
98
+ if (typeof q['text'] !== 'string' ||
99
+ !Array.isArray(q['options']) ||
100
+ typeof q['correctOption'] !== 'number' ||
101
+ typeof q['artifactSource'] !== 'string') {
102
+ throw new Error(`LLM response missing required fields: ${JSON.stringify(q)}`);
103
+ }
104
+ const question = {
105
+ text: q['text'],
106
+ options: q['options'],
107
+ correctOption: q['correctOption'],
108
+ artifactSource: q['artifactSource'] ?? artifactType,
109
+ };
110
+ this.validateQuestion(question);
111
+ return question;
112
+ }
113
+ /**
114
+ * Validate generated questions before returning
115
+ *
116
+ * Ensures all questions have:
117
+ * - Non-empty text
118
+ * - Exactly 3 options
119
+ * - Valid correct option index (0-2)
120
+ * - Valid artifact source
121
+ *
122
+ * @param questions - Questions to validate
123
+ * @throws Error if any question is invalid
124
+ */
125
+ validateQuestions(questions) {
126
+ for (const question of questions) {
127
+ this.validateQuestion(question);
128
+ }
129
+ }
130
+ /**
131
+ * Validate a single question object.
132
+ * @param question - Question to validate
133
+ * @throws Error if invalid
134
+ */
135
+ validateQuestion(question) {
136
+ if (!question.text || question.text.trim().length === 0) {
137
+ throw new Error('Question text cannot be empty');
138
+ }
139
+ if (question.options.length !== 3) {
140
+ throw new Error('Each question must have exactly 3 options');
141
+ }
142
+ if (question.correctOption < 0 || question.correctOption > 2) {
143
+ throw new Error('Correct option index must be 0, 1, or 2');
144
+ }
145
+ if (!['proposal', 'design', 'specs', 'plan', 'tasks'].includes(question.artifactSource)) {
146
+ throw new Error('Invalid artifact source');
147
+ }
148
+ }
149
+ }
150
+ //# sourceMappingURL=interface.js.map
@@ -0,0 +1,35 @@
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
+ import type { ProviderConfig, Question } from '../types.js';
11
+ /**
12
+ * Local model provider for question generation
13
+ *
14
+ * Requires LOCAL_MODEL_PATH environment variable to be set.
15
+ */
16
+ export declare class LocalProvider extends BaseProvider {
17
+ constructor(config: ProviderConfig);
18
+ /**
19
+ * Validate local model configuration
20
+ *
21
+ * @throws Error if model path is missing
22
+ */
23
+ validateConfig(): void;
24
+ /**
25
+ * Generate quiz questions using local model
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
+ generateSingleQuestion(artifactContent: string, artifactType: 'proposal' | 'design' | 'specs' | 'plan' | 'tasks', questionIndex: number, totalQuestions: number, previousQuestionTexts: string[]): Promise<Question>;
34
+ }
35
+ //# sourceMappingURL=local.d.ts.map
@@ -0,0 +1,69 @@
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
+ const questions = [];
39
+ for (let i = 0; i < questionCount; i++) {
40
+ const q = await this.generateSingleQuestion(artifactContent, artifactType, i, questionCount, questions.map((q) => q.text));
41
+ questions.push(q);
42
+ }
43
+ return questions;
44
+ }
45
+ async generateSingleQuestion(artifactContent, artifactType, questionIndex, totalQuestions, previousQuestionTexts) {
46
+ const { system, user } = this.buildSingleQuestionPrompt(artifactContent, artifactType, questionIndex, totalQuestions, previousQuestionTexts);
47
+ const endpoint = this.config.endpoint ?? 'http://localhost:11434';
48
+ const response = await fetch(`${endpoint}/api/chat`, {
49
+ method: 'POST',
50
+ headers: { 'content-type': 'application/json' },
51
+ body: JSON.stringify({
52
+ model: this.config.model,
53
+ stream: false,
54
+ format: 'json',
55
+ messages: [
56
+ { role: 'system', content: system },
57
+ { role: 'user', content: user },
58
+ ],
59
+ }),
60
+ });
61
+ if (!response.ok) {
62
+ throw new Error(`Local model API error ${response.status}: ${await response.text()}`);
63
+ }
64
+ const data = (await response.json());
65
+ const raw = data.message?.content ?? '';
66
+ return this.parseSingleQuestionResponse(raw, artifactType);
67
+ }
68
+ }
69
+ //# sourceMappingURL=local.js.map
@@ -0,0 +1,35 @@
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
+ generateSingleQuestion(artifactContent: string, artifactType: 'proposal' | 'design' | 'specs' | 'plan' | 'tasks', questionIndex: number, totalQuestions: number, previousQuestionTexts: string[]): Promise<Question>;
34
+ }
35
+ //# sourceMappingURL=ollama.d.ts.map
@@ -0,0 +1,69 @@
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
+ const questions = [];
39
+ for (let i = 0; i < questionCount; i++) {
40
+ const q = await this.generateSingleQuestion(artifactContent, artifactType, i, questionCount, questions.map((q) => q.text));
41
+ questions.push(q);
42
+ }
43
+ return questions;
44
+ }
45
+ async generateSingleQuestion(artifactContent, artifactType, questionIndex, totalQuestions, previousQuestionTexts) {
46
+ const { system, user } = this.buildSingleQuestionPrompt(artifactContent, artifactType, questionIndex, totalQuestions, previousQuestionTexts);
47
+ const baseUrl = this.config.endpoint ?? 'http://localhost:11434';
48
+ const response = await fetch(`${baseUrl}/api/chat`, {
49
+ method: 'POST',
50
+ headers: { 'content-type': 'application/json' },
51
+ body: JSON.stringify({
52
+ model: this.config.model ?? 'llama2',
53
+ stream: false,
54
+ format: 'json',
55
+ messages: [
56
+ { role: 'system', content: system },
57
+ { role: 'user', content: user },
58
+ ],
59
+ }),
60
+ });
61
+ if (!response.ok) {
62
+ throw new Error(`Ollama API error ${response.status}: ${await response.text()}`);
63
+ }
64
+ const data = (await response.json());
65
+ const raw = data.message?.content ?? '';
66
+ return this.parseSingleQuestionResponse(raw, artifactType);
67
+ }
68
+ }
69
+ //# sourceMappingURL=ollama.js.map
@@ -0,0 +1,35 @@
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
+ generateSingleQuestion(artifactContent: string, artifactType: 'proposal' | 'design' | 'specs' | 'plan' | 'tasks', questionIndex: number, totalQuestions: number, previousQuestionTexts: string[]): Promise<Question>;
34
+ }
35
+ //# sourceMappingURL=openai.d.ts.map
@@ -0,0 +1,72 @@
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
+ const questions = [];
39
+ for (let i = 0; i < questionCount; i++) {
40
+ const q = await this.generateSingleQuestion(artifactContent, artifactType, i, questionCount, questions.map((q) => q.text));
41
+ questions.push(q);
42
+ }
43
+ return questions;
44
+ }
45
+ async generateSingleQuestion(artifactContent, artifactType, questionIndex, totalQuestions, previousQuestionTexts) {
46
+ const { system, user } = this.buildSingleQuestionPrompt(artifactContent, artifactType, questionIndex, totalQuestions, previousQuestionTexts);
47
+ const response = await fetch('https://api.openai.com/v1/chat/completions', {
48
+ method: 'POST',
49
+ headers: {
50
+ Authorization: `Bearer ${this.config.apiKey}`,
51
+ 'content-type': 'application/json',
52
+ },
53
+ body: JSON.stringify({
54
+ model: this.config.model ?? 'gpt-4',
55
+ max_tokens: 512,
56
+ temperature: 0.7,
57
+ response_format: { type: 'json_object' },
58
+ messages: [
59
+ { role: 'system', content: system },
60
+ { role: 'user', content: user },
61
+ ],
62
+ }),
63
+ });
64
+ if (!response.ok) {
65
+ throw new Error(`OpenAI API error ${response.status}: ${await response.text()}`);
66
+ }
67
+ const data = (await response.json());
68
+ const raw = data.choices[0]?.message?.content ?? '';
69
+ return this.parseSingleQuestionResponse(raw, artifactType);
70
+ }
71
+ }
72
+ //# sourceMappingURL=openai.js.map
@@ -0,0 +1,117 @@
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
+ * On-demand question stream for the quiz executor.
53
+ *
54
+ * This class resolves the artifact contents and allocation plan upfront, but
55
+ * NEVER pre-generates questions. Each call to `next()` fetches exactly ONE
56
+ * question from the LLM — only after the previous question has been answered.
57
+ *
58
+ * This enforces FR-10: questions are fetched on-demand, never pre-generated.
59
+ * The correct answer (correctOption) is held in process memory; it is never
60
+ * written to stdout, disk, or any external surface.
61
+ */
62
+ export declare class QuizQuestionStream {
63
+ private provider;
64
+ private plan;
65
+ private totalQuestions;
66
+ private fetchedCount;
67
+ private askedTexts;
68
+ private constructor();
69
+ /**
70
+ * Create and initialise a QuizQuestionStream.
71
+ * Reads artifact files and builds the question plan, but does NOT generate any questions.
72
+ *
73
+ * @param artifactPaths - Object mapping artifact types to file paths
74
+ * @param totalQuestions - Total number of questions the quiz will ask
75
+ * @param provider - LLM provider (optional, uses fallback if not provided)
76
+ */
77
+ static create(artifactPaths: {
78
+ proposal?: string;
79
+ design?: string;
80
+ specs?: string;
81
+ plan?: string;
82
+ tasks?: string;
83
+ }, totalQuestions: number, provider?: LLMProvider): Promise<QuizQuestionStream>;
84
+ /** Total number of questions this quiz will ask. */
85
+ get total(): number;
86
+ /** Whether there are more questions to fetch. */
87
+ get hasNext(): boolean;
88
+ /**
89
+ * Fetch the next question from the LLM.
90
+ * MUST only be called after the user has answered the current question.
91
+ * Only one question is held in memory at a time; this method discards the
92
+ * previous question before fetching the next.
93
+ *
94
+ * @returns The next Question, or null if all questions have been asked.
95
+ */
96
+ next(): Promise<Question | null>;
97
+ }
98
+ /**
99
+ * Generate complete quiz question set for all artifacts.
100
+ *
101
+ * NOTE: This function pre-generates all questions and should only be used for
102
+ * non-interactive contexts (e.g. testing, pass recording). During live quiz
103
+ * execution use QuizQuestionStream.create() instead.
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 declare function generateQuizQuestions(artifactPaths: {
111
+ proposal?: string;
112
+ design?: string;
113
+ specs?: string;
114
+ plan?: string;
115
+ tasks?: string;
116
+ }, totalQuestions: number, provider?: LLMProvider): Promise<Question[]>;
117
+ //# sourceMappingURL=question-generator.d.ts.map