projscan 2.1.0 → 2.8.0

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 (87) hide show
  1. package/README.md +57 -26
  2. package/dist/analyzers/supplyChainCheck.d.ts +2 -0
  3. package/dist/analyzers/supplyChainCheck.js +400 -0
  4. package/dist/analyzers/supplyChainCheck.js.map +1 -0
  5. package/dist/cli/commands/agentBrief.d.ts +1 -0
  6. package/dist/cli/commands/agentBrief.js +68 -0
  7. package/dist/cli/commands/agentBrief.js.map +1 -0
  8. package/dist/cli/commands/bugHunt.d.ts +1 -0
  9. package/dist/cli/commands/bugHunt.js +59 -0
  10. package/dist/cli/commands/bugHunt.js.map +1 -0
  11. package/dist/cli/commands/evidencePack.d.ts +1 -0
  12. package/dist/cli/commands/evidencePack.js +70 -0
  13. package/dist/cli/commands/evidencePack.js.map +1 -0
  14. package/dist/cli/commands/qualityScorecard.d.ts +1 -0
  15. package/dist/cli/commands/qualityScorecard.js +61 -0
  16. package/dist/cli/commands/qualityScorecard.js.map +1 -0
  17. package/dist/cli/commands/regressionPlan.d.ts +1 -0
  18. package/dist/cli/commands/regressionPlan.js +77 -0
  19. package/dist/cli/commands/regressionPlan.js.map +1 -0
  20. package/dist/cli/commands/releaseTrain.d.ts +1 -0
  21. package/dist/cli/commands/releaseTrain.js +58 -0
  22. package/dist/cli/commands/releaseTrain.js.map +1 -0
  23. package/dist/cli/commands/workplan.d.ts +1 -0
  24. package/dist/cli/commands/workplan.js +136 -0
  25. package/dist/cli/commands/workplan.js.map +1 -0
  26. package/dist/cli/index.js +14 -0
  27. package/dist/cli/index.js.map +1 -1
  28. package/dist/core/agentBrief.d.ts +6 -0
  29. package/dist/core/agentBrief.js +192 -0
  30. package/dist/core/agentBrief.js.map +1 -0
  31. package/dist/core/bugHunt.d.ts +6 -0
  32. package/dist/core/bugHunt.js +278 -0
  33. package/dist/core/bugHunt.js.map +1 -0
  34. package/dist/core/issueEngine.js +2 -0
  35. package/dist/core/issueEngine.js.map +1 -1
  36. package/dist/core/preflight.js +38 -4
  37. package/dist/core/preflight.js.map +1 -1
  38. package/dist/core/qualityScorecard.d.ts +6 -0
  39. package/dist/core/qualityScorecard.js +220 -0
  40. package/dist/core/qualityScorecard.js.map +1 -0
  41. package/dist/core/regressionPlan.d.ts +7 -0
  42. package/dist/core/regressionPlan.js +226 -0
  43. package/dist/core/regressionPlan.js.map +1 -0
  44. package/dist/core/releaseEvidence.d.ts +7 -0
  45. package/dist/core/releaseEvidence.js +174 -0
  46. package/dist/core/releaseEvidence.js.map +1 -0
  47. package/dist/core/releaseTrain.d.ts +5 -0
  48. package/dist/core/releaseTrain.js +348 -0
  49. package/dist/core/releaseTrain.js.map +1 -0
  50. package/dist/core/review.js +31 -2
  51. package/dist/core/review.js.map +1 -1
  52. package/dist/core/workplan.d.ts +12 -0
  53. package/dist/core/workplan.js +440 -0
  54. package/dist/core/workplan.js.map +1 -0
  55. package/dist/index.d.ts +8 -1
  56. package/dist/index.js +7 -0
  57. package/dist/index.js.map +1 -1
  58. package/dist/mcp/tools/agentBrief.d.ts +2 -0
  59. package/dist/mcp/tools/agentBrief.js +39 -0
  60. package/dist/mcp/tools/agentBrief.js.map +1 -0
  61. package/dist/mcp/tools/bugHunt.d.ts +2 -0
  62. package/dist/mcp/tools/bugHunt.js +31 -0
  63. package/dist/mcp/tools/bugHunt.js.map +1 -0
  64. package/dist/mcp/tools/evidencePack.d.ts +2 -0
  65. package/dist/mcp/tools/evidencePack.js +39 -0
  66. package/dist/mcp/tools/evidencePack.js.map +1 -0
  67. package/dist/mcp/tools/qualityScorecard.d.ts +2 -0
  68. package/dist/mcp/tools/qualityScorecard.js +26 -0
  69. package/dist/mcp/tools/qualityScorecard.js.map +1 -0
  70. package/dist/mcp/tools/regressionPlan.d.ts +2 -0
  71. package/dist/mcp/tools/regressionPlan.js +47 -0
  72. package/dist/mcp/tools/regressionPlan.js.map +1 -0
  73. package/dist/mcp/tools/releaseTrain.d.ts +2 -0
  74. package/dist/mcp/tools/releaseTrain.js +27 -0
  75. package/dist/mcp/tools/releaseTrain.js.map +1 -0
  76. package/dist/mcp/tools/workplan.d.ts +2 -0
  77. package/dist/mcp/tools/workplan.js +70 -0
  78. package/dist/mcp/tools/workplan.js.map +1 -0
  79. package/dist/mcp/tools.js +14 -0
  80. package/dist/mcp/tools.js.map +1 -1
  81. package/dist/projscan-sbom.cdx.json +4589 -0
  82. package/dist/tool-manifest.json +196 -3
  83. package/dist/types.d.ts +245 -1
  84. package/dist/utils/formatSupport.d.ts +8 -0
  85. package/dist/utils/formatSupport.js +8 -0
  86. package/dist/utils/formatSupport.js.map +1 -1
  87. package/package.json +9 -6
