jumpstart-mode 1.1.11 → 1.1.13

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 (188) hide show
  1. package/.github/agents/jumpstart-adversary.agent.md +2 -1
  2. package/.github/agents/jumpstart-architect.agent.md +6 -7
  3. package/.github/agents/jumpstart-challenger.agent.md +2 -1
  4. package/.github/agents/jumpstart-developer.agent.md +1 -1
  5. package/.github/agents/jumpstart-devops.agent.md +2 -2
  6. package/.github/agents/jumpstart-diagram-verifier.agent.md +2 -1
  7. package/.github/agents/jumpstart-maintenance.agent.md +1 -0
  8. package/.github/agents/jumpstart-performance.agent.md +1 -0
  9. package/.github/agents/jumpstart-pm.agent.md +1 -1
  10. package/.github/agents/jumpstart-refactor.agent.md +1 -0
  11. package/.github/agents/jumpstart-requirements-extractor.agent.md +1 -0
  12. package/.github/agents/jumpstart-researcher.agent.md +1 -0
  13. package/.github/agents/jumpstart-retrospective.agent.md +1 -0
  14. package/.github/agents/jumpstart-reviewer.agent.md +2 -0
  15. package/.github/agents/jumpstart-scout.agent.md +1 -1
  16. package/.github/agents/jumpstart-scrum-master.agent.md +1 -0
  17. package/.github/agents/jumpstart-security.agent.md +2 -1
  18. package/.github/agents/jumpstart-tech-writer.agent.md +1 -0
  19. package/.github/agents/jumpstart-uiux-designer.agent.md +66 -0
  20. package/.github/workflows/quality.yml +19 -2
  21. package/.jumpstart/agents/analyst.md +38 -0
  22. package/.jumpstart/agents/architect.md +39 -1
  23. package/.jumpstart/agents/challenger.md +38 -0
  24. package/.jumpstart/agents/developer.md +41 -0
  25. package/.jumpstart/agents/pm.md +38 -0
  26. package/.jumpstart/agents/scout.md +33 -0
  27. package/.jumpstart/agents/ux-designer.md +29 -9
  28. package/.jumpstart/commands/commands.md +6 -5
  29. package/.jumpstart/config.yaml +25 -1
  30. package/.jumpstart/roadmap.md +1 -1
  31. package/.jumpstart/schemas/timeline.schema.json +1 -0
  32. package/.jumpstart/skills/README.md +1 -0
  33. package/.jumpstart/skills/quality-gates/SKILL.md +126 -0
  34. package/.jumpstart/skills/skill-creator/SKILL.md +485 -357
  35. package/.jumpstart/skills/skill-creator/agents/analyzer.md +274 -0
  36. package/.jumpstart/skills/skill-creator/agents/comparator.md +202 -0
  37. package/.jumpstart/skills/skill-creator/agents/grader.md +223 -0
  38. package/.jumpstart/skills/skill-creator/assets/eval_review.html +146 -0
  39. package/.jumpstart/skills/skill-creator/eval-viewer/generate_review.py +471 -0
  40. package/.jumpstart/skills/skill-creator/eval-viewer/viewer.html +1325 -0
  41. package/.jumpstart/skills/skill-creator/references/schemas.md +430 -0
  42. package/.jumpstart/skills/skill-creator/scripts/__init__.py +0 -0
  43. package/.jumpstart/skills/skill-creator/scripts/aggregate_benchmark.py +401 -0
  44. package/.jumpstart/skills/skill-creator/scripts/generate_report.py +326 -0
  45. package/.jumpstart/skills/skill-creator/scripts/improve_description.py +247 -0
  46. package/.jumpstart/skills/skill-creator/scripts/package_skill.py +136 -110
  47. package/.jumpstart/skills/skill-creator/scripts/run_eval.py +310 -0
  48. package/.jumpstart/skills/skill-creator/scripts/run_loop.py +328 -0
  49. package/.jumpstart/skills/skill-creator/scripts/utils.py +47 -0
  50. package/.jumpstart/skills/ui-ux-pro-max/SKILL.md +266 -0
  51. package/.jumpstart/skills/ui-ux-pro-max/data/charts.csv +26 -0
  52. package/.jumpstart/skills/ui-ux-pro-max/data/colors.csv +97 -0
  53. package/.jumpstart/skills/ui-ux-pro-max/data/icons.csv +101 -0
  54. package/.jumpstart/skills/ui-ux-pro-max/data/landing.csv +31 -0
  55. package/.jumpstart/skills/ui-ux-pro-max/data/products.csv +97 -0
  56. package/.jumpstart/skills/ui-ux-pro-max/data/react-performance.csv +45 -0
  57. package/.jumpstart/skills/ui-ux-pro-max/data/stacks/astro.csv +54 -0
  58. package/.jumpstart/skills/ui-ux-pro-max/data/stacks/flutter.csv +53 -0
  59. package/.jumpstart/skills/ui-ux-pro-max/data/stacks/html-tailwind.csv +56 -0
  60. package/.jumpstart/skills/ui-ux-pro-max/data/stacks/jetpack-compose.csv +53 -0
  61. package/.jumpstart/skills/ui-ux-pro-max/data/stacks/nextjs.csv +53 -0
  62. package/.jumpstart/skills/ui-ux-pro-max/data/stacks/nuxt-ui.csv +51 -0
  63. package/.jumpstart/skills/ui-ux-pro-max/data/stacks/nuxtjs.csv +59 -0
  64. package/.jumpstart/skills/ui-ux-pro-max/data/stacks/react-native.csv +52 -0
  65. package/.jumpstart/skills/ui-ux-pro-max/data/stacks/react.csv +54 -0
  66. package/.jumpstart/skills/ui-ux-pro-max/data/stacks/shadcn.csv +61 -0
  67. package/.jumpstart/skills/ui-ux-pro-max/data/stacks/svelte.csv +54 -0
  68. package/.jumpstart/skills/ui-ux-pro-max/data/stacks/swiftui.csv +51 -0
  69. package/.jumpstart/skills/ui-ux-pro-max/data/stacks/vue.csv +50 -0
  70. package/.jumpstart/skills/ui-ux-pro-max/data/styles.csv +68 -0
  71. package/.jumpstart/skills/ui-ux-pro-max/data/typography.csv +58 -0
  72. package/.jumpstart/skills/ui-ux-pro-max/data/ui-reasoning.csv +101 -0
  73. package/.jumpstart/skills/ui-ux-pro-max/data/ux-guidelines.csv +100 -0
  74. package/.jumpstart/skills/ui-ux-pro-max/data/web-interface.csv +31 -0
  75. package/.jumpstart/skills/ui-ux-pro-max/scripts/core.py +253 -0
  76. package/.jumpstart/skills/ui-ux-pro-max/scripts/design_system.py +1067 -0
  77. package/.jumpstart/skills/ui-ux-pro-max/scripts/search.py +114 -0
  78. package/.jumpstart/state/timeline.json +659 -0
  79. package/.jumpstart/templates/model-map.md +1 -1
  80. package/.jumpstart/templates/ux-design.md +3 -3
  81. package/.jumpstart/usage-log.json +74 -3
  82. package/AGENTS.md +1 -1
  83. package/README.md +64 -3
  84. package/bin/cli.js +3217 -1
  85. package/bin/headless-runner.js +62 -2
  86. package/bin/lib/agent-checkpoint.js +168 -0
  87. package/bin/lib/ai-evaluation.js +104 -0
  88. package/bin/lib/ai-intake.js +152 -0
  89. package/bin/lib/ambiguity-heatmap.js +152 -0
  90. package/bin/lib/artifact-comparison.js +104 -0
  91. package/bin/lib/ast-edit-engine.js +157 -0
  92. package/bin/lib/backlog-sync.js +338 -0
  93. package/bin/lib/bcdr-planning.js +158 -0
  94. package/bin/lib/bidirectional-trace.js +199 -0
  95. package/bin/lib/branch-workflow.js +266 -0
  96. package/bin/lib/cab-output.js +119 -0
  97. package/bin/lib/chat-integration.js +122 -0
  98. package/bin/lib/ci-cd-integration.js +208 -0
  99. package/bin/lib/codebase-retrieval.js +125 -0
  100. package/bin/lib/collaboration.js +168 -0
  101. package/bin/lib/compliance-packs.js +213 -0
  102. package/bin/lib/context-chunker.js +128 -0
  103. package/bin/lib/context-onboarding.js +122 -0
  104. package/bin/lib/contract-first.js +124 -0
  105. package/bin/lib/cost-router.js +148 -0
  106. package/bin/lib/credential-boundary.js +155 -0
  107. package/bin/lib/data-classification.js +180 -0
  108. package/bin/lib/data-contracts.js +129 -0
  109. package/bin/lib/db-evolution.js +158 -0
  110. package/bin/lib/decision-conflicts.js +299 -0
  111. package/bin/lib/delivery-confidence.js +361 -0
  112. package/bin/lib/dependency-upgrade.js +153 -0
  113. package/bin/lib/design-system.js +133 -0
  114. package/bin/lib/deterministic-artifacts.js +151 -0
  115. package/bin/lib/diagram-studio.js +115 -0
  116. package/bin/lib/domain-ontology.js +140 -0
  117. package/bin/lib/ea-review-packet.js +151 -0
  118. package/bin/lib/enterprise-search.js +123 -0
  119. package/bin/lib/enterprise-templates.js +140 -0
  120. package/bin/lib/environment-promotion.js +220 -0
  121. package/bin/lib/estimation-studio.js +130 -0
  122. package/bin/lib/event-modeling.js +133 -0
  123. package/bin/lib/evidence-collector.js +179 -0
  124. package/bin/lib/finops-planner.js +182 -0
  125. package/bin/lib/fitness-functions.js +279 -0
  126. package/bin/lib/focus.js +448 -0
  127. package/bin/lib/governance-dashboard.js +165 -0
  128. package/bin/lib/guided-handoff.js +120 -0
  129. package/bin/lib/impact-analysis.js +190 -0
  130. package/bin/lib/incident-feedback.js +157 -0
  131. package/bin/lib/integrate.js +1 -1
  132. package/bin/lib/knowledge-graph.js +122 -0
  133. package/bin/lib/legacy-modernizer.js +160 -0
  134. package/bin/lib/migration-planner.js +144 -0
  135. package/bin/lib/model-governance.js +185 -0
  136. package/bin/lib/model-router.js +144 -0
  137. package/bin/lib/multi-repo.js +272 -0
  138. package/bin/lib/next-phase.js +53 -8
  139. package/bin/lib/ops-ownership.js +152 -0
  140. package/bin/lib/parallel-agents.js +257 -0
  141. package/bin/lib/pattern-library.js +115 -0
  142. package/bin/lib/persona-packs.js +99 -0
  143. package/bin/lib/plan-executor.js +366 -0
  144. package/bin/lib/platform-engineering.js +119 -0
  145. package/bin/lib/playback-summaries.js +126 -0
  146. package/bin/lib/policy-engine.js +240 -0
  147. package/bin/lib/portfolio-reporting.js +357 -0
  148. package/bin/lib/pr-package.js +197 -0
  149. package/bin/lib/project-memory.js +235 -0
  150. package/bin/lib/prompt-governance.js +130 -0
  151. package/bin/lib/promptless-mode.js +128 -0
  152. package/bin/lib/quality-graph.js +193 -0
  153. package/bin/lib/raci-matrix.js +188 -0
  154. package/bin/lib/refactor-planner.js +167 -0
  155. package/bin/lib/reference-architectures.js +304 -0
  156. package/bin/lib/release-readiness.js +171 -0
  157. package/bin/lib/repo-graph.js +262 -0
  158. package/bin/lib/requirements-baseline.js +358 -0
  159. package/bin/lib/risk-register.js +211 -0
  160. package/bin/lib/role-approval.js +249 -0
  161. package/bin/lib/role-views.js +142 -0
  162. package/bin/lib/root-cause-analysis.js +132 -0
  163. package/bin/lib/runtime-debugger.js +154 -0
  164. package/bin/lib/safe-rename.js +135 -0
  165. package/bin/lib/secret-scanner.js +313 -0
  166. package/bin/lib/semantic-diff.js +335 -0
  167. package/bin/lib/sla-slo.js +210 -0
  168. package/bin/lib/smoke-tester.js +344 -0
  169. package/bin/lib/spec-comments.js +147 -0
  170. package/bin/lib/spec-maturity.js +287 -0
  171. package/bin/lib/sre-integration.js +154 -0
  172. package/bin/lib/structured-elicitation.js +174 -0
  173. package/bin/lib/telemetry-feedback.js +118 -0
  174. package/bin/lib/test-generator.js +146 -0
  175. package/bin/lib/timeline.js +2 -1
  176. package/bin/lib/tool-bridge.js +159 -0
  177. package/bin/lib/tool-guardrails.js +139 -0
  178. package/bin/lib/tool-schemas.js +281 -3
  179. package/bin/lib/transcript-ingestion.js +150 -0
  180. package/bin/lib/type-checker.js +261 -0
  181. package/bin/lib/uat-coverage.js +411 -0
  182. package/bin/lib/vendor-risk.js +173 -0
  183. package/bin/lib/waiver-workflow.js +174 -0
  184. package/bin/lib/web-dashboard.js +126 -0
  185. package/bin/lib/workshop-mode.js +165 -0
  186. package/bin/lib/workstream-ownership.js +104 -0
  187. package/package.json +1 -1
  188. package/.github/agents/jumpstart-ux-designer.agent.md +0 -45
