@slope-dev/slope 1.59.2 → 1.60.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 (135) hide show
  1. package/dist/cli/actor.d.ts +18 -0
  2. package/dist/cli/actor.d.ts.map +1 -0
  3. package/dist/cli/actor.js +133 -0
  4. package/dist/cli/actor.js.map +1 -0
  5. package/dist/cli/commands/agent.d.ts.map +1 -1
  6. package/dist/cli/commands/agent.js +8 -6
  7. package/dist/cli/commands/agent.js.map +1 -1
  8. package/dist/cli/commands/briefing.d.ts.map +1 -1
  9. package/dist/cli/commands/briefing.js +12 -1
  10. package/dist/cli/commands/briefing.js.map +1 -1
  11. package/dist/cli/commands/claim.d.ts.map +1 -1
  12. package/dist/cli/commands/claim.js +10 -6
  13. package/dist/cli/commands/claim.js.map +1 -1
  14. package/dist/cli/commands/commit-ready.d.ts.map +1 -1
  15. package/dist/cli/commands/commit-ready.js +4 -2
  16. package/dist/cli/commands/commit-ready.js.map +1 -1
  17. package/dist/cli/commands/init.d.ts.map +1 -1
  18. package/dist/cli/commands/init.js +6 -0
  19. package/dist/cli/commands/init.js.map +1 -1
  20. package/dist/cli/commands/interview.d.ts.map +1 -1
  21. package/dist/cli/commands/interview.js +5 -0
  22. package/dist/cli/commands/interview.js.map +1 -1
  23. package/dist/cli/commands/release.d.ts.map +1 -1
  24. package/dist/cli/commands/release.js +7 -3
  25. package/dist/cli/commands/release.js.map +1 -1
  26. package/dist/cli/commands/retro.d.ts.map +1 -1
  27. package/dist/cli/commands/retro.js +27 -6
  28. package/dist/cli/commands/retro.js.map +1 -1
  29. package/dist/cli/commands/review-run.d.ts +2 -0
  30. package/dist/cli/commands/review-run.d.ts.map +1 -1
  31. package/dist/cli/commands/review-run.js +38 -8
  32. package/dist/cli/commands/review-run.js.map +1 -1
  33. package/dist/cli/commands/review-state.d.ts +2 -5
  34. package/dist/cli/commands/review-state.d.ts.map +1 -1
  35. package/dist/cli/commands/review-state.js +166 -43
  36. package/dist/cli/commands/review-state.js.map +1 -1
  37. package/dist/cli/commands/roadmap.d.ts.map +1 -1
  38. package/dist/cli/commands/roadmap.js +17 -4
  39. package/dist/cli/commands/roadmap.js.map +1 -1
  40. package/dist/cli/commands/sprint.d.ts.map +1 -1
  41. package/dist/cli/commands/sprint.js +255 -28
  42. package/dist/cli/commands/sprint.js.map +1 -1
  43. package/dist/cli/commands/start.d.ts.map +1 -1
  44. package/dist/cli/commands/start.js +20 -4
  45. package/dist/cli/commands/start.js.map +1 -1
  46. package/dist/cli/commands/ticket.d.ts.map +1 -1
  47. package/dist/cli/commands/ticket.js +31 -9
  48. package/dist/cli/commands/ticket.js.map +1 -1
  49. package/dist/cli/commands/version.d.ts +12 -0
  50. package/dist/cli/commands/version.d.ts.map +1 -1
  51. package/dist/cli/commands/version.js +169 -4
  52. package/dist/cli/commands/version.js.map +1 -1
  53. package/dist/cli/git-preflight.d.ts +9 -0
  54. package/dist/cli/git-preflight.d.ts.map +1 -0
  55. package/dist/cli/git-preflight.js +36 -0
  56. package/dist/cli/git-preflight.js.map +1 -0
  57. package/dist/cli/guards/phase-boundary.d.ts.map +1 -1
  58. package/dist/cli/guards/phase-boundary.js +52 -8
  59. package/dist/cli/guards/phase-boundary.js.map +1 -1
  60. package/dist/cli/guards/post-push.d.ts.map +1 -1
  61. package/dist/cli/guards/post-push.js +7 -1
  62. package/dist/cli/guards/post-push.js.map +1 -1
  63. package/dist/cli/guards/pr-review.d.ts +6 -0
  64. package/dist/cli/guards/pr-review.d.ts.map +1 -1
  65. package/dist/cli/guards/pr-review.js +22 -11
  66. package/dist/cli/guards/pr-review.js.map +1 -1
  67. package/dist/cli/guards/session-briefing.d.ts.map +1 -1
  68. package/dist/cli/guards/session-briefing.js +20 -2
  69. package/dist/cli/guards/session-briefing.js.map +1 -1
  70. package/dist/cli/guards/sprint-completion.js +14 -1
  71. package/dist/cli/guards/sprint-completion.js.map +1 -1
  72. package/dist/cli/guards/workflow-step-gate.d.ts.map +1 -1
  73. package/dist/cli/guards/workflow-step-gate.js +25 -6
  74. package/dist/cli/guards/workflow-step-gate.js.map +1 -1
  75. package/dist/cli/registry.d.ts.map +1 -1
  76. package/dist/cli/registry.js +20 -3
  77. package/dist/cli/registry.js.map +1 -1
  78. package/dist/cli/reviewer-agents.d.ts +22 -0
  79. package/dist/cli/reviewer-agents.d.ts.map +1 -0
  80. package/dist/cli/reviewer-agents.js +141 -0
  81. package/dist/cli/reviewer-agents.js.map +1 -0
  82. package/dist/cli/sprint-state.d.ts +28 -2
  83. package/dist/cli/sprint-state.d.ts.map +1 -1
  84. package/dist/cli/sprint-state.js +146 -9
  85. package/dist/cli/sprint-state.js.map +1 -1
  86. package/dist/cli/workflow-resync.d.ts +2 -0
  87. package/dist/cli/workflow-resync.d.ts.map +1 -1
  88. package/dist/cli/workflow-resync.js +25 -4
  89. package/dist/cli/workflow-resync.js.map +1 -1
  90. package/dist/core/analyzers/git.d.ts.map +1 -1
  91. package/dist/core/analyzers/git.js +95 -5
  92. package/dist/core/analyzers/git.js.map +1 -1
  93. package/dist/core/constants.d.ts.map +1 -1
  94. package/dist/core/constants.js +1 -0
  95. package/dist/core/constants.js.map +1 -1
  96. package/dist/core/findings.d.ts +20 -0
  97. package/dist/core/findings.d.ts.map +1 -0
  98. package/dist/core/findings.js +85 -0
  99. package/dist/core/findings.js.map +1 -0
  100. package/dist/core/generators/first-sprint.js +1 -1
  101. package/dist/core/generators/first-sprint.js.map +1 -1
  102. package/dist/core/generators/roadmap.js +3 -3
  103. package/dist/core/generators/roadmap.js.map +1 -1
  104. package/dist/core/index.d.ts +3 -1
  105. package/dist/core/index.d.ts.map +1 -1
  106. package/dist/core/index.js +2 -0
  107. package/dist/core/index.js.map +1 -1
  108. package/dist/core/interview-engine.d.ts.map +1 -1
  109. package/dist/core/interview-engine.js +5 -4
  110. package/dist/core/interview-engine.js.map +1 -1
  111. package/dist/core/interview-metaphor.d.ts +5 -0
  112. package/dist/core/interview-metaphor.d.ts.map +1 -0
  113. package/dist/core/interview-metaphor.js +20 -0
  114. package/dist/core/interview-metaphor.js.map +1 -0
  115. package/dist/core/interview-steps.d.ts.map +1 -1
  116. package/dist/core/interview-steps.js +3 -6
  117. package/dist/core/interview-steps.js.map +1 -1
  118. package/dist/core/interview.d.ts.map +1 -1
  119. package/dist/core/interview.js +5 -6
  120. package/dist/core/interview.js.map +1 -1
  121. package/dist/core/types.d.ts +11 -1
  122. package/dist/core/types.d.ts.map +1 -1
  123. package/dist/store/index.d.ts +13 -0
  124. package/dist/store/index.d.ts.map +1 -1
  125. package/dist/store/index.js +60 -7
  126. package/dist/store/index.js.map +1 -1
  127. package/package.json +1 -1
  128. package/src/core/workflows/sprint-standard.yaml +6 -0
  129. package/templates/claude-code/commands/post-sprint.md +2 -0
  130. package/templates/claude-code/commands/start-sprint.md +1 -0
  131. package/templates/codex/plugins/slope/.codex-plugin/plugin.json +1 -1
  132. package/templates/codex/plugins/slope/skills/slope-retro/SKILL.md +1 -1
  133. package/templates/generic/SLOPE-CHECKLIST.md +3 -2
  134. package/templates/pi/skills/post-sprint.md +2 -0
  135. package/templates/pi/skills/start-sprint.md +1 -0
