codeninja 3.1.0 → 3.2.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 (27) hide show
  1. package/ide/antigravity/.agents/personas/global-orchestrator.md +103 -84
  2. package/ide/antigravity/.agents/workflows/codeninja-api.md +98 -15
  3. package/ide/antigravity/.agents/workflows/codeninja-audit.md +69 -11
  4. package/ide/antigravity/.agents/workflows/codeninja-db-create.md +118 -5
  5. package/ide/antigravity/.agents/workflows/codeninja-db-drop.md +81 -5
  6. package/ide/antigravity/.agents/workflows/codeninja-db-index.md +64 -5
  7. package/ide/antigravity/.agents/workflows/codeninja-db-modify.md +100 -5
  8. package/ide/antigravity/.agents/workflows/codeninja-db-seed.md +70 -4
  9. package/ide/antigravity/.agents/workflows/codeninja-db-sync.md +64 -6
  10. package/ide/antigravity/.agents/workflows/codeninja-debug.md +76 -6
  11. package/ide/antigravity/.agents/workflows/codeninja-design.md +45 -12
  12. package/ide/antigravity/.agents/workflows/codeninja-explain.md +35 -6
  13. package/ide/antigravity/.agents/workflows/codeninja-init.md +329 -22
  14. package/ide/antigravity/.agents/workflows/codeninja-integrate-api.md +334 -9
  15. package/ide/antigravity/.agents/workflows/codeninja-modularize.md +214 -9
  16. package/ide/antigravity/.agents/workflows/codeninja-optimize.md +78 -7
  17. package/ide/antigravity/.agents/workflows/codeninja-refactor.md +58 -13
  18. package/ide/antigravity/.agents/workflows/codeninja-review.md +64 -6
  19. package/ide/antigravity/.agents/workflows/codeninja-sync.md +172 -12
  20. package/ide/antigravity/.agents/workflows/codeninja-test.md +51 -9
  21. package/ide/antigravity/.agents/workflows/codeninja-validate-page.md +248 -9
  22. package/ide/cursor/.cursor/rules/01-global-orchestrator.mdc +35 -32
  23. package/ide/cursor/.cursor/rules/03-api-builder.mdc +100 -50
  24. package/ide/cursor/.cursor/rules/04-database.mdc +73 -70
  25. package/ide/cursor/.cursor/rules/05-reactjs.mdc +133 -69
  26. package/ide/vscode/.github/copilot-instructions.md +304 -190
  27. package/package.json +1 -1
@@ -1,11 +1,336 @@
1
1
  ---
2
- slash_command: @integrate-api
2
+ slash_command: /codeninja:integrate-api
3
3
  personas: [global-orchestrator, reactjs-frontend]
