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,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
+ };