forge-workflow 0.0.1
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/.claude/commands/dev.md +314 -0
- package/.claude/commands/plan.md +389 -0
- package/.claude/commands/premerge.md +179 -0
- package/.claude/commands/research.md +42 -0
- package/.claude/commands/review.md +442 -0
- package/.claude/commands/rollback.md +721 -0
- package/.claude/commands/ship.md +134 -0
- package/.claude/commands/sonarcloud.md +152 -0
- package/.claude/commands/status.md +77 -0
- package/.claude/commands/validate.md +237 -0
- package/.claude/commands/verify.md +221 -0
- package/.claude/rules/greptile-review-process.md +285 -0
- package/.claude/rules/workflow.md +105 -0
- package/.claude/scripts/greptile-resolve.sh +526 -0
- package/.claude/scripts/load-env.sh +32 -0
- package/.forge/hooks/check-tdd.js +240 -0
- package/.github/PLUGIN_TEMPLATE.json +32 -0
- package/.mcp.json.example +12 -0
- package/AGENTS.md +169 -0
- package/CLAUDE.md +99 -0
- package/LICENSE +21 -0
- package/README.md +414 -0
- package/bin/forge-cmd.js +313 -0
- package/bin/forge-validate.js +303 -0
- package/bin/forge.js +4228 -0
- package/docs/AGENT_INSTALL_PROMPT.md +342 -0
- package/docs/ENHANCED_ONBOARDING.md +602 -0
- package/docs/EXAMPLES.md +482 -0
- package/docs/GREPTILE_SETUP.md +400 -0
- package/docs/MANUAL_REVIEW_GUIDE.md +106 -0
- package/docs/ROADMAP.md +359 -0
- package/docs/SETUP.md +632 -0
- package/docs/TOOLCHAIN.md +849 -0
- package/docs/VALIDATION.md +363 -0
- package/docs/WORKFLOW.md +400 -0
- package/docs/planning/PROGRESS.md +396 -0
- package/docs/plans/.gitkeep +0 -0
- package/docs/plans/2026-02-27-forge-test-suite-v2-decisions.md +21 -0
- package/docs/plans/2026-02-27-forge-test-suite-v2-design.md +362 -0
- package/docs/plans/2026-02-27-forge-test-suite-v2-tasks.md +343 -0
- package/docs/plans/2026-03-02-superpowers-gaps-decisions.md +26 -0
- package/docs/plans/2026-03-02-superpowers-gaps-design.md +239 -0
- package/docs/plans/2026-03-02-superpowers-gaps-tasks.md +260 -0
- package/docs/plans/2026-03-04-agent-command-parity-design.md +163 -0
- package/docs/plans/2026-03-04-verify-worktree-cleanup-decisions.md +7 -0
- package/docs/plans/2026-03-04-verify-worktree-cleanup-design.md +165 -0
- package/docs/plans/2026-03-05-forge-uto-decisions.md +6 -0
- package/docs/plans/2026-03-05-forge-uto-design.md +116 -0
- package/docs/plans/2026-03-05-forge-uto-tasks.md +244 -0
- package/docs/plans/2026-03-10-command-creator-and-eval-decisions.md +52 -0
- package/docs/plans/2026-03-10-command-creator-and-eval-design.md +350 -0
- package/docs/plans/2026-03-10-command-creator-and-eval-tasks.md +426 -0
- package/docs/plans/2026-03-10-stale-workflow-refs-decisions.md +8 -0
- package/docs/plans/2026-03-10-stale-workflow-refs-design.md +80 -0
- package/docs/plans/2026-03-10-stale-workflow-refs-tasks.md +90 -0
- package/docs/plans/2026-03-14-beads-plan-context-decisions.md +9 -0
- package/docs/plans/2026-03-14-beads-plan-context-design.md +171 -0
- package/docs/plans/2026-03-14-beads-plan-context-tasks.md +160 -0
- package/docs/plans/2026-03-14-skill-eval-loop-decisions.md +33 -0
- package/docs/plans/2026-03-14-skill-eval-loop-design.md +118 -0
- package/docs/plans/2026-03-14-skill-eval-loop-results.md +78 -0
- package/docs/plans/2026-03-14-skill-eval-loop-tasks.md +160 -0
- package/docs/plans/2026-03-15-agent-command-parity-v2-decisions.md +11 -0
- package/docs/plans/2026-03-15-agent-command-parity-v2-design.md +145 -0
- package/docs/plans/2026-03-15-agent-command-parity-v2-tasks.md +211 -0
- package/docs/research/TEMPLATE.md +292 -0
- package/docs/research/advanced-testing.md +297 -0
- package/docs/research/agent-permissions.md +167 -0
- package/docs/research/dependency-chain.md +328 -0
- package/docs/research/forge-workflow-v2.md +550 -0
- package/docs/research/plugin-architecture.md +772 -0
- package/docs/research/pr4-cli-automation.md +326 -0
- package/docs/research/premerge-verify-restructure.md +205 -0
- package/docs/research/skills-restructure.md +508 -0
- package/docs/research/sonarcloud-perfection-plan.md +166 -0
- package/docs/research/sonarcloud-quality-gate.md +184 -0
- package/docs/research/superpowers-integration.md +403 -0
- package/docs/research/superpowers.md +319 -0
- package/docs/research/test-environment.md +519 -0
- package/install.sh +1062 -0
- package/lefthook.yml +39 -0
- package/lib/agents/README.md +198 -0
- package/lib/agents/claude.plugin.json +28 -0
- package/lib/agents/cline.plugin.json +22 -0
- package/lib/agents/codex.plugin.json +19 -0
- package/lib/agents/copilot.plugin.json +24 -0
- package/lib/agents/cursor.plugin.json +25 -0
- package/lib/agents/kilocode.plugin.json +22 -0
- package/lib/agents/opencode.plugin.json +20 -0
- package/lib/agents/roo.plugin.json +23 -0
- package/lib/agents-config.js +2112 -0
- package/lib/commands/dev.js +513 -0
- package/lib/commands/plan.js +696 -0
- package/lib/commands/recommend.js +119 -0
- package/lib/commands/ship.js +377 -0
- package/lib/commands/status.js +378 -0
- package/lib/commands/validate.js +602 -0
- package/lib/context-merge.js +359 -0
- package/lib/plugin-catalog.js +360 -0
- package/lib/plugin-manager.js +166 -0
- package/lib/plugin-recommender.js +141 -0
- package/lib/project-discovery.js +491 -0
- package/lib/setup.js +118 -0
- package/lib/workflow-profiles.js +203 -0
- package/package.json +115 -0
|
@@ -0,0 +1,378 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Status Command - Intelligent Stage Detection
|
|
3
|
+
* Detects workflow stage (1-9) with confidence scoring
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const WORKFLOW_STAGES = {
|
|
7
|
+
1: { name: 'Fresh Start', nextCommand: 'research' },
|
|
8
|
+
2: { name: 'Research', nextCommand: 'research' },
|
|
9
|
+
3: { name: 'Planning', nextCommand: 'plan' },
|
|
10
|
+
4: { name: 'Development', nextCommand: 'dev' },
|
|
11
|
+
5: { name: 'Validation', nextCommand: 'validate' },
|
|
12
|
+
6: { name: 'Shipping', nextCommand: 'ship' },
|
|
13
|
+
7: { name: 'Review', nextCommand: 'review' },
|
|
14
|
+
8: { name: 'Merge', nextCommand: 'merge' },
|
|
15
|
+
9: { name: 'Verification', nextCommand: 'verify' },
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Analyze branch state
|
|
20
|
+
* @param {string} branch - Current branch name
|
|
21
|
+
* @returns {object} Branch analysis
|
|
22
|
+
*/
|
|
23
|
+
function analyzeBranch(branch) {
|
|
24
|
+
// Guard: branch may be undefined if git command failed
|
|
25
|
+
if (!branch || typeof branch !== 'string') {
|
|
26
|
+
return { branch: '', isMain: false, onFeatureBranch: false, featureSlug: null };
|
|
27
|
+
}
|
|
28
|
+
const isMain = branch === 'master' || branch === 'main';
|
|
29
|
+
const onFeatureBranch = branch.startsWith('feat/') || branch.startsWith('feature/');
|
|
30
|
+
|
|
31
|
+
let featureSlug = null;
|
|
32
|
+
if (onFeatureBranch) {
|
|
33
|
+
featureSlug = branch.replace(/^(feat|feature)\//, '');
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return {
|
|
37
|
+
branch,
|
|
38
|
+
isMain,
|
|
39
|
+
onFeatureBranch,
|
|
40
|
+
featureSlug,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Analyze file existence
|
|
46
|
+
* @param {object} context - Context with file paths
|
|
47
|
+
* @returns {object} File analysis
|
|
48
|
+
*/
|
|
49
|
+
function analyzeFiles(context) {
|
|
50
|
+
return {
|
|
51
|
+
hasResearch: !!context.researchDoc,
|
|
52
|
+
hasPlan: !!context.plan,
|
|
53
|
+
hasTests: context.tests && context.tests.length > 0,
|
|
54
|
+
testsPass: context.testsPass === true,
|
|
55
|
+
researchDoc: context.researchDoc,
|
|
56
|
+
plan: context.plan,
|
|
57
|
+
tests: context.tests || [],
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Analyze PR state
|
|
63
|
+
* @param {object} pr - PR object
|
|
64
|
+
* @returns {object} PR analysis
|
|
65
|
+
*/
|
|
66
|
+
function analyzePR(pr) {
|
|
67
|
+
if (!pr) {
|
|
68
|
+
return {
|
|
69
|
+
hasPR: false,
|
|
70
|
+
prOpen: false,
|
|
71
|
+
prMerged: false,
|
|
72
|
+
prApproved: false,
|
|
73
|
+
checksPass: false,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return {
|
|
78
|
+
hasPR: true,
|
|
79
|
+
prNumber: pr.number,
|
|
80
|
+
prOpen: pr.state === 'open',
|
|
81
|
+
prMerged: pr.state === 'merged',
|
|
82
|
+
prApproved: pr.approved === true,
|
|
83
|
+
checksPass: pr.checksPass === true,
|
|
84
|
+
reviews: pr.reviews || [],
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Analyze check results
|
|
90
|
+
* @param {object} context - Context with check results
|
|
91
|
+
* @returns {object} Check analysis
|
|
92
|
+
*/
|
|
93
|
+
function analyzeChecks(context) {
|
|
94
|
+
return {
|
|
95
|
+
checksPass: context.checksPass === true,
|
|
96
|
+
testsPass: context.testsPass === true,
|
|
97
|
+
lintPass: context.lintPass !== false, // Assume true if not specified
|
|
98
|
+
typeCheckPass: context.typeCheckPass !== false,
|
|
99
|
+
allChecksPass: context.checksPass === true && context.testsPass === true,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Analyze Beads issue state
|
|
105
|
+
* @param {object} beadsIssue - Beads issue object
|
|
106
|
+
* @returns {object} Beads analysis
|
|
107
|
+
*/
|
|
108
|
+
function analyzeBeads(beadsIssue) {
|
|
109
|
+
if (!beadsIssue) {
|
|
110
|
+
return {
|
|
111
|
+
hasActiveIssue: false,
|
|
112
|
+
issueStatus: null,
|
|
113
|
+
issueType: null,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return {
|
|
118
|
+
hasActiveIssue: true,
|
|
119
|
+
issueStatus: beadsIssue.status,
|
|
120
|
+
issueType: beadsIssue.type,
|
|
121
|
+
isInProgress: beadsIssue.status === 'in_progress',
|
|
122
|
+
isClosed: beadsIssue.status === 'closed',
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Calculate confidence score
|
|
128
|
+
* @param {object} factors - All analysis factors
|
|
129
|
+
* @param {number} stage - Detected stage
|
|
130
|
+
* @returns {object} Confidence result
|
|
131
|
+
*/
|
|
132
|
+
function calculateConfidence(factors, stage) {
|
|
133
|
+
let score = 0;
|
|
134
|
+
let maxScore = 0;
|
|
135
|
+
|
|
136
|
+
// Weight different factors based on importance
|
|
137
|
+
const weights = {
|
|
138
|
+
branch: 20,
|
|
139
|
+
files: 30,
|
|
140
|
+
pr: 25,
|
|
141
|
+
checks: 15,
|
|
142
|
+
beads: 10,
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
// Branch state
|
|
146
|
+
maxScore += weights.branch;
|
|
147
|
+
if (stage === 1 && factors.branch.isMain && !factors.files.hasResearch) {
|
|
148
|
+
score += weights.branch; // Clear stage 1
|
|
149
|
+
} else if (stage >= 4 && factors.branch.onFeatureBranch) {
|
|
150
|
+
score += weights.branch; // On feature branch for dev stages
|
|
151
|
+
} else if (stage <= 3 && factors.branch.isMain) {
|
|
152
|
+
score += weights.branch; // On main for early stages
|
|
153
|
+
} else if ((stage === 8 || stage === 9) && factors.branch.isMain) {
|
|
154
|
+
score += weights.branch; // Back on main after merge
|
|
155
|
+
} else {
|
|
156
|
+
score += weights.branch / 2; // Partial match
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// File existence
|
|
160
|
+
maxScore += weights.files;
|
|
161
|
+
if (stage === 1 && !factors.files.hasResearch && !factors.files.hasPlan) {
|
|
162
|
+
score += weights.files; // No files for fresh start
|
|
163
|
+
} else if (stage === 3 && factors.files.hasResearch && !factors.files.hasPlan) {
|
|
164
|
+
score += weights.files; // Research but no plan
|
|
165
|
+
} else if (stage >= 4 && factors.files.hasResearch && factors.files.hasPlan) {
|
|
166
|
+
score += weights.files; // Both research and plan exist
|
|
167
|
+
} else if (stage === 2 && factors.files.hasResearch) {
|
|
168
|
+
score += weights.files / 2; // Research in progress
|
|
169
|
+
} else {
|
|
170
|
+
score += weights.files / 3; // Weak match
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// PR state
|
|
174
|
+
maxScore += weights.pr;
|
|
175
|
+
if (stage <= 6 && !factors.pr.hasPR) {
|
|
176
|
+
score += weights.pr; // No PR before shipping
|
|
177
|
+
} else if (stage === 7 && factors.pr.prOpen && !factors.pr.prApproved) {
|
|
178
|
+
score += weights.pr; // PR open, awaiting review
|
|
179
|
+
} else if (stage === 8 && factors.pr.prApproved) {
|
|
180
|
+
score += weights.pr; // PR approved, ready to merge
|
|
181
|
+
} else if (stage === 9 && factors.pr.prMerged) {
|
|
182
|
+
score += weights.pr; // PR merged
|
|
183
|
+
} else {
|
|
184
|
+
score += weights.pr / 2; // Partial match
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// Check results
|
|
188
|
+
maxScore += weights.checks;
|
|
189
|
+
if (stage === 6 && factors.checks.allChecksPass) {
|
|
190
|
+
score += weights.checks; // All checks pass for shipping
|
|
191
|
+
} else if (stage === 5 && !factors.checks.allChecksPass) {
|
|
192
|
+
score += weights.checks; // Still working on checks
|
|
193
|
+
} else if (stage >= 7 && factors.checks.allChecksPass) {
|
|
194
|
+
score += weights.checks; // Checks pass for later stages
|
|
195
|
+
} else {
|
|
196
|
+
score += weights.checks / 2; // Partial match
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// Beads issue
|
|
200
|
+
maxScore += weights.beads;
|
|
201
|
+
if (factors.beads.isInProgress && stage >= 2 && stage <= 7) {
|
|
202
|
+
score += weights.beads; // Active work
|
|
203
|
+
} else if (factors.beads.isClosed && stage >= 8) {
|
|
204
|
+
score += weights.beads; // Closed for late stages
|
|
205
|
+
} else if (!factors.beads.hasActiveIssue && stage === 1) {
|
|
206
|
+
score += weights.beads; // No issue for fresh start
|
|
207
|
+
} else {
|
|
208
|
+
score += weights.beads / 2; // Partial match
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
const percentage = Math.round((score / maxScore) * 100);
|
|
212
|
+
|
|
213
|
+
let confidence;
|
|
214
|
+
if (percentage >= 90) {
|
|
215
|
+
confidence = 'high';
|
|
216
|
+
} else if (percentage >= 70) {
|
|
217
|
+
confidence = 'medium';
|
|
218
|
+
} else {
|
|
219
|
+
confidence = 'low';
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
return {
|
|
223
|
+
confidence,
|
|
224
|
+
confidenceScore: percentage,
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Detect workflow stage
|
|
230
|
+
* @param {object} context - Full context object
|
|
231
|
+
* @returns {object} Detection result
|
|
232
|
+
*/
|
|
233
|
+
function detectStage(context) {
|
|
234
|
+
// Analyze all factors
|
|
235
|
+
const branchFactors = analyzeBranch(context.branch || 'master');
|
|
236
|
+
const fileFactors = analyzeFiles(context);
|
|
237
|
+
const prFactors = analyzePR(context.pr);
|
|
238
|
+
const checkFactors = analyzeChecks(context);
|
|
239
|
+
const beadsFactors = analyzeBeads(context.beadsIssue);
|
|
240
|
+
|
|
241
|
+
const factors = {
|
|
242
|
+
branch: branchFactors,
|
|
243
|
+
files: fileFactors,
|
|
244
|
+
pr: prFactors,
|
|
245
|
+
checks: checkFactors,
|
|
246
|
+
beads: beadsFactors,
|
|
247
|
+
};
|
|
248
|
+
|
|
249
|
+
// Stage detection logic
|
|
250
|
+
let stage;
|
|
251
|
+
|
|
252
|
+
// Stage 9: PR merged, verify docs
|
|
253
|
+
if (prFactors.prMerged && beadsFactors.isClosed) {
|
|
254
|
+
stage = 9;
|
|
255
|
+
}
|
|
256
|
+
// Stage 8: PR approved, ready to merge
|
|
257
|
+
else if (prFactors.prApproved && checkFactors.allChecksPass) {
|
|
258
|
+
stage = 8;
|
|
259
|
+
}
|
|
260
|
+
// Stage 7: PR open, awaiting review
|
|
261
|
+
else if (prFactors.prOpen && !prFactors.prApproved) {
|
|
262
|
+
stage = 7;
|
|
263
|
+
}
|
|
264
|
+
// Stage 6: Ready to ship (all checks pass, no PR yet)
|
|
265
|
+
else if (checkFactors.allChecksPass && fileFactors.hasTests && !prFactors.hasPR) {
|
|
266
|
+
stage = 6;
|
|
267
|
+
}
|
|
268
|
+
// Stage 5: Dev in progress, tests failing or checks not done
|
|
269
|
+
else if (fileFactors.hasTests && !checkFactors.allChecksPass) {
|
|
270
|
+
stage = 5;
|
|
271
|
+
}
|
|
272
|
+
// Stage 4: Plan exists, no tests yet
|
|
273
|
+
else if (fileFactors.hasPlan && !fileFactors.hasTests && branchFactors.onFeatureBranch) {
|
|
274
|
+
stage = 4;
|
|
275
|
+
}
|
|
276
|
+
// Stage 3: Research exists, no plan yet
|
|
277
|
+
else if (fileFactors.hasResearch && !fileFactors.hasPlan) {
|
|
278
|
+
stage = 3;
|
|
279
|
+
}
|
|
280
|
+
// Stage 2: Research in progress
|
|
281
|
+
else if (beadsFactors.issueType === 'research' && beadsFactors.isInProgress) {
|
|
282
|
+
stage = 2;
|
|
283
|
+
}
|
|
284
|
+
// Stage 1: Fresh project (default)
|
|
285
|
+
else {
|
|
286
|
+
stage = 1;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// Calculate confidence
|
|
290
|
+
const confidenceResult = calculateConfidence(factors, stage);
|
|
291
|
+
|
|
292
|
+
// Get next command
|
|
293
|
+
const nextCommand = WORKFLOW_STAGES[stage].nextCommand;
|
|
294
|
+
|
|
295
|
+
return {
|
|
296
|
+
stage,
|
|
297
|
+
stageName: WORKFLOW_STAGES[stage].name,
|
|
298
|
+
confidence: confidenceResult.confidence,
|
|
299
|
+
confidenceScore: confidenceResult.confidenceScore,
|
|
300
|
+
nextCommand,
|
|
301
|
+
factors,
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* Format status output
|
|
307
|
+
* @param {object} result - Detection result
|
|
308
|
+
* @returns {string} Formatted output
|
|
309
|
+
*/
|
|
310
|
+
function formatStatus(result) {
|
|
311
|
+
const lines = [];
|
|
312
|
+
|
|
313
|
+
// Header
|
|
314
|
+
lines.push('');
|
|
315
|
+
lines.push(`✓ Current Stage: ${result.stage} - ${result.stageName}`);
|
|
316
|
+
lines.push(` Confidence: ${result.confidence.toUpperCase()} (${result.confidenceScore}%)`);
|
|
317
|
+
lines.push('');
|
|
318
|
+
|
|
319
|
+
// Completed checks
|
|
320
|
+
const completed = [];
|
|
321
|
+
if (result.factors.files.hasResearch) {
|
|
322
|
+
completed.push('✓ Research doc exists');
|
|
323
|
+
}
|
|
324
|
+
if (result.factors.files.hasPlan) {
|
|
325
|
+
completed.push('✓ Plan created');
|
|
326
|
+
}
|
|
327
|
+
if (result.factors.branch.onFeatureBranch) {
|
|
328
|
+
completed.push('✓ Feature branch created');
|
|
329
|
+
}
|
|
330
|
+
if (result.factors.files.hasTests) {
|
|
331
|
+
completed.push('✓ Tests written');
|
|
332
|
+
}
|
|
333
|
+
if (result.factors.files.testsPass) {
|
|
334
|
+
completed.push('✓ Tests passing');
|
|
335
|
+
}
|
|
336
|
+
if (result.factors.checks.allChecksPass) {
|
|
337
|
+
completed.push('✓ All checks passing');
|
|
338
|
+
}
|
|
339
|
+
if (result.factors.pr.hasPR) {
|
|
340
|
+
completed.push(`✓ PR created (#${result.factors.pr.prNumber})`);
|
|
341
|
+
}
|
|
342
|
+
if (result.factors.pr.prApproved) {
|
|
343
|
+
completed.push('✓ PR approved');
|
|
344
|
+
}
|
|
345
|
+
if (result.factors.pr.prMerged) {
|
|
346
|
+
completed.push('✓ PR merged');
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
if (completed.length > 0) {
|
|
350
|
+
lines.push('Completed:');
|
|
351
|
+
completed.forEach(item => lines.push(` ${item}`));
|
|
352
|
+
lines.push('');
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
// Next command
|
|
356
|
+
lines.push(`Next: /${result.nextCommand}`);
|
|
357
|
+
lines.push('');
|
|
358
|
+
|
|
359
|
+
// Low confidence warning
|
|
360
|
+
if (result.confidence === 'low') {
|
|
361
|
+
lines.push('⚠️ Low confidence - Manual verification suggested');
|
|
362
|
+
lines.push(' Conflicting signals detected. Please verify current stage.');
|
|
363
|
+
lines.push('');
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
return lines.join('\n');
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
module.exports = {
|
|
370
|
+
detectStage,
|
|
371
|
+
analyzeBranch,
|
|
372
|
+
analyzeFiles,
|
|
373
|
+
analyzePR,
|
|
374
|
+
analyzeChecks,
|
|
375
|
+
analyzeBeads,
|
|
376
|
+
calculateConfidence,
|
|
377
|
+
formatStatus,
|
|
378
|
+
};
|