codeninja 2.0.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.
- package/README.md +122 -251
- package/agent/global-agent.md +8 -0
- package/cli.js +248 -223
- package/commands/debug.workflow.md +94 -0
- package/commands/explain.workflow.md +59 -0
- package/commands/optimize.workflow.md +124 -0
- package/commands/review.workflow.md +85 -0
- package/ide/antigravity/.agents/personas/database-architect.md +249 -0
- package/ide/antigravity/.agents/personas/global-orchestrator.md +144 -0
- package/ide/antigravity/.agents/personas/nodejs-backend.md +250 -0
- package/ide/antigravity/.agents/personas/reactjs-frontend.md +179 -0
- package/ide/antigravity/.agents/skills/api-builder/SKILL.md +179 -0
- package/ide/antigravity/.agents/skills/code-intelligence/SKILL.md +184 -0
- package/ide/antigravity/.agents/skills/database/SKILL.md +165 -0
- package/ide/antigravity/.agents/skills/mcp-and-context/SKILL.md +111 -0
- package/ide/antigravity/.agents/skills/reactjs/SKILL.md +211 -0
- package/ide/antigravity/.agents/workflows/codeninja-api.md +111 -0
- package/ide/antigravity/.agents/workflows/codeninja-audit.md +81 -0
- package/ide/antigravity/.agents/workflows/codeninja-db-create.md +124 -0
- package/ide/antigravity/.agents/workflows/codeninja-db-drop.md +87 -0
- package/ide/antigravity/.agents/workflows/codeninja-db-index.md +70 -0
- package/ide/antigravity/.agents/workflows/codeninja-db-modify.md +106 -0
- package/ide/antigravity/.agents/workflows/codeninja-db-seed.md +76 -0
- package/ide/antigravity/.agents/workflows/codeninja-db-sync.md +70 -0
- package/ide/antigravity/.agents/workflows/codeninja-debug.md +82 -0
- package/ide/antigravity/.agents/workflows/codeninja-design.md +54 -0
- package/ide/antigravity/.agents/workflows/codeninja-explain.md +40 -0
- package/ide/antigravity/.agents/workflows/codeninja-init.md +336 -0
- package/ide/antigravity/.agents/workflows/codeninja-integrate-api.md +336 -0
- package/ide/antigravity/.agents/workflows/codeninja-modularize.md +216 -0
- package/ide/antigravity/.agents/workflows/codeninja-optimize.md +84 -0
- package/ide/antigravity/.agents/workflows/codeninja-refactor.md +68 -0
- package/ide/antigravity/.agents/workflows/codeninja-review.md +70 -0
- package/ide/antigravity/.agents/workflows/codeninja-sync.md +183 -0
- package/ide/antigravity/.agents/workflows/codeninja-test.md +61 -0
- package/ide/antigravity/.agents/workflows/codeninja-validate-page.md +250 -0
- package/ide/cursor/.cursor/mcp.json +8 -0
- package/ide/cursor/.cursor/rules/01-global-orchestrator.mdc +63 -0
- package/ide/cursor/.cursor/rules/02-mcp-and-context.mdc +38 -0
- package/ide/cursor/.cursor/rules/03-api-builder.mdc +124 -0
- package/ide/cursor/.cursor/rules/04-database.mdc +90 -0
- package/ide/cursor/.cursor/rules/05-reactjs.mdc +147 -0
- package/ide/cursor/.cursor/rules/06-code-intelligence.mdc +112 -0
- package/ide/vscode/.github/copilot-instructions.md +399 -0
- package/ide/vscode/.vscode/mcp.json +9 -0
- package/package.json +24 -23
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
---
|
|
2
|
+
skill: reactjs
|
|
3
|
+
scope: reactjs-commands
|
|
4
|
+
loaded-for:
|
|
5
|
+
- /codeninja:init (reactjs type)
|
|
6
|
+
- @modularize
|
|
7
|
+
- @validate-page
|
|
8
|
+
- @integrate-api
|
|
9
|
+
description: >
|
|
10
|
+
All technical standards for ReactJS frontend development — file structure,
|
|
11
|
+
apiClient/apiHandler patterns, encryption inheritance, routing standards,
|
|
12
|
+
and component conventions. The reactjs-frontend persona uses this skill.
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
# Skill: ReactJS Frontend
|
|
16
|
+
|
|
17
|
+
Technical standards for every ReactJS file in this project.
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## Backend Linking (enforced before any generation)
|
|
22
|
+
|
|
23
|
+
```
|
|
24
|
+
context.current_init.linked_service → backend service name
|
|
25
|
+
context.services[linked].port → REACT_APP_BASE_URL port
|
|
26
|
+
context.services[linked].encryption_key → REACT_APP_KEY
|
|
27
|
+
context.services[linked].encryption_iv → REACT_APP_IV
|
|
28
|
+
context.services[linked].api_key → REACT_APP_API_KEY
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
These 4 values are inherited — NEVER ask the user for them.
|
|
32
|
+
NEVER hardcode any key, IV, or API key value.
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## apiClient.js — Exact Specification
|
|
37
|
+
|
|
38
|
+
```javascript
|
|
39
|
+
// src/api/apiClient.js
|
|
40
|
+
// Axios instance — all cross-cutting concerns live here
|
|
41
|
+
|
|
42
|
+
import axios from 'axios';
|
|
43
|
+
import CryptoJS from 'crypto-js';
|
|
44
|
+
import { logOutRedirectCall, showErrorMessage } from '../pages/common/Utils';
|
|
45
|
+
|
|
46
|
+
const KEY = CryptoJS.enc.Hex.parse(process.env.REACT_APP_KEY);
|
|
47
|
+
const IV = CryptoJS.enc.Hex.parse(process.env.REACT_APP_IV);
|
|
48
|
+
|
|
49
|
+
const axiosClient = axios.create({
|
|
50
|
+
baseURL: process.env.REACT_APP_BASE_URL,
|
|
51
|
+
headers: {
|
|
52
|
+
'api-key': process.env.REACT_APP_API_KEY,
|
|
53
|
+
'Content-Type': 'text/plain',
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
// Request interceptor: encrypt body, attach token
|
|
58
|
+
axiosClient.interceptors.request.use((config) => {
|
|
59
|
+
const token = localStorage.getItem('wa_token');
|
|
60
|
+
if (token) {
|
|
61
|
+
config.headers['token'] = CryptoJS.AES.encrypt(token, KEY, { iv: IV }).toString();
|
|
62
|
+
}
|
|
63
|
+
if (config.data) {
|
|
64
|
+
config.data = CryptoJS.AES.encrypt(JSON.stringify(config.data), KEY, { iv: IV }).toString();
|
|
65
|
+
}
|
|
66
|
+
return config;
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
// Response interceptor: decrypt body
|
|
70
|
+
axiosClient.interceptors.response.use(
|
|
71
|
+
(response) => {
|
|
72
|
+
try {
|
|
73
|
+
const bytes = CryptoJS.AES.decrypt(response.data, KEY, { iv: IV });
|
|
74
|
+
const parsed = JSON.parse(bytes.toString(CryptoJS.enc.Utf8));
|
|
75
|
+
if (parsed.status === -1) { logOutRedirectCall(); }
|
|
76
|
+
return { ...response, data: parsed };
|
|
77
|
+
} catch {
|
|
78
|
+
return response;
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
(error) => {
|
|
82
|
+
if (!error.response || error.response.status === 401) {
|
|
83
|
+
logOutRedirectCall();
|
|
84
|
+
showErrorMessage('Session expired. Please log in again.');
|
|
85
|
+
}
|
|
86
|
+
return Promise.reject(error);
|
|
87
|
+
}
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
export default axiosClient;
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## apiHandler.js — Pattern
|
|
96
|
+
|
|
97
|
+
```javascript
|
|
98
|
+
// src/api/apiHandler.js
|
|
99
|
+
import axiosClient from './apiClient';
|
|
100
|
+
import { saveWebSession } from '../pages/common/Utils';
|
|
101
|
+
|
|
102
|
+
// POST /login — authenticate user
|
|
103
|
+
export const webLogin = async ({ email, password }) => {
|
|
104
|
+
const payload = { email, password, device_type: 'web', device_token: '' };
|
|
105
|
+
const res = await axiosClient.post('/login', payload);
|
|
106
|
+
if (res.data.status === 1) saveWebSession(res.data.data);
|
|
107
|
+
return res.data;
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
// POST /<path> — description
|
|
111
|
+
export const <functionName> = async (data) => {
|
|
112
|
+
const res = await axiosClient.post('/<path>', data);
|
|
113
|
+
return res.data;
|
|
114
|
+
};
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Rules:
|
|
118
|
+
- One function per endpoint
|
|
119
|
+
- No try/catch here — interceptors handle errors
|
|
120
|
+
- No decryption here — interceptors handle it
|
|
121
|
+
- Session saving happens in the handler, not in UI components
|
|
122
|
+
- Generate handlers matching `context.api_routes` for the linked service
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
## Component Standards
|
|
127
|
+
|
|
128
|
+
- Functional components only — no class components
|
|
129
|
+
- JSDoc above every exported function and component
|
|
130
|
+
- No inline styles — `.module.css` per page, `global.css` for shared
|
|
131
|
+
- No `console.log` — use `showMessage` / `showErrorMessage`
|
|
132
|
+
- No hardcoded API paths — all calls through `apiHandler.js`
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
## Welcome Page Standard
|
|
137
|
+
|
|
138
|
+
```jsx
|
|
139
|
+
// src/pages/Welcome/index.jsx
|
|
140
|
+
import React from 'react';
|
|
141
|
+
import styles from './Welcome.module.css';
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Default landing page displayed after app initialisation.
|
|
145
|
+
* @returns {JSX.Element} Welcome screen with project name.
|
|
146
|
+
*/
|
|
147
|
+
const Welcome = () => (
|
|
148
|
+
<div className={styles.container}>
|
|
149
|
+
<h1>{process.env.REACT_APP_PROJECT_NAME || '<project_name>'}</h1>
|
|
150
|
+
<p>Welcome. Your application is ready.</p>
|
|
151
|
+
</div>
|
|
152
|
+
);
|
|
153
|
+
|
|
154
|
+
export default Welcome;
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
## App.jsx Standard
|
|
160
|
+
|
|
161
|
+
```jsx
|
|
162
|
+
import { BrowserRouter, Routes, Route } from 'react-router-dom';
|
|
163
|
+
import Welcome from './pages/Welcome';
|
|
164
|
+
|
|
165
|
+
function App() {
|
|
166
|
+
return (
|
|
167
|
+
<BrowserRouter>
|
|
168
|
+
<Routes>
|
|
169
|
+
<Route path="/" element={<Welcome />} />
|
|
170
|
+
{/* Additional routes added as project grows */}
|
|
171
|
+
</Routes>
|
|
172
|
+
</BrowserRouter>
|
|
173
|
+
);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
export default App;
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
---
|
|
180
|
+
|
|
181
|
+
## @modularize Workflow
|
|
182
|
+
|
|
183
|
+
1. Scan all pages in `src/pages/`
|
|
184
|
+
2. Identify repeated layout blocks (header, footer, sidebar, nav)
|
|
185
|
+
3. Show user: "Found repeated blocks in X pages. Extract to components?"
|
|
186
|
+
4. For each block → create `src/components/<BlockName>/index.jsx` + `.module.css`
|
|
187
|
+
5. Rewrite each page to import and use the component
|
|
188
|
+
6. Never change the page's data-fetching logic or state — layout only
|
|
189
|
+
|
|
190
|
+
---
|
|
191
|
+
|
|
192
|
+
## @validate-page Workflow
|
|
193
|
+
|
|
194
|
+
1. Ask: which page to add validation to
|
|
195
|
+
2. Read the page file
|
|
196
|
+
3. Ask: preferred validation library (validatorjs / Yup / custom)
|
|
197
|
+
4. Add validation on form submit — check required fields, types, formats
|
|
198
|
+
5. Display error messages per field below the input
|
|
199
|
+
6. Never add validation that requires a backend call — client-side only
|
|
200
|
+
|
|
201
|
+
---
|
|
202
|
+
|
|
203
|
+
## @integrate-api Workflow
|
|
204
|
+
|
|
205
|
+
1. Ask: which page to wire up
|
|
206
|
+
2. Read the page file and `src/api/apiHandler.js`
|
|
207
|
+
3. Identify buttons/forms in the page that need API calls
|
|
208
|
+
4. Add the appropriate handler function in `apiHandler.js` if not present
|
|
209
|
+
5. Wire form submit and button clicks to handler functions
|
|
210
|
+
6. Add loading state (boolean), error state (string), success state
|
|
211
|
+
7. Show loading spinner during API call, error message on failure, success feedback on completion
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
---
|
|
2
|
+
slash_command: /codeninja:api
|
|
3
|
+
personas: [global-orchestrator, nodejs-backend]
|
|
4
|
+
skills: [mcp-and-context, api-builder]
|
|
5
|
+
description: Add a new API module (route.js + model.js) to an existing NodeJS service.
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# /codeninja:api
|
|
9
|
+
|
|
10
|
+
## Before Running
|
|
11
|
+
1. Call `context_check_stale`
|
|
12
|
+
2. Call `context_read` — load `context.services` and `context.db.schema`
|
|
13
|
+
3. Read 1–2 existing modules in the target service to understand current patterns
|
|
14
|
+
|
|
15
|
+
## Execution — Full Step-by-Step
|
|
16
|
+
|
|
17
|
+
### Phase 0 — Existing Pattern Review
|
|
18
|
+
Before asking any questions, read existing modules in `context.services[<service_name>].modules`
|
|
19
|
+
and scan 1–2 existing `route.js` and `_model.js` files from the service.
|
|
20
|
+
|
|
21
|
+
Identify:
|
|
22
|
+
- Naming conventions (camelCase vs PascalCase)
|
|
23
|
+
- Common validation patterns
|
|
24
|
+
- Auth patterns (all protected? mixed?)
|
|
25
|
+
- Response patterns beyond standard contract
|
|
26
|
+
|
|
27
|
+
Surface: "I've reviewed [n] existing modules. I'll follow the same structure." Then proceed.
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
### Phase 1 — Target Service
|
|
32
|
+
|
|
33
|
+
**Step 1.** Ask: "Which service?" (list from `context.services`)
|
|
34
|
+
- Store: `context.current_api.service_name`
|
|
35
|
+
|
|
36
|
+
**Step 2.** Ask: "API version?" (default: v1)
|
|
37
|
+
- Store: `context.current_api.version`
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
### Phase 2 — Module Identity
|
|
42
|
+
|
|
43
|
+
**Step 3.** Ask: "Module name?" (e.g. Products, Orders, Invoice)
|
|
44
|
+
- Store: `context.current_api.module_name`
|
|
45
|
+
|
|
46
|
+
**Step 4.** Ask: "HTTP method?" (GET / POST / PUT / PATCH / DELETE)
|
|
47
|
+
- Store: `context.current_api.method`
|
|
48
|
+
|
|
49
|
+
**Step 5.** Ask: "Route path?" (e.g. /products, /products/:id)
|
|
50
|
+
- Store: `context.current_api.route_path`
|
|
51
|
+
|
|
52
|
+
**Step 6.** Ask: "Route description?" (one sentence)
|
|
53
|
+
- Store: `context.current_api.description`
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
### Phase 3 — Database Binding
|
|
58
|
+
|
|
59
|
+
**Step 7.** Ask: "Which table does this route primarily use?"
|
|
60
|
+
- Show available tables from `context.db.schema.tables`
|
|
61
|
+
- Store: `context.current_api.primary_table`
|
|
62
|
+
|
|
63
|
+
**Step 8.** Ask: "Does this route require authentication?" (yes / no)
|
|
64
|
+
- Store: `context.current_api.requires_auth`
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
### Phase 4 — Confirm and Generate
|
|
69
|
+
|
|
70
|
+
**Step 9.** Confirm: "Generate [METHOD] [path] in [service]/modules/[version]/[Module]? (yes/no)"
|
|
71
|
+
|
|
72
|
+
**Step 10.** Delegate to nodejs-agent — generate ALL files simultaneously:
|
|
73
|
+
|
|
74
|
+
- `modules/<version>/<ModuleName>/route.js`
|
|
75
|
+
- Full validation schema using `validatorjs`
|
|
76
|
+
- All middleware applied in correct order
|
|
77
|
+
- Calls model function, returns via `sendResponse`
|
|
78
|
+
- JSDoc on every handler
|
|
79
|
+
|
|
80
|
+
- `modules/<version>/<ModuleName>/<module>_model.js`
|
|
81
|
+
- Parameterized queries only — no string concatenation
|
|
82
|
+
- References actual column names from `context.db.schema`
|
|
83
|
+
- Returns exactly `{ responsecode, responsemsg, responsedata }`
|
|
84
|
+
- No `res.json()` anywhere in this file
|
|
85
|
+
|
|
86
|
+
- Append to `modules/<version>/route_manager.js`
|
|
87
|
+
- Use `file_insert_after` MCP tool — NEVER rewrite this file
|
|
88
|
+
- Surgical insert of `router.use('/<path>', require('./<Module>/route'))` only
|
|
89
|
+
- Use `file_contains` first to avoid duplicate registration
|
|
90
|
+
|
|
91
|
+
- Patch `document/<version>/swagger_doc.json`
|
|
92
|
+
- Use `file_insert_after` MCP tool — NEVER rewrite this file
|
|
93
|
+
- Add new path key to the `paths` object only
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
### Phase 5 — Finalize
|
|
98
|
+
|
|
99
|
+
**Step 11.** Call `context_write`:
|
|
100
|
+
- Append to `context.api_routes`
|
|
101
|
+
- Update `context.services[<service>].modules`
|
|
102
|
+
- Set `last_command` = "create-api"
|
|
103
|
+
- Append to `change_log`
|
|
104
|
+
|
|
105
|
+
**Step 12.** Call `context_clear_scratchpad` with keys: ["current_api"]
|
|
106
|
+
|
|
107
|
+
**Step 13.** Show final summary:
|
|
108
|
+
- Files created/modified
|
|
109
|
+
- Route registered in route_manager
|
|
110
|
+
- Swagger patched
|
|
111
|
+
- Offer next steps: /codeninja:design, /codeninja:db:create
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
---
|
|
2
|
+
slash_command: /codeninja:audit
|
|
3
|
+
personas: [global-orchestrator, nodejs-backend]
|
|
4
|
+
skills: [mcp-and-context, api-builder, code-intelligence]
|
|
5
|
+
description: Deep security and quality review of an existing NodeJS service.
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# /codeninja:audit
|
|
9
|
+
|
|
10
|
+
## Before Running
|
|
11
|
+
1. Call `context_read`
|
|
12
|
+
2. Call `context_check_stale`
|
|
13
|
+
|
|
14
|
+
## Execution — Full Step-by-Step
|
|
15
|
+
|
|
16
|
+
**Step 1.** Ask: "Which service to audit?" (list from `context.services`)
|
|
17
|
+
|
|
18
|
+
**Step 2.** Delegate to nodejs-agent. Run all checks:
|
|
19
|
+
|
|
20
|
+
### Security Checks
|
|
21
|
+
- [ ] API key validation middleware on ALL routes?
|
|
22
|
+
- [ ] Input validation on all POST/PUT/PATCH routes?
|
|
23
|
+
- [ ] SQL injection prevention (parameterized queries only)?
|
|
24
|
+
- [ ] Sensitive values only from env vars (no hardcoded keys/passwords)?
|
|
25
|
+
- [ ] `.env` in `.gitignore`?
|
|
26
|
+
- [ ] Real AES-256-CBC encryption (not base64)?
|
|
27
|
+
- [ ] `utilities/encryption.js` is the ONLY file importing crypto-js or cryptlib?
|
|
28
|
+
- [ ] `res.json()` never called directly in route.js or model files?
|
|
29
|
+
- [ ] Validator package never imported directly in route files?
|
|
30
|
+
- [ ] SMTP credentials only in .env — never hardcoded in notification.js or template.js?
|
|
31
|
+
- [ ] Firebase service account file in `pem/` and in `.gitignore`?
|
|
32
|
+
- [ ] `GLOBALS` object frozen using `Object.freeze()`?
|
|
33
|
+
|
|
34
|
+
### Code Quality Checks
|
|
35
|
+
- [ ] Only services called from controllers (no DB queries in controllers)?
|
|
36
|
+
- [ ] Models contain only DB queries and business logic?
|
|
37
|
+
- [ ] Global error handler present and used?
|
|
38
|
+
- [ ] All routes call `checkValidationRules` from `utilities/validator.js`?
|
|
39
|
+
- [ ] No separate `_validator.js` files per module?
|
|
40
|
+
- [ ] `rateLimiter` is FIRST middleware in `route_manager.js`?
|
|
41
|
+
- [ ] `extractLanguage` runs BEFORE `validateApiKey` in `route_manager.js`?
|
|
42
|
+
- [ ] `decryptRequest` is LAST middleware in the chain?
|
|
43
|
+
- [ ] No route handlers defined directly in `route_manager.js`?
|
|
44
|
+
- [ ] `asyncHandler` wraps every middleware in `route_manager.js`?
|
|
45
|
+
- [ ] All model functions return exactly `{ responsecode, responsemsg, responsedata }`?
|
|
46
|
+
- [ ] No `req/res` objects in any model file?
|
|
47
|
+
- [ ] Passwords encrypted via `utilities/encryption.js` before storage?
|
|
48
|
+
- [ ] Session tokens generated only via `common.generateSessionCode()`?
|
|
49
|
+
|
|
50
|
+
### Consistency Checks
|
|
51
|
+
- [ ] All routes documented in `swagger_doc.json`?
|
|
52
|
+
- [ ] Response format consistent (success, message, data, timestamp)?
|
|
53
|
+
- [ ] snake_case for DB, camelCase for JS?
|
|
54
|
+
- [ ] Port matches `context.services[<n>].port`?
|
|
55
|
+
- [ ] DB config matches `context.db`?
|
|
56
|
+
- [ ] All message keywords in `sendResponse` calls exist in `languages/en.js`?
|
|
57
|
+
- [ ] All language files have the same keys as `en.js`?
|
|
58
|
+
- [ ] No two services share the same port in context.services?
|
|
59
|
+
- [ ] All encryption keys exactly 32 chars in context.services?
|
|
60
|
+
- [ ] All encryption IVs exactly 16 chars in context.services?
|
|
61
|
+
|
|
62
|
+
### Context Alignment
|
|
63
|
+
- [ ] All routes present in `context.api_routes`?
|
|
64
|
+
- [ ] All DB tables referenced match `context.db.schema`?
|
|
65
|
+
- [ ] All `router.use()` lines in route_manager.js have a corresponding entry in context.services modules?
|
|
66
|
+
- [ ] All context.services modules have a corresponding `router.use()` in route_manager.js?
|
|
67
|
+
- [ ] All swagger_doc.json paths have a corresponding entry in context.api_routes?
|
|
68
|
+
|
|
69
|
+
**Step 3.** Present audit report:
|
|
70
|
+
```
|
|
71
|
+
AUDIT REPORT — <service_name>
|
|
72
|
+
══════════════════════════════════════
|
|
73
|
+
🔴 CRITICAL (must fix)
|
|
74
|
+
🟡 WARNING (should fix)
|
|
75
|
+
🟢 INFO (nice to have)
|
|
76
|
+
══════════════════════════════════════
|
|
77
|
+
[list findings with file + line context]
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
**Step 4.** Ask: "Auto-fix critical issues? (yes/no)"
|
|
81
|
+
If yes → delegate to nodejs-agent for fixes → call `context_write` after.
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
---
|
|
2
|
+
slash_command: /codeninja:db:create
|
|
3
|
+
personas: [global-orchestrator, database-architect]
|
|
4
|
+
skills: [mcp-and-context, database]
|
|
5
|
+
description: Design and generate a new database table with migration file.
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# /codeninja:db:create
|
|
9
|
+
|
|
10
|
+
## Before Running
|
|
11
|
+
1. Call `context_read` — load `context.db` fully
|
|
12
|
+
2. Call `context_check_stale`
|
|
13
|
+
3. Call `migration_next_number` MCP tool — get next sequential migration number
|
|
14
|
+
|
|
15
|
+
## Execution — Full Step-by-Step
|
|
16
|
+
|
|
17
|
+
### Phase 1 — Table Identity
|
|
18
|
+
|
|
19
|
+
**Step 1.** Ask: "What is this table for?" (free text — used by agent for suggestions)
|
|
20
|
+
- Store: `context.current_db.table_purpose`
|
|
21
|
+
|
|
22
|
+
**Step 2.** Ask: "Table name?" (must start with `tbl_`, snake_case, lowercase)
|
|
23
|
+
- Enforce prefix and casing
|
|
24
|
+
- Store: `context.current_db.table_name`
|
|
25
|
+
|
|
26
|
+
**Step 3.** Ask: "Migration file number?" (agent reads migrations/ and suggests next)
|
|
27
|
+
- Call `migration_next_number` to get suggestion
|
|
28
|
+
- Store: `context.current_db.file_number`
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
### Phase 2 — Standard Columns Decision
|
|
33
|
+
|
|
34
|
+
**Step 4.** Ask: "Does this table need `status` and `is_deleted` columns?"
|
|
35
|
+
- Suggest YES for user/entity tables, NO for event/log tables
|
|
36
|
+
- Store: `context.current_db.needs_status`
|
|
37
|
+
|
|
38
|
+
**Step 5.** Ask: "Does this table support soft delete (`is_deleted`)?"
|
|
39
|
+
- Auto-suggest YES if needs_status is YES
|
|
40
|
+
- Store: `context.current_db.needs_soft_delete`
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
### Phase 3 — Column Collection (repeat until done)
|
|
45
|
+
|
|
46
|
+
**Step 6.** Ask: "Enter next column name (or type 'done' to finish):"
|
|
47
|
+
- Show columns collected so far
|
|
48
|
+
- Enforce: snake_case, lowercase
|
|
49
|
+
- Append to: `context.current_db.columns[]`
|
|
50
|
+
|
|
51
|
+
**Step 7.** Ask: "Column type?" — show type suggestion based on name pattern:
|
|
52
|
+
- `*_id` → BIGINT NOT NULL DEFAULT 0 (also check for FK — ask if foreign key)
|
|
53
|
+
- `is_*` → BOOLEAN NOT NULL DEFAULT FALSE
|
|
54
|
+
- `*_at` → TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP
|
|
55
|
+
- `status` → INTEGER NOT NULL DEFAULT 0 CHECK (status IN (0,1))
|
|
56
|
+
- `*_count` → BIGINT NOT NULL DEFAULT 0
|
|
57
|
+
- `*_price`, `*_amount` → NUMERIC(18,8) NOT NULL DEFAULT 0.00000000
|
|
58
|
+
- `email` → VARCHAR(132) NOT NULL DEFAULT ''
|
|
59
|
+
- `phone` → VARCHAR(16) NOT NULL DEFAULT ''
|
|
60
|
+
- `password` → TEXT NOT NULL DEFAULT ''
|
|
61
|
+
- `*_image`, `*_url` → VARCHAR(255) NOT NULL DEFAULT ''
|
|
62
|
+
- `payload`, `metadata`, `*_result` → JSON NOT NULL DEFAULT '{}'
|
|
63
|
+
- default → VARCHAR(255) NOT NULL DEFAULT ''
|
|
64
|
+
|
|
65
|
+
**Step 8.** Ask: "Does this column have a fixed set of allowed values? (enum-like)"
|
|
66
|
+
- If yes → ask for the allowed values and generate a CHECK constraint + COMMENT
|
|
67
|
+
|
|
68
|
+
**Step 9.** Return to Step 6 until user types 'done'
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
### Phase 4 — Index Decision
|
|
73
|
+
|
|
74
|
+
**Step 10.** Agent auto-suggests indexes based on collected columns:
|
|
75
|
+
- Every `*_id` (FK) column → suggest index
|
|
76
|
+
- `status + is_deleted` compound → suggest if both exist
|
|
77
|
+
- `created_at DESC` → suggest for event/log tables
|
|
78
|
+
Ask user to confirm suggested indexes or add custom ones.
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
### Phase 5 — Seed Data
|
|
83
|
+
|
|
84
|
+
**Step 11.** Ask: "Does this table need initial/seed data?"
|
|
85
|
+
- Guide: suggest YES only for reference/master data tables
|
|
86
|
+
- If yes → collect row values column by column, repeat per row
|
|
87
|
+
- Store: `context.current_db.seed_rows[]`
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
### Phase 6 — Summary and Generate
|
|
92
|
+
|
|
93
|
+
**Step 12.** Show complete table definition:
|
|
94
|
+
- Table name, file number, all columns with types, indexes, seed rows
|
|
95
|
+
- Ask: "Generate this table? (yes / no / change a value)"
|
|
96
|
+
- If change → re-run specific step → return to summary
|
|
97
|
+
- If no → abort
|
|
98
|
+
- If yes → proceed
|
|
99
|
+
|
|
100
|
+
**Step 13.** Delegate to database-agent:
|
|
101
|
+
- Generate: `<repo_root>/database/<db_type>/migrations/<number>-setup-tbl-<n>.sql`
|
|
102
|
+
- File header comment
|
|
103
|
+
- `BEGIN;`
|
|
104
|
+
- Standard system columns: `id BIGSERIAL PRIMARY KEY`
|
|
105
|
+
- All collected columns in order
|
|
106
|
+
- `status INTEGER NOT NULL DEFAULT 0 CHECK (status IN (0,1))` if needs_status
|
|
107
|
+
- `is_deleted BOOLEAN NOT NULL DEFAULT FALSE` if needs_soft_delete
|
|
108
|
+
- `created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP`
|
|
109
|
+
- All CHECK constraints and COMMENTs for enum columns
|
|
110
|
+
- All per-table CREATE INDEX statements
|
|
111
|
+
- GRANT SELECT, INSERT, UPDATE, DELETE to `<db_user>`
|
|
112
|
+
- Seed data INSERT if collected
|
|
113
|
+
- `COMMIT;`
|
|
114
|
+
- Update: `<repo_root>/database/<db_type>/create-schema.sql` (add `\i` entry in order)
|
|
115
|
+
- If any indexes belong in shared file → update `111-setup-database-indexes.sql`
|
|
116
|
+
|
|
117
|
+
**Step 14.** Call `context_write`:
|
|
118
|
+
- Append table to `context.db.schema.tables`
|
|
119
|
+
- Append to `context.db.schema.change_log`
|
|
120
|
+
- Clear `context.current_db`
|
|
121
|
+
|
|
122
|
+
**Step 15.** Call `context_clear_scratchpad` with keys: ["current_db"]
|
|
123
|
+
|
|
124
|
+
**Step 16.** Show final summary with file path and next steps.
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
---
|
|
2
|
+
slash_command: /codeninja:db:drop
|
|
3
|
+
personas: [global-orchestrator, database-architect]
|
|
4
|
+
skills: [mcp-and-context, database]
|
|
5
|
+
description: Generate a DROP TABLE migration. Never deletes the original setup file.
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# /codeninja:db:drop
|
|
9
|
+
|
|
10
|
+
## Before Running
|
|
11
|
+
1. Call `context_read` — load `context.db.schema`
|
|
12
|
+
2. Call `context_check_stale`
|
|
13
|
+
|
|
14
|
+
## Execution — Full Step-by-Step
|
|
15
|
+
|
|
16
|
+
### Phase 1 — Target
|
|
17
|
+
|
|
18
|
+
**Step 1.** Ask: "Which table to drop?" (list from `context.db.schema.tables`)
|
|
19
|
+
- Store: `context.current_db.table_name`
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
### Phase 2 — Impact Analysis
|
|
24
|
+
|
|
25
|
+
**Step 2.** Agent scans context:
|
|
26
|
+
- Check `context.api_routes` for routes referencing this table as `primary_table`
|
|
27
|
+
- Check `context.services` for modules using this table
|
|
28
|
+
- Check `context.db.schema.tables` for FK columns pointing to this table
|
|
29
|
+
|
|
30
|
+
**Step 3.** If references found, display warning:
|
|
31
|
+
```
|
|
32
|
+
⚠ WARNING: This table is referenced by:
|
|
33
|
+
- [service]/modules/[Module] (primary_table)
|
|
34
|
+
- tbl_<other_table>.<col> → <this_table> (FK dependency)
|
|
35
|
+
|
|
36
|
+
Dropping this table will break these references.
|
|
37
|
+
Make sure to update or remove dependent code first.
|
|
38
|
+
```
|
|
39
|
+
Ask: "Do you still want to proceed? (yes / no)"
|
|
40
|
+
If no → abort.
|
|
41
|
+
|
|
42
|
+
**Step 4.** Final confirmation:
|
|
43
|
+
Ask: "Type the table name to confirm the drop."
|
|
44
|
+
Must match exactly — if wrong → abort.
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
### Phase 3 — File Numbering
|
|
49
|
+
|
|
50
|
+
**Step 5.** Ask: "Migration file number?" (suggest next available)
|
|
51
|
+
- Store: `context.current_db.file_number`
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
### Phase 4 — Generate
|
|
56
|
+
|
|
57
|
+
**Step 6.** Delegate to database-agent:
|
|
58
|
+
Generate: `<repo_root>/database/<db_type>/migrations/<number>-drop-tbl-<n>.sql`
|
|
59
|
+
|
|
60
|
+
```sql
|
|
61
|
+
-- Drop tbl_<table_name>
|
|
62
|
+
-- Migration: <number>-drop-tbl-<n>.sql
|
|
63
|
+
-- Generated: <ISO date>
|
|
64
|
+
-- WARNING: This migration is irreversible in production.
|
|
65
|
+
-- Original table definition: <original_setup_file>
|
|
66
|
+
|
|
67
|
+
BEGIN;
|
|
68
|
+
|
|
69
|
+
DROP TABLE IF EXISTS public.<table_name> CASCADE;
|
|
70
|
+
|
|
71
|
+
COMMIT;
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Update `create-schema.sql`:
|
|
75
|
+
- Keep the original `\i <setup_file>` entry
|
|
76
|
+
- Add the drop file entry AFTER it (never remove original)
|
|
77
|
+
|
|
78
|
+
**Step 7.** Call `context_write`:
|
|
79
|
+
- Snapshot full column list before removing from active tables
|
|
80
|
+
- Append to `context.db.schema.change_log`:
|
|
81
|
+
`{ type: "table_dropped", table: "<n>", snapshot: { full column list }, file: "<path>" }`
|
|
82
|
+
- Remove table from `context.db.schema.tables`
|
|
83
|
+
- Clear `context.current_db`
|
|
84
|
+
|
|
85
|
+
**Step 8.** Call `context_clear_scratchpad` with keys: ["current_db"]
|
|
86
|
+
|
|
87
|
+
**Step 9.** Show final summary.
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
---
|
|
2
|
+
slash_command: /codeninja:db:index
|
|
3
|
+
personas: [global-orchestrator, database-architect]
|
|
4
|
+
skills: [mcp-and-context, database]
|
|
5
|
+
description: Add a new index to an existing table.
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# /codeninja:db:index
|
|
9
|
+
|
|
10
|
+
## Before Running
|
|
11
|
+
1. Call `context_read` — load `context.db.schema`
|
|
12
|
+
2. Call `context_check_stale`
|
|
13
|
+
|
|
14
|
+
## Execution — Full Step-by-Step
|
|
15
|
+
|
|
16
|
+
### Phase 1 — Target Table
|
|
17
|
+
|
|
18
|
+
**Step 1.** Ask: "Which table?" (list from `context.db.schema.tables`)
|
|
19
|
+
- Store: `context.current_db.table_name`
|
|
20
|
+
|
|
21
|
+
### Phase 2 — Index Columns
|
|
22
|
+
|
|
23
|
+
**Step 2.** Ask: "Which column(s) for this index?"
|
|
24
|
+
- List available columns from `context.db.schema.tables[<table>].columns`
|
|
25
|
+
- Allow one or multiple (compound index)
|
|
26
|
+
- Store: `context.current_db.index_columns[]`
|
|
27
|
+
|
|
28
|
+
**Step 3.** Ask: "Should any column be sorted DESC?" (common: `created_at DESC`, `time DESC`)
|
|
29
|
+
- If yes → ask which column(s)
|
|
30
|
+
- Store: `context.current_db.index_desc_columns[]`
|
|
31
|
+
|
|
32
|
+
**Step 4.** Ask: "Standard or partial index?"
|
|
33
|
+
- Standard: covers all rows
|
|
34
|
+
- Partial: only rows matching a WHERE condition — if partial, ask for WHERE clause
|
|
35
|
+
- Store: `context.current_db.index_where_clause`
|
|
36
|
+
|
|
37
|
+
### Phase 3 — File Placement
|
|
38
|
+
|
|
39
|
+
**Step 5.** Ask: "Where should this index be defined?"
|
|
40
|
+
1. In the table's own setup file (for new/just-created tables)
|
|
41
|
+
2. In `111-setup-database-indexes.sql` (for existing tables — auto-suggested)
|
|
42
|
+
- Store: `context.current_db.index_file`
|
|
43
|
+
|
|
44
|
+
### Phase 4 — Generate
|
|
45
|
+
|
|
46
|
+
**Step 6.** Agent auto-generates index name:
|
|
47
|
+
- In table file: `idx_<table_without_tbl_prefix>_<columns_joined>`
|
|
48
|
+
- In shared file: `idx_tbl_<table_without_tbl_prefix>_<columns_joined>`
|
|
49
|
+
- Show: "Index will be named: <name> — OK? (yes / rename)"
|
|
50
|
+
|
|
51
|
+
**Step 7.** Confirm: "Generate this index? (yes / no)"
|
|
52
|
+
|
|
53
|
+
**Step 8.** Delegate to database-agent:
|
|
54
|
+
```sql
|
|
55
|
+
--
|
|
56
|
+
-- Name: <index_name>; Type: INDEX; Schema: public
|
|
57
|
+
--
|
|
58
|
+
CREATE INDEX <index_name> ON public.<table_name> (<col> [DESC], ...)
|
|
59
|
+
[WHERE <where_clause>];
|
|
60
|
+
```
|
|
61
|
+
Append to correct file (table setup file OR `111-setup-database-indexes.sql`).
|
|
62
|
+
|
|
63
|
+
**Step 9.** Call `context_write`:
|
|
64
|
+
- Append index to `context.db.schema.tables[<table>].indexes`
|
|
65
|
+
- Append to `context.db.schema.change_log`
|
|
66
|
+
- Clear `context.current_db`
|
|
67
|
+
|
|
68
|
+
**Step 10.** Call `context_clear_scratchpad` with keys: ["current_db"]
|
|
69
|
+
|
|
70
|
+
**Step 11.** Show final summary.
|