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.
- package/.github/agents/jumpstart-adversary.agent.md +2 -1
- package/.github/agents/jumpstart-architect.agent.md +6 -7
- package/.github/agents/jumpstart-challenger.agent.md +2 -1
- package/.github/agents/jumpstart-developer.agent.md +1 -1
- package/.github/agents/jumpstart-devops.agent.md +2 -2
- package/.github/agents/jumpstart-diagram-verifier.agent.md +2 -1
- package/.github/agents/jumpstart-maintenance.agent.md +1 -0
- package/.github/agents/jumpstart-performance.agent.md +1 -0
- package/.github/agents/jumpstart-pm.agent.md +1 -1
- package/.github/agents/jumpstart-refactor.agent.md +1 -0
- package/.github/agents/jumpstart-requirements-extractor.agent.md +1 -0
- package/.github/agents/jumpstart-researcher.agent.md +1 -0
- package/.github/agents/jumpstart-retrospective.agent.md +1 -0
- package/.github/agents/jumpstart-reviewer.agent.md +2 -0
- package/.github/agents/jumpstart-scout.agent.md +1 -1
- package/.github/agents/jumpstart-scrum-master.agent.md +1 -0
- package/.github/agents/jumpstart-security.agent.md +2 -1
- package/.github/agents/jumpstart-tech-writer.agent.md +1 -0
- package/.github/agents/jumpstart-uiux-designer.agent.md +66 -0
- package/.github/workflows/quality.yml +19 -2
- package/.jumpstart/agents/analyst.md +38 -0
- package/.jumpstart/agents/architect.md +39 -1
- package/.jumpstart/agents/challenger.md +38 -0
- package/.jumpstart/agents/developer.md +41 -0
- package/.jumpstart/agents/pm.md +38 -0
- package/.jumpstart/agents/scout.md +33 -0
- package/.jumpstart/agents/ux-designer.md +29 -9
- package/.jumpstart/commands/commands.md +6 -5
- package/.jumpstart/config.yaml +25 -1
- package/.jumpstart/roadmap.md +1 -1
- package/.jumpstart/schemas/timeline.schema.json +1 -0
- package/.jumpstart/skills/README.md +1 -0
- package/.jumpstart/skills/quality-gates/SKILL.md +126 -0
- package/.jumpstart/skills/skill-creator/SKILL.md +485 -357
- package/.jumpstart/skills/skill-creator/agents/analyzer.md +274 -0
- package/.jumpstart/skills/skill-creator/agents/comparator.md +202 -0
- package/.jumpstart/skills/skill-creator/agents/grader.md +223 -0
- package/.jumpstart/skills/skill-creator/assets/eval_review.html +146 -0
- package/.jumpstart/skills/skill-creator/eval-viewer/generate_review.py +471 -0
- package/.jumpstart/skills/skill-creator/eval-viewer/viewer.html +1325 -0
- package/.jumpstart/skills/skill-creator/references/schemas.md +430 -0
- package/.jumpstart/skills/skill-creator/scripts/__init__.py +0 -0
- package/.jumpstart/skills/skill-creator/scripts/aggregate_benchmark.py +401 -0
- package/.jumpstart/skills/skill-creator/scripts/generate_report.py +326 -0
- package/.jumpstart/skills/skill-creator/scripts/improve_description.py +247 -0
- package/.jumpstart/skills/skill-creator/scripts/package_skill.py +136 -110
- package/.jumpstart/skills/skill-creator/scripts/run_eval.py +310 -0
- package/.jumpstart/skills/skill-creator/scripts/run_loop.py +328 -0
- package/.jumpstart/skills/skill-creator/scripts/utils.py +47 -0
- package/.jumpstart/skills/ui-ux-pro-max/SKILL.md +266 -0
- package/.jumpstart/skills/ui-ux-pro-max/data/charts.csv +26 -0
- package/.jumpstart/skills/ui-ux-pro-max/data/colors.csv +97 -0
- package/.jumpstart/skills/ui-ux-pro-max/data/icons.csv +101 -0
- package/.jumpstart/skills/ui-ux-pro-max/data/landing.csv +31 -0
- package/.jumpstart/skills/ui-ux-pro-max/data/products.csv +97 -0
- package/.jumpstart/skills/ui-ux-pro-max/data/react-performance.csv +45 -0
- package/.jumpstart/skills/ui-ux-pro-max/data/stacks/astro.csv +54 -0
- package/.jumpstart/skills/ui-ux-pro-max/data/stacks/flutter.csv +53 -0
- package/.jumpstart/skills/ui-ux-pro-max/data/stacks/html-tailwind.csv +56 -0
- package/.jumpstart/skills/ui-ux-pro-max/data/stacks/jetpack-compose.csv +53 -0
- package/.jumpstart/skills/ui-ux-pro-max/data/stacks/nextjs.csv +53 -0
- package/.jumpstart/skills/ui-ux-pro-max/data/stacks/nuxt-ui.csv +51 -0
- package/.jumpstart/skills/ui-ux-pro-max/data/stacks/nuxtjs.csv +59 -0
- package/.jumpstart/skills/ui-ux-pro-max/data/stacks/react-native.csv +52 -0
- package/.jumpstart/skills/ui-ux-pro-max/data/stacks/react.csv +54 -0
- package/.jumpstart/skills/ui-ux-pro-max/data/stacks/shadcn.csv +61 -0
- package/.jumpstart/skills/ui-ux-pro-max/data/stacks/svelte.csv +54 -0
- package/.jumpstart/skills/ui-ux-pro-max/data/stacks/swiftui.csv +51 -0
- package/.jumpstart/skills/ui-ux-pro-max/data/stacks/vue.csv +50 -0
- package/.jumpstart/skills/ui-ux-pro-max/data/styles.csv +68 -0
- package/.jumpstart/skills/ui-ux-pro-max/data/typography.csv +58 -0
- package/.jumpstart/skills/ui-ux-pro-max/data/ui-reasoning.csv +101 -0
- package/.jumpstart/skills/ui-ux-pro-max/data/ux-guidelines.csv +100 -0
- package/.jumpstart/skills/ui-ux-pro-max/data/web-interface.csv +31 -0
- package/.jumpstart/skills/ui-ux-pro-max/scripts/core.py +253 -0
- package/.jumpstart/skills/ui-ux-pro-max/scripts/design_system.py +1067 -0
- package/.jumpstart/skills/ui-ux-pro-max/scripts/search.py +114 -0
- package/.jumpstart/state/timeline.json +659 -0
- package/.jumpstart/templates/model-map.md +1 -1
- package/.jumpstart/templates/ux-design.md +3 -3
- package/.jumpstart/usage-log.json +74 -3
- package/AGENTS.md +1 -1
- package/README.md +64 -3
- package/bin/cli.js +3217 -1
- package/bin/headless-runner.js +62 -2
- package/bin/lib/agent-checkpoint.js +168 -0
- package/bin/lib/ai-evaluation.js +104 -0
- package/bin/lib/ai-intake.js +152 -0
- package/bin/lib/ambiguity-heatmap.js +152 -0
- package/bin/lib/artifact-comparison.js +104 -0
- package/bin/lib/ast-edit-engine.js +157 -0
- package/bin/lib/backlog-sync.js +338 -0
- package/bin/lib/bcdr-planning.js +158 -0
- package/bin/lib/bidirectional-trace.js +199 -0
- package/bin/lib/branch-workflow.js +266 -0
- package/bin/lib/cab-output.js +119 -0
- package/bin/lib/chat-integration.js +122 -0
- package/bin/lib/ci-cd-integration.js +208 -0
- package/bin/lib/codebase-retrieval.js +125 -0
- package/bin/lib/collaboration.js +168 -0
- package/bin/lib/compliance-packs.js +213 -0
- package/bin/lib/context-chunker.js +128 -0
- package/bin/lib/context-onboarding.js +122 -0
- package/bin/lib/contract-first.js +124 -0
- package/bin/lib/cost-router.js +148 -0
- package/bin/lib/credential-boundary.js +155 -0
- package/bin/lib/data-classification.js +180 -0
- package/bin/lib/data-contracts.js +129 -0
- package/bin/lib/db-evolution.js +158 -0
- package/bin/lib/decision-conflicts.js +299 -0
- package/bin/lib/delivery-confidence.js +361 -0
- package/bin/lib/dependency-upgrade.js +153 -0
- package/bin/lib/design-system.js +133 -0
- package/bin/lib/deterministic-artifacts.js +151 -0
- package/bin/lib/diagram-studio.js +115 -0
- package/bin/lib/domain-ontology.js +140 -0
- package/bin/lib/ea-review-packet.js +151 -0
- package/bin/lib/enterprise-search.js +123 -0
- package/bin/lib/enterprise-templates.js +140 -0
- package/bin/lib/environment-promotion.js +220 -0
- package/bin/lib/estimation-studio.js +130 -0
- package/bin/lib/event-modeling.js +133 -0
- package/bin/lib/evidence-collector.js +179 -0
- package/bin/lib/finops-planner.js +182 -0
- package/bin/lib/fitness-functions.js +279 -0
- package/bin/lib/focus.js +448 -0
- package/bin/lib/governance-dashboard.js +165 -0
- package/bin/lib/guided-handoff.js +120 -0
- package/bin/lib/impact-analysis.js +190 -0
- package/bin/lib/incident-feedback.js +157 -0
- package/bin/lib/integrate.js +1 -1
- package/bin/lib/knowledge-graph.js +122 -0
- package/bin/lib/legacy-modernizer.js +160 -0
- package/bin/lib/migration-planner.js +144 -0
- package/bin/lib/model-governance.js +185 -0
- package/bin/lib/model-router.js +144 -0
- package/bin/lib/multi-repo.js +272 -0
- package/bin/lib/next-phase.js +53 -8
- package/bin/lib/ops-ownership.js +152 -0
- package/bin/lib/parallel-agents.js +257 -0
- package/bin/lib/pattern-library.js +115 -0
- package/bin/lib/persona-packs.js +99 -0
- package/bin/lib/plan-executor.js +366 -0
- package/bin/lib/platform-engineering.js +119 -0
- package/bin/lib/playback-summaries.js +126 -0
- package/bin/lib/policy-engine.js +240 -0
- package/bin/lib/portfolio-reporting.js +357 -0
- package/bin/lib/pr-package.js +197 -0
- package/bin/lib/project-memory.js +235 -0
- package/bin/lib/prompt-governance.js +130 -0
- package/bin/lib/promptless-mode.js +128 -0
- package/bin/lib/quality-graph.js +193 -0
- package/bin/lib/raci-matrix.js +188 -0
- package/bin/lib/refactor-planner.js +167 -0
- package/bin/lib/reference-architectures.js +304 -0
- package/bin/lib/release-readiness.js +171 -0
- package/bin/lib/repo-graph.js +262 -0
- package/bin/lib/requirements-baseline.js +358 -0
- package/bin/lib/risk-register.js +211 -0
- package/bin/lib/role-approval.js +249 -0
- package/bin/lib/role-views.js +142 -0
- package/bin/lib/root-cause-analysis.js +132 -0
- package/bin/lib/runtime-debugger.js +154 -0
- package/bin/lib/safe-rename.js +135 -0
- package/bin/lib/secret-scanner.js +313 -0
- package/bin/lib/semantic-diff.js +335 -0
- package/bin/lib/sla-slo.js +210 -0
- package/bin/lib/smoke-tester.js +344 -0
- package/bin/lib/spec-comments.js +147 -0
- package/bin/lib/spec-maturity.js +287 -0
- package/bin/lib/sre-integration.js +154 -0
- package/bin/lib/structured-elicitation.js +174 -0
- package/bin/lib/telemetry-feedback.js +118 -0
- package/bin/lib/test-generator.js +146 -0
- package/bin/lib/timeline.js +2 -1
- package/bin/lib/tool-bridge.js +159 -0
- package/bin/lib/tool-guardrails.js +139 -0
- package/bin/lib/tool-schemas.js +281 -3
- package/bin/lib/transcript-ingestion.js +150 -0
- package/bin/lib/type-checker.js +261 -0
- package/bin/lib/uat-coverage.js +411 -0
- package/bin/lib/vendor-risk.js +173 -0
- package/bin/lib/waiver-workflow.js +174 -0
- package/bin/lib/web-dashboard.js +126 -0
- package/bin/lib/workshop-mode.js +165 -0
- package/bin/lib/workstream-ownership.js +104 -0
- package/package.json +1 -1
- package/.github/agents/jumpstart-ux-designer.agent.md +0 -45
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* cab-output.js — Change Advisory Board Output Mode (Item 37)
|
|
3
|
+
*
|
|
4
|
+
* Generate CAB-ready summaries and implementation risk memos.
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* node bin/lib/cab-output.js generate|status [options]
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
'use strict';
|
|
11
|
+
|
|
12
|
+
const fs = require('fs');
|
|
13
|
+
const path = require('path');
|
|
14
|
+
|
|
15
|
+
const CAB_SECTIONS = ['change-description', 'risk-assessment', 'impact-analysis', 'rollback-plan',
|
|
16
|
+
'testing-summary', 'approval-status', 'implementation-schedule', 'communication-plan'];
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Generate a CAB-ready change summary.
|
|
20
|
+
*
|
|
21
|
+
* @param {string} root - Project root.
|
|
22
|
+
* @param {object} [options]
|
|
23
|
+
* @returns {object}
|
|
24
|
+
*/
|
|
25
|
+
function generateCABSummary(root, options = {}) {
|
|
26
|
+
const summary = {
|
|
27
|
+
id: `CAB-${Date.now()}`,
|
|
28
|
+
generated_at: new Date().toISOString(),
|
|
29
|
+
sections: {}
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
// Change description from specs
|
|
33
|
+
const prdFile = path.join(root, 'specs', 'prd.md');
|
|
34
|
+
if (fs.existsSync(prdFile)) {
|
|
35
|
+
try {
|
|
36
|
+
const content = fs.readFileSync(prdFile, 'utf8');
|
|
37
|
+
const title = (content.match(/^#\s+(.+)$/m) || [])[1] || 'Untitled';
|
|
38
|
+
const stories = (content.match(/\bE\d+-S\d+\b/g) || []).length;
|
|
39
|
+
summary.sections['change-description'] = { present: true, title, user_stories: stories };
|
|
40
|
+
} catch { summary.sections['change-description'] = { present: false }; }
|
|
41
|
+
} else {
|
|
42
|
+
summary.sections['change-description'] = { present: false };
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Risk assessment
|
|
46
|
+
const riskFile = path.join(root, '.jumpstart', 'state', 'risk-register.json');
|
|
47
|
+
if (fs.existsSync(riskFile)) {
|
|
48
|
+
try {
|
|
49
|
+
const risks = JSON.parse(fs.readFileSync(riskFile, 'utf8'));
|
|
50
|
+
const high = (risks.risks || []).filter(r => r.score >= 15);
|
|
51
|
+
summary.sections['risk-assessment'] = { present: true, total_risks: (risks.risks || []).length, high_risks: high.length };
|
|
52
|
+
} catch { summary.sections['risk-assessment'] = { present: false }; }
|
|
53
|
+
} else {
|
|
54
|
+
summary.sections['risk-assessment'] = { present: false };
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Impact analysis
|
|
58
|
+
const archFile = path.join(root, 'specs', 'architecture.md');
|
|
59
|
+
summary.sections['impact-analysis'] = { present: fs.existsSync(archFile) };
|
|
60
|
+
|
|
61
|
+
// Rollback plan
|
|
62
|
+
summary.sections['rollback-plan'] = {
|
|
63
|
+
present: false,
|
|
64
|
+
recommendation: 'Define rollback strategy in architecture specs'
|
|
65
|
+
};
|
|
66
|
+
if (fs.existsSync(archFile)) {
|
|
67
|
+
try {
|
|
68
|
+
const content = fs.readFileSync(archFile, 'utf8');
|
|
69
|
+
if (/rollback|roll.back|revert/i.test(content)) {
|
|
70
|
+
summary.sections['rollback-plan'] = { present: true };
|
|
71
|
+
}
|
|
72
|
+
} catch { /* ignore */ }
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Testing summary
|
|
76
|
+
const hasTests = fs.existsSync(path.join(root, 'tests')) || fs.existsSync(path.join(root, 'test'));
|
|
77
|
+
summary.sections['testing-summary'] = { present: hasTests };
|
|
78
|
+
|
|
79
|
+
// Approval status
|
|
80
|
+
const approvalFile = path.join(root, '.jumpstart', 'state', 'role-approvals.json');
|
|
81
|
+
if (fs.existsSync(approvalFile)) {
|
|
82
|
+
try {
|
|
83
|
+
const approvals = JSON.parse(fs.readFileSync(approvalFile, 'utf8'));
|
|
84
|
+
const workflows = Object.values(approvals.workflows || {});
|
|
85
|
+
const approved = workflows.filter(w => w.status === 'approved').length;
|
|
86
|
+
summary.sections['approval-status'] = { present: true, total: workflows.length, approved };
|
|
87
|
+
} catch { summary.sections['approval-status'] = { present: false }; }
|
|
88
|
+
} else {
|
|
89
|
+
summary.sections['approval-status'] = { present: false };
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Implementation schedule
|
|
93
|
+
const planFile = path.join(root, 'specs', 'implementation-plan.md');
|
|
94
|
+
summary.sections['implementation-schedule'] = { present: fs.existsSync(planFile) };
|
|
95
|
+
|
|
96
|
+
// Communication plan
|
|
97
|
+
summary.sections['communication-plan'] = { present: false, recommendation: 'Add communication plan' };
|
|
98
|
+
|
|
99
|
+
const presentSections = Object.values(summary.sections).filter(s => s.present).length;
|
|
100
|
+
const completeness = Math.round((presentSections / CAB_SECTIONS.length) * 100);
|
|
101
|
+
|
|
102
|
+
const riskLevel = summary.sections['risk-assessment'] && summary.sections['risk-assessment'].high_risks > 0
|
|
103
|
+
? 'high' : completeness >= 70 ? 'standard' : 'elevated';
|
|
104
|
+
|
|
105
|
+
return {
|
|
106
|
+
success: true,
|
|
107
|
+
cab_id: summary.id,
|
|
108
|
+
completeness,
|
|
109
|
+
risk_level: riskLevel,
|
|
110
|
+
recommendation: completeness >= 80 ? 'Ready for CAB review' : 'Additional documentation needed',
|
|
111
|
+
sections: summary.sections,
|
|
112
|
+
gaps: CAB_SECTIONS.filter(s => !summary.sections[s] || !summary.sections[s].present)
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
module.exports = {
|
|
117
|
+
generateCABSummary,
|
|
118
|
+
CAB_SECTIONS
|
|
119
|
+
};
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* chat-integration.js — Slack and Teams Integration (Item 75)
|
|
3
|
+
*
|
|
4
|
+
* Notify on approvals, risks, drift, and blockers;
|
|
5
|
+
* accept structured approvals from chat.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* node bin/lib/chat-integration.js configure|notify|status [options]
|
|
9
|
+
*
|
|
10
|
+
* State file: .jumpstart/state/chat-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', 'chat-integration.json');
|
|
19
|
+
|
|
20
|
+
const PLATFORMS = ['slack', 'teams'];
|
|
21
|
+
const EVENT_TYPES = ['approval', 'risk', 'drift', 'blocker', 'phase_change', 'comment'];
|
|
22
|
+
|
|
23
|
+
function defaultState() {
|
|
24
|
+
return {
|
|
25
|
+
version: '1.0.0',
|
|
26
|
+
configurations: [],
|
|
27
|
+
notifications: [],
|
|
28
|
+
last_updated: null
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function loadState(stateFile) {
|
|
33
|
+
const fp = stateFile || DEFAULT_STATE_FILE;
|
|
34
|
+
if (!fs.existsSync(fp)) return defaultState();
|
|
35
|
+
try { return JSON.parse(fs.readFileSync(fp, 'utf8')); }
|
|
36
|
+
catch { return defaultState(); }
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function saveState(state, stateFile) {
|
|
40
|
+
const fp = stateFile || DEFAULT_STATE_FILE;
|
|
41
|
+
const dir = path.dirname(fp);
|
|
42
|
+
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
|
43
|
+
state.last_updated = new Date().toISOString();
|
|
44
|
+
fs.writeFileSync(fp, JSON.stringify(state, null, 2) + '\n', 'utf8');
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Configure a chat integration.
|
|
49
|
+
*/
|
|
50
|
+
function configure(platform, options = {}) {
|
|
51
|
+
if (!PLATFORMS.includes(platform)) {
|
|
52
|
+
return { success: false, error: `Unknown platform: ${platform}. Valid: ${PLATFORMS.join(', ')}` };
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const stateFile = options.stateFile || DEFAULT_STATE_FILE;
|
|
56
|
+
const state = loadState(stateFile);
|
|
57
|
+
|
|
58
|
+
const config = {
|
|
59
|
+
id: `CHAT-${Date.now()}`,
|
|
60
|
+
platform,
|
|
61
|
+
channel: options.channel || 'general',
|
|
62
|
+
webhook_url: options.webhook_url || null,
|
|
63
|
+
events: options.events || EVENT_TYPES,
|
|
64
|
+
enabled: true,
|
|
65
|
+
configured_at: new Date().toISOString()
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
state.configurations.push(config);
|
|
69
|
+
saveState(state, stateFile);
|
|
70
|
+
|
|
71
|
+
return { success: true, configuration: config };
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Queue a notification.
|
|
76
|
+
*/
|
|
77
|
+
function queueNotification(eventType, message, options = {}) {
|
|
78
|
+
if (!EVENT_TYPES.includes(eventType)) {
|
|
79
|
+
return { success: false, error: `Unknown event type: ${eventType}. Valid: ${EVENT_TYPES.join(', ')}` };
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const stateFile = options.stateFile || DEFAULT_STATE_FILE;
|
|
83
|
+
const state = loadState(stateFile);
|
|
84
|
+
|
|
85
|
+
const notification = {
|
|
86
|
+
id: `NOTIF-${Date.now()}`,
|
|
87
|
+
event_type: eventType,
|
|
88
|
+
message,
|
|
89
|
+
platform: options.platform || 'all',
|
|
90
|
+
status: 'queued',
|
|
91
|
+
created_at: new Date().toISOString(),
|
|
92
|
+
sent_at: null
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
state.notifications.push(notification);
|
|
96
|
+
saveState(state, stateFile);
|
|
97
|
+
|
|
98
|
+
return { success: true, notification };
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Get integration status.
|
|
103
|
+
*/
|
|
104
|
+
function getStatus(options = {}) {
|
|
105
|
+
const stateFile = options.stateFile || DEFAULT_STATE_FILE;
|
|
106
|
+
const state = loadState(stateFile);
|
|
107
|
+
|
|
108
|
+
return {
|
|
109
|
+
success: true,
|
|
110
|
+
configurations: state.configurations.length,
|
|
111
|
+
active: state.configurations.filter(c => c.enabled).length,
|
|
112
|
+
notifications_queued: state.notifications.filter(n => n.status === 'queued').length,
|
|
113
|
+
notifications_sent: state.notifications.filter(n => n.status === 'sent').length,
|
|
114
|
+
platforms: state.configurations.map(c => c.platform)
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
module.exports = {
|
|
119
|
+
configure, queueNotification, getStatus,
|
|
120
|
+
loadState, saveState, defaultState,
|
|
121
|
+
PLATFORMS, EVENT_TYPES
|
|
122
|
+
};
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ci-cd-integration.js — GitHub Actions & Azure DevOps Deep Integration (Item 21)
|
|
3
|
+
*
|
|
4
|
+
* Trigger validation, drift checks, reviews, and approvals
|
|
5
|
+
* automatically in CI/CD pipelines.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* node bin/lib/ci-cd-integration.js generate|validate|status [options]
|
|
9
|
+
*
|
|
10
|
+
* State file: .jumpstart/state/ci-cd-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', 'ci-cd-integration.json');
|
|
19
|
+
|
|
20
|
+
const SUPPORTED_PLATFORMS = ['github-actions', 'azure-devops'];
|
|
21
|
+
|
|
22
|
+
const PIPELINE_STAGES = ['validate', 'drift-check', 'review', 'approve', 'promote'];
|
|
23
|
+
|
|
24
|
+
const BUILT_IN_CHECKS = [
|
|
25
|
+
{ id: 'schema-validation', name: 'Schema Validation', stage: 'validate', command: 'jumpstart-mode validate-all' },
|
|
26
|
+
{ id: 'spec-drift', name: 'Spec Drift Detection', stage: 'drift-check', command: 'jumpstart-mode spec-drift' },
|
|
27
|
+
{ id: 'coverage-check', name: 'Story-to-Task Coverage', stage: 'validate', command: 'jumpstart-mode coverage' },
|
|
28
|
+
{ id: 'secret-scan', name: 'Secret Scanning', stage: 'validate', command: 'jumpstart-mode scan-secrets' },
|
|
29
|
+
{ id: 'freshness-audit', name: 'Documentation Freshness', stage: 'review', command: 'jumpstart-mode freshness-audit' },
|
|
30
|
+
{ id: 'policy-check', name: 'Policy Compliance', stage: 'review', command: 'jumpstart-mode policy check' },
|
|
31
|
+
{ id: 'quality-gate', name: 'Quality Gate', stage: 'approve', command: 'npm test' }
|
|
32
|
+
];
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Default CI/CD integration state.
|
|
36
|
+
* @returns {object}
|
|
37
|
+
*/
|
|
38
|
+
function defaultState() {
|
|
39
|
+
return {
|
|
40
|
+
version: '1.0.0',
|
|
41
|
+
created_at: new Date().toISOString(),
|
|
42
|
+
last_updated: null,
|
|
43
|
+
platform: null,
|
|
44
|
+
pipelines: [],
|
|
45
|
+
run_history: []
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Load state from disk.
|
|
51
|
+
* @param {string} [stateFile]
|
|
52
|
+
* @returns {object}
|
|
53
|
+
*/
|
|
54
|
+
function loadState(stateFile) {
|
|
55
|
+
const filePath = stateFile || DEFAULT_STATE_FILE;
|
|
56
|
+
if (!fs.existsSync(filePath)) return defaultState();
|
|
57
|
+
try {
|
|
58
|
+
return JSON.parse(fs.readFileSync(filePath, 'utf8'));
|
|
59
|
+
} catch { return defaultState(); }
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Save state to disk.
|
|
64
|
+
* @param {object} state
|
|
65
|
+
* @param {string} [stateFile]
|
|
66
|
+
*/
|
|
67
|
+
function saveState(state, stateFile) {
|
|
68
|
+
const filePath = stateFile || DEFAULT_STATE_FILE;
|
|
69
|
+
const dir = path.dirname(filePath);
|
|
70
|
+
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
|
71
|
+
state.last_updated = new Date().toISOString();
|
|
72
|
+
fs.writeFileSync(filePath, JSON.stringify(state, null, 2) + '\n', 'utf8');
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Generate a CI/CD pipeline configuration.
|
|
77
|
+
*
|
|
78
|
+
* @param {string} platform - 'github-actions' or 'azure-devops'
|
|
79
|
+
* @param {object} [options]
|
|
80
|
+
* @returns {object}
|
|
81
|
+
*/
|
|
82
|
+
function generatePipeline(platform, options = {}) {
|
|
83
|
+
if (!SUPPORTED_PLATFORMS.includes(platform)) {
|
|
84
|
+
return { success: false, error: `Unsupported platform: ${platform}. Use: ${SUPPORTED_PLATFORMS.join(', ')}` };
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const checks = options.checks || BUILT_IN_CHECKS;
|
|
88
|
+
const stages = options.stages || PIPELINE_STAGES;
|
|
89
|
+
|
|
90
|
+
if (platform === 'github-actions') {
|
|
91
|
+
const workflow = {
|
|
92
|
+
name: 'JumpStart Quality Gate',
|
|
93
|
+
on: {
|
|
94
|
+
pull_request: { paths: ['specs/**', '.jumpstart/**', 'src/**', 'tests/**'] },
|
|
95
|
+
push: { branches: ['main'], paths: ['specs/**', '.jumpstart/**'] }
|
|
96
|
+
},
|
|
97
|
+
jobs: {}
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
for (const stage of stages) {
|
|
101
|
+
const stageChecks = checks.filter(c => c.stage === stage);
|
|
102
|
+
if (stageChecks.length === 0) continue;
|
|
103
|
+
workflow.jobs[stage] = {
|
|
104
|
+
'runs-on': 'ubuntu-latest',
|
|
105
|
+
steps: [
|
|
106
|
+
{ uses: 'actions/checkout@v4' },
|
|
107
|
+
{ uses: 'actions/setup-node@v4', with: { 'node-version': '20' } },
|
|
108
|
+
{ run: 'npm ci' },
|
|
109
|
+
...stageChecks.map(c => ({ name: c.name, run: `npx ${c.command}` }))
|
|
110
|
+
]
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return { success: true, platform, format: 'yaml', content: workflow, path: '.github/workflows/jumpstart-quality.yml' };
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (platform === 'azure-devops') {
|
|
118
|
+
const pipeline = {
|
|
119
|
+
trigger: { branches: { include: ['main'] }, paths: { include: ['specs/*', '.jumpstart/*'] } },
|
|
120
|
+
pool: { vmImage: 'ubuntu-latest' },
|
|
121
|
+
stages: stages.map(stage => ({
|
|
122
|
+
stage,
|
|
123
|
+
displayName: stage.charAt(0).toUpperCase() + stage.slice(1),
|
|
124
|
+
jobs: [{
|
|
125
|
+
job: `${stage}_checks`,
|
|
126
|
+
steps: [
|
|
127
|
+
{ task: 'NodeTool@0', inputs: { versionSpec: '20.x' } },
|
|
128
|
+
{ script: 'npm ci', displayName: 'Install dependencies' },
|
|
129
|
+
...checks.filter(c => c.stage === stage).map(c => ({
|
|
130
|
+
script: `npx ${c.command}`,
|
|
131
|
+
displayName: c.name
|
|
132
|
+
}))
|
|
133
|
+
]
|
|
134
|
+
}]
|
|
135
|
+
}))
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
return { success: true, platform, format: 'yaml', content: pipeline, path: 'azure-pipelines.yml' };
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return { success: false, error: 'Unknown platform' };
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Validate that pipeline configuration is up to date.
|
|
146
|
+
*
|
|
147
|
+
* @param {string} root - Project root.
|
|
148
|
+
* @param {object} [options]
|
|
149
|
+
* @returns {object}
|
|
150
|
+
*/
|
|
151
|
+
function validatePipeline(root, options = {}) {
|
|
152
|
+
const results = [];
|
|
153
|
+
|
|
154
|
+
for (const platform of SUPPORTED_PLATFORMS) {
|
|
155
|
+
const generated = generatePipeline(platform, options);
|
|
156
|
+
if (!generated.success) continue;
|
|
157
|
+
|
|
158
|
+
const pipelinePath = path.join(root, generated.path);
|
|
159
|
+
const exists = fs.existsSync(pipelinePath);
|
|
160
|
+
|
|
161
|
+
results.push({
|
|
162
|
+
platform,
|
|
163
|
+
path: generated.path,
|
|
164
|
+
exists,
|
|
165
|
+
up_to_date: exists,
|
|
166
|
+
expected_checks: (options.checks || BUILT_IN_CHECKS).length
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
return {
|
|
171
|
+
success: true,
|
|
172
|
+
pipelines: results,
|
|
173
|
+
all_configured: results.some(r => r.exists),
|
|
174
|
+
recommendations: results.filter(r => !r.exists).map(r => `Configure ${r.platform} pipeline at ${r.path}`)
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Get integration status summary.
|
|
180
|
+
*
|
|
181
|
+
* @param {object} [options]
|
|
182
|
+
* @returns {object}
|
|
183
|
+
*/
|
|
184
|
+
function getStatus(options = {}) {
|
|
185
|
+
const stateFile = options.stateFile || DEFAULT_STATE_FILE;
|
|
186
|
+
const state = loadState(stateFile);
|
|
187
|
+
|
|
188
|
+
return {
|
|
189
|
+
success: true,
|
|
190
|
+
platform: state.platform,
|
|
191
|
+
pipelines: state.pipelines.length,
|
|
192
|
+
last_run: state.run_history.length > 0 ? state.run_history[state.run_history.length - 1] : null,
|
|
193
|
+
total_runs: state.run_history.length,
|
|
194
|
+
available_checks: BUILT_IN_CHECKS.length
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
module.exports = {
|
|
199
|
+
defaultState,
|
|
200
|
+
loadState,
|
|
201
|
+
saveState,
|
|
202
|
+
generatePipeline,
|
|
203
|
+
validatePipeline,
|
|
204
|
+
getStatus,
|
|
205
|
+
SUPPORTED_PLATFORMS,
|
|
206
|
+
PIPELINE_STAGES,
|
|
207
|
+
BUILT_IN_CHECKS
|
|
208
|
+
};
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* codebase-retrieval.js — Codebase-Native Retrieval Layer (Item 41)
|
|
3
|
+
*
|
|
4
|
+
* Retrieve the right files, ADRs, test patterns, and prior
|
|
5
|
+
* implementations automatically during execution.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* node bin/lib/codebase-retrieval.js query|index|status [options]
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
'use strict';
|
|
12
|
+
|
|
13
|
+
const fs = require('fs');
|
|
14
|
+
const path = require('path');
|
|
15
|
+
|
|
16
|
+
const RETRIEVABLE_TYPES = ['adrs', 'test-patterns', 'implementations', 'specs', 'configs'];
|
|
17
|
+
|
|
18
|
+
const FILE_PATTERNS = {
|
|
19
|
+
adrs: ['specs/decisions/*.md', 'docs/decisions/*.md', 'adr/*.md'],
|
|
20
|
+
'test-patterns': ['tests/**/*.test.*', 'test/**/*.test.*', '__tests__/**/*'],
|
|
21
|
+
specs: ['specs/*.md', 'docs/*.md'],
|
|
22
|
+
configs: ['.jumpstart/*.yaml', '.jumpstart/*.json', 'package.json', 'tsconfig.json']
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Index project files by type.
|
|
27
|
+
*
|
|
28
|
+
* @param {string} root - Project root.
|
|
29
|
+
* @param {object} [options]
|
|
30
|
+
* @returns {object}
|
|
31
|
+
*/
|
|
32
|
+
function indexProject(root, options = {}) {
|
|
33
|
+
const index = {};
|
|
34
|
+
const excludeDirs = options.excludeDirs || ['node_modules', '.git', 'dist', 'build'];
|
|
35
|
+
|
|
36
|
+
function walk(dir, relDir) {
|
|
37
|
+
if (!fs.existsSync(dir)) return [];
|
|
38
|
+
const results = [];
|
|
39
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
40
|
+
const rel = path.join(relDir, entry.name);
|
|
41
|
+
if (entry.isDirectory()) {
|
|
42
|
+
if (!excludeDirs.includes(entry.name)) {
|
|
43
|
+
results.push(...walk(path.join(dir, entry.name), rel));
|
|
44
|
+
}
|
|
45
|
+
} else if (entry.isFile()) {
|
|
46
|
+
results.push(rel.replace(/\\/g, '/'));
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return results;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const allFiles = walk(root, '');
|
|
53
|
+
|
|
54
|
+
// Categorize files
|
|
55
|
+
index.adrs = allFiles.filter(f => /specs\/decisions\/|docs\/decisions\/|^adr\//i.test(f) && f.endsWith('.md'));
|
|
56
|
+
index['test-patterns'] = allFiles.filter(f => /\.test\.|\.spec\.|__tests__/i.test(f));
|
|
57
|
+
index.specs = allFiles.filter(f => /^specs\/.*\.md$/i.test(f));
|
|
58
|
+
index.configs = allFiles.filter(f => /package\.json$|tsconfig|\.jumpstart\//i.test(f));
|
|
59
|
+
index.implementations = allFiles.filter(f => /^src\//i.test(f));
|
|
60
|
+
|
|
61
|
+
return {
|
|
62
|
+
success: true,
|
|
63
|
+
total_files: allFiles.length,
|
|
64
|
+
indexed: Object.entries(index).reduce((sum, [, files]) => sum + files.length, 0),
|
|
65
|
+
categories: Object.entries(index).map(([type, files]) => ({ type, count: files.length })),
|
|
66
|
+
index
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Query for relevant files based on context.
|
|
72
|
+
*
|
|
73
|
+
* @param {string} root - Project root.
|
|
74
|
+
* @param {string} query - Search query.
|
|
75
|
+
* @param {object} [options]
|
|
76
|
+
* @returns {object}
|
|
77
|
+
*/
|
|
78
|
+
function queryFiles(root, query, options = {}) {
|
|
79
|
+
if (!query) return { success: false, error: 'query is required' };
|
|
80
|
+
|
|
81
|
+
const idx = indexProject(root, options);
|
|
82
|
+
const queryLower = query.toLowerCase();
|
|
83
|
+
const results = [];
|
|
84
|
+
|
|
85
|
+
// Search through all indexed files
|
|
86
|
+
for (const [type, files] of Object.entries(idx.index)) {
|
|
87
|
+
for (const file of files) {
|
|
88
|
+
const absPath = path.join(root, file);
|
|
89
|
+
try {
|
|
90
|
+
const content = fs.readFileSync(absPath, 'utf8');
|
|
91
|
+
if (content.toLowerCase().includes(queryLower) || file.toLowerCase().includes(queryLower)) {
|
|
92
|
+
const lines = content.split('\n');
|
|
93
|
+
const matchingLines = lines
|
|
94
|
+
.map((line, i) => ({ line: i + 1, content: line }))
|
|
95
|
+
.filter(l => l.content.toLowerCase().includes(queryLower))
|
|
96
|
+
.slice(0, 5);
|
|
97
|
+
|
|
98
|
+
results.push({
|
|
99
|
+
file,
|
|
100
|
+
type,
|
|
101
|
+
matches: matchingLines.length,
|
|
102
|
+
preview: matchingLines
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
} catch { /* skip */ }
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Sort by match count
|
|
110
|
+
results.sort((a, b) => b.matches - a.matches);
|
|
111
|
+
|
|
112
|
+
return {
|
|
113
|
+
success: true,
|
|
114
|
+
query,
|
|
115
|
+
total_results: results.length,
|
|
116
|
+
results: results.slice(0, options.limit || 20)
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
module.exports = {
|
|
121
|
+
indexProject,
|
|
122
|
+
queryFiles,
|
|
123
|
+
RETRIEVABLE_TYPES,
|
|
124
|
+
FILE_PATTERNS
|
|
125
|
+
};
|