codeninja 2.0.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 (140) hide show
  1. package/.gitattributes +11 -0
  2. package/README.md +293 -0
  3. package/agent/database-agent.md +504 -0
  4. package/agent/designs/README.md +10 -0
  5. package/agent/global-agent.md +236 -0
  6. package/agent/nodejs-agent.md +406 -0
  7. package/agent/reactjs-agent.md +260 -0
  8. package/cli.js +352 -0
  9. package/commands/audit.workflow.md +111 -0
  10. package/commands/create-api.workflow.md +99 -0
  11. package/commands/db-add-index.workflow.md +97 -0
  12. package/commands/db-create-table.workflow.md +132 -0
  13. package/commands/db-drop-table.workflow.md +103 -0
  14. package/commands/db-modify-table.workflow.md +159 -0
  15. package/commands/db-seed.workflow.md +99 -0
  16. package/commands/db-sync.workflow.md +100 -0
  17. package/commands/design.workflow.md +66 -0
  18. package/commands/initialize-project.workflow.md +500 -0
  19. package/commands/integrate-api.workflow.md +448 -0
  20. package/commands/modularize.workflow.md +329 -0
  21. package/commands/refactor.workflow.md +70 -0
  22. package/commands/sync.workflow.md +962 -0
  23. package/commands/test.workflow.md +40 -0
  24. package/commands/validate-page.workflow.md +543 -0
  25. package/mcp-server.js +842 -0
  26. package/package.json +24 -0
  27. package/tasks/README.md +283 -0
  28. package/tasks/add-health-route.task.md +103 -0
  29. package/tasks/ask-api-integration-scope.task.md +34 -0
  30. package/tasks/ask-api-key.task.md +23 -0
  31. package/tasks/ask-api-version.task.md +28 -0
  32. package/tasks/ask-client-type.task.md +24 -0
  33. package/tasks/ask-column-enum-values.task.md +51 -0
  34. package/tasks/ask-column-is-enum.task.md +39 -0
  35. package/tasks/ask-column-name.task.md +39 -0
  36. package/tasks/ask-column-position.task.md +39 -0
  37. package/tasks/ask-column-type.task.md +59 -0
  38. package/tasks/ask-database-config.task.md +66 -0
  39. package/tasks/ask-database-host.task.md +16 -0
  40. package/tasks/ask-database-name.task.md +18 -0
  41. package/tasks/ask-database-port.task.md +23 -0
  42. package/tasks/ask-database-type.task.md +30 -0
  43. package/tasks/ask-database-user.task.md +14 -0
  44. package/tasks/ask-design-description.task.md +16 -0
  45. package/tasks/ask-design-target.task.md +24 -0
  46. package/tasks/ask-encrypted-transport.task.md +25 -0
  47. package/tasks/ask-encryption-iv.task.md +23 -0
  48. package/tasks/ask-encryption-key.task.md +23 -0
  49. package/tasks/ask-feature-name.task.md +20 -0
  50. package/tasks/ask-http-method.task.md +21 -0
  51. package/tasks/ask-index-columns.task.md +46 -0
  52. package/tasks/ask-index-file-placement.task.md +33 -0
  53. package/tasks/ask-index-sort-order.task.md +37 -0
  54. package/tasks/ask-index-type.task.md +42 -0
  55. package/tasks/ask-init-mode.task.md +28 -0
  56. package/tasks/ask-linked-service.task.md +57 -0
  57. package/tasks/ask-modify-operation.task.md +36 -0
  58. package/tasks/ask-modularize-scope.task.md +31 -0
  59. package/tasks/ask-module-name.task.md +30 -0
  60. package/tasks/ask-new-column-name.task.md +21 -0
  61. package/tasks/ask-new-table-name.task.md +22 -0
  62. package/tasks/ask-old-column-name.task.md +22 -0
  63. package/tasks/ask-package-author.task.md +16 -0
  64. package/tasks/ask-package-name.task.md +23 -0
  65. package/tasks/ask-page-path.task.md +40 -0
  66. package/tasks/ask-primary-table.task.md +30 -0
  67. package/tasks/ask-project-figma.task.md +71 -0
  68. package/tasks/ask-project-info-doc.task.md +57 -0
  69. package/tasks/ask-project-scope-of-work.task.md +57 -0
  70. package/tasks/ask-project-type.task.md +24 -0
  71. package/tasks/ask-react-target-service.task.md +32 -0
  72. package/tasks/ask-redis-config.task.md +42 -0
  73. package/tasks/ask-redis-host.task.md +16 -0
  74. package/tasks/ask-redis-port.task.md +18 -0
  75. package/tasks/ask-refactor-type.task.md +26 -0
  76. package/tasks/ask-requires-auth.task.md +22 -0
  77. package/tasks/ask-response-mode.task.md +38 -0
  78. package/tasks/ask-route-description.task.md +20 -0
  79. package/tasks/ask-route-path.task.md +29 -0
  80. package/tasks/ask-seed-row-values.task.md +42 -0
  81. package/tasks/ask-seed-rows-count.task.md +22 -0
  82. package/tasks/ask-service-description.task.md +16 -0
  83. package/tasks/ask-service-name.task.md +27 -0
  84. package/tasks/ask-service-port.task.md +24 -0
  85. package/tasks/ask-supported-languages.task.md +40 -0
  86. package/tasks/ask-table-file-number.task.md +36 -0
  87. package/tasks/ask-table-indexes.task.md +47 -0
  88. package/tasks/ask-table-name.task.md +32 -0
  89. package/tasks/ask-table-needs-soft-delete.task.md +29 -0
  90. package/tasks/ask-table-needs-status.task.md +30 -0
  91. package/tasks/ask-table-purpose.task.md +28 -0
  92. package/tasks/ask-table-seed-data.task.md +44 -0
  93. package/tasks/ask-target-service.task.md +32 -0
  94. package/tasks/ask-test-type.task.md +20 -0
  95. package/tasks/ask-validation-library.task.md +38 -0
  96. package/tasks/detect-repository-state.task.md +92 -0
  97. package/tasks/generate-app.task.md +146 -0
  98. package/tasks/generate-common.task.md +330 -0
  99. package/tasks/generate-constants.task.md +123 -0
  100. package/tasks/generate-database.task.md +168 -0
  101. package/tasks/generate-docker-compose.task.md +298 -0
  102. package/tasks/generate-dockerfile.task.md +126 -0
  103. package/tasks/generate-dockerignore.task.md +123 -0
  104. package/tasks/generate-enc-dec-html.task.md +127 -0
  105. package/tasks/generate-enc-dec-php.task.md +145 -0
  106. package/tasks/generate-encryption.task.md +159 -0
  107. package/tasks/generate-fast-defaults.task.md +68 -0
  108. package/tasks/generate-gitignore.task.md +79 -0
  109. package/tasks/generate-headerValidator.task.md +377 -0
  110. package/tasks/generate-ide-configs.task.md +114 -0
  111. package/tasks/generate-ioRedis.task.md +120 -0
  112. package/tasks/generate-language-en.task.md +155 -0
  113. package/tasks/generate-logging.task.md +257 -0
  114. package/tasks/generate-model.task.md +180 -0
  115. package/tasks/generate-notification.task.md +251 -0
  116. package/tasks/generate-package-json.task.md +114 -0
  117. package/tasks/generate-rateLimiter.task.md +125 -0
  118. package/tasks/generate-react-api-client.task.md +169 -0
  119. package/tasks/generate-react-api-handler.task.md +102 -0
  120. package/tasks/generate-react-app-jsx.task.md +56 -0
  121. package/tasks/generate-react-dockerfile.task.md +175 -0
  122. package/tasks/generate-react-env.task.md +58 -0
  123. package/tasks/generate-react-gitignore.task.md +49 -0
  124. package/tasks/generate-react-htaccess.task.md +54 -0
  125. package/tasks/generate-react-index-html.task.md +53 -0
  126. package/tasks/generate-react-index-jsx.task.md +51 -0
  127. package/tasks/generate-react-package-json.task.md +77 -0
  128. package/tasks/generate-react-welcome-page.task.md +71 -0
  129. package/tasks/generate-readme.task.md +160 -0
  130. package/tasks/generate-response.task.md +202 -0
  131. package/tasks/generate-route-manager.task.md +173 -0
  132. package/tasks/generate-route.task.md +203 -0
  133. package/tasks/generate-swagger.task.md +290 -0
  134. package/tasks/generate-tbl-user-deviceinfo.task.md +75 -0
  135. package/tasks/generate-template.task.md +129 -0
  136. package/tasks/generate-validator.task.md +122 -0
  137. package/tasks/show-db-table-summary.task.md +66 -0
  138. package/tasks/show-final-summary.task.md +108 -0
  139. package/tasks/show-init-summary.task.md +257 -0
  140. package/tasks/write-context.task.md +314 -0