4
- skills: [mcp-and-context, reactjs]
5
- description: Wire forms and action buttons to API handler functions
6
- ---
7
- # @integrate-api
8
- Delegates to: `.codeninja/commands/integrate-api.workflow.md`
9
- Before: `context_read`. Read target page and apiHandler.js.
10
- Add handler functions in apiHandler.js if missing.
11
- Wire buttons/forms to handlers. Add loading, error, success states.
4
+ skills: [mcp-and-context, reactjs, api-builder]
5
+ description: >
6
+ Wire a ReactJS page's forms and action buttons to backend API calls
7
+ through apiHandler.js and apiClient.js. Adds loading states, error
8
+ display, and success feedback. Never touches validation or layout.
9
+ ---
10
+
11
+ # /codeninja:integrate-api
12
+
13
+ ## Before Running
14
+ 1. Call `context_check_stale`
15
+ 2. Call `context_read` — load `context.services` and `context.api_routes`
16
+ 3. Call `service_scan` — verify services on disk
17
+
18
+ ## Rules
19
+ - Target ONE specific page per run
20
+ - NEVER modify layout, CSS, or validation logic
21
+ - ALWAYS use `apiHandler.js` for API calls — never call `axiosClient` directly from a page
22
+ - ALWAYS add handler functions to `apiHandler.js` if the needed function doesn't exist
23
+ - NEVER hardcode API endpoints in page files
24
+ - ONE confirmation before any file is written
25
+ - After writing files → call `context_write`
26
+
27
+ ---
28
+
29
+ ## Execution — Full Step-by-Step
30
+
31
+ ### Phase 1 — Target Selection
32
+
33
+ **Step 1.** Ask: "Which ReactJS service?" (list ReactJS services from `context.services`)
34
+ - Store: `context.current_action.service_name`
35
+
36
+ **Step 2.** Ask: "Which page path?" (e.g. `src/pages/Login/index.jsx`)
37
+ - Store: `context.current_action.page_path`, `context.current_action.page_name`
38
+
39
+ **Step 3.** Ask: "What scope of integration?"
40
+ 1. All forms and buttons on this page
41
+ 2. Specific form or button only
42
+ - Store: `context.current_action.api_integration_scope`
43
+ - If specific → ask: "Which form or button?" → Store: `context.current_action.api_integration_target`
44
+
45
+ ---
46
+
47
+ ### Phase 2 — Read Service Context
48
+
49
+ Read from context:
50
+ - `context.services[<service_name>].linked_service` → the NodeJS backend
51
+ - `context.api_routes` filtered by linked NodeJS service → available API routes
52
+
53
+ Read from disk:
54
+ - Full content of `context.current_action.page_path` (target page)
55
+ - Full content of `src/api/apiHandler.js`
56
+ - Full content of `src/api/apiClient.js` (read-only reference)
57
+
58
+ ---
59
+
60
+ ### Phase 3 — Scan the Page for Integration Points
61
+
62
+ #### 3a — Forms
63
+ For each `<form>` found:
64
+ - Note the form's apparent purpose (infer from field names, labels, heading text)
65
+ - Check if `onSubmit` is already connected
66
+ - Check if form imports anything from `apiHandler.js`
67
+
68
+ #### 3b — Action Buttons
69
+ For each `<button>` NOT a submit button:
70
+ - Check if `onClick` is connected
71
+ - Infer action from button text: Delete/Remove → delete, Edit/Update → update,
72
+ Save → save/create, Logout → logout, Load more/Next → pagination, Export/Download → export
73
+
74
+ #### 3c — Existing API Calls
75
+ Detect any existing API calls:
76
+ - Imports from `apiHandler.js` (existing — note them)
77
+ - Direct `axiosClient` calls (flag — should be moved to apiHandler)
78
+ - `fetch(` or `axios.` direct calls (flag — should be moved)
79
+
80
+ If scope == "specific" → focus only on the matching form/button.
81
+
82
+ ---
83
+
84
+ ### Phase 4 — Match Forms to API Routes
85
+
86
+ For each integration point, determine which API route it should call:
87
+
88
+ 1. **Exact match** — `apiHandler.js` function already exists for this purpose → use as-is
89
+ 2. **Route match** — matching route exists in `context.api_routes` for linked backend →
90
+ new handler function will be added to `apiHandler.js`
91
+ 3. **No match** — no suitable route exists yet → scaffold with TODO placeholder
92
+
93
+ Record: `{ form_purpose, handler_function_name, route_path, route_method, match_type }`
94
+
95
+ ---
96
+
97
+ ### Phase 5 — Design the Integration
98
+
99
+ For each integration point:
100
+
101
+ #### State requirements
102
+ - `loading` state — boolean, false by default
103
+ - `error` state — string or null
104
+ - Response data state based on form type:
105
+ - Auth forms → no data state (session stored by apiHandler)
106
+ - List/search → `data` state (array, [])
107
+ - Single item → `item` state (object, null)
108
+ - Delete/update → list refresh or redirect
109
+
110
+ #### Submit handler patterns
111
+
112
+ **Auth / destructive (login, delete, logout):**
113
+ ```jsx
114
+ const handle[Action] = async (e) => {
115
+ e?.preventDefault();
116
+ setLoading(true);
117
+ setError(null);
118
+ const res = await [handlerFunction]({ ...formData });
119
+ setLoading(false);
120
+ if (res?.code === 1) {
121
+ navigate('/dashboard');
122
+ } else {
123
+ setError(res?.message || 'Something went wrong. Please try again.');
124
+ }
125
+ };
126
+ ```
127
+
128
+ **Data fetch / load (get list, get details):**
129
+ ```jsx
130
+ const fetch[Resource] = async () => {
131
+ setLoading(true);
132
+ setError(null);
133
+ const res = await [handlerFunction]({ ...filters });
134
+ setLoading(false);
135
+ if (res?.code === 1) {
136
+ setData(res?.data ?? []);
137
+ } else {
138
+ setError(res?.message || 'Failed to load data. Please try again.');
139
+ }
140
+ };
141
+ // Also add: useEffect(() => { fetch[Resource](); }, []);
142
+ ```
143
+
144
+ **Create / Update (form submit):**
145
+ ```jsx
146
+ const handle[Action] = async (e) => {
147
+ e?.preventDefault();
148
+ setLoading(true);
149
+ setError(null);
150
+ const res = await [handlerFunction](formData);
151
+ setLoading(false);
152
+ if (res?.code === 1) {
153
+ setSuccessMsg(res?.message || '[Action] successful.');
154
+ resetForm();
155
+ } else {
156
+ setError(res?.message || 'Something went wrong. Please try again.');
157
+ }
158
+ };
159
+ ```
160
+
161
+ #### Loading feedback
162
+ ```jsx
163
+ <button type="submit" disabled={loading}>
164
+ {loading ? 'Please wait...' : '[Original Button Text]'}
165
+ </button>
166
+ ```
167
+
168
+ #### Error display (above submit button)
169
+ ```jsx
170
+ {error && <p className={styles.apiError}>{error}</p>}
171
+ ```
172
+
173
+ #### Success display (for non-navigating actions)
174
+ ```jsx
175
+ {successMsg && <p className={styles.successMsg}>{successMsg}</p>}
176
+ ```
177
+
178
+ ---
179
+
180
+ ### Phase 6 — Show Integration Plan
181
+
182
+ ```
183
+ ┌──────────────────────────────────────────────────────┐
184
+ │ API INTEGRATION PLAN │
185
+ ├──────────────────────────────────────────────────────┤
186
+ │ Page : [page_name] │
187
+ │ Service : [service_name] │
188
+ │ Backend : [linked_service] (port [port]) │
189
+ ├──────────────────────────────────────────────────────┤
190
+ │ INTEGRATIONS │
191
+ │ │
192
+ │ ① Login Form → webLogin() │
193
+ │ Route : POST /login │
194
+ │ Handler : webLogin (already in apiHandler.js) │
195
+ │ State add: loading, error │
196
+ │ Pattern : auth/destructive │
197
+ │ On success: navigate('/dashboard') │
198
+ │ │
199
+ │ ② Delete Button → deleteUser() │
200
+ │ Route : DELETE /users/:id │
201
+ │ Handler : deleteUser (NEW → will add to │
202
+ │ apiHandler.js) │
203
+ │ Pattern : destructive │
204
+ │ On success: refresh user list │
205
+ ├──────────────────────────────────────────────────────┤
206
+ │ GAPS (no backend route yet) │
207
+ │ ③ Export CSV Button — no route exists yet │
208
+ │ Will add TODO placeholder │
209
+ ├──────────────────────────────────────────────────────┤
210
+ │ FILES TO MODIFY │
211
+ │ → src/pages/[PageName]/index.jsx │
212
+ │ → src/pages/[PageName]/[PageName].module.css │
213
+ │ → src/api/apiHandler.js ([n] new function(s)) │
214
+ └──────────────────────────────────────────────────────┘
215
+ ```
216
+
217
+ Ask: "Apply this integration plan? (yes / no / adjust)"
218
+
219
+ ---
220
+
221
+ ### Phase 7 — Apply Integration
222
+
223
+ #### 7a — Update apiHandler.js (new functions only)
224
+
225
+ For each `match_type == "new_handler"`:
226
+ Append to `src/api/apiHandler.js`:
227
+ ```jsx
228
+ /**
229
+ * [Route description from context.api_routes or inferred].
230
+ *
231
+ * @param {Object} data - Request payload.
232
+ * @returns {Promise<Object>} API response.
233
+ */
234
+ export async function [functionName](data) {
235
+ const res = await axiosClient.[method]('[route_path]', data);
236
+ return res;
237
+ }
238
+ ```
239
+ Use correct method: `.get`, `.post`, `.put`, `.patch`, `.delete`.
240
+ For DELETE/GET with ID: `axiosClient.delete(\`/users/${data.id}\`)`
241
+
242
+ For `match_type == "no_route"`:
243
+ ```jsx
244
+ /**
245
+ * TODO: Connect to backend route once created via /codeninja:api.
246
+ */
247
+ export async function [functionName](data) {
248
+ console.warn('[functionName] is not yet connected to a backend route.');
249
+ return { code: 0, message: 'API not connected yet.' };
250
+ }
251
+ ```
252
+
253
+ #### 7b — Update the page file (surgical edits only)
254
+
255
+ 1. Add imports for new apiHandler functions (only new ones):
256
+ ```jsx
257
+ import { webLogin, deleteUser } from '../../api/apiHandler';
258
+ ```
259
+ Add `useNavigate` if any handler navigates:
260
+ ```jsx
261
+ import { useNavigate } from 'react-router-dom';
262
+ ```
263
+
264
+ 2. Add state declarations inside component:
265
+ ```jsx
266
+ const [loading, setLoading] = React.useState(false);
267
+ const [error, setError] = React.useState(null);
268
+ const navigate = useNavigate(); // if navigate is used
269
+ ```
270
+
271
+ 3. Add handler functions just before the return statement.
272
+ If a handler already exists → add API call logic inside it, don't create duplicate.
273
+
274
+ 4. Wire form `onSubmit` / button `onClick`:
275
+ - `<form onSubmit={handle[Action]}>`
276
+ - `<button onClick={handle[Action]}>`
277
+
278
+ 5. Add `disabled={loading}` and conditional button text to submit buttons.
279
+
280
+ 6. Add error and success display elements adjacent to submit buttons.
281
+
282
+ 7. Add `useEffect` for data-fetching handlers (load on mount).
283
+
284
+ #### 7c — Update page CSS module
285
+ Add `.apiError` and `.successMsg` classes (if not already present):
286
+ ```css
287
+ .apiError {
288
+ color: #dc3545;
289
+ font-size: 0.875rem;
290
+ margin-bottom: 0.75rem;
291
+ padding: 0.5rem 0.75rem;
292
+ background-color: #fff5f5;
293
+ border: 1px solid #f5c6cb;
294
+ border-radius: 4px;
295
+ }
296
+
297
+ .successMsg {
298
+ color: #155724;
299
+ font-size: 0.875rem;
300
+ margin-bottom: 0.75rem;
301
+ padding: 0.5rem 0.75rem;
302
+ background-color: #d4edda;
303
+ border: 1px solid #c3e6cb;
304
+ border-radius: 4px;
305
+ }
306
+ ```
307
+
308
+ ---
309
+
310
+ ### Phase 8 — Finalize
311
+
312
+ **Step 1.** Call `context_write`:
313
+ - Append to `context.services[<service_name>].integrated_pages`:
314
+ `{ page, integrations: [{ form_purpose, handler, route }], timestamp: ISO now }`
315
+ - Set `last_command` = "integrate-api"
316
+ - Append to `change_log`
317
+
318
+ **Step 2.** Call `context_clear_scratchpad` with keys: ["current_action"]
319
+
320
+ **Step 3.** Show completion report:
321
+ ```
322
+ /codeninja:integrate-api Complete
323
+ ─────────────────────────────────────────
324
+ Page : [page_name]
325
+ Integrations : [n] connected, [n] placeholders
326
+ ─────────────────────────────────────────
327
+ ✓ src/pages/[PageName]/index.jsx — updated
328
+ ✓ src/pages/[PageName]/[PageName].module.css — error/success styles added
329
+ [✓ src/api/apiHandler.js — [n] new function(s) added]
330
+ ─────────────────────────────────────────
331
+ [If gaps exist:]
332
+ ⚠ [n] action(s) have no backend route yet.
333
+ Placeholders added. Run /codeninja:api to create backend routes,
334
+ then re-run /codeninja:integrate-api to connect them.
335
+ ─────────────────────────────────────────
336
+ ```
@@ -1,11 +1,216 @@
1
1
  ---
