jumpstart-mode 1.1.12 → 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 (146) hide show
  1. package/.github/agents/jumpstart-adversary.agent.md +2 -1
  2. package/.github/agents/jumpstart-architect.agent.md +5 -6
  3. package/.github/agents/jumpstart-challenger.agent.md +2 -1
  4. package/.github/agents/jumpstart-devops.agent.md +2 -2
  5. package/.github/agents/jumpstart-diagram-verifier.agent.md +2 -1
  6. package/.github/agents/jumpstart-maintenance.agent.md +1 -0
  7. package/.github/agents/jumpstart-performance.agent.md +1 -0
  8. package/.github/agents/jumpstart-pm.agent.md +1 -1
  9. package/.github/agents/jumpstart-refactor.agent.md +1 -0
  10. package/.github/agents/jumpstart-requirements-extractor.agent.md +1 -0
  11. package/.github/agents/jumpstart-researcher.agent.md +1 -0
  12. package/.github/agents/jumpstart-retrospective.agent.md +1 -0
  13. package/.github/agents/jumpstart-reviewer.agent.md +2 -0
  14. package/.github/agents/jumpstart-scout.agent.md +1 -1
  15. package/.github/agents/jumpstart-scrum-master.agent.md +1 -0
  16. package/.github/agents/jumpstart-security.agent.md +2 -1
  17. package/.github/agents/jumpstart-tech-writer.agent.md +1 -0
  18. package/.github/workflows/quality.yml +19 -2
  19. package/.jumpstart/agents/analyst.md +38 -0
  20. package/.jumpstart/agents/architect.md +38 -0
  21. package/.jumpstart/agents/challenger.md +38 -0
  22. package/.jumpstart/agents/developer.md +41 -0
  23. package/.jumpstart/agents/pm.md +38 -0
  24. package/.jumpstart/agents/scout.md +33 -0
  25. package/.jumpstart/agents/ux-designer.md +4 -0
  26. package/.jumpstart/config.yaml +24 -0
  27. package/.jumpstart/schemas/timeline.schema.json +1 -0
  28. package/.jumpstart/skills/skill-creator/SKILL.md +485 -357
  29. package/.jumpstart/skills/skill-creator/agents/analyzer.md +274 -0
  30. package/.jumpstart/skills/skill-creator/agents/comparator.md +202 -0
  31. package/.jumpstart/skills/skill-creator/agents/grader.md +223 -0
  32. package/.jumpstart/skills/skill-creator/assets/eval_review.html +146 -0
  33. package/.jumpstart/skills/skill-creator/eval-viewer/generate_review.py +471 -0
  34. package/.jumpstart/skills/skill-creator/eval-viewer/viewer.html +1325 -0
  35. package/.jumpstart/skills/skill-creator/references/schemas.md +430 -0
  36. package/.jumpstart/skills/skill-creator/scripts/__init__.py +0 -0
  37. package/.jumpstart/skills/skill-creator/scripts/aggregate_benchmark.py +401 -0
  38. package/.jumpstart/skills/skill-creator/scripts/generate_report.py +326 -0
  39. package/.jumpstart/skills/skill-creator/scripts/improve_description.py +247 -0
  40. package/.jumpstart/skills/skill-creator/scripts/package_skill.py +136 -110
  41. package/.jumpstart/skills/skill-creator/scripts/run_eval.py +310 -0
  42. package/.jumpstart/skills/skill-creator/scripts/run_loop.py +328 -0
  43. package/.jumpstart/skills/skill-creator/scripts/utils.py +47 -0
  44. package/.jumpstart/state/timeline.json +659 -0
  45. package/.jumpstart/usage-log.json +74 -3
  46. package/README.md +62 -1
  47. package/bin/cli.js +3217 -1
  48. package/bin/headless-runner.js +62 -2
  49. package/bin/lib/agent-checkpoint.js +168 -0
  50. package/bin/lib/ai-evaluation.js +104 -0
  51. package/bin/lib/ai-intake.js +152 -0
  52. package/bin/lib/ambiguity-heatmap.js +152 -0
  53. package/bin/lib/artifact-comparison.js +104 -0
  54. package/bin/lib/ast-edit-engine.js +157 -0
  55. package/bin/lib/backlog-sync.js +338 -0
  56. package/bin/lib/bcdr-planning.js +158 -0
  57. package/bin/lib/bidirectional-trace.js +199 -0
  58. package/bin/lib/branch-workflow.js +266 -0
  59. package/bin/lib/cab-output.js +119 -0
  60. package/bin/lib/chat-integration.js +122 -0
  61. package/bin/lib/ci-cd-integration.js +208 -0
  62. package/bin/lib/codebase-retrieval.js +125 -0
  63. package/bin/lib/collaboration.js +168 -0
  64. package/bin/lib/compliance-packs.js +213 -0
  65. package/bin/lib/context-chunker.js +128 -0
  66. package/bin/lib/context-onboarding.js +122 -0
  67. package/bin/lib/contract-first.js +124 -0
  68. package/bin/lib/cost-router.js +148 -0
  69. package/bin/lib/credential-boundary.js +155 -0
  70. package/bin/lib/data-classification.js +180 -0
  71. package/bin/lib/data-contracts.js +129 -0
  72. package/bin/lib/db-evolution.js +158 -0
  73. package/bin/lib/decision-conflicts.js +299 -0
  74. package/bin/lib/delivery-confidence.js +361 -0
  75. package/bin/lib/dependency-upgrade.js +153 -0
  76. package/bin/lib/design-system.js +133 -0
  77. package/bin/lib/deterministic-artifacts.js +151 -0
  78. package/bin/lib/diagram-studio.js +115 -0
  79. package/bin/lib/domain-ontology.js +140 -0
  80. package/bin/lib/ea-review-packet.js +151 -0
  81. package/bin/lib/enterprise-search.js +123 -0
  82. package/bin/lib/enterprise-templates.js +140 -0
  83. package/bin/lib/environment-promotion.js +220 -0
  84. package/bin/lib/estimation-studio.js +130 -0
  85. package/bin/lib/event-modeling.js +133 -0
  86. package/bin/lib/evidence-collector.js +179 -0
  87. package/bin/lib/finops-planner.js +182 -0
  88. package/bin/lib/fitness-functions.js +279 -0
  89. package/bin/lib/focus.js +448 -0
  90. package/bin/lib/governance-dashboard.js +165 -0
  91. package/bin/lib/guided-handoff.js +120 -0
  92. package/bin/lib/impact-analysis.js +190 -0
  93. package/bin/lib/incident-feedback.js +157 -0
  94. package/bin/lib/integrate.js +1 -1
  95. package/bin/lib/knowledge-graph.js +122 -0
  96. package/bin/lib/legacy-modernizer.js +160 -0
  97. package/bin/lib/migration-planner.js +144 -0
  98. package/bin/lib/model-governance.js +185 -0
  99. package/bin/lib/model-router.js +144 -0
  100. package/bin/lib/multi-repo.js +272 -0
  101. package/bin/lib/next-phase.js +53 -8
  102. package/bin/lib/ops-ownership.js +152 -0
  103. package/bin/lib/parallel-agents.js +257 -0
  104. package/bin/lib/pattern-library.js +115 -0
  105. package/bin/lib/persona-packs.js +99 -0
  106. package/bin/lib/plan-executor.js +366 -0
  107. package/bin/lib/platform-engineering.js +119 -0
  108. package/bin/lib/playback-summaries.js +126 -0
  109. package/bin/lib/policy-engine.js +240 -0
  110. package/bin/lib/portfolio-reporting.js +357 -0
  111. package/bin/lib/pr-package.js +197 -0
  112. package/bin/lib/project-memory.js +235 -0
  113. package/bin/lib/prompt-governance.js +130 -0
  114. package/bin/lib/promptless-mode.js +128 -0
  115. package/bin/lib/quality-graph.js +193 -0
  116. package/bin/lib/raci-matrix.js +188 -0
  117. package/bin/lib/refactor-planner.js +167 -0
  118. package/bin/lib/reference-architectures.js +304 -0
  119. package/bin/lib/release-readiness.js +171 -0
  120. package/bin/lib/repo-graph.js +262 -0
  121. package/bin/lib/requirements-baseline.js +358 -0
  122. package/bin/lib/risk-register.js +211 -0
  123. package/bin/lib/role-approval.js +249 -0
  124. package/bin/lib/role-views.js +142 -0
  125. package/bin/lib/root-cause-analysis.js +132 -0
  126. package/bin/lib/runtime-debugger.js +154 -0
  127. package/bin/lib/safe-rename.js +135 -0
  128. package/bin/lib/semantic-diff.js +335 -0
  129. package/bin/lib/sla-slo.js +210 -0
  130. package/bin/lib/spec-comments.js +147 -0
  131. package/bin/lib/spec-maturity.js +287 -0
  132. package/bin/lib/sre-integration.js +154 -0
  133. package/bin/lib/structured-elicitation.js +174 -0
  134. package/bin/lib/telemetry-feedback.js +118 -0
  135. package/bin/lib/test-generator.js +146 -0
  136. package/bin/lib/timeline.js +2 -1
  137. package/bin/lib/tool-bridge.js +107 -0
  138. package/bin/lib/tool-guardrails.js +139 -0
  139. package/bin/lib/tool-schemas.js +172 -3
  140. package/bin/lib/transcript-ingestion.js +150 -0
  141. package/bin/lib/vendor-risk.js +173 -0
  142. package/bin/lib/waiver-workflow.js +174 -0
  143. package/bin/lib/web-dashboard.js +126 -0
  144. package/bin/lib/workshop-mode.js +165 -0
  145. package/bin/lib/workstream-ownership.js +104 -0
  146. package/package.json +1 -1