@@ -0,0 +1,174 @@
1
+ import { computeBugHunt } from './bugHunt.js';
2
+ import { computePreflight } from './preflight.js';
3
+ import { computeReleaseTrain } from './releaseTrain.js';
4
+ import { computeWorkplan } from './workplan.js';
5
+ export async function computeEvidencePack(rootPath, options = {}) {
6
+ const [train, bugHunt, workplan, preflight] = await Promise.all([
7
+ computeReleaseTrain(rootPath, { lines: options.lines }),
8
+ computeBugHunt(rootPath, { maxFindings: options.maxFindings }),
9
+ computeWorkplan(rootPath, { mode: 'release', maxTasks: 6 }),
10
+ computePreflight(rootPath, { mode: 'before_merge' }),
11
+ ]);
12
+ const artifacts = buildArtifacts(train, bugHunt, workplan, preflight);
13
+ const verdict = packVerdict(artifacts);
14
+ const blockingReasons = blockingEvidence(preflight, bugHunt, workplan);
15
+ const changelogEntries = buildChangelogEntries();
16
+ const suggestedNextActions = dedupeActions([
17
+ ...train.suggestedNextActions,
18
+ ...workplan.suggestedNextActions,
19
+ ...preflight.suggestedNextActions,
20
+ ...bugHunt.fixQueue.slice(0, 4).map((finding) => ({
21
+ label: finding.title,
22
+ command: finding.verification.commands[0],
23
+ })),
24
+ ]);
25
+ return {
26
+ schemaVersion: 1,
27
+ currentVersion: train.currentVersion,
28
+ readOnly: true,
29
+ verdict,
30
+ summary: summarize(verdict, train, blockingReasons),
31
+ train: {
32
+ lines: train.plan.lines,
33
+ readiness: train.readiness,
34
+ },
35
+ approval: {
36
+ required: true,
37
+ recommendation: approvalRecommendation(verdict),
38
+ blockingReasons,
39
+ },
40
+ artifacts,
41
+ changelogEntries,
42
+ ...(options.includeWebsitePrompt ? { websitePrompt: buildWebsitePrompt(train, changelogEntries) } : {}),
43
+ suggestedNextActions,
44
+ };
45
+ }
46
+ function buildArtifacts(train, bugHunt, workplan, preflight) {
47
+ return [
48
+ {
49
+ id: 'ep-release-train',
50
+ title: 'Product plan readiness',
51
+ status: statusFromPreflight(train.readiness.verdict),
52
+ summary: train.readiness.summary,
53
+ evidence: [
54
+ `${train.plan.lines.length} product line(s): ${train.plan.lines.join(', ')}`,
55
+ `${train.readiness.blockers} blocker(s), ${train.readiness.cautions} caution(s)`,
56
+ 'read-only evidence: yes',
57
+ ],
58
+ commands: ['projscan release-train --format json'],
59
+ },
60
+ {
61
+ id: 'ep-bug-hunt',
62
+ title: 'Bug-hunt queue',
63
+ status: bugHunt.verdict === 'block' ? 'blocked' : bugHunt.verdict === 'fix' ? 'caution' : 'ready',
64
+ summary: bugHunt.summary,
65
+ evidence: [
66
+ `health score ${bugHunt.health.score}`,
67
+ `${bugHunt.fixQueue.length} fix target(s) in queue`,
68
+ `preflight evidence during bug hunt: ${bugHunt.evidence.preflightVerdict}`,
69
+ ],
70
+ commands: ['projscan bug-hunt --format json'],
71
+ },
72
+ {
73
+ id: 'ep-workplan',
74
+ title: 'Agent workplan',
75
+ status: statusFromPreflight(workplan.verdict),
76
+ summary: workplan.summary,
77
+ evidence: [
78
+ `${workplan.tasks.length} task(s)`,
79
+ `${workplan.topRisks.length} top risk(s)`,
80
+ workplan.coordination.recommendedNextAgent,
81
+ ],
82
+ commands: ['projscan workplan --mode release --format json', 'projscan handoff --mode release'],
83
+ },
84
+ {
85
+ id: 'ep-preflight',
86
+ title: 'Preflight gate',
87
+ status: statusFromPreflight(preflight.verdict),
88
+ summary: preflight.summary,
89
+ evidence: preflight.requiredChecks.map((check) => `${check.name}: ${check.status}`),
90
+ commands: ['projscan preflight --mode before_merge --format json'],
91
+ },
92
+ ];
93
+ }
94
+ function blockingEvidence(preflight, bugHunt, workplan) {
95
+ return dedupeStrings([
96
+ ...preflight.reasons
97
+ .filter((reason) => reason.severity === 'error')
98
+ .map((reason) => reason.message),
99
+ ...(bugHunt.verdict === 'block'
100
+ ? bugHunt.fixQueue
101
+ .filter((finding) => finding.priority === 'p0')
102
+ .map((finding) => finding.title)
103
+ : []),
104
+ ...(workplan.verdict === 'block'
105
+ ? workplan.topRisks
106
+ .filter((risk) => risk.priority === 'p0')
107
+ .map((risk) => risk.message)
108
+ : []),
109
+ ]).slice(0, 10);
110
+ }
111
+ function buildChangelogEntries() {
112
+ return [
113
+ '`projscan_evidence_pack` / `projscan evidence-pack` produce one approval-ready packet with planning, preflight, workplan, bug-hunt, changelog, and website-update evidence.',
114
+ '`projscan_regression_plan` / `projscan regression-plan` build a smoke/focused/full verification matrix from bug-hunt, preflight, and product risk.',
115
+ '`projscan_agent_brief` / `projscan agent-brief` create compact next-agent context packets with focus items, guardrails, and repo context.',
116
+ '`projscan_quality_scorecard` / `projscan quality-scorecard` summarize health, security, tests, maintainability, and coordination with top risks and commands.',
117
+ ];
118
+ }
119
+ function buildWebsitePrompt(train, changelogEntries) {
120
+ return [
121
+ 'Update the projscan website for the next release using the current repository evidence.',
122
+ `Product lines covered: ${train.plan.lines.join(', ')}.`,
123
+ 'Highlight the new agent-facing surfaces: projscan_workplan, projscan_bug_hunt, projscan_release_train, projscan_evidence_pack, projscan_regression_plan, projscan_agent_brief, and projscan_quality_scorecard.',
124
+ 'Use these product bullets:',
125
+ ...changelogEntries.map((entry) => `- ${entry}`),
126
+ 'Keep claims grounded in the completed product evidence.',
127
+ ].join('\n');
128
+ }
129
+ function packVerdict(artifacts) {
130
+ if (artifacts.some((artifact) => artifact.status === 'blocked'))
131
+ return 'blocked';
132
+ if (artifacts.some((artifact) => artifact.status === 'caution'))
133
+ return 'caution';
134
+ return 'ready';
135
+ }
136
+ function summarize(verdict, train, blockingReasons) {
137
+ if (verdict === 'blocked') {
138
+ return `blocked: ${blockingReasons[0] ?? 'product evidence still contains blocking signals'}`;
139
+ }
140
+ if (verdict === 'caution') {
141
+ return `caution: ${train.plan.lines.join(', ')} evidence is assembled but still needs explicit review`;
142
+ }
143
+ return `ready: ${train.plan.lines.join(', ')} evidence is assembled for approval`;
144
+ }
145
+ function approvalRecommendation(verdict) {
146
+ if (verdict === 'blocked')
147
+ return 'Do not approve launch until p0 evidence is cleared or accepted.';
148
+ if (verdict === 'caution')
149
+ return 'Review cautions, then approve only after the regression plan passes.';
150
+ return 'Approval can proceed after the recorded regression commands pass.';
151
+ }
152
+ function statusFromPreflight(verdict) {
153
+ if (verdict === 'block')
154
+ return 'blocked';
155
+ if (verdict === 'caution')
156
+ return 'caution';
157
+ return 'ready';
158
+ }
159
+ function dedupeActions(actions) {
160
+ const seen = new Set();
161
+ const result = [];
162
+ for (const action of actions) {
163
+ const key = `${action.label}:${action.command ?? ''}:${action.tool ?? ''}`;
164
+ if (seen.has(key))
165
+ continue;
166
+ seen.add(key);
167
+ result.push(action);
168
+ }
169
+ return result.slice(0, 12);
170
+ }
171
+ function dedupeStrings(values) {
172
+ return [...new Set(values.filter(Boolean))];
173
+ }
174
+ //# sourceMappingURL=releaseEvidence.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"releaseEvidence.js","sourceRoot":"","sources":["../../src/core/releaseEvidence.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import type { ReleaseTrainReport } from '../types.js';
2
+ export interface ComputeReleaseTrainOptions {
3
+ lines?: string[];
4
+ }
5
+ export declare function computeReleaseTrain(rootPath: string, options?: ComputeReleaseTrainOptions): Promise<ReleaseTrainReport>;
@@ -0,0 +1,348 @@
1
+ import fs from 'node:fs/promises';
2
+ import path from 'node:path';
3
+ import { computePreflight } from './preflight.js';
4
+ export async function computeReleaseTrain(rootPath, options = {}) {
5
+ const currentVersion = await readPackageVersion(rootPath);
6
+ const lines = normalizeLines(options.lines, currentVersion);
7
+ const preflight = await computePreflight(rootPath, { mode: 'before_merge' });
8
+ const blockers = preflight.reasons.filter((reason) => reason.severity === 'error').length;
9
+ const cautions = preflight.reasons.filter((reason) => reason.severity === 'warning').length;
10
+ const tracks = lines.map(trackForLine);
11
+ const tasks = rankTasks([
12
+ ...(blockers > 0
13
+ ? [{
14
+ id: 'rt-blockers-first',
15
+ priority: 'p0',
16
+ title: 'Clear readiness blockers',
17
+ why: 'Product planning should stay anchored to active safety and quality evidence.',
18
+ track: 'plan',
19
+ files: filesFromPreflight(preflight.reasons),
20
+ verification: {
21
+ commands: ['projscan preflight --mode before_merge --format json'],
22
+ expected: 'Preflight no longer returns block.',
23
+ },
24
+ }]
25
+ : []),
26
+ ...tracks.flatMap(tasksForTrack),
27
+ {
28
+ id: 'rt-plan-readiness',
29
+ priority: blockers > 0 ? 'p1' : 'p0',
30
+ title: 'Prove product readiness',
31
+ why: 'The product needs one final local gate across docs, tests, stability metadata, and package contents before handoff.',
32
+ track: 'plan',
33
+ files: ['CHANGELOG.md', 'README.md', 'docs/STABILITY.md', 'package.json'],
34
+ verification: {
35
+ commands: ['npm test', 'npm run build', 'npm run check:stability', 'npm run release:check'],
36
+ expected: 'All readiness checks pass before handoff.',
37
+ },
38
+ },
39
+ ]);
40
+ return {
41
+ schemaVersion: 1,
42
+ currentVersion,
43
+ plan: {
44
+ policy: 'product-readiness-plan',
45
+ lines,
46
+ readOnly: true,
47
+ },
48
+ readiness: {
49
+ verdict: preflight.verdict,
50
+ blockers,
51
+ cautions,
52
+ summary: preflight.summary,
53
+ },
54
+ tracks,
55
+ tasks,
56
+ suggestedNextActions: suggestedActions(tasks, preflight.suggestedNextActions),
57
+ };
58
+ }
59
+ function trackForLine(line) {
60
+ if (line.startsWith('2.3')) {
61
+ return {
62
+ line,
63
+ theme: 'Agent Mission Control',
64
+ outcome: 'Agents can decide what to do next, hand off safely, and prove readiness without rereading the whole repo.',
65
+ includedInPlan: true,
66
+ scope: [
67
+ 'prioritized workplans',
68
+ 'handoff-ready next actions',
69
+ 'readiness planning',
70
+ ],
71
+ successCriteria: [
72
+ 'MCP and CLI expose the same planning contracts',
73
+ 'plans include evidence, priority, and verification commands',
74
+ 'planning output stays read-only',
75
+ ],
76
+ };
77
+ }
78
+ if (line.startsWith('2.4')) {
79
+ return {
80
+ line,
81
+ theme: 'Autonomous Bug Hunt',
82
+ outcome: 'Agents get a ranked fix queue that combines health, preflight, hotspots, and coordination evidence.',
83
+ includedInPlan: true,
84
+ scope: [
85
+ 'bug-hunt fix queue',
86
+ 'verification matrix',
87
+ 'broad test-suite reliability pass',
88
+ ],
89
+ successCriteria: [
90
+ 'bug-hunt output names the first fix target and commands to prove it',
91
+ 'clean repos still receive reproducible verification guidance',
92
+ 'full project verification passes from the committed tree',
93
+ ],
94
+ };
95
+ }
96
+ if (line.startsWith('2.5')) {
97
+ return {
98
+ line,
99
+ theme: 'Release Evidence Pack',
100
+ outcome: 'Humans and agents get one approval packet that ties product scope, preflight evidence, bug-hunt status, workplan tasks, and website-update copy together.',
101
+ includedInPlan: true,
102
+ scope: [
103
+ 'approval-ready evidence packet',
104
+ 'product-facing changelog and website prompt',
105
+ 'read-only evidence gathering',
106
+ ],
107
+ successCriteria: [
108
+ 'evidence pack includes planning, bug hunt, workplan, and preflight artifacts',
109
+ 'website update prompt is generated only as text evidence',
110
+ 'evidence generation stays read-only',
111
+ ],
112
+ };
113
+ }
114
+ if (line.startsWith('2.6')) {
115
+ return {
116
+ line,
117
+ theme: 'Regression Planning',
118
+ outcome: 'Agents get a smoke, focused, or full regression matrix that turns product risk into concrete verification commands.',
119
+ includedInPlan: true,
120
+ scope: [
121
+ 'risk-based regression targets',
122
+ 'smoke/focused/full verification levels',
123
+ 'deduplicated command matrix',
124
+ ],
125
+ successCriteria: [
126
+ 'regression plan includes commands for the selected level',
127
+ 'bug-hunt and preflight signals become explicit regression targets',
128
+ 'full level covers tests, build, lint, stability, and package checks',
129
+ ],
130
+ };
131
+ }
132
+ if (line.startsWith('2.7')) {
133
+ return {
134
+ line,
135
+ theme: 'Agent Brief',
136
+ outcome: 'Agents get a compact context packet with focus items, repo context, guardrails, and suggested next actions.',
137
+ includedInPlan: true,
138
+ scope: [
139
+ 'next-agent focus packet',
140
+ 'guardrail commands',
141
+ 'session and repo context summary',
142
+ ],
143
+ successCriteria: [
144
+ 'brief includes health, context, focus, guardrails, and next actions',
145
+ 'CLI and MCP expose the same schema',
146
+ 'brief output stays compact enough for handoff',
147
+ ],
148
+ };
149
+ }
150
+ if (line.startsWith('2.8')) {
151
+ return {
152
+ line,
153
+ theme: 'Quality Scorecard',
154
+ outcome: 'Agents and reviewers get a dimensioned quality view with top risks and verification commands.',
155
+ includedInPlan: true,
156
+ scope: [
157
+ 'quality dimensions',
158
+ 'top-risk ranking',
159
+ 'verification command set',
160
+ ],
161
+ successCriteria: [
162
+ 'scorecard reports health, security, tests, maintainability, and coordination',
163
+ 'top risks include concrete commands',
164
+ 'CLI and MCP expose the same scorecard schema',
165
+ ],
166
+ };
167
+ }
168
+ return {
169
+ line,
170
+ theme: 'Quality Hardening',
171
+ outcome: 'The line gets explicit readiness checks.',
172
+ includedInPlan: true,
173
+ scope: ['quality fixes', 'documentation alignment', 'readiness checks'],
174
+ successCriteria: ['all checks pass', 'public surface is documented', 'planning output stays read-only'],
175
+ };
176
+ }
177
+ function tasksForTrack(track) {
178
+ if (track.line.startsWith('2.3')) {
179
+ return [
180
+ {
181
+ id: 'rt-2-3-agent-readiness',
182
+ priority: 'p0',
183
+ title: 'Finish agent mission-control readiness',
184
+ why: 'Planning tools only matter if they produce short, ordered, evidence-backed actions that another agent can execute.',
185
+ track: track.line,
186
+ files: ['src/core/workplan.ts', 'src/cli/commands/workplan.ts', 'src/mcp/tools/workplan.ts'],
187
+ verification: {
188
+ commands: ['projscan workplan --mode release --format json', 'projscan handoff'],
189
+ expected: 'Workplan and handoff both include prioritized tasks and verification commands.',
190
+ },
191
+ },
192
+ ];
193
+ }
194
+ if (track.line.startsWith('2.4')) {
195
+ return [
196
+ {
197
+ id: 'rt-2-4-bug-hunt-gate',
198
+ priority: 'p0',
199
+ title: 'Ship the autonomous bug-hunt gate',
200
+ why: 'Before a larger release, the product should tell agents where to polish first and how to prove each fix.',
201
+ track: track.line,
202
+ files: ['src/core/bugHunt.ts', 'src/cli/commands/bugHunt.ts', 'src/mcp/tools/bugHunt.ts'],
203
+ verification: {
204
+ commands: ['projscan bug-hunt --format json', 'npm test'],
205
+ expected: 'Bug hunt returns a prioritized fix queue and the test suite passes.',
206
+ },
207
+ },
208
+ ];
209
+ }
210
+ if (track.line.startsWith('2.5')) {
211
+ return [
212
+ {
213
+ id: 'rt-2-5-evidence-pack',
214
+ priority: 'p0',
215
+ title: 'Assemble the release evidence pack',
216
+ why: 'A larger product update needs one human-readable evidence packet instead of scattered command output.',
217
+ track: track.line,
218
+ files: ['src/core/releaseEvidence.ts', 'src/cli/commands/evidencePack.ts', 'src/mcp/tools/evidencePack.ts'],
219
+ verification: {
220
+ commands: ['projscan evidence-pack --line 2.3.x --line 2.4.x --line 2.5.x --line 2.6.x --line 2.7.x --line 2.8.x --format json'],
221
+ expected: 'Evidence pack returns all planned lines, approval evidence, and changelog entries.',
222
+ },
223
+ },
224
+ ];
225
+ }
226
+ if (track.line.startsWith('2.6')) {
227
+ return [
228
+ {
229
+ id: 'rt-2-6-regression-plan',
230
+ priority: 'p0',
231
+ title: 'Ship the regression planning matrix',
232
+ why: 'A bigger product update should tell agents exactly which smoke, focused, and full checks prove readiness.',
233
+ track: track.line,
234
+ files: ['src/core/regressionPlan.ts', 'src/cli/commands/regressionPlan.ts', 'src/mcp/tools/regressionPlan.ts'],
235
+ verification: {
236
+ commands: ['projscan regression-plan --level full --format json', 'npm test'],
237
+ expected: 'Regression plan returns a deduplicated command matrix and the project suite passes.',
238
+ },
239
+ },
240
+ ];
241
+ }
242
+ if (track.line.startsWith('2.7')) {
243
+ return [
244
+ {
245
+ id: 'rt-2-7-agent-brief',
246
+ priority: 'p0',
247
+ title: 'Ship the agent brief',
248
+ why: 'Agents need a compact context packet that can be read quickly before choosing the next action.',
249
+ track: track.line,
250
+ files: ['src/core/agentBrief.ts', 'src/cli/commands/agentBrief.ts', 'src/mcp/tools/agentBrief.ts'],
251
+ verification: {
252
+ commands: ['projscan agent-brief --intent release --format json'],
253
+ expected: 'Agent brief returns focus, context, guardrails, and suggested next actions.',
254
+ },
255
+ },
256
+ ];
257
+ }
258
+ if (track.line.startsWith('2.8')) {
259
+ return [
260
+ {
261
+ id: 'rt-2-8-quality-scorecard',
262
+ priority: 'p0',
263
+ title: 'Ship the quality scorecard',
264
+ why: 'Agents and reviewers need a dimensioned quality view before deciding what to polish next.',
265
+ track: track.line,
266
+ files: ['src/core/qualityScorecard.ts', 'src/cli/commands/qualityScorecard.ts', 'src/mcp/tools/qualityScorecard.ts'],
267
+ verification: {
268
+ commands: ['projscan quality-scorecard --format json'],
269
+ expected: 'Quality scorecard returns dimensions, top risks, and verification commands.',
270
+ },
271
+ },
272
+ ];
273
+ }
274
+ return [
275
+ {
276
+ id: `rt-${slug(track.line)}-quality`,
277
+ priority: 'p1',
278
+ title: `Plan ${track.line} quality work`,
279
+ why: 'Every product line needs an explicit verification task.',
280
+ track: track.line,
281
+ files: [],
282
+ verification: {
283
+ commands: ['npm test', 'npm run lint'],
284
+ expected: 'Quality checks pass for this product line.',
285
+ },
286
+ },
287
+ ];
288
+ }
289
+ function suggestedActions(tasks, preflightActions) {
290
+ return [
291
+ ...tasks.slice(0, 5).map((task) => ({
292
+ label: task.title,
293
+ command: task.verification.commands[0],
294
+ })),
295
+ ...preflightActions,
296
+ ].slice(0, 12);
297
+ }
298
+ async function readPackageVersion(rootPath) {
299
+ try {
300
+ const raw = await fs.readFile(path.join(rootPath, 'package.json'), 'utf-8');
301
+ const pkg = JSON.parse(raw);
302
+ return typeof pkg.version === 'string' ? pkg.version : null;
303
+ }
304
+ catch {
305
+ return null;
306
+ }
307
+ }
308
+ function normalizeLines(lines, currentVersion) {
309
+ const cleaned = (lines ?? []).map((line) => line.trim()).filter(Boolean);
310
+ if (cleaned.length > 0)
311
+ return [...new Set(cleaned)];
312
+ const [major = 0, minor = 0] = (currentVersion ?? '2.2.0').split('.').map((part) => Number.parseInt(part, 10));
313
+ const safeMajor = Number.isFinite(major) ? major : 2;
314
+ const safeMinor = Number.isFinite(minor) ? minor : 2;
315
+ return [
316
+ `${safeMajor}.${safeMinor + 1}.x`,
317
+ `${safeMajor}.${safeMinor + 2}.x`,
318
+ `${safeMajor}.${safeMinor + 3}.x`,
319
+ `${safeMajor}.${safeMinor + 4}.x`,
320
+ `${safeMajor}.${safeMinor + 5}.x`,
321
+ `${safeMajor}.${safeMinor + 6}.x`,
322
+ ];
323
+ }
324
+ function rankTasks(tasks) {
325
+ return tasks.sort((a, b) => {
326
+ const blocker = blockerRank(a.id) - blockerRank(b.id);
327
+ if (blocker !== 0)
328
+ return blocker;
329
+ return priorityRank(a.priority) - priorityRank(b.priority) || a.id.localeCompare(b.id);
330
+ });
331
+ }
332
+ function filesFromPreflight(reasons) {
333
+ return [...new Set(reasons.map((reason) => reason.file).filter((file) => typeof file === 'string'))];
334
+ }
335
+ function priorityRank(priority) {
336
+ if (priority === 'p0')
337
+ return 0;
338
+ if (priority === 'p1')
339
+ return 1;
340
+ return 2;
341
+ }
342
+ function blockerRank(id) {
343
+ return id === 'rt-blockers-first' ? 0 : 1;
344
+ }
345
+ function slug(value) {
346
+ return value.replace(/[^a-zA-Z0-9]+/g, '-').replace(/^-+|-+$/g, '').toLowerCase() || 'line';
347
+ }
348
+ //# sourceMappingURL=releaseTrain.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"releaseTrain.js","sourceRoot":"","sources":["../../src/core/releaseTrain.ts"],"names":[],"mappings":"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"}
@@ -40,6 +40,32 @@ export async function computeReview(rootPath, options = {}) {
40
40
  if (!baseSha) {
41
41
  return unavailable(`Could not resolve base ref "${baseRef}".`, options, baseRef, headRef, headSha);
42
42
  }
43
+ if (headSha && headSha === baseSha) {
44
+ const report = {
45
+ available: true,
46
+ base: { ref: baseRef, resolvedSha: baseSha },
47
+ head: { ref: headRef, resolvedSha: headSha },
48
+ prDiff: {
49
+ available: true,
50
+ base: { ref: baseRef, resolvedSha: baseSha },
51
+ head: { ref: headRef, resolvedSha: headSha },
52
+ filesAdded: [],
53
+ filesRemoved: [],
54
+ filesModified: [],
55
+ totalFilesChanged: 0,
56
+ },
57
+ changedFiles: [],
58
+ newCycles: [],
59
+ riskyFunctions: [],
60
+ dependencyChanges: [],
61
+ contractChanges: [],
62
+ newTaintFlows: [],
63
+ verdict: 'ok',
64
+ summary: ['No structural changes detected between base and head.'],
65
+ };
66
+ applyIntent(report, options.intent);
67
+ return report;
68
+ }
43
69
  // Head-side data: scan + graph + issues + hotspots.
44
70
  const headScan = await scanRepository(rootPath);
45
71
  const headGraph = await buildCodeGraph(rootPath, headScan.files);
@@ -159,7 +185,11 @@ export async function computeReview(rootPath, options = {}) {
159
185
  // annotate each finding with an alignment label, and append a
160
186
  // small intent summary to the verdict bullets. Does NOT change the
161
187
  // verdict — verdict stays structural.
162
- const intent = parseIntent(options.intent);
188
+ applyIntent(report, options.intent);
189
+ return report;
190
+ }
191
+ function applyIntent(report, rawIntent) {
192
+ const intent = parseIntent(rawIntent);
163
193
  if (intent) {
164
194
  const analysis = annotateReviewWithIntent(report, intent);
165
195
  report.intent = {
@@ -173,7 +203,6 @@ export async function computeReview(rootPath, options = {}) {
173
203
  };
174
204
  appendIntentToSummary(report.summary, analysis);
175
205
  }
176
- return report;
177
206
  }
178
207
  async function computeNewTaintFlows(rootPath, baseGraph, headGraph, touchedFiles) {
179
208
  const { config } = await loadConfig(rootPath);