2
- slash_command: @modularize
2
+ slash_command: /codeninja:modularize
3
3
  personas: [global-orchestrator, reactjs-frontend]
4
- skills: [mcp-and-context, reactjs]
5
- description: Extract repeated layout blocks into reusable React components
6
- ---
7
- # @modularize
8
- Delegates to: `.codeninja/commands/modularize.workflow.md`
9
- Before: `context_read`. Confirm linked NodeJS service exists.
10
- Scan all pages, identify repeated layout blocks.
11
- Show user what will be extracted and confirm before changes.
4
+ skills: [mcp-and-context, reactjs, code-intelligence]
5
+ description: >
6
+ Scan ReactJS pages, extract repeated layout blocks into reusable components
7
+ under src/components/, and update each page to import and use them.
8
+ Layout structure only — never touches business logic, state, or API calls.
9
+ ---
10
+
11
+ # /codeninja:modularize
12
+
13
+ ## Before Running
14
+ 1. Call `context_check_stale`
15
+ 2. Call `context_read` — load `context.services` to find ReactJS services
16
+ 3. Call `service_scan` — verify ReactJS service exists on disk
17
+
18
+ ## Rules
19
+ - Read ALL target pages fully before creating any component
20
+ - NEVER create a component that already exists in `src/components/` — reuse it
21
+ - NEVER modify business logic, state, API calls, or event handlers in any page
22
+ - NEVER break existing imports or prop flows
23
+ - ONE confirmation before any file is written
24
+ - After writing files → call `context_write`
25
+
26
+ ---
27
+
28
+ ## Execution — Full Step-by-Step
29
+
30
+ ### Phase 1 — Target Selection
31
+
32
+ **Step 1.** Ask: "Which ReactJS service?" (list ReactJS services from `context.services`)
33
+ - Store: `context.current_action.service_name`
34
+
35
+ **Step 2.** Ask: "What scope?"
36
+ 1. All pages — scan every page in `src/pages/` and `src/views/`
37
+ 2. Specific page — I'll provide the path
38
+ - Store: `context.current_action.modularize_scope`
39
+ - If specific → also ask: "Page path?" → Store: `context.current_action.page_path`
40
+
41
+ ---
42
+
43
+ ### Phase 2 — Inventory Existing Components
44
+
45
+ Before scanning any pages, inventory what already exists:
46
+
47
+ **Step 1.** Scan `src/components/` in the target service.
48
+ For each subdirectory → record component name and file path.
49
+
50
+ **Step 2.** For each existing component:
51
+ - Read the file
52
+ - Identify structural role: header, footer, sidebar, navbar, modal wrapper, card shell, breadcrumbs, etc.
53
+ - Record: `{ name, path, role, props_accepted }`
54
+
55
+ Store this as the "existing components registry" — the source of truth for reuse decisions.
56
+
57
+ ---
58
+
59
+ ### Phase 3 — Scan Target Pages
60
+
61
+ #### If scope == "all":
62
+ Scan `src/pages/` — each subdirectory with `index.jsx` or `index.js` = one page.
63
+ Also scan `src/views/` if it exists.
64
+
65
+ #### If scope == "specific":
66
+ Pages list = [ context.current_action.page_path ]
67
+
68
+ For each page:
69
+
70
+ **Step 1.** Read the full file content.
71
+
72
+ **Step 2.** Identify all structural blocks (layout HTML — NOT business logic):
73
+ - Look for repeated layout patterns: `<header>`, `<nav>`, `<footer>`, `<aside>`, sidebar wrappers
74
+ - Look for structural patterns repeated across pages: top nav bars, breadcrumb areas, page wrappers
75
+ - Record each structural block as: `{ block_type, jsx_content, props_needed }`
76
+
77
+ **Step 3.** Cross-check against existing components registry:
78
+ - Does a component already exist that covers this block?
79
+ - If YES → mark as "reuse existing: <ComponentName>"
80
+ - If NO → mark as "new component needed: <ComponentName>"
81
+
82
+ ---
83
+
84
+ ### Phase 4 — Deduplicate Across Pages
85
+
86
+ After scanning all pages:
87
+
88
+ **Step 1.** Group blocks by structural similarity across pages.
89
+ - If the same header JSX appears in 3+ pages → one shared Header component
90
+ - If a sidebar appears in 2+ pages → one shared Sidebar component
91
+ - If a block appears in only 1 page → do NOT extract it (no duplication benefit)
92
+
93
+ **Step 2.** For each component to create, decide:
94
+ - Component name (PascalCase, descriptive: `PageHeader`, `AppSidebar`, `MainFooter`)
95
+ - Props needed (what varies between pages: title, navLinks, userName, etc.)
96
+ - File location: `src/components/<ComponentName>/index.jsx` and `<ComponentName>.module.css`
97
+
98
+ ---
99
+
100
+ ### Phase 5 — Show Extraction Plan
101
+
102
+ Display the plan before writing anything:
103
+
104
+ ```
105
+ ┌─────────────────────────────────────────────────────┐
106
+ │ MODULARIZE PLAN │
107
+ ├─────────────────────────────────────────────────────┤
108
+ │ Service : [service_name] │
109
+ │ Scope : [all pages | specific page] │
110
+ │ Pages : [n] scanned │
111
+ ├─────────────────────────────────────────────────────┤
112
+ │ COMPONENTS TO CREATE │
113
+ │ ✦ AppHeader — appears in [n] pages │
114
+ │ Props: title (string) │
115
+ │ File: src/components/AppHeader/index.jsx │
116
+ │ │
117
+ │ ✦ MainSidebar — appears in [n] pages │
118
+ │ Props: activeRoute (string) │
119
+ │ File: src/components/MainSidebar/index.jsx │
120
+ ├─────────────────────────────────────────────────────┤
121
+ │ COMPONENTS REUSED (already exist) │
122
+ │ ✓ Footer — src/components/Footer/index.jsx │
123
+ ├─────────────────────────────────────────────────────┤
124
+ │ PAGES TO UPDATE │
125
+ │ → src/pages/Dashboard/index.jsx │
126
+ │ → src/pages/Profile/index.jsx │
127
+ │ → src/pages/Settings/index.jsx │
128
+ └─────────────────────────────────────────────────────┘
129
+ ```
130
+
131
+ Ask: "Apply this plan? (yes / no / adjust)"
132
+ - If yes → proceed to Phase 6
133
+ - If no → abort, nothing written
134
+ - If adjust → ask what to change → re-display plan
135
+
136
+ ---
137
+
138
+ ### Phase 6 — Generate Components
139
+
140
+ For each new component:
141
+
142
+ **Step 1.** Generate `src/components/<ComponentName>/index.jsx`:
143
+ ```jsx
144
+ /**
145
+ * <ComponentName> — <one-line description of structural role>.
146
+ *
147
+ * @param {Object} props
148
+ * @param {string} props.<propName> - <description>
149
+ * @returns {JSX.Element}
150
+ */
151
+ function <ComponentName>({ <props> }) {
152
+ return (
153
+ <extracted JSX block, using props where values varied>
154
+ );
155
+ }
156
+
157
+ export default <ComponentName>;
158
+ ```
159
+
160
+ **Step 2.** Generate `src/components/<ComponentName>/<ComponentName>.module.css`:
161
+ - Extract any inline styles or className references that were in the original block
162
+ - Create CSS classes for them
163
+ - If no styles → empty file with a comment: `/* <ComponentName> styles */`
164
+
165
+ ---
166
+
167
+ ### Phase 7 — Update Pages
168
+
169
+ For each page that used the extracted block:
170
+
171
+ **Step 1.** Read the current page file.
172
+
173
+ **Step 2.** Apply changes surgically:
174
+ 1. Add import at top of file:
175
+ ```jsx
176
+ import <ComponentName> from '../../components/<ComponentName>';
177
+ ```
178
+ (adjust relative path based on page depth)
179
+
180
+ 2. Replace the extracted JSX block with the component:
181
+ ```jsx
182
+ <ComponentName <prop>={<value>} />
183
+ ```
184
+
185
+ 3. Remove any now-unused imports that were only used by the extracted block.
186
+
187
+ 4. Remove any CSS classes in the page's `.module.css` that are now handled by the component's own CSS file.
188
+
189
+ **Step 3.** Write the updated file.
190
+
191
+ ---
192
+
193
+ ### Phase 8 — Finalize
194
+
195
+ **Step 1.** Call `context_write`:
196
+ - Append to `context.services[<service_name>].components`:
197
+ `{ name, path, role, props_accepted, used_in: [list of page paths] }`
198
+ - Set `last_command` = "modularize"
199
+ - Append to `change_log`: `{ timestamp, command: "modularize", action: "Created [n] component(s) from [n] pages" }`
200
+
201
+ **Step 2.** Call `context_clear_scratchpad` with keys: ["current_action"]
202
+
203
+ **Step 3.** Show completion report:
204
+ ```
205
+ /codeninja:modularize Complete
206
+ ─────────────────────────────────────────
207
+ Components created : [n]
208
+ Components reused : [n]
209
+ Pages updated : [n]
210
+ ─────────────────────────────────────────
211
+ [list created files]
212
+ [list modified files]
213
+ ─────────────────────────────────────────
214
+ Next: /codeninja:validate-page to add validation
215
+ /codeninja:integrate-api to wire forms to backend
216
+ ```
@@ -2,12 +2,83 @@
2
2
  slash_command: /codeninja:optimize