@@ -0,0 +1,377 @@
1
+ ---
2
+ type: task
3
+ name: generate-headerValidator
4
+ agent: nodejs-agent
5
+ ---
6
+
7
+ # File: middleware/headerValidator.js
8
+
9
+ ## Purpose
10
+ Central middleware file for all inbound request validation. Runs on every
11
+ request in sequence: language extraction → API key validation → token
12
+ validation. Also exposes request body decryption as a per-route middleware
13
+ when encrypted transport is enabled. All encryption/decryption operations
14
+ are delegated to `utilities/encryption.js`. All response sending is
15
+ delegated to `utilities/response.js`. All validation rule checking is
16
+ delegated to `utilities/validator.js`.
17
+
18
+ ---
19
+
20
+ ## Dependencies to Import
21
+
22
+ - `../config/constants` — GLOBALS object containing API_KEY and other
23
+ app-wide constants. Note: ENCRYPTED_TRANSPORT is read from
24
+ process.env directly, not from constants.
25
+ - `../utilities/encryption` — imports `decrypt` function only.
26
+ The actual crypto library (crypto-js or cryptlib) is abstracted away.
27
+ headerValidator never calls crypto directly.
28
+ - `../utilities/response` — imports `sendResponse` function for all
29
+ outbound responses from this middleware.
30
+ - `../logger/logging` — imports `log` for info/debug/error logging.
31
+ - `localizify` — imported as `{ default: localizify }` and `{ t }`
32
+ separately in two destructured require statements.
33
+ - All language files from `../languages/` — imported individually, one
34
+ require per supported language. The list of supported languages comes
35
+ from `process.env.SUPPORTED_LANGUAGES` parsed as a comma-separated
36
+ array at module load time. Each language is imported as a variable
37
+ named by its code: e.g. `en` from `../languages/en.js`, `ar` from
38
+ `../languages/ar.js`. Agent generates one require line per language
39
+ in `context.services[<name>].supported_languages`.
40
+ - `jsonwebtoken` — for JWT verify operations in validateToken.
41
+ - `../utilities/ioRedis` — Redis client for token version lookup.
42
+
43
+ ---
44
+
45
+ ## Module-Level Constants
46
+
47
+ ### languageMap
48
+ Built once at module load time. A plain object that maps each language
49
+ code string to its imported language object.
50
+ Example structure: `{ "en": en, "ar": ar, "fr": fr }`
51
+ Keys are the language code strings from SUPPORTED_LANGUAGES parsed from
52
+ process.env. Values are the imported language file objects.
53
+ Used in `extractLanguage` for O(1) lookup by header value.
54
+
55
+ ### DEFAULT_LANGUAGE
56
+ Read `process.env.DEFAULT_LANGUAGE` once at module load time.
57
+ Used as fallback in `extractLanguage` when the header is absent or
58
+ contains an unrecognized language code.
59
+
60
+ ### bypassMethod
61
+ Array of route name strings that skip token validation entirely.
62
+ These are the final path segment of public endpoints — the segment at
63
+ index 2 when the path is split by `/`.
64
+ Default values to populate: `"login"`, `"signup"`, `"requestotp"`,
65
+ `"forgot-password"`, `"set-password"`.
66
+ Developer appends to this list as new public endpoints are added.
67
+
68
+ ### bypassHeaderKey
69
+ Array of route name strings that skip API key validation.
70
+ Initialized as an empty array. Exists so future public or webhook routes
71
+ can be excluded without modifying validation logic. Developer adds
72
+ values here when needed.
73
+
74
+ ### JWT_SECRET
75
+ Read `process.env.KEY` once at module load time.
76
+ Store as module-level constant `JWT_SECRET`.
77
+ This is the same KEY used for AES encryption throughout the service
78
+ and for JWT signing in `config/common.js` — they must always match.
79
+ Used by `jsonwebtoken.verify()` in validateToken.
80
+
81
+ ---
82
+
83
+ ## Functions
84
+
85
+ ---
86
+
87
+ ### extractLanguage(req, res, next)
88
+
89
+ **Purpose**: Determine the request language, register it with localizify,
90
+ and attach everything needed for translation onto the request object so
91
+ all downstream handlers work without any additional setup.
92
+
93
+ **Flow**:
94
+
95
+ 1. Read the `accept-language` header from `req.headers`. Lowercase and
96
+ trim the value. If the header is absent or empty, assign
97
+ DEFAULT_LANGUAGE immediately and skip to step 3.
98
+
99
+ 2. Check if the extracted value exists as a key in `languageMap`.
100
+ If it does not exist — the client sent an unsupported language code.
101
+ Fall back to DEFAULT_LANGUAGE silently. Language fallback must always
102
+ be transparent to the client. Never return an error for a bad language
103
+ header.
104
+
105
+ 3. Using the resolved language code, look up the corresponding language
106
+ object from `languageMap`.
107
+
108
+ 4. Register with localizify:
109
+ Call `localizify.add(resolvedCode, resolvedLanguageObject)` to
110
+ register the translations for this language in this request context.
111
+ Call `localizify.setLocale(resolvedCode)` to activate it.
112
+ Both calls must happen before any `t()` call in this request lifecycle.
113
+
114
+ Note on getMessage: `response.js` getMessage also calls
115
+ localizify.add and setLocale on every call, making it safe under
116
+ concurrent requests. The setLocale call here in extractLanguage is
117
+ for `req.t` — the function bound to the request object for use in
118
+ route handlers. These two patterns coexist correctly.
119
+
120
+ 5. Attach to the request object:
121
+ - `req.lang` — the resolved language code string (e.g. `"en"`, `"ar"`).
122
+ Passed to `sendResponse` for message resolution on all subsequent
123
+ responses in this request.
124
+ - `req.languageData` — the full language object from `languageMap`.
125
+ Available to route handlers if they need direct key access without
126
+ going through localizify.
127
+ - `req.t` — the `t` function from localizify bound directly onto the
128
+ request. Route handlers call `req.t("keyword")` without importing
129
+ localizify themselves.
130
+
131
+ 6. Log at info level: the resolved language code, whether fallback was
132
+ used (true/false), and the original header value.
133
+
134
+ 7. Call `next()`.
135
+
136
+ ---
137
+
138
+ ### validateApiKey(req, res, next)
139
+
140
+ **Purpose**: Verify that the inbound request carries a valid API key.
141
+ The client always sends the API key AES-encrypted. This middleware
142
+ decrypts it and compares against the expected value from constants.
143
+
144
+ **Flow**:
145
+
146
+ 1. Split `req.path` by `/` and store as `pathSegments`. Extract
147
+ `pathSegments[2]` as the route identifier for bypass checking.
148
+
149
+ 2. If `bypassHeaderKey` includes the route identifier — call `next()`
150
+ and return immediately. No further checks for this request.
151
+
152
+ 3. Read the `api-key` header from `req.headers`. If the header is absent
153
+ or empty — send a 401 response using `sendResponse` with keyword
154
+ `rest_keywords_invalid_api_key` and response code `"-1"`. Log at
155
+ info level that the header was missing. Do not call `next()`.
156
+
157
+ 4. Inside a try/catch block:
158
+ Call `decrypt(encryptedToken)` from `utilities/encryption.js`.
159
+ Strip all whitespace characters from the decrypted result.
160
+ Strip surrounding double-quote characters if present.
161
+ If the cleaned result is an empty string — call sendResponse with
162
+ 401, keyword `rest_keywords_tokeninvalid`, response code `"-1"`.
163
+ Log at debug level: "Empty token after decryption".
164
+ Return immediately. Do not call next().
165
+
166
+ 5. Verify the decrypted string as a JWT:
167
+ Call `jsonwebtoken.verify(token, JWT_SECRET, { algorithms: ['HS256'] })`.
168
+ JWT_SECRET is the module-level constant loaded at startup from
169
+ process.env.KEY. Algorithm must be HS256.
170
+ Wrap this call in the try/catch. If verification fails for any
171
+ reason (expired, tampered, wrong algorithm, malformed) — the catch
172
+ block handles the response. Do not throw manually.
173
+ On success, extract three fields from the decoded payload:
174
+ - `user_id` — numeric user identifier
175
+ - `user_type` — role or type string
176
+ - `version` — integer session version issued at login time
177
+ If any of these three fields is missing or undefined — call
178
+ sendResponse with 401, keyword `rest_keywords_tokeninvalid`,
179
+ response code `"-1"`. Log at debug level. Return immediately.
180
+ Do not call next().
181
+
182
+ 6. If match — log success at info level with the path. Call `next()`.
183
+
184
+ 7. In the catch block — any decryption failure (malformed cipher, wrong
185
+ key, encoding corruption) sends 401 with the same keyword. Log at
186
+ info level only — not error level — because this is an expected
187
+ attack surface. Never expose the decryption error detail to the
188
+ client.
189
+
190
+ ---
191
+
192
+ ### validateToken(req, res, next)
193
+
194
+ **Purpose**: Verify caller identity on protected routes using a JWT that
195
+ travels AES-encrypted in a custom header. Uses Redis for session version
196
+ checking to enforce logout invalidation without a database query on
197
+ every request.
198
+
199
+ **Flow**:
200
+
201
+ 1. Split `req.path` by `/` and extract `pathSegments[2]` as the route
202
+ identifier.
203
+
204
+ 2. If `bypassMethod` includes the route identifier — log the bypass at
205
+ info level, call `next()`, and return immediately. No token check
206
+ for public routes.
207
+
208
+ 3. Read the `token` header from `req.headers`. If absent or empty —
209
+ send 401 with keyword `rest_keywords_tokeninvalid` and response code
210
+ `"-1"`. Do not call `next()`.
211
+
212
+ 4. Inside a try/catch block:
213
+ Call `decrypt(encryptedToken)` from `utilities/encryption.js`.
214
+ Strip all whitespace characters from the decrypted result.
215
+ Strip surrounding double-quote characters if present.
216
+ If the cleaned result is an empty string — throw an error immediately
217
+ with a descriptive message such as "Empty token after decryption".
218
+
219
+ 5. Verify the decrypted string as a JWT:
220
+ Call `jsonwebtoken.verify(token, JWT_SECRET, { algorithms: ['HS256'] })`.
221
+ JWT_SECRET is the module-level constant loaded at startup from
222
+ process.env.KEY — the same key used by common.generateSessionCode
223
+ to sign the token. Algorithm must be HS256 — the same algorithm
224
+ used at signing time.
225
+ If verification fails for any reason (expired, tampered, wrong
226
+ algorithm, malformed) — throw. Let the catch block handle the response.
227
+ On success, extract three fields from the decoded payload:
228
+ - `user_id` — numeric user identifier
229
+ - `user_type` — role or type string
230
+ - `version` — integer session version issued at login time
231
+ If any of these three fields is missing or undefined in the decoded
232
+ payload — throw immediately.
233
+
234
+ 6. Query Redis using the ioRedis client from `utilities/ioRedis.js`:
235
+ Convert `user_id` to a string. Call `redis.get(user_id_string)`.
236
+ The stored value is a plain integer string — the current valid
237
+ session version for this user.
238
+ If the Redis key does not exist (returns null) — the user has no
239
+ active session. Send 401 with keyword `rest_keywords_tokeninvalid`.
240
+ Do not call `next()`.
241
+
242
+ 7. Parse the Redis value as an integer. Call it `redisVersion`.
243
+ Compare with the `version` from the JWT payload:
244
+ - If JWT version is greater than or equal to redisVersion —
245
+ session is valid. Proceed.
246
+ - If JWT version is less than redisVersion — the session was
247
+ invalidated (user logged in elsewhere or was logged out).
248
+ Send 401 with keyword `rest_keywords_tokeninvalid`.
249
+ Log at info level: user_id, JWT version, Redis version.
250
+ Do not call `next()`.
251
+
252
+ 8. On successful validation — attach to the request:
253
+ - `req.user_id` — the numeric user ID from the JWT payload
254
+ - `req.user_type` — the user type string from the JWT payload
255
+ Log at info level: token validated, user_id, user_type.
256
+ Call `next()`.
257
+
258
+ 9. In the catch block — this handles only genuine exceptions from
259
+ jsonwebtoken.verify() (malformed token, wrong algorithm, expired).
260
+ Call sendResponse with 401, keyword `rest_keywords_tokeninvalid`,
261
+ response code `"-1"`. Log at debug level with the error message.
262
+ Never expose JWT internals or decryption details to the client.
263
+ All other failure conditions (empty token, missing payload fields,
264
+ Redis null, version mismatch) are handled inline above with direct
265
+ sendResponse calls and early returns — they never reach this catch.
266
+
267
+ ---
268
+
269
+ ### decryptRequest(req, res, next)
270
+
271
+ **Generation rule**:
272
+ Read `context.services[<name>].encrypted_transport`.
273
+ - If `false` — do not generate this function at all. It will not exist
274
+ in the file and will not be exported. No reference to it anywhere.
275
+ - If `true` — generate this function as described below.
276
+
277
+ **Purpose**: Global middleware that decrypts the incoming request body
278
+ before any route handler runs. Applied in route_manager.js as part of
279
+ the global middleware chain — not per-route. Only generated when
280
+ `encrypted_transport == true`.
281
+
282
+ **Flow**:
283
+
284
+ 1. Check the HTTP method via `req.method`. If the method is `"GET"` or
285
+ `"DELETE"` — call `next()` immediately and return. These methods
286
+ carry no body by convention. Decrypting an empty body causes
287
+ unnecessary errors.
288
+
289
+ 2. Check `req.originalUrl` for demo route patterns. If the URL contains
290
+ `/decryption_demo` or `/encryption_demo` — call `next()` immediately.
291
+ These routes are used for testing and receive raw unencrypted bodies.
292
+
293
+ 3. If `req.body` is absent, null, undefined, or an empty string — set
294
+ `req.body` to an empty object `{}` and call `next()` without
295
+ attempting decryption.
296
+
297
+ 4. Inside a try/catch — call `decrypt(req.body)` from
298
+ `utilities/encryption.js`. Replace `req.body` entirely with the
299
+ decrypted and JSON-parsed result.
300
+
301
+ 5. If `req.body.user_id` is undefined after decryption — inject it from
302
+ `req.user_id` if that value was set by `validateToken`, otherwise
303
+ set to `0`. This ensures every downstream model function receives
304
+ `req.body.user_id` without needing to check two sources.
305
+
306
+ 6. Log at info level: decryption successful, request path.
307
+ Call `next()`.
308
+
309
+ 7. In the catch block — log at error level with the full error. Send a
310
+ 500 response with keyword `rest_keywords_decryption_failure` using
311
+ `sendResponse`.
312
+
313
+ ---
314
+
315
+ ## Redis Session Version Contract
316
+
317
+ This is the source of truth for the login/logout version system. All
318
+ agents that generate login, logout, and session management logic must
319
+ follow this contract exactly.
320
+
321
+ - On every successful login:
322
+ Read current version from Redis for this user_id.
323
+ If the key exists — increment the stored value by 1.
324
+ If the key does not exist — set it to 1.
325
+ Store using `redis.set(user_id_string, newVersion)` with no expiry.
326
+ Issue the JWT with `version: newVersion` in the payload.
327
+
328
+ - On logout:
329
+ Increment the Redis version by 1. Do not delete the key.
330
+ All existing JWTs for this user become stale immediately because their
331
+ version value will now be less than the Redis value.
332
+
333
+ - On validateToken:
334
+ JWT version must be greater than or equal to Redis version.
335
+ Less than means logged out or superseded by a newer login —
336
+ treat as invalid.
337
+
338
+ - On force-logout all devices:
339
+ Set the Redis value to any number greater than the highest issued JWT
340
+ version for this user. All tokens across all devices become invalid
341
+ simultaneously without touching the database.
342
+
343
+ ---
344
+
345
+ ## Export
346
+
347
+ Export as a plain object:
348
+ `module.exports = headerValidator`
349
+
350
+ Exported keys when `encrypted_transport == true`:
351
+ `extractLanguage`, `validateApiKey`, `validateToken`, `decryptRequest`
352
+
353
+ Exported keys when `encrypted_transport == false`:
354
+ `extractLanguage`, `validateApiKey`, `validateToken`
355
+
356
+ Do not export any encryption functions, response functions, getMessage,
357
+ or checkValidationRules from this file — those live in their own utility
358
+ files.
359
+
360
+ ---
361
+
362
+ ## What This File Does NOT Do
363
+
364
+ - Does not call crypto-js or cryptlib directly — all crypto goes through
365
+ `utilities/encryption.js`
366
+ - Does not call `res.json()` or `res.status()` directly — all responses
367
+ go through `utilities/response.js`
368
+ - Does not perform field-level request validation — that is in
369
+ `utilities/validator.js`
370
+ - Does not connect to the database — token validation uses Redis only
371
+ - Does not use RSA PEM keys — JWT uses HMAC-SHA256 (HS256) with
372
+ process.env.KEY, consistent with how tokens are signed in
373
+ config/common.js generateSessionCode
374
+ - Does not define getMessage, sendResponse, encrypt, or
375
+ checkValidationRules — those live in their own utility files
376
+ - Does not generate decryptRequest when `encrypted_transport == false` —
377
+ the function simply does not exist in the file in that case
@@ -0,0 +1,114 @@
1
+ ---
2
+ type: task
3
+ name: generate-ide-configs
4
+ ---
5
+
6
+ # Task: Generate IDE Configuration Files
7
+
8
+ ## Purpose
9
+ Confirms IDE configuration status when @initialize-project runs.
10
+
11
+ All IDE config files are written automatically during `codeninja init`
12
+ (the npm install step), NOT during this task. This task exists only to
13
+ surface the confirmation to the user so they know their IDE is connected.
14
+
15
+ If for any reason the config files are missing (e.g. the developer
16
+ copied .codeninja manually without running init), this task re-creates them.
17
+
18
+ ---
19
+
20
+ ## When to Run
21
+
22
+ Called from `initialize-project.workflow.md` at step 23b.
23
+ Only runs on the FIRST @initialize-project in this repo.
24
+
25
+ ---
26
+
27
+ ## What to Check and Report
28
+
29
+ ### File 1 — .vscode/mcp.json
30
+ Check if `.vscode/mcp.json` exists.
31
+ - If YES → report ✓ already configured
32
+ - If NO → create it:
33
+
34
+ ```json
35
+ {
36
+ "servers": {
37
+ "codeninja": {
38
+ "type": "stdio",
39
+ "command": "node",
40
+ "args": ["${workspaceFolder}/.codeninja/mcp-server.js"]
41
+ }
42
+ }
43
+ }
44
+ ```
45
+
46
+ Note: VS Code uses `"servers"` not `"mcpServers"`.
47
+ Note: `${workspaceFolder}` is a VS Code variable — write it literally.
48
+
49
+ ---
50
+
51
+ ### File 2 — .cursor/mcp.json
52
+ Check if `.cursor/mcp.json` exists.
53
+ - If YES → report ✓ already configured
54
+ - If NO → create it:
55
+
56
+ ```json
57
+ {
58
+ "mcpServers": {
59
+ "codeninja": {
60
+ "command": "node",
61
+ "args": [".codeninja/mcp-server.js"]
62
+ }
63
+ }
64
+ }
65
+ ```
66
+
67
+ ---
68
+
69
+ ### File 3 — Antigravity (~/.gemini/antigravity/mcp_config.json)
70
+ Antigravity uses a GLOBAL config file outside the project.
71
+ Check if the codeninja entry exists in it.
72
+ - If YES → report ✓ already configured
73
+ - If NO → inform the user it should have been written by `codeninja init`
74
+ and show them the manual fallback:
75
+
76
+ ```
77
+ ─── Antigravity (manual fallback) ───────────────────────
78
+ Config file: ~/.gemini/antigravity/mcp_config.json
79
+ (Windows: %USERPROFILE%\.gemini\antigravity\mcp_config.json)
80
+
81
+ Add inside "mcpServers":
82
+
83
+ "codeninja": {
84
+ "command": "node",
85
+ "args": ["/ABSOLUTE/PATH/TO/PROJECT/.codeninja/mcp-server.js"]
86
+ }
87
+
88
+ Then go to Antigravity → ... → MCP Servers → Manage MCP Servers → Refresh.
89
+ ─────────────────────────────────────────────────────────
90
+ ```
91
+
92
+ ---
93
+
94
+ ### Claude Desktop — Print Only
95
+ Claude Desktop config lives outside the project.
96
+ Always print this reminder block regardless of whether it was already set up.
97
+
98
+ ```
99
+ ─── Claude Desktop (manual step — one time only) ──────
100
+ Config file:
101
+ macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
102
+ Windows: %APPDATA%\Claude\claude_desktop_config.json
103
+ Linux: ~/.config/claude/claude_desktop_config.json
104
+
105
+ Add inside "mcpServers":
106
+
107
+ "codeninja": {
108
+ "command": "node",
109
+ "args": ["/ABSOLUTE/PATH/TO/PROJECT/.codeninja/mcp-server.js"]
110
+ }
111
+
112
+ Save and restart Claude Desktop.
113
+ ─────────────────────────────────────────────────────────
114
+ ```
@@ -0,0 +1,120 @@
1
+ ---
2
+ type: task
3
+ name: generate-ioRedis
4
+ agent: nodejs-agent
5
+ ---
6
+
7
+ # File: utilities/ioRedis.js
8
+
9
+ ## Purpose
10
+ Creates, configures, and exports a single ioredis connection instance.
11
+ All files that need Redis (headerValidator for token version checking,
12
+ model files for caching) import this single shared connection. The
13
+ connection is established once at module load time.
14
+
15
+ This task also defines the Redis installation and startup commands that
16
+ the agent outputs to the developer as part of the `@initialize-project`
17
+ final summary, so the developer can get Redis running locally before
18
+ starting the service.
19
+
20
+ ---
21
+
22
+ ## Dependencies to Import
23
+
24
+ - `ioredis` — imported as `IORedis` (capital letters). The Redis client
25
+ library.
26
+ - `../logger/logging` — imported as `log`. Used for connection success
27
+ and failure logging.
28
+
29
+ ---
30
+
31
+ ## Module-Level Variables
32
+
33
+ ### connection
34
+ Declared with `let` before the try/catch block so it is in scope for
35
+ the export line. Initialized inside the try block.
36
+
37
+ ---
38
+
39
+ ## Connection Setup
40
+
41
+ Wrap the entire connection creation in a try/catch block.
42
+
43
+ Inside try:
44
+ Create `new IORedis` instance with these configuration values:
45
+ - `host` — read from `process.env.REDIS_HOST`. This value is already
46
+ in `.env` from the initialize-project workflow.
47
+ - `port` — read from `process.env.REDIS_PORT` parsed as an integer.
48
+ - `maxRetriesPerRequest: null` — required when using ioredis with
49
+ BullMQ or any queue library. Also prevents ioredis from throwing
50
+ on commands during reconnection. Set this always regardless of
51
+ whether queues are used — it is a safe default.
52
+
53
+ After successful instantiation — log at info level with message
54
+ "Successfully connected to Redis" and include host and port values.
55
+
56
+ Inside catch:
57
+ Log at error level with message "Failed to connect to Redis" and the
58
+ error object. Re-throw the error. A Redis connection failure at startup
59
+ is unrecoverable — the service should not start without Redis since
60
+ token validation depends on it.
61
+
62
+ ---
63
+
64
+ ## Redis Setup Instructions (output by agent in final summary)
65
+
66
+ When this file is generated, the agent appends the following Redis
67
+ setup instructions to the `@initialize-project` final summary output.
68
+ These are not written into the file itself — they are printed to the
69
+ developer as next steps.
70
+
71
+ ### macOS (Homebrew)
72
+ ```
73
+ brew install redis
74
+ brew services start redis
75
+ ```
76
+
77
+ ### Ubuntu / Debian Linux
78
+ ```
79
+ sudo apt update
80
+ sudo apt install redis-server
81
+ sudo systemctl start redis
82
+ sudo systemctl enable redis
83
+ ```
84
+
85
+ ### Windows
86
+ ```
87
+ winget install Redis.Redis
88
+ redis-server
89
+ ```
90
+
91
+ ### Verify Redis is running (all platforms)
92
+ ```
93
+ redis-cli ping
94
+ ```
95
+ Expected response: `PONG`
96
+
97
+ ---
98
+
99
+ ## Export
100
+ ```
101
+ module.exports = connection
102
+ ```
103
+
104
+ The connection instance is exported directly. Imported as:
105
+ `const redis = require('../utilities/ioRedis')`
106
+
107
+ Then used as: `redis.get(key)`, `redis.set(key, value)`, etc.
108
+
109
+ ---
110
+
111
+ ## What This File Does NOT Do
112
+
113
+ - Does not define any Redis helper functions — raw ioredis methods are
114
+ used directly by callers
115
+ - Does not implement retry logic beyond ioredis built-in reconnection
116
+ - Does not expire keys — TTL decisions belong to the caller
117
+ - Does not implement pub/sub — that would be a separate connection
118
+ instance if needed
119
+ - Does not fall back to in-memory storage if Redis is unavailable —
120
+ startup failure is the correct behavior