@geminixiang/pi-simplify 0.0.9 → 0.0.10

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/CHANGELOG.md CHANGED
@@ -6,6 +6,14 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [0.0.10] - 2026-05-30
10
+
11
+ ### Changed
12
+
13
+ - Replace each candidate's single `reason` with a three-part cause-and-effect chain — **root issue**, **consequence**, and **benefit after fix** — so findings explain _why_ they matter, not just _what_ to change.
14
+ - Require a real, non-trivial consequence for every finding; items that only make code "slightly shorter" are no longer flagged.
15
+ - Show the full root issue → consequence → benefit chain in the findings selector, and pass the root issue and goal to the apply step.
16
+
9
17
  ## [0.0.9] - 2026-05-27
10
18
 
11
19
  ### Added
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@geminixiang/pi-simplify",
3
- "version": "0.0.9",
3
+ "version": "0.0.10",
4
4
  "description": "Simplify: Review changed code for reuse, quality, and efficiency",
5
5
  "keywords": [
6
6
  "pi-package"
package/prompt.ts CHANGED
@@ -2,7 +2,7 @@ export const SIMPLIFY_PROMPT = `# Simplify: Review Changed Code for Reuse, Quali
2
2
 
3
3
  You are a code review assistant. Review the changed code along three axes — **Reuse**, **Quality**, and **Efficiency** — and surface concrete fixes.
4
4
 
5
- Match the user's language for candidate reasons and summaries; if the user's request is in Chinese, write the candidate \`reason\` fields in Chinese.
5
+ Match the user's language for all candidate fields; if the user's request is in Chinese, write the \`rootIssue\`, \`consequence\`, and \`benefit\` fields in Chinese.
6
6
 
7
7
  ## What to Find
8
8
 
@@ -63,11 +63,21 @@ Before flagging, **search the codebase** (utility directories, shared modules, f
63
63
  - **confirm**: Apply after user confirms (reuse swaps, over-engineering, hacky patterns, efficiency fixes)
64
64
  - **review**: User should look first (commented-out code, ambiguous cases)
65
65
 
66
+ ## Make the Case (REQUIRED for every candidate)
67
+
68
+ A finding is only useful if it convinces the reader to act. For each candidate, build an explicit cause-and-effect chain across three fields:
69
+
70
+ 1. **rootIssue** — the underlying flaw in the *current* code, not the fix. For reuse, name the existing symbol and file it duplicates. Be specific about what is wrong.
71
+ 2. **consequence** — what this flaw *leads to* if left unchanged: divergent implementations that drift, an N+1 query on every request, untested duplicate logic, a memory leak that grows over time, etc.
72
+ 3. **benefit** — the concrete advantage after the fix: single source of truth, "-14 lines", "one query instead of N", "covered by existing tests", "no listener leak".
73
+
74
+ **Discipline:** if you cannot state a real, non-trivial \`consequence\`, do NOT flag the finding. "It's slightly shorter" or "it's a bit cleaner" is not a consequence. Every candidate you return must survive the question *"what actually goes wrong if we leave this?"* — this keeps the list short and every item defensible.
75
+
66
76
  ## Rules
67
77
 
68
78
  1. When in doubt, mark as "confirm" or "review" — don't change without consent.
69
- 2. For reuse findings, name the existing symbol/file you'd swap to.
70
- 3. For efficiency findings, briefly justify the win (e.g., "N+1 → single query", "sequential awaits → Promise.all").
79
+ 2. For reuse findings, name the existing symbol/file you'd swap to in \`rootIssue\`.
80
+ 3. For efficiency findings, justify the win in \`benefit\` (e.g., "N+1 → single query", "sequential awaits → Promise.all").
71
81
  4. Don't flag necessary code just because it's simple.
72
82
  5. Respect existing abstraction boundaries.
73
83
  6. Be especially careful with:
@@ -85,7 +95,9 @@ Field notes:
85
95
  - \`risk\` — one of: "safe", "confirm", "review"
86
96
  - \`file\` — repository-relative path, no backticks, no markdown
87
97
  - \`lines\` — line number or range ("42" or "42-57"); empty string if unknown
88
- - \`reason\` — single plain-text sentence stating the concrete fix
98
+ - \`rootIssue\` — the underlying problem with the current code (for reuse, name the existing symbol + file)
99
+ - \`consequence\` — what goes wrong if left unchanged (no real consequence ⇒ don't flag)
100
+ - \`benefit\` — the concrete advantage gained after the fix
89
101
  - \`action\` — one of: "delete", "inline", "refactor", "parallelize"
90
102
 
91
103
  If there are no candidates, call \`simplify_candidates\` with an empty \`candidates\` array.
package/selector.ts CHANGED
@@ -133,12 +133,21 @@ export async function showCandidateSelector(
133
133
  const detailIndent = " ";
134
134
  const detailPrefix = `${detailIndent}│ `;
135
135
  const location = current.lines ? `${current.file}:${current.lines}` : current.file;
136
- lines.push(theme.fg("borderMuted", `${detailIndent}┌─ recommendation`));
137
- lines.push(
138
- ...wrapTextWithAnsi(current.reason, Math.max(1, width - detailPrefix.length)).map(
139
- (wrappedLine) => theme.fg("muted", `${detailPrefix}${wrappedLine}`),
140
- ),
141
- );
136
+ const wrapWidth = Math.max(1, width - detailPrefix.length);
137
+
138
+ const pushSection = (heading: string, body: string) => {
139
+ if (!body) return;
140
+ lines.push(theme.fg("borderMuted", `${detailIndent}┌─ ${heading}`));
141
+ lines.push(
142
+ ...wrapTextWithAnsi(body, wrapWidth).map((wrappedLine) =>
143
+ theme.fg("muted", `${detailPrefix}${wrappedLine}`),
144
+ ),
145
+ );
146
+ };
147
+
148
+ pushSection("Root issue", current.rootIssue);
149
+ pushSection("Consequence", current.consequence);
150
+ pushSection("Benefit after fix", current.benefit);
142
151
  lines.push(theme.fg("muted", `${detailPrefix}`));
143
152
  lines.push(theme.fg("muted", `${detailPrefix}File: ${location}`));
144
153
  lines.push(
package/types.ts CHANGED
@@ -6,7 +6,12 @@ export type SimplifyResult = {
6
6
  category: Category;
7
7
  file: string;
8
8
  lines: string;
9
- reason: string;
9
+ /** The underlying problem with the current code. */
10
+ rootIssue: string;
11
+ /** What this problem leads to if left unchanged. */
12
+ consequence: string;
13
+ /** The concrete advantage gained after applying the fix. */
14
+ benefit: string;
10
15
  risk: Risk;
11
16
  action: Action;
12
17
  };
package/workflow.ts CHANGED
@@ -100,7 +100,21 @@ function registerSimplifyCandidatesTool(
100
100
  pattern: "^(?!/)(?!.*(?:^|/)\\.\\.(?:/|$)).+$",
101
101
  }),
102
102
  lines: Type.String({ description: "Line number or range, or empty string if unknown" }),
103
- reason: Type.String({ description: "Concrete fix in one sentence" }),
103
+ rootIssue: Type.String({
104
+ description:
105
+ "The root problem with the current code. For reuse, name the existing symbol + file it duplicates. State the underlying flaw, not the fix.",
106
+ minLength: 1,
107
+ }),
108
+ consequence: Type.String({
109
+ description:
110
+ "What this problem leads to if left unchanged (e.g. divergent implementations, N+1 queries on every request, untested duplicate logic). If there is no real consequence, do not flag it.",
111
+ minLength: 1,
112
+ }),
113
+ benefit: Type.String({
114
+ description:
115
+ "The concrete advantage after applying the fix (e.g. single source of truth, -14 lines, one query instead of N, covered by existing tests).",
116
+ minLength: 1,
117
+ }),
104
118
  action: actionSchema,
105
119
  }),
106
120
  ),
@@ -252,7 +266,12 @@ async function applyFindings(
252
266
 
253
267
  Apply the following findings. Each item includes a bracketed action (e.g. \`[delete]\`, \`[refactor]\`, \`[parallelize]\`, \`[inline]\`) — follow that action, not a blanket delete.
254
268
 
255
- ${selected.map((c) => `- ${c.file} (${c.lines || "?"}): ${c.reason} [${c.action}]`).join("\n")}
269
+ ${selected
270
+ .map(
271
+ (c) =>
272
+ `- ${c.file} (${c.lines || "?"}) [${c.action}]\n - Root issue: ${c.rootIssue}\n - Goal: ${c.benefit}`,
273
+ )
274
+ .join("\n")}
256
275
 
257
276
  For each item:
258
277
  1. Read the file to find the exact location