@@ -0,0 +1,361 @@
1
+ /**
2
+ * delivery-confidence.js — Delivery Confidence Scoring
3
+ *
4
+ * Score a planned or implemented feature on completeness, risk,
5
+ * ambiguity, quality, and enterprise readiness.
6
+ *
7
+ * Usage:
8
+ * node bin/lib/delivery-confidence.js score|report [options]
9
+ */
10
+
11
+ 'use strict';
12
+
13
+ const fs = require('fs');
14
+ const path = require('path');
15
+
16
+ const DIMENSIONS = ['completeness', 'risk', 'ambiguity', 'quality', 'enterprise_readiness'];
17
+
18
+ const WEIGHT_DEFAULTS = {
19
+ completeness: 0.25,
20
+ risk: 0.20,
21
+ ambiguity: 0.20,
22
+ quality: 0.20,
23
+ enterprise_readiness: 0.15
24
+ };
25
+
26
+ const CONFIDENCE_LEVELS = [
27
+ { min: 90, label: 'Very High', emoji: '🟢' },
28
+ { min: 75, label: 'High', emoji: '🟡' },
29
+ { min: 50, label: 'Medium', emoji: '🟠' },
30
+ { min: 25, label: 'Low', emoji: '🔴' },
31
+ { min: 0, label: 'Very Low', emoji: '⛔' }
32
+ ];
33
+
34
+ /**
35
+ * Analyze completeness of an artifact.
36
+ * @param {string} content
37
+ * @param {string} artifactType
38
+ * @returns {object}
39
+ */
40
+ function analyzeCompleteness(content, artifactType) {
41
+ const checks = [];
42
+ const lines = content.split('\n');
43
+
44
+ // Check for required sections
45
+ const hasFrontmatter = content.startsWith('---');
46
+ checks.push({ check: 'has_frontmatter', passed: hasFrontmatter });
47
+
48
+ const hasApproval = content.includes('Phase Gate Approval');
49
+ checks.push({ check: 'has_approval_section', passed: hasApproval });
50
+
51
+ const headingCount = (content.match(/^#{1,4}\s+/gm) || []).length;
52
+ checks.push({ check: 'has_sections', passed: headingCount >= 3 });
53
+
54
+ // Check for placeholder content
55
+ const placeholders = (content.match(/\[TODO\]|\[TBD\]|\[PLACEHOLDER\]|\[NEEDS CLARIFICATION\]/gi) || []).length;
56
+ checks.push({ check: 'no_placeholders', passed: placeholders === 0 });
57
+
58
+ // Check for empty sections
59
+ const emptySections = [];
60
+ let currentHeading = null;
61
+ let hasContent = false;
62
+ for (const line of lines) {
63
+ if (/^#{1,4}\s+/.test(line)) {
64
+ if (currentHeading && !hasContent) emptySections.push(currentHeading);
65
+ currentHeading = line.trim();
66
+ hasContent = false;
67
+ } else if (line.trim().length > 0) {
68
+ hasContent = true;
69
+ }
70
+ }
71
+ checks.push({ check: 'no_empty_sections', passed: emptySections.length === 0 });
72
+
73
+ // Check minimum content length
74
+ checks.push({ check: 'sufficient_content', passed: content.length > 500 });
75
+
76
+ const passed = checks.filter(c => c.passed).length;
77
+ return {
78
+ score: Math.round((passed / checks.length) * 100),
79
+ checks,
80
+ gaps: checks.filter(c => !c.passed).map(c => c.check),
81
+ placeholders_found: placeholders
82
+ };
83
+ }
84
+
85
+ /**
86
+ * Analyze risk factors.
87
+ * @param {string} content
88
+ * @returns {object}
89
+ */
90
+ function analyzeRisk(content) {
91
+ const risks = [];
92
+
93
+ // Check for risk-related keywords
94
+ const riskKeywords = ['risk', 'concern', 'unknown', 'assumption', 'constraint', 'blocker', 'dependency'];
95
+ for (const keyword of riskKeywords) {
96
+ const pattern = new RegExp(`\\b${keyword}s?\\b`, 'gi');
97
+ const matches = content.match(pattern) || [];
98
+ if (matches.length > 0) {
99
+ risks.push({ factor: keyword, mentions: matches.length });
100
+ }
101
+ }
102
+
103
+ // Check for explicit risk sections
104
+ const hasRiskSection = /#{1,4}\s+.*risk/i.test(content);
105
+ const hasMitigations = /mitigation|mitigate|contingency|fallback/i.test(content);
106
+
107
+ // Score: more risk identification + mitigations = higher score (better managed)
108
+ const riskIdentified = risks.length > 0;
109
+ const score = riskIdentified
110
+ ? (hasMitigations ? 85 : 55)
111
+ : (hasRiskSection ? 70 : 40);
112
+
113
+ return {
114
+ score,
115
+ risk_factors: risks,
116
+ has_risk_section: hasRiskSection,
117
+ has_mitigations: hasMitigations
118
+ };
119
+ }
120
+
121
+ /**
122
+ * Analyze ambiguity in content.
123
+ * @param {string} content
124
+ * @returns {object}
125
+ */
126
+ function analyzeAmbiguity(content) {
127
+ const ambiguousTerms = [
128
+ 'should', 'might', 'could', 'may', 'possibly', 'potentially',
129
+ 'approximately', 'roughly', 'maybe', 'etc', 'and so on',
130
+ 'as needed', 'as appropriate', 'if necessary', 'TBD', 'TBA'
131
+ ];
132
+
133
+ const findings = [];
134
+ for (const term of ambiguousTerms) {
135
+ const pattern = new RegExp(`\\b${term}\\b`, 'gi');
136
+ const matches = content.match(pattern) || [];
137
+ if (matches.length > 0) {
138
+ findings.push({ term, count: matches.length });
139
+ }
140
+ }
141
+
142
+ const totalAmbiguous = findings.reduce((sum, f) => sum + f.count, 0);
143
+ const wordCount = content.split(/\s+/).length;
144
+ const ambiguityRate = wordCount > 0 ? totalAmbiguous / wordCount : 0;
145
+
146
+ // Lower ambiguity rate = higher score
147
+ const score = Math.max(0, Math.round(100 - (ambiguityRate * 2000)));
148
+
149
+ return {
150
+ score,
151
+ ambiguous_terms: findings,
152
+ total_ambiguous: totalAmbiguous,
153
+ word_count: wordCount,
154
+ ambiguity_rate: Math.round(ambiguityRate * 10000) / 100
155
+ };
156
+ }
157
+
158
+ /**
159
+ * Analyze quality indicators.
160
+ * @param {string} content
161
+ * @param {string} root
162
+ * @returns {object}
163
+ */
164
+ function analyzeQuality(content, root) {
165
+ const checks = [];
166
+
167
+ // Check for acceptance criteria
168
+ const hasAC = /acceptance\s+criteria/i.test(content);
169
+ checks.push({ check: 'acceptance_criteria', passed: hasAC });
170
+
171
+ // Check for test references
172
+ const hasTests = /test|spec|verify|validate/i.test(content);
173
+ checks.push({ check: 'test_references', passed: hasTests });
174
+
175
+ // Check for diagrams
176
+ const hasDiagrams = /```mermaid|flowchart|sequenceDiagram|classDiagram/i.test(content);
177
+ checks.push({ check: 'has_diagrams', passed: hasDiagrams });
178
+
179
+ // Check for traceability IDs
180
+ const hasTracing = /\b(REQ-\d+|E\d+-S\d+|NFR-\d+|M\d+-T\d+)\b/.test(content);
181
+ checks.push({ check: 'traceability_ids', passed: hasTracing });
182
+
183
+ // Check for code examples
184
+ const hasCodeExamples = /```\w+/.test(content);
185
+ checks.push({ check: 'code_examples', passed: hasCodeExamples });
186
+
187
+ // Check for cross-references
188
+ const hasCrossRefs = /\[.*\]\(.*\.md\)/.test(content);
189
+ checks.push({ check: 'cross_references', passed: hasCrossRefs });
190
+
191
+ const passed = checks.filter(c => c.passed).length;
192
+ return {
193
+ score: Math.round((passed / checks.length) * 100),
194
+ checks,
195
+ gaps: checks.filter(c => !c.passed).map(c => c.check)
196
+ };
197
+ }
198
+
199
+ /**
200
+ * Analyze enterprise readiness.
201
+ * @param {string} content
202
+ * @returns {object}
203
+ */
204
+ function analyzeEnterpriseReadiness(content) {
205
+ const checks = [];
206
+
207
+ // Security considerations
208
+ const hasSecurity = /security|auth|encryption|RBAC|access control|OWASP/i.test(content);
209
+ checks.push({ check: 'security_considerations', passed: hasSecurity });
210
+
211
+ // Scalability
212
+ const hasScalability = /scalab|performance|latency|throughput|load/i.test(content);
213
+ checks.push({ check: 'scalability', passed: hasScalability });
214
+
215
+ // Compliance
216
+ const hasCompliance = /compliance|regulatory|GDPR|HIPAA|SOC|PCI|audit/i.test(content);
217
+ checks.push({ check: 'compliance', passed: hasCompliance });
218
+
219
+ // Monitoring / Observability
220
+ const hasMonitoring = /monitor|observab|logging|tracing|alert|metric/i.test(content);
221
+ checks.push({ check: 'monitoring', passed: hasMonitoring });
222
+
223
+ // Deployment
224
+ const hasDeployment = /deploy|CI\/CD|pipeline|container|kubernetes|docker/i.test(content);
225
+ checks.push({ check: 'deployment', passed: hasDeployment });
226
+
227
+ // Documentation
228
+ const hasDocumentation = /document|README|runbook|wiki|onboard/i.test(content);
229
+ checks.push({ check: 'documentation', passed: hasDocumentation });
230
+
231
+ const passed = checks.filter(c => c.passed).length;
232
+ return {
233
+ score: Math.round((passed / checks.length) * 100),
234
+ checks,
235
+ gaps: checks.filter(c => !c.passed).map(c => c.check)
236
+ };
237
+ }
238
+
239
+ /**
240
+ * Compute overall delivery confidence score.
241
+ *
242
+ * @param {string} content - Artifact content.
243
+ * @param {object} [options]
244
+ * @returns {object}
245
+ */
246
+ function scoreConfidence(content, options = {}) {
247
+ const weights = { ...WEIGHT_DEFAULTS, ...options.weights };
248
+ const root = options.root || '.';
249
+ const artifactType = options.artifactType || 'generic';
250
+
251
+ const dimensions = {
252
+ completeness: analyzeCompleteness(content, artifactType),
253
+ risk: analyzeRisk(content),
254
+ ambiguity: analyzeAmbiguity(content),
255
+ quality: analyzeQuality(content, root),
256
+ enterprise_readiness: analyzeEnterpriseReadiness(content)
257
+ };
258
+
259
+ const weightedScore = Math.round(
260
+ dimensions.completeness.score * weights.completeness +
261
+ dimensions.risk.score * weights.risk +
262
+ dimensions.ambiguity.score * weights.ambiguity +
263
+ dimensions.quality.score * weights.quality +
264
+ dimensions.enterprise_readiness.score * weights.enterprise_readiness
265
+ );
266
+
267
+ const level = CONFIDENCE_LEVELS.find(l => weightedScore >= l.min) || CONFIDENCE_LEVELS[CONFIDENCE_LEVELS.length - 1];
268
+
269
+ const allGaps = [
270
+ ...(dimensions.completeness.gaps || []),
271
+ ...(dimensions.quality.gaps || []),
272
+ ...(dimensions.enterprise_readiness.gaps || [])
273
+ ];
274
+
275
+ return {
276
+ success: true,
277
+ overall_score: weightedScore,
278
+ confidence_level: level.label,
279
+ confidence_emoji: level.emoji,
280
+ dimensions,
281
+ top_gaps: allGaps.slice(0, 5),
282
+ weights_used: weights
283
+ };
284
+ }
285
+
286
+ /**
287
+ * Score a file on disk.
288
+ *
289
+ * @param {string} filePath - Path to artifact.
290
+ * @param {object} [options]
291
+ * @returns {object}
292
+ */
293
+ function scoreFile(filePath, options = {}) {
294
+ if (!fs.existsSync(filePath)) {
295
+ return { success: false, error: `File not found: ${filePath}` };
296
+ }
297
+
298
+ const content = fs.readFileSync(filePath, 'utf8');
299
+ const result = scoreConfidence(content, options);
300
+ result.file = filePath;
301
+ return result;
302
+ }
303
+
304
+ /**
305
+ * Score all spec artifacts in a project.
306
+ *
307
+ * @param {string} root - Project root.
308
+ * @param {object} [options]
309
+ * @returns {object}
310
+ */
311
+ function scoreProject(root, options = {}) {
312
+ const specsDir = path.join(root, 'specs');
313
+ if (!fs.existsSync(specsDir)) {
314
+ return { success: false, error: 'specs/ directory not found' };
315
+ }
316
+
317
+ const results = [];
318
+ const artifacts = ['challenger-brief.md', 'product-brief.md', 'prd.md', 'architecture.md', 'implementation-plan.md'];
319
+
320
+ for (const artifact of artifacts) {
321
+ const fullPath = path.join(specsDir, artifact);
322
+ if (fs.existsSync(fullPath)) {
323
+ const result = scoreFile(fullPath, { ...options, root });
324
+ results.push({ artifact, ...result });
325
+ }
326
+ }
327
+
328
+ const avgScore = results.length > 0
329
+ ? Math.round(results.reduce((sum, r) => sum + (r.overall_score || 0), 0) / results.length)
330
+ : 0;
331
+
332
+ const level = CONFIDENCE_LEVELS.find(l => avgScore >= l.min) || CONFIDENCE_LEVELS[CONFIDENCE_LEVELS.length - 1];
333
+
334
+ return {
335
+ success: true,
336
+ project_score: avgScore,
337
+ project_confidence: level.label,
338
+ project_emoji: level.emoji,
339
+ artifacts: results,
340
+ summary: {
341
+ artifacts_scored: results.length,
342
+ average_score: avgScore,
343
+ highest: results.length > 0 ? results.reduce((a, b) => (a.overall_score || 0) > (b.overall_score || 0) ? a : b).artifact : null,
344
+ lowest: results.length > 0 ? results.reduce((a, b) => (a.overall_score || 0) < (b.overall_score || 0) ? a : b).artifact : null
345
+ }
346
+ };
347
+ }
348
+
349
+ module.exports = {
350
+ analyzeCompleteness,
351
+ analyzeRisk,
352
+ analyzeAmbiguity,
353
+ analyzeQuality,
354
+ analyzeEnterpriseReadiness,
355
+ scoreConfidence,
356
+ scoreFile,
357
+ scoreProject,
358
+ DIMENSIONS,
359
+ WEIGHT_DEFAULTS,
360
+ CONFIDENCE_LEVELS
361
+ };
@@ -0,0 +1,153 @@
1
+ /**
2
+ * dependency-upgrade.js — Dependency Upgrade Autopilot (Item 51)
3
+ *
4
+ * Plan, test, patch, and validate framework/library upgrades
5
+ * in a governed manner.
6
+ *
7
+ * Usage:
8
+ * node bin/lib/dependency-upgrade.js scan|plan|report [options]
9
+ *
10
+ * State file: .jumpstart/state/dependency-upgrades.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', 'dependency-upgrades.json');
19
+
20
+ const UPGRADE_TYPES = ['patch', 'minor', 'major'];
21
+ const RISK_BY_TYPE = { patch: 'low', minor: 'medium', major: 'high' };
22
+
23
+ function defaultState() {
24
+ return {
25
+ version: '1.0.0',
26
+ created_at: new Date().toISOString(),
27
+ last_updated: null,
28
+ scans: [],
29
+ upgrade_plans: []
30
+ };
31
+ }
32
+
33
+ function loadState(stateFile) {
34
+ const filePath = stateFile || DEFAULT_STATE_FILE;
35
+ if (!fs.existsSync(filePath)) return defaultState();
36
+ try { return JSON.parse(fs.readFileSync(filePath, 'utf8')); }
37
+ catch { return defaultState(); }
38
+ }
39
+
40
+ function saveState(state, stateFile) {
41
+ const filePath = stateFile || DEFAULT_STATE_FILE;
42
+ const dir = path.dirname(filePath);
43
+ if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
44
+ state.last_updated = new Date().toISOString();
45
+ fs.writeFileSync(filePath, JSON.stringify(state, null, 2) + '\n', 'utf8');
46
+ }
47
+
48
+ /**
49
+ * Scan for available dependency upgrades.
50
+ *
51
+ * @param {string} root - Project root.
52
+ * @param {object} [options]
53
+ * @returns {object}
54
+ */
55
+ function scanUpgrades(root, options = {}) {
56
+ const packageFile = path.join(root, 'package.json');
57
+ if (!fs.existsSync(packageFile)) {
58
+ return { success: false, error: 'package.json not found' };
59
+ }
60
+
61
+ let pkg;
62
+ try { pkg = JSON.parse(fs.readFileSync(packageFile, 'utf8')); }
63
+ catch { return { success: false, error: 'Invalid package.json' }; }
64
+
65
+ const deps = { ...pkg.dependencies, ...pkg.devDependencies };
66
+ const candidates = [];
67
+
68
+ for (const [name, version] of Object.entries(deps)) {
69
+ const clean = version.replace(/^[\^~>=<]/, '');
70
+ candidates.push({
71
+ name,
72
+ current_version: clean,
73
+ specified: version,
74
+ type: version.startsWith('^') ? 'minor-range' : version.startsWith('~') ? 'patch-range' : 'fixed',
75
+ is_dev: !!(pkg.devDependencies && pkg.devDependencies[name])
76
+ });
77
+ }
78
+
79
+ const stateFile = options.stateFile || path.join(root, DEFAULT_STATE_FILE);
80
+ const state = loadState(stateFile);
81
+ state.scans.push({
82
+ scanned_at: new Date().toISOString(),
83
+ total: candidates.length
84
+ });
85
+ saveState(state, stateFile);
86
+
87
+ return { success: true, dependencies: candidates, total: candidates.length };
88
+ }
89
+
90
+ /**
91
+ * Create an upgrade plan.
92
+ *
93
+ * @param {object} plan - { name, upgrades[] }
94
+ * @param {object} [options]
95
+ * @returns {object}
96
+ */
97
+ function createUpgradePlan(plan, options = {}) {
98
+ if (!plan || !plan.name) return { success: false, error: 'plan.name is required' };
99
+
100
+ const stateFile = options.stateFile || DEFAULT_STATE_FILE;
101
+ const state = loadState(stateFile);
102
+
103
+ const upgradePlan = {
104
+ id: `UPG-${(state.upgrade_plans.length + 1).toString().padStart(3, '0')}`,
105
+ name: plan.name,
106
+ upgrades: (plan.upgrades || []).map(u => ({
107
+ package: u.package || u.name,
108
+ from: u.from || u.current_version,
109
+ to: u.to || u.target_version,
110
+ type: u.type || 'minor',
111
+ risk: RISK_BY_TYPE[u.type] || 'medium',
112
+ status: 'planned',
113
+ test_result: null
114
+ })),
115
+ status: 'draft',
116
+ created_at: new Date().toISOString()
117
+ };
118
+
119
+ state.upgrade_plans.push(upgradePlan);
120
+ saveState(state, stateFile);
121
+
122
+ return { success: true, plan: upgradePlan };
123
+ }
124
+
125
+ /**
126
+ * Generate upgrade report.
127
+ *
128
+ * @param {object} [options]
129
+ * @returns {object}
130
+ */
131
+ function generateReport(options = {}) {
132
+ const stateFile = options.stateFile || DEFAULT_STATE_FILE;
133
+ const state = loadState(stateFile);
134
+
135
+ return {
136
+ success: true,
137
+ total_plans: state.upgrade_plans.length,
138
+ total_scans: state.scans.length,
139
+ plans: state.upgrade_plans,
140
+ last_scan: state.scans.length > 0 ? state.scans[state.scans.length - 1] : null
141
+ };
142
+ }
143
+
144
+ module.exports = {
145
+ defaultState,
146
+ loadState,
147
+ saveState,
148
+ scanUpgrades,
149
+ createUpgradePlan,
150
+ generateReport,
151
+ UPGRADE_TYPES,
152
+ RISK_BY_TYPE
153
+ };
@@ -0,0 +1,133 @@
1
+ /**
2
+ * design-system.js — Design System Integration (Item 69)
3
+ *
4
+ * Connect to enterprise design tokens, component libraries,
5
+ * accessibility standards, and brand rules.
6
+ *
7
+ * Usage:
8
+ * node bin/lib/design-system.js register|check|report [options]
9
+ *
10
+ * State file: .jumpstart/state/design-system.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', 'design-system.json');
19
+
20
+ const TOKEN_CATEGORIES = ['color', 'typography', 'spacing', 'elevation', 'breakpoint', 'motion'];
21
+ const ACCESSIBILITY_LEVELS = ['A', 'AA', 'AAA'];
22
+
23
+ function defaultState() {
24
+ return { version: '1.0.0', tokens: {}, components: [], accessibility: { level: 'AA' }, brand: {}, 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
+ /**
43
+ * Register design tokens.
44
+ */
45
+ function registerTokens(category, tokens, options = {}) {
46
+ if (!category || !tokens) return { success: false, error: 'category and tokens are required' };
47
+ if (!TOKEN_CATEGORIES.includes(category)) {
48
+ return { success: false, error: `Unknown category: ${category}. Valid: ${TOKEN_CATEGORIES.join(', ')}` };
49
+ }
50
+
51
+ const stateFile = options.stateFile || DEFAULT_STATE_FILE;
52
+ const state = loadState(stateFile);
53
+ state.tokens[category] = tokens;
54
+ saveState(state, stateFile);
55
+
56
+ return { success: true, category, token_count: Object.keys(tokens).length };
57
+ }
58
+
59
+ /**
60
+ * Register a component.
61
+ */
62
+ function registerComponent(name, spec, options = {}) {
63
+ if (!name) return { success: false, error: 'Component name is required' };
64
+
65
+ const stateFile = options.stateFile || DEFAULT_STATE_FILE;
66
+ const state = loadState(stateFile);
67
+
68
+ const component = {
69
+ name,
70
+ props: spec.props || [],
71
+ accessibility: spec.accessibility || [],
72
+ tokens_used: spec.tokens_used || [],
73
+ registered_at: new Date().toISOString()
74
+ };
75
+
76
+ state.components.push(component);
77
+ saveState(state, stateFile);
78
+
79
+ return { success: true, component };
80
+ }
81
+
82
+ /**
83
+ * Check design system compliance.
84
+ */
85
+ function checkCompliance(options = {}) {
86
+ const stateFile = options.stateFile || DEFAULT_STATE_FILE;
87
+ const state = loadState(stateFile);
88
+
89
+ const issues = [];
90
+ const tokenCategories = Object.keys(state.tokens);
91
+
92
+ for (const required of ['color', 'typography', 'spacing']) {
93
+ if (!tokenCategories.includes(required)) {
94
+ issues.push({ type: 'missing_tokens', category: required, severity: 'warning' });
95
+ }
96
+ }
97
+
98
+ for (const comp of state.components) {
99
+ if (!comp.accessibility || comp.accessibility.length === 0) {
100
+ issues.push({ type: 'missing_accessibility', component: comp.name, severity: 'warning' });
101
+ }
102
+ }
103
+
104
+ return {
105
+ success: true,
106
+ compliant: issues.length === 0,
107
+ issues,
108
+ token_categories: tokenCategories.length,
109
+ components: state.components.length,
110
+ accessibility_level: state.accessibility.level
111
+ };
112
+ }
113
+
114
+ /**
115
+ * Generate design system report.
116
+ */
117
+ function generateReport(options = {}) {
118
+ const stateFile = options.stateFile || DEFAULT_STATE_FILE;
119
+ const state = loadState(stateFile);
120
+
121
+ return {
122
+ success: true,
123
+ tokens: Object.fromEntries(Object.entries(state.tokens).map(([k, v]) => [k, Object.keys(v).length])),
124
+ components: state.components.length,
125
+ accessibility_level: state.accessibility.level,
126
+ brand: state.brand
127
+ };
128
+ }
129
+
130
+ module.exports = {
131
+ registerTokens, registerComponent, checkCompliance, generateReport,
132
+ loadState, saveState, defaultState, TOKEN_CATEGORIES, ACCESSIBILITY_LEVELS
133
+ };