@geminixiang/pi-simplify 0.0.9 → 0.0.11
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 +14 -0
- package/package.json +1 -1
- package/prompt.ts +38 -5
- package/selector.ts +15 -6
- package/types.ts +6 -1
- package/workflow.ts +21 -2
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,20 @@ 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.11] - 2026-06-03
|
|
10
|
+
|
|
11
|
+
### Changed
|
|
12
|
+
|
|
13
|
+
- Add thin-wrapper review heuristics so `/simplify` flags rename-only wrappers, pass-through factories, single-call-site helpers, duplicated write APIs, and test-only exports only when they create real maintenance cost.
|
|
14
|
+
|
|
15
|
+
## [0.0.10] - 2026-05-30
|
|
16
|
+
|
|
17
|
+
### Changed
|
|
18
|
+
|
|
19
|
+
- 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.
|
|
20
|
+
- Require a real, non-trivial consequence for every finding; items that only make code "slightly shorter" are no longer flagged.
|
|
21
|
+
- Show the full root issue → consequence → benefit chain in the findings selector, and pass the root issue and goal to the apply step.
|
|
22
|
+
|
|
9
23
|
## [0.0.9] - 2026-05-27
|
|
10
24
|
|
|
11
25
|
### Added
|
package/package.json
CHANGED
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
|
|
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
|
|
|
@@ -25,8 +25,15 @@ Before flagging, **search the codebase** (utility directories, shared modules, f
|
|
|
25
25
|
#### B3. Commented-out Code (Review)
|
|
26
26
|
- Old logic left in comments, disabled features, uncustomized templates
|
|
27
27
|
|
|
28
|
-
#### B4. Over-engineering (Confirm)
|
|
28
|
+
#### B4. Over-engineering / Thin Wrappers (Confirm)
|
|
29
29
|
- Abstractions created "for future use" but unused, single-call-site helpers that should be inlined, useless indirection
|
|
30
|
+
- Thin wrappers that only rename another function or constructor without adding validation, policy, error handling, logging, or a stable public boundary
|
|
31
|
+
- Platform-specific wrapper modules that merely re-export generic session/config helpers under different names
|
|
32
|
+
- Method wrappers on classes that only delegate to a free function already available to callers
|
|
33
|
+
- Test-only exported helpers that can use the real internal/public helper directly instead
|
|
34
|
+
- Small formatting/command helpers whose name repeats a one-line call and have only one call site
|
|
35
|
+
|
|
36
|
+
**Thin-wrapper discipline:** prefer deleting the wrapper and calling the underlying primitive directly when the wrapper has no independent semantic responsibility. Keep the wrapper if it protects a public API, documents a domain boundary, centralizes cross-cutting behavior, or isolates an unstable dependency.
|
|
30
37
|
|
|
31
38
|
#### B5. Hacky Patterns (Confirm)
|
|
32
39
|
- **Redundant state**: state that duplicates other state, cached values that could be derived, observers that could be direct calls
|
|
@@ -57,17 +64,41 @@ Before flagging, **search the codebase** (utility directories, shared modules, f
|
|
|
57
64
|
- Assign **category** (reuse / quality / efficiency) and **risk**
|
|
58
65
|
- State the concrete fix (which existing utility to call, which lines to delete, how to parallelize, etc.)
|
|
59
66
|
|
|
67
|
+
## Thin Wrapper Review Heuristics
|
|
68
|
+
|
|
69
|
+
When hunting simplification opportunities, explicitly scan for these patterns:
|
|
70
|
+
|
|
71
|
+
- **Rename-only wrapper:** \`foo()\` only calls \`bar()\` with the same inputs. Inline \`bar()\` unless \`foo\` is a real public/domain concept.
|
|
72
|
+
- **Constructor/factory wrapper:** \`createX(args)\` only returns \`new X(args)\`. Inline construction unless the factory selects implementations or enforces policy.
|
|
73
|
+
- **Scope-specific alias:** \`SlackThing\`/\`ConversationThing\` only wraps a generic helper. Delete it if the generic name is already clear at call sites.
|
|
74
|
+
- **Single-call-site helper:** a helper with one caller and no meaningful name compression. Inline it, especially for one-line formatting, parsing, or path helpers.
|
|
75
|
+
- **Duplicated write APIs:** several \`saveFooConfig\` functions patch different fields in the same file. Consolidate into one \`updateSettings(patch)\`-style API.
|
|
76
|
+
- **Test-only export:** exported solely so tests can call a thin wrapper. Test the underlying public helper or observable behavior instead.
|
|
77
|
+
- **Pass-through class method:** a class method only delegates to a module-level function and is not required by an interface. Remove the method or call the function directly.
|
|
78
|
+
|
|
79
|
+
Do **not** flag wrappers whose consequence is only "one extra line". Flag them when they create a real maintenance cost: multiple ways to do the same operation, unclear source of truth, misleading domain boundaries, duplicated tests for delegated behavior, or user/developer uncertainty about which API is authoritative.
|
|
80
|
+
|
|
60
81
|
## Risk Levels
|
|
61
82
|
|
|
62
83
|
- **safe**: Definitely apply (dead code, debug remnants)
|
|
63
84
|
- **confirm**: Apply after user confirms (reuse swaps, over-engineering, hacky patterns, efficiency fixes)
|
|
64
85
|
- **review**: User should look first (commented-out code, ambiguous cases)
|
|
65
86
|
|
|
87
|
+
## Make the Case (REQUIRED for every candidate)
|
|
88
|
+
|
|
89
|
+
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:
|
|
90
|
+
|
|
91
|
+
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.
|
|
92
|
+
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.
|
|
93
|
+
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".
|
|
94
|
+
|
|
95
|
+
**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.
|
|
96
|
+
|
|
66
97
|
## Rules
|
|
67
98
|
|
|
68
99
|
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,
|
|
100
|
+
2. For reuse findings, name the existing symbol/file you'd swap to in \`rootIssue\`.
|
|
101
|
+
3. For efficiency findings, justify the win in \`benefit\` (e.g., "N+1 → single query", "sequential awaits → Promise.all").
|
|
71
102
|
4. Don't flag necessary code just because it's simple.
|
|
72
103
|
5. Respect existing abstraction boundaries.
|
|
73
104
|
6. Be especially careful with:
|
|
@@ -85,7 +116,9 @@ Field notes:
|
|
|
85
116
|
- \`risk\` — one of: "safe", "confirm", "review"
|
|
86
117
|
- \`file\` — repository-relative path, no backticks, no markdown
|
|
87
118
|
- \`lines\` — line number or range ("42" or "42-57"); empty string if unknown
|
|
88
|
-
- \`
|
|
119
|
+
- \`rootIssue\` — the underlying problem with the current code (for reuse, name the existing symbol + file)
|
|
120
|
+
- \`consequence\` — what goes wrong if left unchanged (no real consequence ⇒ don't flag)
|
|
121
|
+
- \`benefit\` — the concrete advantage gained after the fix
|
|
89
122
|
- \`action\` — one of: "delete", "inline", "refactor", "parallelize"
|
|
90
123
|
|
|
91
124
|
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
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|