3
3
  personas: [global-orchestrator, nodejs-backend, database-architect]
4
4
  skills: [mcp-and-context, api-builder, database, code-intelligence]
5
- description: Find and fix performance bottlenecks with concrete impact estimates
5
+ description: Analyse and improve performance using real project context.
6
6
  ---
7
+
7
8
  # /codeninja:optimize
8
- Delegates to: `.codeninja/commands/optimize.workflow.md`
9
- Before: `context_read` for `context.db.schema` and `context.services`.
10
- Ask: slow endpoint / heavy query / startup / describe it.
11
- Cross-reference existing indexes. Generate migration via `migration_next_number`.
12
- Output: [HIGH|MED|LOW] ranked. Confirm before applying.
13
- `context_write` after index additions.
9
+
10
+ ## Before Running
11
+ 1. Call `context_read` load `context.db.schema`, `context.services`
12
+ 2. Call `context_check_stale`
13
+
14
+ ## Execution Full Step-by-Step
15
+
16
+ ### Step 1 — Identify Target
17
+ If not specified, ask:
18
+ "What would you like to optimise?
19
+ (a) A slow API endpoint — paste the route path
20
+ (b) A heavy SQL query — paste the query or file path
21
+ (c) Overall service startup / memory usage
22
+ (d) Something else — describe it"
23
+
24
+ ### Step 2 — Load Context
25
+ 1. Call `fs_read` on the relevant files (route.js, _model.js)
26
+ 2. For DB queries: list existing indexes from `context.db.schema.<table>.indexes`
27
+
28
+ ### Step 3A — Database Query Analysis
29
+
30
+ For each query in the target:
31
+
32
+ **Check 1 — Missing Indexes**
33
+ Compare WHERE / JOIN / ORDER BY columns against existing indexes.
34
+ Generate `CREATE INDEX CONCURRENTLY` for missing ones.
35
+
36
+ **Check 2 — SELECT * Anti-Pattern**
37
+ Replace with explicit column list. Show before/after.
38
+
39
+ **Check 3 — N+1 Query Pattern**
40
+ Flag any loop calling a DB function per iteration. Suggest single query with IN or JOIN.
41
+
42
+ **Check 4 — Window Function Choice**
43
+ - `RANK()` → gaps after ties (wrong for leaderboards)
44
+ - `DENSE_RANK()` → no gaps (correct for leaderboards)
45
+ - `ROW_NUMBER()` → unique position (correct for pagination)
46
+
47
+ **Check 5 — Duplicate Row Prevention**
48
+ Flag duplicate rows from missing dedup. Suggest `MIN(id) GROUP BY user_id`.
49
+
50
+ **Check 6 — Functional Index Trap**
51
+ Flag `DATE(created_at) = '...'` → suggest range form for index usage.
52
+
53
+ **Check 7 — work_mem for Sort Operations**
54
+ If EXPLAIN shows external merge disk sort → suggest `SET work_mem = '64MB'`.
55
+
56
+ ### Step 3B — API Route Analysis
57
+
58
+ - Is heavy middleware on lightweight routes?
59
+ - Synchronous blocking in request path?
60
+ - Repeated DB lookups that could be cached in Redis?
61
+ - Pagination missing on list endpoints?
62
+
63
+ ### Step 4 — Output Recommendations
64
+
65
+ ```
66
+ [HIGH | MED | LOW] — Impact label
67
+
68
+ Target: what's being optimised
69
+ Root cause: why it's slow right now
70
+ Fix:
71
+ [exact SQL or code change]
72
+ Estimated gain: concrete estimate
73
+ Side effects: anything developer should know
74
+ ```
75
+
76
+ List all, highest impact first.
77
+
78
+ ### Step 5 — Offer to Apply
79
+ "I've found [N] optimisations. Want me to apply them?
80
+ I'll implement each one and show you the change before writing."
81
+
82
+ For index changes → generate `NNN_add_index_<n>.sql` migration file.
83
+ For code changes → edit the relevant model or route file surgically.
84
+ Always call `context_write` after applying index additions.