@@ -9,6 +9,7 @@
9
9
  */
10
10
  import { execSync } from 'node:child_process';
11
11
  import { loadConfig, detectLatestSprint } from '../../core/index.js';
12
+ import { buildReviewerAgentSpecs } from '../reviewer-agents.js';
12
13
  function getPrDiff(prNumber) {
13
14
  try {
14
15
  const prArg = prNumber ? String(prNumber) : '';
@@ -22,11 +23,21 @@ function getPrDiff(prNumber) {
22
23
  return null;
23
24
  }
24
25
  }
25
- function buildArchitectPrompt(diff, files, sprint) {
26
+ function reviewerAgentIntro(spec) {
27
+ if (!spec)
28
+ return [];
29
+ return [
30
+ '## Purpose-built Reviewer Agent',
31
+ spec.prompt,
32
+ '',
33
+ ];
34
+ }
35
+ function buildArchitectPrompt(diff, files, sprint, reviewer) {
26
36
  return [
27
37
  'You are performing an ARCHITECT REVIEW of a pull request.',
28
38
  'You have a clean context — no prior implementation knowledge.',
29
39
  '',
40
+ ...reviewerAgentIntro(reviewer),
30
41
  '## Review Criteria',
31
42
  '1. Does the design match codebase patterns? Check for duplication of existing infrastructure.',
32
43
  '2. Are dependencies correct and ordering optimal?',
@@ -50,11 +61,12 @@ function buildArchitectPrompt(diff, files, sprint) {
50
61
  'If no issues found, say "No architect findings."',
51
62
  ].join('\n');
52
63
  }
53
- function buildCodePrompt(diff, files, sprint) {
64
+ function buildCodePrompt(diff, files, sprint, reviewer) {
54
65
  return [
55
66
  'You are performing a CODE REVIEW of a pull request.',
56
67
  'You have a clean context — no prior implementation knowledge.',
57
68
  '',
69
+ ...reviewerAgentIntro(reviewer),
58
70
  '## Review Criteria',
59
71
  '1. Correctness: Does the code do what it claims? Edge cases?',
60
72
  '2. Error handling: Are errors caught and handled appropriately?',
@@ -109,18 +121,33 @@ export async function reviewRunCommand(args) {
109
121
  }
110
122
  const diffLines = pr.diff.split('\n').length;
111
123
  const prompts = [];
124
+ const recommendations = [];
125
+ if (reviewType === 'architect' || reviewType === 'both') {
126
+ recommendations.push({ review_type: 'architect', priority: 'required', reason: 'PR architect review requested' });
127
+ }
128
+ if (reviewType === 'code' || reviewType === 'both') {
129
+ recommendations.push({ review_type: 'code', priority: 'optional', reason: 'PR code review requested' });
130
+ }
131
+ const reviewerAgents = buildReviewerAgentSpecs(recommendations, {
132
+ sprintNumber: sprint,
133
+ filePatterns: pr.files,
134
+ artifacts: pr.files,
135
+ });
136
+ const reviewerByLane = new Map(reviewerAgents.map(spec => [spec.lane, spec]));
112
137
  if (reviewType === 'architect' || reviewType === 'both') {
138
+ const reviewer = reviewerByLane.get('architect');
113
139
  prompts.push({
114
140
  type: 'architect',
115
- prompt: buildArchitectPrompt(pr.diff, pr.files, sprint),
116
- context: { pr_number: pr.prNum, sprint, changed_files: pr.files, diff_lines: diffLines },
141
+ prompt: buildArchitectPrompt(pr.diff, pr.files, sprint, reviewer),
142
+ context: { pr_number: pr.prNum, sprint, changed_files: pr.files, diff_lines: diffLines, reviewer_agent: reviewer },
117
143
  });
118
144
  }
119
145
  if (reviewType === 'code' || reviewType === 'both') {
146
+ const reviewer = reviewerByLane.get('code');
120
147
  prompts.push({
121
148
  type: 'code',
122
- prompt: buildCodePrompt(pr.diff, pr.files, sprint),
123
- context: { pr_number: pr.prNum, sprint, changed_files: pr.files, diff_lines: diffLines },
149
+ prompt: buildCodePrompt(pr.diff, pr.files, sprint, reviewer),
150
+ context: { pr_number: pr.prNum, sprint, changed_files: pr.files, diff_lines: diffLines, reviewer_agent: reviewer },
124
151
  });
125
152
  }
126
153
  if (json) {
@@ -132,11 +159,14 @@ export async function reviewRunCommand(args) {
132
159
  console.log(`Sprint: ${sprint ?? '?'} | Files: ${pr.files.length} | Diff: ${diffLines} lines\n`);
133
160
  for (const p of prompts) {
134
161
  console.log(`--- ${p.type.toUpperCase()} REVIEW PROMPT ---`);
135
- console.log('Use this with Claude Code\'s Agent tool (model: "haiku") for an isolated review:\n');
162
+ if (p.context.reviewer_agent) {
163
+ console.log(`Suggested reviewer agent: ${p.context.reviewer_agent.name} (${p.context.reviewer_agent.id})`);
164
+ }
165
+ console.log('Use this with Codex or Claude Code Agent tool for an isolated review:\n');
136
166
  console.log(p.prompt);
137
167
  console.log('');
138
168
  }
139
- console.log('To run both reviews as subagents, use:');
169
+ console.log('To run both reviews as purpose-built subagents, use:');
140
170
  console.log(' slope review run --json | # pass to Agent tool prompts');
141
171
  console.log('');
142
172
  }
@@ -1 +1 @@
1
- {"version":3,"file":"review-run.js","sourceRoot":"","sources":["../../../src/cli/commands/review-run.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"review-run.js","sourceRoot":"","sources":["../../../src/cli/commands/review-run.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAErE,OAAO,EAAE,uBAAuB,EAA0B,MAAM,uBAAuB,CAAC;AAcxF,SAAS,SAAS,CAAC,QAAiB;IAClC,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAC/C,MAAM,IAAI,GAAG,QAAQ,CAAC,cAAc,KAAK,EAAE,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;QAC1F,MAAM,QAAQ,GAAG,QAAQ,CAAC,cAAc,KAAK,cAAc,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;QAC1G,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QACnD,MAAM,GAAG,GAAG,QAAQ,IAAI,QAAQ,CAAC,QAAQ,CAAC,qCAAqC,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;QACnI,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC;IACrC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,SAAS,kBAAkB,CAAC,IAAwB;IAClD,IAAI,CAAC,IAAI;QAAE,OAAO,EAAE,CAAC;IACrB,OAAO;QACL,iCAAiC;QACjC,IAAI,CAAC,MAAM;QACX,EAAE;KACH,CAAC;AACJ,CAAC;AAED,SAAS,oBAAoB,CAAC,IAAY,EAAE,KAAe,EAAE,MAAe,EAAE,QAA4B;IACxG,OAAO;QACL,2DAA2D;QAC3D,+DAA+D;QAC/D,EAAE;QACF,GAAG,kBAAkB,CAAC,QAAQ,CAAC;QAC/B,oBAAoB;QACpB,+FAA+F;QAC/F,mDAAmD;QACnD,oDAAoD;QACpD,8CAA8C;QAC9C,yEAAyE;QACzE,EAAE;QACF,kBAAkB;QAClB,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;QACnC,EAAE;QACF,SAAS;QACT,SAAS;QACT,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,GAAG,mBAAmB,CAAC,CAAC,CAAC,IAAI;QACvE,KAAK;QACL,EAAE;QACF,kBAAkB;QAClB,2BAA2B;QAC3B,KAAK;QACL,6CAA6C,MAAM,CAAC,CAAC,CAAC,aAAa,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,uEAAuE;QACvJ,KAAK;QACL,kDAAkD;KACnD,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC;AAED,SAAS,eAAe,CAAC,IAAY,EAAE,KAAe,EAAE,MAAe,EAAE,QAA4B;IACnG,OAAO;QACL,qDAAqD;QACrD,+DAA+D;QAC/D,EAAE;QACF,GAAG,kBAAkB,CAAC,QAAQ,CAAC;QAC/B,oBAAoB;QACpB,8DAA8D;QAC9D,iEAAiE;QACjE,mDAAmD;QACnD,yEAAyE;QACzE,0DAA0D;QAC1D,EAAE;QACF,kBAAkB;QAClB,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;QACnC,EAAE;QACF,SAAS;QACT,SAAS;QACT,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,GAAG,mBAAmB,CAAC,CAAC,CAAC,IAAI;QACvE,KAAK;QACL,EAAE;QACF,kBAAkB;QAClB,2BAA2B;QAC3B,KAAK;QACL,wCAAwC,MAAM,CAAC,CAAC,CAAC,aAAa,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,uEAAuE;QAClJ,KAAK;QACL,6CAA6C;KAC9C,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,IAAc;IACnD,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;IAC1B,MAAM,KAAK,GAA2B,EAAE,CAAC;IACzC,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,0BAA0B,CAAC,CAAC;QACpD,IAAI,KAAK;YAAE,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,MAAM,CAAC;IAClD,CAAC;IAED,MAAM,QAAQ,GAAG,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAC/D,MAAM,UAAU,GAAG,CAAC,KAAK,CAAC,IAAI,IAAI,MAAM,CAAkC,CAAC;IAC3E,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,KAAK,MAAM,CAAC;IAEnC,gBAAgB;IAChB,IAAI,MAA0B,CAAC;IAC/B,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;QACjB,MAAM,GAAG,QAAQ,CAAC,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IACtC,CAAC;SAAM,CAAC;QACN,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC;YAC/B,MAAM,GAAG,MAAM,CAAC,aAAa,IAAI,kBAAkB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QACnE,CAAC;QAAC,MAAM,CAAC,CAAC,eAAe,CAAC,CAAC;IAC7B,CAAC;IAED,cAAc;IACd,MAAM,EAAE,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;IAC/B,IAAI,CAAC,EAAE,EAAE,CAAC;QACR,OAAO,CAAC,KAAK,CAAC,6FAA6F,CAAC,CAAC;QAC7G,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,SAAS,GAAG,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;IAC7C,MAAM,OAAO,GAAmB,EAAE,CAAC;IACnC,MAAM,eAAe,GAA2B,EAAE,CAAC;IACnD,IAAI,UAAU,KAAK,WAAW,IAAI,UAAU,KAAK,MAAM,EAAE,CAAC;QACxD,eAAe,CAAC,IAAI,CAAC,EAAE,WAAW,EAAE,WAAW,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,EAAE,+BAA+B,EAAE,CAAC,CAAC;IACpH,CAAC;IACD,IAAI,UAAU,KAAK,MAAM,IAAI,UAAU,KAAK,MAAM,EAAE,CAAC;QACnD,eAAe,CAAC,IAAI,CAAC,EAAE,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,EAAE,0BAA0B,EAAE,CAAC,CAAC;IAC1G,CAAC;IACD,MAAM,cAAc,GAAG,uBAAuB,CAAC,eAAe,EAAE;QAC9D,YAAY,EAAE,MAAM;QACpB,YAAY,EAAE,EAAE,CAAC,KAAK;QACtB,SAAS,EAAE,EAAE,CAAC,KAAK;KACpB,CAAC,CAAC;IACH,MAAM,cAAc,GAAG,IAAI,GAAG,CAAC,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;IAE9E,IAAI,UAAU,KAAK,WAAW,IAAI,UAAU,KAAK,MAAM,EAAE,CAAC;QACxD,MAAM,QAAQ,GAAG,cAAc,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;QACjD,OAAO,CAAC,IAAI,CAAC;YACX,IAAI,EAAE,WAAW;YACjB,MAAM,EAAE,oBAAoB,CAAC,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC;YACjE,OAAO,EAAE,EAAE,SAAS,EAAE,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,EAAE,CAAC,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,cAAc,EAAE,QAAQ,EAAE;SACnH,CAAC,CAAC;IACL,CAAC;IAED,IAAI,UAAU,KAAK,MAAM,IAAI,UAAU,KAAK,MAAM,EAAE,CAAC;QACnD,MAAM,QAAQ,GAAG,cAAc,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAC5C,OAAO,CAAC,IAAI,CAAC;YACX,IAAI,EAAE,MAAM;YACZ,MAAM,EAAE,eAAe,CAAC,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC;YAC5D,OAAO,EAAE,EAAE,SAAS,EAAE,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,EAAE,CAAC,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,cAAc,EAAE,QAAQ,EAAE;SACnH,CAAC,CAAC;IACL,CAAC;IAED,IAAI,IAAI,EAAE,CAAC;QACT,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QAC9C,OAAO;IACT,CAAC;IAED,uCAAuC;IACvC,OAAO,CAAC,GAAG,CAAC,gCAAgC,EAAE,CAAC,KAAK,MAAM,CAAC,CAAC;IAC5D,OAAO,CAAC,GAAG,CAAC,WAAW,MAAM,IAAI,GAAG,aAAa,EAAE,CAAC,KAAK,CAAC,MAAM,YAAY,SAAS,UAAU,CAAC,CAAC;IAEjG,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;QACxB,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,oBAAoB,CAAC,CAAC;QAC7D,IAAI,CAAC,CAAC,OAAO,CAAC,cAAc,EAAE,CAAC;YAC7B,OAAO,CAAC,GAAG,CAAC,6BAA6B,CAAC,CAAC,OAAO,CAAC,cAAc,CAAC,IAAI,KAAK,CAAC,CAAC,OAAO,CAAC,cAAc,CAAC,EAAE,GAAG,CAAC,CAAC;QAC7G,CAAC;QACD,OAAO,CAAC,GAAG,CAAC,yEAAyE,CAAC,CAAC;QACvF,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;QACtB,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAClB,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,sDAAsD,CAAC,CAAC;IACpE,OAAO,CAAC,GAAG,CAAC,0DAA0D,CAAC,CAAC;IACxE,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;AAClB,CAAC"}
@@ -1,4 +1,5 @@
1
- import type { ReviewFinding } from '../../core/types.js';
1
+ export { loadFindings } from '../../core/findings.js';
2
+ export type { FindingsFile } from '../../core/findings.js';
2
3
  export interface ReviewState {
3
4
  rounds_required: number;
4
5
  rounds_completed: number;
@@ -8,10 +9,6 @@ export interface ReviewState {
8
9
  }
9
10
  export declare function loadReviewState(cwd: string): ReviewState | null;
10
11
  export declare function saveReviewState(cwd: string, state: ReviewState): void;
11
- export interface FindingsFile {
12
- sprints: Record<number, ReviewFinding[]>;
13
- }
14
- export declare function loadFindings(cwd: string): FindingsFile | null;
15
12
  export declare const REVIEW_STATE_SUBCOMMANDS: string[];
16
13
  export declare function shouldRouteToReviewState(args: string[]): boolean;
17
14
  export declare function reviewStateCommand(args: string[]): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"review-state.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/review-state.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAA8B,MAAM,qBAAqB,CAAC;AAYrF,MAAM,WAAW,WAAW;IAC1B,eAAe,EAAE,MAAM,CAAC;IACxB,gBAAgB,EAAE,MAAM,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;CACpB;AAWD,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAQ/D;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,GAAG,IAAI,CAIrE;AAsHD,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,EAAE,CAAC,CAAC;CAC1C;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,CAc7D;AA0ZD,eAAO,MAAM,wBAAwB,UAYpC,CAAC;AAEF,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAIhE;AA0GD,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAqDtE"}
1
+ {"version":3,"file":"review-state.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/review-state.ts"],"names":[],"mappings":"AAmBA,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACtD,YAAY,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAO3D,MAAM,WAAW,WAAW;IAC1B,eAAe,EAAE,MAAM,CAAC;IACxB,gBAAgB,EAAE,MAAM,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;CACpB;AAWD,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAQ/D;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,GAAG,IAAI,CAIrE;AA+pBD,eAAO,MAAM,wBAAwB,UAYpC,CAAC;AAEF,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAIhE;AA2GD,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAqDtE"}
@@ -4,9 +4,12 @@ import { recommendReviews, amendScorecardWithFindings } from '../../core/review.
4
4
  import { loadConfig, detectLatestSprint, normalizeScorecard, parseSprintNumber } from '../../core/index.js';
5
5
  import { createDeferred, listDeferred, resolveDeferred } from '../../core/deferred.js';
6
6
  import { HAZARD_SEVERITY_PENALTIES } from '../../core/constants.js';
7
+ import { FINDINGS_FILE, createFindingId, displayFindingId, formatCodificationMetadata, isCodificationCandidate, loadFindings, matchesFindingId, saveFindings, } from '../../core/findings.js';
8
+ export { loadFindings } from '../../core/findings.js';
7
9
  import { findPlanContent, countTickets, countPackageRefs } from '../guards/plan-analysis.js';
8
10
  import { inferSprintContext, loadRoadmapForInference } from '../sprint-inference.js';
9
11
  import { isActiveSprintState, loadSprintState } from '../sprint-state.js';
12
+ import { buildReviewerAgentSpecs, formatReviewerAgentGuidance } from '../reviewer-agents.js';
10
13
  const REVIEW_STATE_FILE = '.slope/review-state.json';
11
14
  const TIER_ROUNDS = {
12
15
  skip: 0,
@@ -136,31 +139,6 @@ function resetCommand(cwd) {
136
139
  }
137
140
  console.log('Review state cleared.');
138
141
  }
139
- // --- Findings File Management ---
140
- const FINDINGS_FILE = '.slope/review-findings.json';
141
- export function loadFindings(cwd) {
142
- const filePath = join(cwd, FINDINGS_FILE);
143
- if (!existsSync(filePath))
144
- return null;
145
- try {
146
- const raw = JSON.parse(readFileSync(filePath, 'utf8'));
147
- // Migrate legacy single-sprint format
148
- if (raw.sprints)
149
- return { sprints: raw.sprints };
150
- if (raw.sprint_number != null && raw.findings) {
151
- return { sprints: { [raw.sprint_number]: raw.findings } };
152
- }
153
- return null;
154
- }
155
- catch {
156
- return null;
157
- }
158
- }
159
- function saveFindings(cwd, data) {
160
- const dir = join(cwd, '.slope');
161
- mkdirSync(dir, { recursive: true });
162
- writeFileSync(join(cwd, FINDINGS_FILE), JSON.stringify(data, null, 2) + '\n');
163
- }
164
142
  function parseSprintArg(args) {
165
143
  const sprintArg = args.find(a => a.startsWith('--sprint='));
166
144
  if (!sprintArg)
@@ -187,10 +165,17 @@ function collectStringValues(value, out = []) {
187
165
  }
188
166
  return out;
189
167
  }
168
+ function extractHazardLines(values) {
169
+ return values
170
+ .map(value => value.replace(/\s+/g, ' ').trim())
171
+ .filter(value => /\b(hazard|risk|gotcha|warning|failure|safety|security|boundary|review gate)\b/i.test(value))
172
+ .slice(0, 8);
173
+ }
190
174
  function recommendationFromPlan(content) {
191
175
  const filePatterns = [];
192
176
  const slopeMatch = content.match(/\*\*Slope:\*\*\s*(\d+)/);
193
177
  const sprintMatch = content.match(/Sprint\s+(\d+(?:\.\d+)?)/);
178
+ const titleMatch = content.match(/^#\s+(.+)$/m);
194
179
  const fileMatches = content.matchAll(/`([^`]+\.[a-z]+)`/g);
195
180
  for (const m of fileMatches)
196
181
  filePatterns.push(m[1]);
@@ -199,6 +184,9 @@ function recommendationFromPlan(content) {
199
184
  slope: slopeMatch ? parseInt(slopeMatch[1], 10) : 0,
200
185
  sprintNumber: sprintMatch ? parseSprintNumber(sprintMatch[1]) ?? 0 : 0,
201
186
  filePatterns,
187
+ theme: titleMatch?.[1],
188
+ artifacts: filePatterns,
189
+ hazards: extractHazardLines(content.split('\n')),
202
190
  hasNewInfra: /\b(new module|new package|new service|new infrastructure)\b/i.test(content),
203
191
  };
204
192
  }
@@ -210,16 +198,23 @@ function recommendationFromRoadmapSprint(sprint) {
210
198
  slope: sprint.slope ?? 0,
211
199
  sprintNumber: sprint.id,
212
200
  filePatterns,
201
+ theme: sprint.theme,
202
+ artifacts: filePatterns.length > 0 ? filePatterns : sprint.tickets?.map(ticket => `${ticket.key}: ${ticket.title}`),
203
+ hazards: extractHazardLines(stringValues),
213
204
  hasNewInfra: /\b(new module|new package|new service|new infrastructure)\b/i.test(stringValues.join('\n')),
214
205
  };
215
206
  }
216
207
  function recommendationFromScorecard(card) {
217
208
  const stringValues = collectStringValues(card);
209
+ const filePatterns = stringValues.filter(value => /[/.]/.test(value));
218
210
  return {
219
211
  ticketCount: card.shots?.length ?? 0,
220
212
  slope: card.slope ?? 0,
221
213
  sprintNumber: card.sprint_number,
222
- filePatterns: stringValues.filter(value => /[/.]/.test(value)),
214
+ filePatterns,
215
+ theme: card.theme,
216
+ artifacts: filePatterns,
217
+ hazards: extractHazardLines(stringValues),
223
218
  hasNewInfra: /\b(new module|new package|new service|new infrastructure)\b/i.test(stringValues.join('\n')),
224
219
  };
225
220
  }
@@ -247,6 +242,8 @@ function inferRecommendationContext(args, cwd) {
247
242
  slope: 0,
248
243
  filePatterns: [],
249
244
  sprintNumber: explicitSprint,
245
+ artifacts: [],
246
+ hazards: [],
250
247
  hasNewInfra: false,
251
248
  };
252
249
  }
@@ -269,6 +266,8 @@ function inferRecommendationContext(args, cwd) {
269
266
  slope: 0,
270
267
  filePatterns: [],
271
268
  sprintNumber: inferred.sprint,
269
+ artifacts: [],
270
+ hazards: [],
272
271
  hasNewInfra: false,
273
272
  };
274
273
  }
@@ -280,6 +279,8 @@ function inferRecommendationContext(args, cwd) {
280
279
  slope: 0,
281
280
  filePatterns: [],
282
281
  sprintNumber: 0,
282
+ artifacts: [],
283
+ hazards: [],
283
284
  hasNewInfra: false,
284
285
  };
285
286
  }
@@ -294,10 +295,22 @@ function recommendCommand(args, cwd) {
294
295
  const priority = rec.priority.padEnd(13);
295
296
  console.log(` ${type} ${priority} ${rec.reason}`);
296
297
  }
298
+ const reviewerAgents = buildReviewerAgentSpecs(recs, {
299
+ sprintNumber: context.sprintNumber > 0 ? context.sprintNumber : undefined,
300
+ theme: context.theme,
301
+ filePatterns: context.filePatterns,
302
+ artifacts: context.artifacts,
303
+ hazards: context.hazards,
304
+ });
305
+ const guidance = formatReviewerAgentGuidance(reviewerAgents);
306
+ if (guidance)
307
+ console.log(`\n${guidance}`);
297
308
  }
298
309
  // --- Findings Subcommands ---
299
- const VALID_REVIEW_TYPES = ['architect', 'code', 'ml-engineer', 'security', 'ux'];
310
+ const VALID_REVIEW_TYPES = ['architect', 'code', 'ml-engineer', 'security', 'ux', 'workaround'];
300
311
  const VALID_SEVERITIES = ['minor', 'moderate', 'major', 'critical'];
312
+ const VALID_CODIFICATION_COSTS = ['s', 'm', 'l'];
313
+ const VALID_CODIFICATION_STATUSES = ['open', 'paid_down', 'wontfix'];
301
314
  function findingsAddCommand(args, cwd) {
302
315
  const typeArg = args.find(a => a.startsWith('--type='));
303
316
  const ticketArg = args.find(a => a.startsWith('--ticket='));
@@ -305,9 +318,12 @@ function findingsAddCommand(args, cwd) {
305
318
  const descArg = args.find(a => a.startsWith('--description='));
306
319
  const sprintArg = args.find(a => a.startsWith('--sprint='));
307
320
  const resolvedArg = args.includes('--resolved');
308
- if (!typeArg || !ticketArg || !descArg) {
309
- console.error('Error: --type, --ticket, and --description are required.');
321
+ const recursArg = args.includes('--recurs');
322
+ const costArg = args.find(a => a.startsWith('--cost='));
323
+ if (!typeArg || !descArg) {
324
+ console.error('Error: --type and --description are required; --ticket is required except for --type=workaround.');
310
325
  console.error('Usage: slope review findings add --type=architect --ticket=S34-1 --severity=moderate --description="..."');
326
+ console.error('Usage: slope review findings add --type=workaround --recurs --cost=s --description="..."');
311
327
  process.exit(1);
312
328
  }
313
329
  const reviewType = typeArg.slice('--type='.length);
@@ -315,6 +331,27 @@ function findingsAddCommand(args, cwd) {
315
331
  console.error(`Error: Invalid review type "${reviewType}". Use: ${VALID_REVIEW_TYPES.join(', ')}`);
316
332
  process.exit(1);
317
333
  }
334
+ if (!ticketArg && reviewType !== 'workaround') {
335
+ console.error('Error: --ticket is required unless --type=workaround.');
336
+ process.exit(1);
337
+ }
338
+ const cost = costArg ? costArg.slice('--cost='.length) : undefined;
339
+ if (cost && !VALID_CODIFICATION_COSTS.includes(cost)) {
340
+ console.error(`Error: Invalid codification cost "${cost}". Use: ${VALID_CODIFICATION_COSTS.join(', ')}`);
341
+ process.exit(1);
342
+ }
343
+ if (reviewType === 'workaround' && !recursArg) {
344
+ console.error('Error: workaround findings must include --recurs so one-off workarounds are not logged as codification debt.');
345
+ process.exit(1);
346
+ }
347
+ if (recursArg && !cost) {
348
+ console.error('Error: recurring workaround findings require --cost=s|m|l.');
349
+ process.exit(1);
350
+ }
351
+ if (cost && !recursArg) {
352
+ console.error('Error: --cost requires --recurs.');
353
+ process.exit(1);
354
+ }
318
355
  const severity = severityArg
319
356
  ? severityArg.slice('--severity='.length)
320
357
  : 'moderate';
@@ -322,7 +359,7 @@ function findingsAddCommand(args, cwd) {
322
359
  console.error(`Error: Invalid severity "${severity}". Use: ${VALID_SEVERITIES.join(', ')}`);
323
360
  process.exit(1);
324
361
  }
325
- const ticketKey = ticketArg.slice('--ticket='.length);
362
+ const ticketKey = ticketArg ? ticketArg.slice('--ticket='.length) : 'workaround';
326
363
  const description = descArg.slice('--description='.length);
327
364
  // Determine sprint number
328
365
  let sprintNumber = 0;
@@ -337,11 +374,15 @@ function findingsAddCommand(args, cwd) {
337
374
  catch { /* fallback to 0 */ }
338
375
  }
339
376
  const finding = {
377
+ id: createFindingId(),
340
378
  review_type: reviewType,
341
379
  ticket_key: ticketKey,
342
380
  severity,
343
381
  description,
344
382
  resolved: resolvedArg,
383
+ recurs: recursArg || undefined,
384
+ cost,
385
+ codification_status: recursArg ? 'open' : undefined,
345
386
  };
346
387
  const existing = loadFindings(cwd);
347
388
  if (existing && existing.sprints[sprintNumber]) {
@@ -357,9 +398,21 @@ function findingsAddCommand(args, cwd) {
357
398
  saveFindings(cwd, { sprints: { [sprintNumber]: [finding] } });
358
399
  }
359
400
  console.log(`Finding added: [${reviewType}] ${ticketKey} — ${description} (${severity})`);
401
+ console.log(` ID: ${finding.id}`);
402
+ const codification = formatCodificationMetadata(finding);
403
+ if (codification)
404
+ console.log(` ${codification}`);
360
405
  }
361
406
  function findingsListCommand(args, cwd) {
362
407
  const sprintArg = args.find(a => a.startsWith('--sprint='));
408
+ const codificationStatusArg = args.find(a => a.startsWith('--codification-status='));
409
+ const codificationStatus = codificationStatusArg
410
+ ? codificationStatusArg.slice('--codification-status='.length)
411
+ : undefined;
412
+ if (codificationStatus && !VALID_CODIFICATION_STATUSES.includes(codificationStatus)) {
413
+ console.error(`Error: Invalid codification status "${codificationStatus}". Use: ${VALID_CODIFICATION_STATUSES.join(', ')}`);
414
+ process.exit(1);
415
+ }
363
416
  const data = loadFindings(cwd);
364
417
  if (!data || Object.keys(data.sprints).length === 0) {
365
418
  console.log('No review findings recorded.');
@@ -367,36 +420,101 @@ function findingsListCommand(args, cwd) {
367
420
  }
368
421
  if (sprintArg) {
369
422
  const requestedSprint = parseSprintNumber(sprintArg.slice('--sprint='.length)) ?? 0;
370
- const sprintFindings = data.sprints[requestedSprint];
423
+ const sprintFindings = filterFindingsForList(data.sprints[requestedSprint] ?? [], codificationStatus);
371
424
  if (!sprintFindings || sprintFindings.length === 0) {
372
425
  console.log(`No findings for Sprint ${requestedSprint}.`);
373
426
  return;
374
427
  }
375
428
  console.log(`Sprint ${requestedSprint} findings (${sprintFindings.length} total):\n`);
376
- console.log(' Ticket Type Severity Description');
377
- for (const f of sprintFindings) {
429
+ console.log(' ID Ticket Type Severity Description');
430
+ for (const [index, f] of sprintFindings.entries()) {
431
+ const id = displayFindingId(f, requestedSprint, index).padEnd(8);
378
432
  const ticket = f.ticket_key.padEnd(7);
379
433
  const type = f.review_type.padEnd(14);
380
434
  const severity = f.severity.padEnd(10);
381
- console.log(` ${ticket} ${type} ${severity} ${f.description}`);
435
+ const meta = formatCodificationMetadata(f);
436
+ console.log(` ${id} ${ticket} ${type} ${severity} ${f.description}${meta ? ` (${meta})` : ''}`);
382
437
  }
383
438
  }
384
439
  else {
385
440
  // Show all findings grouped by sprint
386
441
  const sprintKeys = Object.keys(data.sprints).map(Number).sort((a, b) => a - b);
442
+ let printed = false;
387
443
  for (const sprint of sprintKeys) {
388
- const sprintFindings = data.sprints[sprint];
444
+ const sprintFindings = filterFindingsForList(data.sprints[sprint] ?? [], codificationStatus);
445
+ if (sprintFindings.length === 0)
446
+ continue;
447
+ printed = true;
389
448
  console.log(`Sprint ${sprint} findings (${sprintFindings.length}):\n`);
390
- console.log(' Ticket Type Severity Description');
391
- for (const f of sprintFindings) {
449
+ console.log(' ID Ticket Type Severity Description');
450
+ for (const [index, f] of sprintFindings.entries()) {
451
+ const id = displayFindingId(f, sprint, index).padEnd(8);
392
452
  const ticket = f.ticket_key.padEnd(7);
393
453
  const type = f.review_type.padEnd(14);
394
454
  const severity = f.severity.padEnd(10);
395
- console.log(` ${ticket} ${type} ${severity} ${f.description}`);
455
+ const meta = formatCodificationMetadata(f);
456
+ console.log(` ${id} ${ticket} ${type} ${severity} ${f.description}${meta ? ` (${meta})` : ''}`);
396
457
  }
397
458
  console.log('');
398
459
  }
460
+ if (!printed) {
461
+ console.log(codificationStatus
462
+ ? `No findings match codification status "${codificationStatus}".`
463
+ : 'No review findings recorded.');
464
+ }
465
+ }
466
+ }
467
+ function filterFindingsForList(findings, codificationStatus) {
468
+ if (!codificationStatus)
469
+ return findings;
470
+ return findings.filter(finding => {
471
+ if (!isCodificationCandidate(finding))
472
+ return false;
473
+ return (finding.codification_status ?? 'open') === codificationStatus;
474
+ });
475
+ }
476
+ function findingsResolveCommand(args, cwd) {
477
+ const id = args.find(a => !a.startsWith('--')) ?? args.find(a => a.startsWith('--id='))?.slice('--id='.length);
478
+ const statusArg = args.find(a => a.startsWith('--status='));
479
+ const status = statusArg ? statusArg.slice('--status='.length) : 'paid_down';
480
+ if (!id) {
481
+ console.error('Error: finding id is required. Usage: slope review findings resolve <id> [--status=paid_down|wontfix]');
482
+ process.exit(1);
483
+ }
484
+ if (!['paid_down', 'wontfix'].includes(status)) {
485
+ console.error('Error: --status must be paid_down or wontfix.');
486
+ process.exit(1);
487
+ }
488
+ const data = loadFindings(cwd);
489
+ if (!data) {
490
+ console.error('Error: no review findings recorded.');
491
+ process.exit(1);
492
+ }
493
+ const now = new Date().toISOString();
494
+ for (const sprint of Object.keys(data.sprints).map(Number).sort((a, b) => a - b)) {
495
+ const findings = data.sprints[sprint] ?? [];
496
+ for (const [index, finding] of findings.entries()) {
497
+ if (!matchesFindingId(finding, sprint, index, id))
498
+ continue;
499
+ if (!isCodificationCandidate(finding)) {
500
+ console.error(`Error: finding ${id} is not a recurring workaround codification candidate.`);
501
+ process.exit(1);
502
+ }
503
+ finding.resolved = true;
504
+ finding.codification_status = status;
505
+ finding.resolved_at = now;
506
+ if (status === 'paid_down')
507
+ finding.codified_at = now;
508
+ else
509
+ delete finding.codified_at;
510
+ saveFindings(cwd, data);
511
+ console.log(`Codification candidate ${status}: ${displayFindingId(finding, sprint, index)}`);
512
+ console.log(` S${sprint}: ${finding.description}`);
513
+ return;
514
+ }
399
515
  }
516
+ console.error(`Error: no finding found matching id "${id}".`);
517
+ process.exit(1);
400
518
  }
401
519
  function findingsClearCommand(args, cwd) {
402
520
  const filePath = join(cwd, FINDINGS_FILE);
@@ -414,8 +532,9 @@ function findingsCommand(args, cwd) {
414
532
  console.log(`Usage: slope review findings <subcommand> [options]
415
533
 
416
534
  Subcommands:
417
- add Add a review finding
535
+ add Add a review finding; workaround candidates use --recurs --cost=s|m|l
418
536
  list List recorded findings
537
+ resolve Mark a codification candidate paid_down or wontfix
419
538
  clear Clear all findings
420
539
 
421
540
  Use 'slope review findings add --help' for add options.`);
@@ -429,11 +548,14 @@ Use 'slope review findings add --help' for add options.`);
429
548
  case 'list':
430
549
  findingsListCommand(args.slice(1), cwd);
431
550
  break;
551
+ case 'resolve':
552
+ findingsResolveCommand(args.slice(1), cwd);
553
+ break;
432
554
  case 'clear':
433
555
  findingsClearCommand(args.slice(1), cwd);
434
556
  break;
435
557
  default:
436
- console.error(`Unknown findings subcommand: ${sub}. Use add, list, or clear.`);
558
+ console.error(`Unknown findings subcommand: ${sub}. Use add, list, resolve, or clear.`);
437
559
  process.exit(1);
438
560
  }
439
561
  }
@@ -587,11 +709,12 @@ ux) apply to the current sprint based on active sprint state, roadmap,
587
709
  scorecard, or plan metadata.`);
588
710
  break;
589
711
  case 'findings':
590
- console.log(`Usage: slope review findings <add|list|clear> [options]
712
+ console.log(`Usage: slope review findings <add|list|resolve|clear> [options]
591
713
 
592
714
  Subcommands:
593
- add Record a review finding (--type, --ticket, --severity, --description)
594
- list List recorded findings (optionally --sprint=N)
715
+ add Record a review finding (--type, --ticket, --severity, --description; workaround uses --recurs --cost=s|m|l)
716
+ list List recorded findings (optionally --sprint=N or --codification-status=open|paid_down|wontfix)
717
+ resolve Mark a recurring workaround candidate paid_down or wontfix by id
595
718
  clear Clear all findings`);
596
719
  break;
597
720
  case 'amend':