@@ -0,0 +1,287 @@
1
+ /**
2
+ * spec-maturity.js — Spec Maturity Model
3
+ *
4
+ * Score artifacts from draft to production-ready with explicit gaps
5
+ * for enterprise delivery.
6
+ *
7
+ * Usage:
8
+ * node bin/lib/spec-maturity.js assess|report [options]
9
+ */
10
+
11
+ 'use strict';
12
+
13
+ const fs = require('fs');
14
+ const path = require('path');
15
+
16
+ const MATURITY_LEVELS = [
17
+ { level: 1, name: 'Draft', min_score: 0, description: 'Initial capture, may contain placeholders and gaps' },
18
+ { level: 2, name: 'Reviewed', min_score: 30, description: 'Peer-reviewed, major gaps addressed' },
19
+ { level: 3, name: 'Approved', min_score: 55, description: 'Stakeholder-approved, phase gate passed' },
20
+ { level: 4, name: 'Implementation-Ready', min_score: 75, description: 'Detailed enough for developers to implement' },
21
+ { level: 5, name: 'Production-Ready', min_score: 90, description: 'Complete, validated, enterprise-ready' }
22
+ ];
23
+
24
+ const MATURITY_CRITERIA = {
25
+ structure: {
26
+ weight: 0.15,
27
+ checks: [
28
+ { id: 'has_frontmatter', description: 'YAML frontmatter present' },
29
+ { id: 'has_toc', description: 'Table of contents present' },
30
+ { id: 'has_sections', description: 'Proper heading hierarchy' },
31
+ { id: 'no_empty_sections', description: 'No empty sections' }
32
+ ]
33
+ },
34
+ completeness: {
35
+ weight: 0.25,
36
+ checks: [
37
+ { id: 'no_placeholders', description: 'No TODO/TBD/placeholder markers' },
38
+ { id: 'no_clarifications', description: 'No [NEEDS CLARIFICATION] tags' },
39
+ { id: 'sufficient_length', description: 'Sufficient content (>1000 chars)' },
40
+ { id: 'has_detail', description: 'Detailed descriptions (avg paragraph >50 words)' }
41
+ ]
42
+ },
43
+ traceability: {
44
+ weight: 0.15,
45
+ checks: [
46
+ { id: 'has_requirement_ids', description: 'Contains requirement/story IDs' },
47
+ { id: 'has_cross_refs', description: 'Cross-references to other artifacts' },
48
+ { id: 'has_version', description: 'Version information present' }
49
+ ]
50
+ },
51
+ quality: {
52
+ weight: 0.20,
53
+ checks: [
54
+ { id: 'has_acceptance_criteria', description: 'Acceptance criteria defined' },
55
+ { id: 'has_diagrams', description: 'Diagrams included (Mermaid/images)' },
56
+ { id: 'has_examples', description: 'Examples or code samples' },
57
+ { id: 'low_ambiguity', description: 'Low ambiguity (minimal should/might/could)' }
58
+ ]
59
+ },
60
+ governance: {
61
+ weight: 0.15,
62
+ checks: [
63
+ { id: 'has_approval', description: 'Phase gate approval section' },
64
+ { id: 'is_approved', description: 'Actually approved (checkboxes checked)' },
65
+ { id: 'has_dates', description: 'Dates and timestamps present' }
66
+ ]
67
+ },
68
+ enterprise: {
69
+ weight: 0.10,
70
+ checks: [
71
+ { id: 'has_nfrs', description: 'Non-functional requirements addressed' },
72
+ { id: 'has_security', description: 'Security considerations' },
73
+ { id: 'has_compliance', description: 'Compliance/regulatory mentions' }
74
+ ]
75
+ }
76
+ };
77
+
78
+ /**
79
+ * Run maturity checks on content.
80
+ * @param {string} content
81
+ * @returns {object}
82
+ */
83
+ function runMaturityChecks(content) {
84
+ const results = {};
85
+ const lines = content.split('\n');
86
+
87
+ // Structure checks
88
+ results.has_frontmatter = content.startsWith('---');
89
+ results.has_toc = /table of contents|## contents|## toc/i.test(content);
90
+ const headings = lines.filter(l => /^#{1,4}\s+/.test(l));
91
+ results.has_sections = headings.length >= 3;
92
+
93
+ let emptyCount = 0;
94
+ let currentHeading = null;
95
+ let hasContentAfterHeading = false;
96
+ for (const line of lines) {
97
+ if (/^#{1,4}\s+/.test(line)) {
98
+ if (currentHeading && !hasContentAfterHeading) emptyCount++;
99
+ currentHeading = line;
100
+ hasContentAfterHeading = false;
101
+ } else if (line.trim().length > 0 && currentHeading) {
102
+ hasContentAfterHeading = true;
103
+ }
104
+ }
105
+ results.no_empty_sections = emptyCount === 0;
106
+
107
+ // Completeness checks
108
+ results.no_placeholders = !/\[TODO\]|\[TBD\]|\[PLACEHOLDER\]/i.test(content);
109
+ results.no_clarifications = !/\[NEEDS CLARIFICATION/i.test(content);
110
+ results.sufficient_length = content.length > 1000;
111
+
112
+ const paragraphs = content.split(/\n\n+/).filter(p => p.trim().length > 0 && !/^#/.test(p.trim()));
113
+ const avgWords = paragraphs.length > 0
114
+ ? paragraphs.reduce((sum, p) => sum + p.split(/\s+/).length, 0) / paragraphs.length
115
+ : 0;
116
+ results.has_detail = avgWords > 20;
117
+
118
+ // Traceability checks
119
+ results.has_requirement_ids = /\b(REQ-\d+|E\d+-S\d+|NFR-\d+|UC-\d+|FR-\d+|AC-\d+|M\d+-T\d+)\b/.test(content);
120
+ results.has_cross_refs = /\[.*\]\(.*\.md\)/.test(content);
121
+ results.has_version = /version[:\s]+\d+/i.test(content) || /^version:/m.test(content);
122
+
123
+ // Quality checks
124
+ results.has_acceptance_criteria = /acceptance\s+criteria/i.test(content);
125
+ results.has_diagrams = /```mermaid|flowchart|sequenceDiagram|classDiagram|\!\[.*\]\(.*\)/i.test(content);
126
+ results.has_examples = /```\w+/.test(content) || /example[:\s]/i.test(content);
127
+
128
+ const ambiguousTerms = ['should', 'might', 'could', 'may', 'possibly', 'potentially', 'TBD', 'TBA'];
129
+ let ambiguousCount = 0;
130
+ for (const term of ambiguousTerms) {
131
+ const pattern = new RegExp(`\\b${term}\\b`, 'gi');
132
+ ambiguousCount += (content.match(pattern) || []).length;
133
+ }
134
+ const wordCount = content.split(/\s+/).length;
135
+ results.low_ambiguity = wordCount > 0 ? (ambiguousCount / wordCount) < 0.02 : true;
136
+
137
+ // Governance checks
138
+ results.has_approval = /Phase Gate Approval/i.test(content);
139
+ results.is_approved = /- \[x\]/i.test(content) && /Approved by[:\s]+(?!Pending)/i.test(content);
140
+ results.has_dates = /\d{4}-\d{2}-\d{2}/.test(content);
141
+
142
+ // Enterprise checks
143
+ results.has_nfrs = /non-functional|NFR|performance|scalab|availab/i.test(content);
144
+ results.has_security = /security|auth|encryption|OWASP/i.test(content);
145
+ results.has_compliance = /compliance|regulatory|GDPR|HIPAA|SOC|audit/i.test(content);
146
+
147
+ return results;
148
+ }
149
+
150
+ /**
151
+ * Assess maturity of an artifact.
152
+ *
153
+ * @param {string} content - Artifact content.
154
+ * @param {object} [options]
155
+ * @returns {object}
156
+ */
157
+ function assessMaturity(content, options = {}) {
158
+ const checkResults = runMaturityChecks(content);
159
+ const categoryScores = {};
160
+ let totalWeightedScore = 0;
161
+ const gaps = [];
162
+
163
+ for (const [category, config] of Object.entries(MATURITY_CRITERIA)) {
164
+ const passed = config.checks.filter(c => checkResults[c.id]);
165
+ const score = config.checks.length > 0
166
+ ? Math.round((passed.length / config.checks.length) * 100)
167
+ : 0;
168
+
169
+ categoryScores[category] = {
170
+ score,
171
+ passed: passed.length,
172
+ total: config.checks.length,
173
+ weight: config.weight
174
+ };
175
+
176
+ totalWeightedScore += score * config.weight;
177
+
178
+ // Record gaps
179
+ for (const check of config.checks) {
180
+ if (!checkResults[check.id]) {
181
+ gaps.push({
182
+ category,
183
+ check: check.id,
184
+ description: check.description
185
+ });
186
+ }
187
+ }
188
+ }
189
+
190
+ const overallScore = Math.round(totalWeightedScore);
191
+ const maturityLevel = [...MATURITY_LEVELS].reverse().find(l => overallScore >= l.min_score) || MATURITY_LEVELS[0];
192
+
193
+ // Compute next level and what's needed
194
+ const nextLevel = MATURITY_LEVELS.find(l => l.min_score > overallScore);
195
+
196
+ return {
197
+ success: true,
198
+ overall_score: overallScore,
199
+ maturity_level: maturityLevel.level,
200
+ maturity_name: maturityLevel.name,
201
+ maturity_description: maturityLevel.description,
202
+ category_scores: categoryScores,
203
+ gaps,
204
+ next_level: nextLevel ? {
205
+ level: nextLevel.level,
206
+ name: nextLevel.name,
207
+ points_needed: nextLevel.min_score - overallScore,
208
+ description: nextLevel.description
209
+ } : null,
210
+ total_checks: Object.values(MATURITY_CRITERIA).reduce((sum, c) => sum + c.checks.length, 0),
211
+ checks_passed: Object.values(MATURITY_CRITERIA).reduce((sum, c) =>
212
+ sum + c.checks.filter(ck => checkResults[ck.id]).length, 0
213
+ )
214
+ };
215
+ }
216
+
217
+ /**
218
+ * Assess maturity of a file.
219
+ *
220
+ * @param {string} filePath
221
+ * @param {object} [options]
222
+ * @returns {object}
223
+ */
224
+ function assessFile(filePath, options = {}) {
225
+ if (!fs.existsSync(filePath)) {
226
+ return { success: false, error: `File not found: ${filePath}` };
227
+ }
228
+
229
+ const content = fs.readFileSync(filePath, 'utf8');
230
+ const result = assessMaturity(content, options);
231
+ result.file = filePath;
232
+ return result;
233
+ }
234
+
235
+ /**
236
+ * Assess maturity across all spec artifacts.
237
+ *
238
+ * @param {string} root - Project root.
239
+ * @param {object} [options]
240
+ * @returns {object}
241
+ */
242
+ function assessProject(root, options = {}) {
243
+ const specsDir = path.join(root, 'specs');
244
+ if (!fs.existsSync(specsDir)) {
245
+ return { success: false, error: 'specs/ directory not found' };
246
+ }
247
+
248
+ const artifacts = ['challenger-brief.md', 'product-brief.md', 'prd.md', 'architecture.md', 'implementation-plan.md'];
249
+ const results = [];
250
+
251
+ for (const artifact of artifacts) {
252
+ const fullPath = path.join(specsDir, artifact);
253
+ if (fs.existsSync(fullPath)) {
254
+ const result = assessFile(fullPath, options);
255
+ results.push({ artifact, ...result });
256
+ }
257
+ }
258
+
259
+ const avgScore = results.length > 0
260
+ ? Math.round(results.reduce((sum, r) => sum + (r.overall_score || 0), 0) / results.length)
261
+ : 0;
262
+
263
+ const avgLevel = [...MATURITY_LEVELS].reverse().find(l => avgScore >= l.min_score) || MATURITY_LEVELS[0];
264
+
265
+ return {
266
+ success: true,
267
+ project_score: avgScore,
268
+ project_maturity: avgLevel.name,
269
+ project_level: avgLevel.level,
270
+ artifacts: results,
271
+ summary: {
272
+ artifacts_assessed: results.length,
273
+ average_score: avgScore,
274
+ production_ready: results.filter(r => (r.maturity_level || 0) >= 5).length,
275
+ draft: results.filter(r => (r.maturity_level || 0) <= 1).length
276
+ }
277
+ };
278
+ }
279
+
280
+ module.exports = {
281
+ runMaturityChecks,
282
+ assessMaturity,
283
+ assessFile,
284
+ assessProject,
285
+ MATURITY_LEVELS,
286
+ MATURITY_CRITERIA
287
+ };
@@ -0,0 +1,154 @@
1
+ /**
2
+ * sre-integration.js — SRE Integration (Item 94)
3
+ *
4
+ * Generate monitors, alerts, runbooks, dashboards,
5
+ * and error-budget alignment.
6
+ *
7
+ * Usage:
8
+ * node bin/lib/sre-integration.js generate|configure|report [options]
9
+ *
10
+ * State file: .jumpstart/state/sre-integration.json
11
+ */
12
+
13
+ 'use strict';
14
+
15
+ const fs = require('fs');
16
+ const path = require('path');
17
+
18
+ const DEFAULT_STATE_FILE = path.join('.jumpstart', 'state', 'sre-integration.json');
19
+
20
+ const MONITOR_TYPES = ['uptime', 'latency', 'error-rate', 'saturation', 'custom'];
21
+ const ALERT_SEVERITIES = ['critical', 'warning', 'info'];
22
+
23
+ function defaultState() {
24
+ return { version: '1.0.0', monitors: [], alerts: [], runbooks: [], error_budgets: [], last_updated: null };
25
+ }
26
+
27
+ function loadState(stateFile) {
28
+ const fp = stateFile || DEFAULT_STATE_FILE;
29
+ if (!fs.existsSync(fp)) return defaultState();
30
+ try { return JSON.parse(fs.readFileSync(fp, 'utf8')); }
31
+ catch { return defaultState(); }
32
+ }
33
+
34
+ function saveState(state, stateFile) {
35
+ const fp = stateFile || DEFAULT_STATE_FILE;
36
+ const dir = path.dirname(fp);
37
+ if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
38
+ state.last_updated = new Date().toISOString();
39
+ fs.writeFileSync(fp, JSON.stringify(state, null, 2) + '\n', 'utf8');
40
+ }
41
+
42
+ function generateMonitor(name, type, options = {}) {
43
+ if (!name || !type) return { success: false, error: 'name and type are required' };
44
+ if (!MONITOR_TYPES.includes(type)) {
45
+ return { success: false, error: `Unknown type: ${type}. Valid: ${MONITOR_TYPES.join(', ')}` };
46
+ }
47
+
48
+ const stateFile = options.stateFile || DEFAULT_STATE_FILE;
49
+ const state = loadState(stateFile);
50
+
51
+ const monitor = {
52
+ id: `MON-${Date.now()}`,
53
+ name,
54
+ type,
55
+ threshold: options.threshold || null,
56
+ interval: options.interval || '60s',
57
+ service: options.service || null,
58
+ created_at: new Date().toISOString()
59
+ };
60
+
61
+ state.monitors.push(monitor);
62
+ saveState(state, stateFile);
63
+
64
+ return { success: true, monitor };
65
+ }
66
+
67
+ function generateAlert(name, severity, options = {}) {
68
+ if (!name || !severity) return { success: false, error: 'name and severity are required' };
69
+ if (!ALERT_SEVERITIES.includes(severity)) {
70
+ return { success: false, error: `Unknown severity: ${severity}. Valid: ${ALERT_SEVERITIES.join(', ')}` };
71
+ }
72
+
73
+ const stateFile = options.stateFile || DEFAULT_STATE_FILE;
74
+ const state = loadState(stateFile);
75
+
76
+ const alert = {
77
+ id: `ALERT-${Date.now()}`,
78
+ name,
79
+ severity,
80
+ condition: options.condition || null,
81
+ notification_channels: options.channels || [],
82
+ runbook_id: options.runbook_id || null,
83
+ created_at: new Date().toISOString()
84
+ };
85
+
86
+ state.alerts.push(alert);
87
+ saveState(state, stateFile);
88
+
89
+ return { success: true, alert };
90
+ }
91
+
92
+ function generateRunbook(name, steps, options = {}) {
93
+ if (!name || !steps) return { success: false, error: 'name and steps are required' };
94
+
95
+ const stateFile = options.stateFile || DEFAULT_STATE_FILE;
96
+ const state = loadState(stateFile);
97
+
98
+ const runbook = {
99
+ id: `RB-${Date.now()}`,
100
+ name,
101
+ steps: Array.isArray(steps) ? steps.map((s, i) => ({ order: i + 1, action: s })) : [],
102
+ service: options.service || null,
103
+ created_at: new Date().toISOString()
104
+ };
105
+
106
+ state.runbooks.push(runbook);
107
+ saveState(state, stateFile);
108
+
109
+ return { success: true, runbook };
110
+ }
111
+
112
+ function configureErrorBudget(service, slo, options = {}) {
113
+ if (!service || !slo) return { success: false, error: 'service and slo are required' };
114
+
115
+ const stateFile = options.stateFile || DEFAULT_STATE_FILE;
116
+ const state = loadState(stateFile);
117
+
118
+ const budget = {
119
+ id: `EB-${Date.now()}`,
120
+ service,
121
+ slo_target: slo,
122
+ budget_remaining: options.remaining || 100,
123
+ window: options.window || '30d',
124
+ created_at: new Date().toISOString()
125
+ };
126
+
127
+ state.error_budgets.push(budget);
128
+ saveState(state, stateFile);
129
+
130
+ return { success: true, error_budget: budget };
131
+ }
132
+
133
+ function generateReport(options = {}) {
134
+ const stateFile = options.stateFile || DEFAULT_STATE_FILE;
135
+ const state = loadState(stateFile);
136
+
137
+ return {
138
+ success: true,
139
+ total_monitors: state.monitors.length,
140
+ total_alerts: state.alerts.length,
141
+ total_runbooks: state.runbooks.length,
142
+ total_error_budgets: state.error_budgets.length,
143
+ monitors: state.monitors,
144
+ alerts: state.alerts,
145
+ runbooks: state.runbooks,
146
+ error_budgets: state.error_budgets
147
+ };
148
+ }
149
+
150
+ module.exports = {
151
+ generateMonitor, generateAlert, generateRunbook, configureErrorBudget, generateReport,
152
+ loadState, saveState, defaultState,
153
+ MONITOR_TYPES, ALERT_SEVERITIES
154
+ };
@@ -0,0 +1,174 @@
1
+ /**
2
+ * structured-elicitation.js — Facilitated Q&A with Structured Elicitation (Item 66)
3
+ *
4
+ * Adaptive questioning based on domain, compliance, and delivery model.
5
+ *
6
+ * Usage:
7
+ * node bin/lib/structured-elicitation.js start|answer|status|report [options]
8
+ *
9
+ * State file: .jumpstart/state/elicitation.json
10
+ */
11
+
12
+ 'use strict';
13
+
14
+ const fs = require('fs');
15
+ const path = require('path');
16
+
17
+ const DEFAULT_STATE_FILE = path.join('.jumpstart', 'state', 'elicitation.json');
18
+
19
+ const DOMAINS = ['healthcare', 'fintech', 'retail', 'manufacturing', 'public-sector', 'general'];
20
+
21
+ const QUESTION_BANKS = {
22
+ general: [
23
+ { id: 'G1', text: 'What problem are you solving?', category: 'problem' },
24
+ { id: 'G2', text: 'Who are the primary users?', category: 'users' },
25
+ { id: 'G3', text: 'What are the success criteria?', category: 'success' },
26
+ { id: 'G4', text: 'What are the key constraints?', category: 'constraints' },
27
+ { id: 'G5', text: 'What is the timeline?', category: 'timeline' }
28
+ ],
29
+ healthcare: [
30
+ { id: 'H1', text: 'Is PHI (Protected Health Information) involved?', category: 'compliance' },
31
+ { id: 'H2', text: 'What HIPAA controls are required?', category: 'compliance' },
32
+ { id: 'H3', text: 'Are there FDA regulatory requirements?', category: 'regulatory' }
33
+ ],
34
+ fintech: [
35
+ { id: 'F1', text: 'What financial regulations apply (PCI-DSS, SOX)?', category: 'compliance' },
36
+ { id: 'F2', text: 'Are there data residency requirements?', category: 'compliance' },
37
+ { id: 'F3', text: 'What audit trail requirements exist?', category: 'audit' }
38
+ ]
39
+ };
40
+
41
+ function defaultState() {
42
+ return { version: '1.0.0', sessions: [], last_updated: null };
43
+ }
44
+
45
+ function loadState(stateFile) {
46
+ const fp = stateFile || DEFAULT_STATE_FILE;
47
+ if (!fs.existsSync(fp)) return defaultState();
48
+ try { return JSON.parse(fs.readFileSync(fp, 'utf8')); }
49
+ catch { return defaultState(); }
50
+ }
51
+
52
+ function saveState(state, stateFile) {
53
+ const fp = stateFile || DEFAULT_STATE_FILE;
54
+ const dir = path.dirname(fp);
55
+ if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
56
+ state.last_updated = new Date().toISOString();
57
+ fs.writeFileSync(fp, JSON.stringify(state, null, 2) + '\n', 'utf8');
58
+ }
59
+
60
+ /**
61
+ * Start a structured elicitation session.
62
+ */
63
+ function startElicitation(domain, options = {}) {
64
+ if (!domain) domain = 'general';
65
+ if (!DOMAINS.includes(domain)) {
66
+ return { success: false, error: `Unknown domain: ${domain}. Valid: ${DOMAINS.join(', ')}` };
67
+ }
68
+
69
+ const stateFile = options.stateFile || DEFAULT_STATE_FILE;
70
+ const state = loadState(stateFile);
71
+
72
+ const questions = [
73
+ ...(QUESTION_BANKS.general || []),
74
+ ...(QUESTION_BANKS[domain] || [])
75
+ ];
76
+
77
+ const session = {
78
+ id: `ELICIT-${Date.now()}`,
79
+ domain,
80
+ status: 'active',
81
+ questions: questions.map(q => ({ ...q, answered: false, answer: null })),
82
+ created_at: new Date().toISOString()
83
+ };
84
+
85
+ state.sessions.push(session);
86
+ saveState(state, stateFile);
87
+
88
+ return { success: true, session };
89
+ }
90
+
91
+ /**
92
+ * Answer a question.
93
+ */
94
+ function answerQuestion(sessionId, questionId, answer, options = {}) {
95
+ if (!sessionId || !questionId || !answer) {
96
+ return { success: false, error: 'sessionId, questionId, and answer are required' };
97
+ }
98
+
99
+ const stateFile = options.stateFile || DEFAULT_STATE_FILE;
100
+ const state = loadState(stateFile);
101
+
102
+ const session = state.sessions.find(s => s.id === sessionId);
103
+ if (!session) return { success: false, error: `Session ${sessionId} not found` };
104
+
105
+ const question = session.questions.find(q => q.id === questionId);
106
+ if (!question) return { success: false, error: `Question ${questionId} not found` };
107
+
108
+ question.answered = true;
109
+ question.answer = answer;
110
+ question.answered_at = new Date().toISOString();
111
+
112
+ saveState(state, stateFile);
113
+
114
+ const remaining = session.questions.filter(q => !q.answered).length;
115
+ return { success: true, question, remaining };
116
+ }
117
+
118
+ /**
119
+ * Get next unanswered question.
120
+ */
121
+ function getNextQuestion(sessionId, options = {}) {
122
+ const stateFile = options.stateFile || DEFAULT_STATE_FILE;
123
+ const state = loadState(stateFile);
124
+
125
+ const session = state.sessions.find(s => s.id === sessionId);
126
+ if (!session) return { success: false, error: `Session ${sessionId} not found` };
127
+
128
+ const next = session.questions.find(q => !q.answered);
129
+ if (!next) return { success: true, complete: true, question: null };
130
+
131
+ return { success: true, complete: false, question: next };
132
+ }
133
+
134
+ /**
135
+ * Generate elicitation report.
136
+ */
137
+ function generateReport(sessionId, options = {}) {
138
+ const stateFile = options.stateFile || DEFAULT_STATE_FILE;
139
+ const state = loadState(stateFile);
140
+
141
+ const session = state.sessions.find(s => s.id === sessionId);
142
+ if (!session) return { success: false, error: `Session ${sessionId} not found` };
143
+
144
+ const answered = session.questions.filter(q => q.answered);
145
+ const unanswered = session.questions.filter(q => !q.answered);
146
+ const byCategory = {};
147
+ for (const q of answered) {
148
+ if (!byCategory[q.category]) byCategory[q.category] = [];
149
+ byCategory[q.category].push({ question: q.text, answer: q.answer });
150
+ }
151
+
152
+ return {
153
+ success: true,
154
+ domain: session.domain,
155
+ total_questions: session.questions.length,
156
+ answered: answered.length,
157
+ unanswered: unanswered.length,
158
+ completion_pct: Math.round((answered.length / session.questions.length) * 100),
159
+ by_category: byCategory,
160
+ gaps: unanswered.map(q => q.text)
161
+ };
162
+ }
163
+
164
+ module.exports = {
165
+ startElicitation,
166
+ answerQuestion,
167
+ getNextQuestion,
168
+ generateReport,
169
+ loadState,
170
+ saveState,
171
+ defaultState,
172
+ DOMAINS,
173
+ QUESTION_BANKS
174
+ };