@ivannikov-pro/ai-context-surgeon 1.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.
- package/LICENSE +22 -0
- package/README.md +372 -0
- package/bin/catalog.js +153 -0
- package/bin/cli.js +380 -0
- package/bin/installer.js +135 -0
- package/bin/prompts.js +371 -0
- package/checklists/phase-1-analysis.md +58 -0
- package/checklists/phase-2-planning.md +67 -0
- package/checklists/phase-3-restructuring.md +77 -0
- package/checklists/phase-4-documentation.md +111 -0
- package/checklists/phase-5-validation.md +91 -0
- package/examples/before-after/README.md +139 -0
- package/examples/ideal-monorepo/README.md +127 -0
- package/knowledge/agent-context-system/artifacts/guide.md +183 -0
- package/knowledge/agent-context-system/artifacts/knowledge.md +177 -0
- package/knowledge/agent-context-system/artifacts/skills.md +101 -0
- package/knowledge/agent-context-system/artifacts/workflows.md +143 -0
- package/knowledge/agent-context-system/metadata.json +26 -0
- package/knowledge/agent-context-system/timestamps.json +5 -0
- package/knowledge/agent-vulnerabilities/LICENSE +21 -0
- package/knowledge/agent-vulnerabilities/artifacts/stealth_injection.md +110 -0
- package/knowledge/agent-vulnerabilities/artifacts/vulnerabilities.md +232 -0
- package/knowledge/agent-vulnerabilities/metadata.json +14 -0
- package/knowledge/agent-vulnerabilities/timestamps.json +5 -0
- package/knowledge/power-words-dictionary/LICENSE +21 -0
- package/knowledge/power-words-dictionary/artifacts/dictionary.md +231 -0
- package/knowledge/power-words-dictionary/artifacts/prompt_amplifier.py +381 -0
- package/knowledge/power-words-dictionary/metadata.json +14 -0
- package/knowledge/power-words-dictionary/timestamps.json +5 -0
- package/package.json +77 -0
- package/roles/README.md +81 -0
- package/roles/architect.md +203 -0
- package/roles/inspector.md +232 -0
- package/roles/librarian.md +176 -0
- package/roles/scout.md +169 -0
- package/roles/surgeon.md +172 -0
- package/roles/tuner.md +204 -0
- package/skills/annotate-jsdoc/SKILL.md +262 -0
- package/skills/prompt-engineering/LICENSE +21 -0
- package/skills/prompt-engineering/SKILL.md +235 -0
- package/skills/prompt-engineering/scripts/extract_instructions.py +416 -0
- package/skills/prompt-engineering/scripts/prompt_amplifier.py +381 -0
- package/skills/prompt-engineering/scripts/prompt_diff_tracker.py +281 -0
- package/skills/prompt-engineering/scripts/prompt_dna_analyzer.py +692 -0
- package/skills/prompt-engineering/scripts/templates/code_review.md +47 -0
- package/skills/prompt-engineering/scripts/templates/dump_extraction.md +59 -0
- package/skills/prompt-engineering/scripts/templates/multi_agent_orchestration.md +100 -0
- package/skills/prompt-engineering/scripts/templates/prompt_audit.md +106 -0
- package/skills/prompt-engineering/scripts/templates/stealth_injection.md +110 -0
- package/skills/prompt-engineering/scripts/templates/task_automation.md +87 -0
- package/skills/prompt-engineering/workflows/amplify.md +36 -0
- package/skills/prompt-engineering/workflows/audit.md +55 -0
- package/skills/prompt-engineering/workflows/context-dump.md +90 -0
- package/skills/prompt-engineering/workflows/diff.md +44 -0
- package/strategy/bash-guide.md +134 -0
- package/strategy/context-exclusion.md +220 -0
- package/strategy/context-weight-theory.md +49 -0
- package/strategy/file-navigation-header.md +562 -0
- package/strategy/jsdoc-guide.md +596 -0
- package/strategy/monorepo_strategy.md +726 -0
- package/strategy/package-json-guide.md +541 -0
- package/templates/AGENTS.md.template +148 -0
- package/templates/antigravityignore.template +64 -0
- package/templates/cursorrules.template +7 -0
- package/templates/knowledge-item.template +44 -0
- package/templates/package-json-ideal.template +26 -0
- package/templates/package-readme.template +45 -0
- package/templates/publish-meta.template +34 -0
- package/templates/skill.template +50 -0
- package/templates/workflow.template +33 -0
- package/tools/analyze-package-json.sh +213 -0
- package/tools/analyze-structure.sh +101 -0
- package/tools/audit-jsdoc.sh +176 -0
- package/tools/check-fnh-freshness.sh +74 -0
- package/tools/detect-circular-deps.sh +147 -0
- package/tools/detect-god-files.sh +71 -0
- package/tools/enforce-god-files.sh +112 -0
- package/tools/enrich-package-json.js +311 -0
- package/tools/generate-jsdoc-headers.sh +109 -0
- package/tools/generate-source-map.sh +71 -0
- package/tools/lint-imports.sh +123 -0
- package/tools/measure-context-cost.sh +206 -0
- package/tools/scan-fnh.sh +174 -0
- package/tools/shared/config.sh +53 -0
- package/tools/validate-context-hygiene.sh +52 -0
- package/tools/validate-context-weight.sh +100 -0
- package/tools/validate-naming.sh +98 -0
|
@@ -0,0 +1,596 @@
|
|
|
1
|
+
<!-- FNH: Strategy — JSDoc standard for AI agents | SECTIONS: Density, Identifiers, Filtering, Barrel Files | DEPS: none -->
|
|
2
|
+
|
|
3
|
+
# 📝 JSDoc for AI Agents — Not for Humans, but for Machines
|
|
4
|
+
|
|
5
|
+
> Guide: how to comment code so that the AI spends minimum tokens on understanding | SECTIONS: Density Rules, First Line Rule, Context Tags, Deprecation | DEPS: none
|
|
6
|
+
|
|
7
|
+
> [!IMPORTANT]
|
|
8
|
+
> **AI AGENT FIRST Manifesto**: We do not optimize for human readability. Humans ideally will never look at this code. YOU (the AI Agent) write the code, and YOU read the code. The codebase is formatted exclusively to improve **your** "life". JSDoc exists to make parsing and reasoning easy for a machine interpreter, not to generate pretty HTML documentation for humans.
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## How an Agent Reads a File
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
Step 1: list_dir("src/services/")
|
|
16
|
+
→ Sees 15 file names
|
|
17
|
+
→ Chooses a candidate by name
|
|
18
|
+
|
|
19
|
+
Step 2: view_file("user.service.ts", lines=1-5) ← EVERYTHING IS DECIDED HERE
|
|
20
|
+
→ Reads FIRST LINES
|
|
21
|
+
→ Decides: "is this the right file?" in 10-20 tokens
|
|
22
|
+
→ If yes — reads further
|
|
23
|
+
→ If no — moves to the next file
|
|
24
|
+
|
|
25
|
+
Step 3: view_file("user.service.ts")
|
|
26
|
+
→ Reads the entire file
|
|
27
|
+
→ Looks for a specific function/class
|
|
28
|
+
→ Each JSDoc block = context tokens
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
**Conclusion**: The first line of the file is the most valuable real estate in the repo.
|
|
32
|
+
Every JSDoc block inside the file is a tradeoff between usefulness and cost.
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## File Header: One Line, Maximum Meaning
|
|
37
|
+
|
|
38
|
+
### Format
|
|
39
|
+
|
|
40
|
+
```typescript
|
|
41
|
+
/** <Category>: <Name> — <Purpose> | EXPORTS: <... > | ROUTES: <...> | DEPS: <...> | <Gotchas> */
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Anatomy (5 Mandatory Layers)
|
|
45
|
+
|
|
46
|
+
As defined in `strategy/file-navigation-header.md`, a complete FNH uses 5 layers:
|
|
47
|
+
|
|
48
|
+
```
|
|
49
|
+
/** Service: UserService — CRUD + auth | EXPORTS: create, getById | DEPS: prisma, bcrypt | @throws Conflict */
|
|
50
|
+
↑ ↑ ↑ ↑ ↑ ↑
|
|
51
|
+
Category Name Purpose Exports Dependencies Gotchas (Layer 5)
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
**Cost**: ~15–25 tokens. The agent immediately knows: type, purpose, dependencies.
|
|
55
|
+
|
|
56
|
+
### Categories (Standardized)
|
|
57
|
+
|
|
58
|
+
Use a **fixed vocabulary** of categories. The agent learns the pattern and predicts the content:
|
|
59
|
+
|
|
60
|
+
| Category | Purpose | Example |
|
|
61
|
+
| --- | --- | --- | --- |
|
|
62
|
+
| `Service` | Business logic | `/** Service: OrderService — create, validate, fulfill orders */` |
|
|
63
|
+
| `Route` | HTTP endpoint | `/** Route: POST /api/v1/users — user registration + validation */` |
|
|
64
|
+
| `Middleware` | Request pipeline | `/** Middleware: AuthGuard — JWT verify, sets req.user, 401 on fail */` |
|
|
65
|
+
| `Controller` | Request handler | `/** Controller: PaymentController — Stripe webhook + checkout flow */` |
|
|
66
|
+
| `Repository` | Data access | `/** Repository: UserRepo — Prisma CRUD for users table */` |
|
|
67
|
+
| `Entity` | Domain model | `/\*\* Entity: Order — id, items[], status, total | immutable after PAID \*/` |
|
|
68
|
+
| `Types` | Type definitions | `/** Types: User DTOs — CreateUserInput, UpdateUserInput, UserResponse */` |
|
|
69
|
+
| `Utility` | Helper functions | `/** Utility: date — formatISO, parseRelative, diffDays */` |
|
|
70
|
+
| `Config` | Configuration | `/** Config: database — Prisma client init, connection pool settings */` |
|
|
71
|
+
| `Schema` | Validation | `/** Schema: user.validation — Zod schemas for user input endpoints */` |
|
|
72
|
+
| `Hook` | React hook | `/** Hook: useAuth — login/logout/refresh, returns { user, isLoading } */` |
|
|
73
|
+
| `Component` | React component | `/** Component: UserCard — displays user avatar + name + role badge */` |
|
|
74
|
+
| `Test` | Test suite | `/** Test: UserService — unit tests for CRUD + edge cases */` |
|
|
75
|
+
| `Migration` | DB migration | `/** Migration: 003 — add phone column to users, backfill from profiles */` |
|
|
76
|
+
| `Script` | CLI/build script | `/** Script: seed — populates dev DB with 100 users + 500 orders */` |
|
|
77
|
+
| `Constants` | Enums/constants | `/** Constants: http-status — SUCCESS, CREATED, BAD_REQUEST, ... */` |
|
|
78
|
+
| `Factory` | Object creation | `/** Factory: createTestUser — generates User with random valid data */` |
|
|
79
|
+
| `Adapter` | External integration | `/** Adapter: StripeClient — wraps Stripe SDK, handles retry + logging */` |
|
|
80
|
+
| `Event` | Event definitions | `/** Event: OrderEvents — CREATED, PAID, SHIPPED, DELIVERED, CANCELLED */` |
|
|
81
|
+
| `Guard` | Access control | `/** Guard: RoleGuard — checks req.user.role against allowed roles */` |
|
|
82
|
+
|
|
83
|
+
### Examples — Good vs Bad
|
|
84
|
+
|
|
85
|
+
```typescript
|
|
86
|
+
// ✅ PERFECT: 1 line, everything is clear
|
|
87
|
+
/** Service: UserService — CRUD + password hashing + email uniqueness check | deps: prisma, bcrypt */
|
|
88
|
+
|
|
89
|
+
// ✅ GOOD: 1 line, sufficient
|
|
90
|
+
/** Route: GET/POST /api/v1/orders — list orders (paginated) + create order */
|
|
91
|
+
|
|
92
|
+
// 🟡 ACCEPTABLE: if 1 line cannot contain critical info
|
|
93
|
+
/** Middleware: RateLimiter — sliding window, 100req/min per IP | MUTATES: req.rateLimit */
|
|
94
|
+
|
|
95
|
+
// ❌ BAD: multiline JSDoc for the file — wasteful
|
|
96
|
+
/**
|
|
97
|
+
* @fileoverview This module provides the UserService class which handles
|
|
98
|
+
* all user-related business logic including creation, updating, deletion,
|
|
99
|
+
* and authentication of user entities in the system.
|
|
100
|
+
*
|
|
101
|
+
* @module services/user
|
|
102
|
+
* @requires prisma
|
|
103
|
+
* @requires bcrypt
|
|
104
|
+
* @author John Doe
|
|
105
|
+
* @since 2024-01-15
|
|
106
|
+
* @version 2.3.1
|
|
107
|
+
*/
|
|
108
|
+
|
|
109
|
+
// ❌ TERRIBLE: empty/meaningless comment
|
|
110
|
+
/** User service */
|
|
111
|
+
/** This file contains the user service */
|
|
112
|
+
/** @module user */
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
## Functions and Methods: Only What TypeScript Doesn't Say
|
|
118
|
+
|
|
119
|
+
### Golden Rule
|
|
120
|
+
|
|
121
|
+
> **If the TypeScript signature fully describes the behavior — JSDoc is not needed.**
|
|
122
|
+
> JSDoc is only needed for what is **not visible from types**: side effects, throws, mutations, non-obvious logic.
|
|
123
|
+
|
|
124
|
+
### What TypeScript ALREADY Says (JSDoc = Noise)
|
|
125
|
+
|
|
126
|
+
```typescript
|
|
127
|
+
// ❌ JSDoc duplicates types — pure noise, +20 tokens for zero information
|
|
128
|
+
/**
|
|
129
|
+
* Creates a new user
|
|
130
|
+
* @param {string} name - The user's name
|
|
131
|
+
* @param {string} email - The user's email
|
|
132
|
+
* @returns {Promise<User>} The created user
|
|
133
|
+
*/
|
|
134
|
+
async function createUser(name: string, email: string): Promise<User>;
|
|
135
|
+
|
|
136
|
+
// ✅ Types speak for themselves — JSDoc is not needed
|
|
137
|
+
async function createUser(name: string, email: string): Promise<User>;
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### What TypeScript DOES NOT Say (JSDoc = Value)
|
|
141
|
+
|
|
142
|
+
```typescript
|
|
143
|
+
// ✅ THROWS — return type does not show errors
|
|
144
|
+
/** @throws {ConflictError} if email already exists */
|
|
145
|
+
async function createUser(input: CreateUserInput): Promise<User>;
|
|
146
|
+
|
|
147
|
+
// ✅ SIDE EFFECTS — invisible in signature
|
|
148
|
+
/** Sends welcome email after creation. Logs to audit trail. */
|
|
149
|
+
async function createUser(input: CreateUserInput): Promise<User>;
|
|
150
|
+
|
|
151
|
+
// ✅ MUTATES — argument mutation is not visible from types
|
|
152
|
+
/** @mutates req.user — sets authenticated user from JWT payload */
|
|
153
|
+
function authMiddleware(req: Request, res: Response, next: NextFunction): void;
|
|
154
|
+
|
|
155
|
+
// ✅ NON-OBVIOUS LOGIC — algorithm is not obvious from name
|
|
156
|
+
/** Uses bcrypt with 12 rounds. Compares timing-safe. */
|
|
157
|
+
async function verifyPassword(plain: string, hash: string): Promise<boolean>;
|
|
158
|
+
|
|
159
|
+
// ✅ CONSTRAINTS — business rules invisible from types
|
|
160
|
+
/** Max 100 items per order. Throws if total > $10,000 without manager approval. */
|
|
161
|
+
async function createOrder(items: OrderItem[]): Promise<Order>;
|
|
162
|
+
|
|
163
|
+
// ✅ PERFORMANCE — critical information
|
|
164
|
+
/** O(n²) — avoid for arrays > 1000 items. Use batchProcess() instead. */
|
|
165
|
+
function processItems(items: Item[]): Result[];
|
|
166
|
+
|
|
167
|
+
// ✅ DEPRECATION + MIGRATION PATH
|
|
168
|
+
/** @deprecated Use UserServiceV2.create() — this ignores email verification */
|
|
169
|
+
async function createUser(name: string, email: string): Promise<User>;
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
---
|
|
173
|
+
|
|
174
|
+
## Priority JSDoc Tag Map
|
|
175
|
+
|
|
176
|
+
### 🔴 Tier 1 — Critical (Agent MUST see)
|
|
177
|
+
|
|
178
|
+
These tags communicate what **cannot be inferred from the code**:
|
|
179
|
+
|
|
180
|
+
| Tag | Purpose | Tokens | Example |
|
|
181
|
+
| --- | --- | --- | --- |
|
|
182
|
+
| `@throws` | Which errors it throws | ~8–15 | `@throws {NotFoundError} if user doesn't exist` |
|
|
183
|
+
| `@mutates` | What it mutates (non-standard but valuable) | ~5–10 | `@mutates req.user` |
|
|
184
|
+
| `@sideeffect` | Side effects | ~8–15 | `Sends email. Writes audit log.` |
|
|
185
|
+
| `@deprecated` | Do not use + alternative | ~10–15 | `@deprecated Use v2/createUser instead` |
|
|
186
|
+
| `@important` / inline `⚠️` | Critical gotcha | ~10–20 | `⚠️ NOT idempotent — calling twice creates duplicate` |
|
|
187
|
+
|
|
188
|
+
### 🟡 Tier 2 — Useful (Situational)
|
|
189
|
+
|
|
190
|
+
| Tag | When needed | Tokens | Example |
|
|
191
|
+
| --- | --- | --- | --- |
|
|
192
|
+
| `@returns` | If return is non-obvious from type | ~5–10 | `@returns null if not found (not undefined)` |
|
|
193
|
+
| `@example` | If API is counterintuitive | ~15–40 | Compact example |
|
|
194
|
+
| `@see` | If there is a related function | ~5 | `@see UserService.update` |
|
|
195
|
+
| `@default` | If default is not visible | ~3 | `@default 30` |
|
|
196
|
+
| `@async` | (TS doesn't need it, JS without types does) | ~2 | — |
|
|
197
|
+
|
|
198
|
+
### 🟢 Tier 3 — Noise (Do not write)
|
|
199
|
+
|
|
200
|
+
| Tag | Why it's noise | Tokens Wasted |
|
|
201
|
+
| --- | --- | --- |
|
|
202
|
+
| `@param {type}` | TypeScript already knows types | ~10–30 per param |
|
|
203
|
+
| `@returns {type}` | TypeScript already knows return type | ~5–10 |
|
|
204
|
+
| `@type` | That is TypeScript's job | ~5 |
|
|
205
|
+
| `@typedef` | Use `type`/`interface` | ~15–30 |
|
|
206
|
+
| `@callback` | Use `type` | ~15–30 |
|
|
207
|
+
| `@template` | Use generics | ~5–10 |
|
|
208
|
+
| `@readonly` | Use `readonly` modifier | ~3 |
|
|
209
|
+
| `@abstract` | Use `abstract` keyword | ~3 |
|
|
210
|
+
| `@override` | Use `override` keyword | ~3 |
|
|
211
|
+
| `@implements` | Obvious from class declaration | ~5 |
|
|
212
|
+
|
|
213
|
+
### ⚫ Tier 4 — Harmful (Remove)
|
|
214
|
+
|
|
215
|
+
| Tag | Why harmful | Tokens Wasted |
|
|
216
|
+
| --- | --- | --- |
|
|
217
|
+
| `@author` | Agent doesn't care who wrote it | ~5–10 |
|
|
218
|
+
| `@since` | Agent doesn't care when added | ~5 |
|
|
219
|
+
| `@version` | git blame is better | ~3 |
|
|
220
|
+
| `@copyright` | Legally meaningless in code | ~10–20 |
|
|
221
|
+
| `@license` | Already in LICENSE file | ~3–5 |
|
|
222
|
+
| `@date` | git log is better | ~5 |
|
|
223
|
+
| `@todo` | Use issues/tasks | ~5–15 |
|
|
224
|
+
| `@hack` / `@fixme` | Use issues | ~5–15 |
|
|
225
|
+
| `@fileoverview` | Replaced by 1-line `/**` header | ~30–80 |
|
|
226
|
+
| `@module` | Obvious from filename | ~5 |
|
|
227
|
+
| `@namespace` | Obvious from structure | ~5 |
|
|
228
|
+
| `@memberof` | Obvious from class structure | ~5 |
|
|
229
|
+
| `@classdesc` | Obvious from class name | ~10–20 |
|
|
230
|
+
| `@constructs` | Obvious from `constructor` | ~5 |
|
|
231
|
+
| `@fires` / `@emits` | Better inline `// emits: 'order.created'` | ~10 |
|
|
232
|
+
| `@listens` | Better inline | ~10 |
|
|
233
|
+
| `@augments` / `@extends` | Obvious from `extends` keyword | ~5 |
|
|
234
|
+
|
|
235
|
+
---
|
|
236
|
+
|
|
237
|
+
## One-Line Annotation Format
|
|
238
|
+
|
|
239
|
+
For maximum density — use **inline format**, not block:
|
|
240
|
+
|
|
241
|
+
```typescript
|
|
242
|
+
// ✅ Inline — 1 line, ~15 tokens
|
|
243
|
+
/** @throws {ConflictError} email exists | @mutates db.users */
|
|
244
|
+
async function createUser(input: CreateUserInput): Promise<User> {
|
|
245
|
+
|
|
246
|
+
// ❌ Block — 5 lines, ~40 tokens (same data, 3x more expensive)
|
|
247
|
+
/**
|
|
248
|
+
* Creates a new user in the database.
|
|
249
|
+
* @throws {ConflictError} Thrown when email already exists
|
|
250
|
+
* @mutates db.users - Inserts a new row into the users table
|
|
251
|
+
*/
|
|
252
|
+
async function createUser(input: CreateUserInput): Promise<User> {
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
### Compact Method Annotations
|
|
256
|
+
|
|
257
|
+
```typescript
|
|
258
|
+
class UserService {
|
|
259
|
+
/** @throws NotFound */
|
|
260
|
+
async getById(id: string): Promise<User> { ... }
|
|
261
|
+
|
|
262
|
+
/** @throws Conflict(email) | sends welcome email */
|
|
263
|
+
async create(input: CreateUserInput): Promise<User> { ... }
|
|
264
|
+
|
|
265
|
+
/** @throws NotFound | partial update, merges with existing */
|
|
266
|
+
async update(id: string, patch: Partial<User>): Promise<User> { ... }
|
|
267
|
+
|
|
268
|
+
/** @throws NotFound | soft delete (sets deletedAt) */
|
|
269
|
+
async delete(id: string): Promise<void> { ... }
|
|
270
|
+
|
|
271
|
+
/** bcrypt 12 rounds | timing-safe compare */
|
|
272
|
+
async verifyPassword(plain: string, hashed: string): Promise<boolean> { ... }
|
|
273
|
+
}
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
**5 methods, 5 JSDoc lines, ~60 tokens.** The agent knows all the gotchas.
|
|
277
|
+
|
|
278
|
+
---
|
|
279
|
+
|
|
280
|
+
## Scenarios: When to Write What
|
|
281
|
+
|
|
282
|
+
### Scenario 1: Simple CRUD Function
|
|
283
|
+
|
|
284
|
+
```typescript
|
|
285
|
+
// Type tells everything. No JSDoc needed.
|
|
286
|
+
async function getUsers(filter: UserFilter): Promise<User[]> {
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
### Scenario 2: Function with Hidden Behavior
|
|
290
|
+
|
|
291
|
+
```typescript
|
|
292
|
+
/** @throws NotFound | returns cached for 60s, invalidates on update */
|
|
293
|
+
async function getUserById(id: string): Promise<User> {
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
### Scenario 3: Middleware with Mutation
|
|
297
|
+
|
|
298
|
+
```typescript
|
|
299
|
+
/** @mutates req.user, req.permissions | 401 if no token, 403 if insufficient role */
|
|
300
|
+
function authorize(...roles: Role[]): Middleware {
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
### Scenario 4: Complex Function with Business Rules
|
|
304
|
+
|
|
305
|
+
```typescript
|
|
306
|
+
/** Max 50 items | free shipping > $100 | @throws OutOfStock, InvalidCoupon | sends confirmation email */
|
|
307
|
+
async function checkout(cart: Cart, coupon?: string): Promise<Order> {
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
### Scenario 5: Utility without Surprises
|
|
311
|
+
|
|
312
|
+
```typescript
|
|
313
|
+
// Name and types tell everything. Zero JSDoc.
|
|
314
|
+
function formatCurrency(amount: number, currency: Currency): string {
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
### Scenario 6: Re-export / Barrel File
|
|
318
|
+
|
|
319
|
+
```typescript
|
|
320
|
+
/** Barrel: public API for @project/core — entities, services, types */
|
|
321
|
+
export { User, Order } from "./entities";
|
|
322
|
+
export { UserService, OrderService } from "./services";
|
|
323
|
+
export type { CreateUserInput, OrderDTO } from "./types";
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
### Scenario 7: Global Dependency Version Pegging
|
|
327
|
+
|
|
328
|
+
AI Agents know global packages up to their training cutoff date. If an API has changed, the agent will hallucinate. Keep global dependencies annotated with versions (either in FNH `DEPS` or directly on the import).
|
|
329
|
+
|
|
330
|
+
```typescript
|
|
331
|
+
// ✅ Annotate directly on the import
|
|
332
|
+
import { useState } from 'react'; // React 18
|
|
333
|
+
import { ReentrancyGuard } from '@openzeppelin/contracts/security/ReentrancyGuard.sol'; // OpenZeppelin ^5.6.0
|
|
334
|
+
|
|
335
|
+
// ✅ Or annotate in the FNH header
|
|
336
|
+
/** Component: UserCard — renders profile | DEPS: react 18, framer-motion 11 */
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
---
|
|
340
|
+
|
|
341
|
+
## JS (Without TypeScript) — Different Rules
|
|
342
|
+
|
|
343
|
+
Without types, JSDoc takes on more work. But **it remains compact**:
|
|
344
|
+
|
|
345
|
+
```javascript
|
|
346
|
+
/** @param {string} id @returns {Promise<User|null>} @throws {DatabaseError} */
|
|
347
|
+
async function getUserById(id) { ... }
|
|
348
|
+
|
|
349
|
+
/** @param {{name: string, email: string}} input @returns {Promise<User>} @throws {ConflictError} email exists */
|
|
350
|
+
async function createUser(input) { ... }
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
Rule: **In JS files, @param and @returns are needed** (they substitute types).
|
|
354
|
+
But write them **on a single line**, not in a multi-line block.
|
|
355
|
+
|
|
356
|
+
---
|
|
357
|
+
|
|
358
|
+
## Quantitative Analysis
|
|
359
|
+
|
|
360
|
+
### Typical File: 200 Lines of Code
|
|
361
|
+
|
|
362
|
+
| JSDoc Style | JSDoc Lines | Tokens | Useful Information |
|
|
363
|
+
| --- | --- | --- | --- |
|
|
364
|
+
| ⚫ Enterprise Style (full) | 80 | ~400 | ~60 tokens really useful |
|
|
365
|
+
| 🟡 Moderate | 25 | ~120 | ~80 tokens really useful |
|
|
366
|
+
| ✅ **AI-Optimized** | 8 | ~50 | ~45 tokens really useful |
|
|
367
|
+
| ❌ No documentation | 0 | 0 | Agent wastes ~200 tokens guessing |
|
|
368
|
+
|
|
369
|
+
**AI-optimized style**: 8x fewer lines, 8x cheaper, same (or greater) usefulness.
|
|
370
|
+
|
|
371
|
+
### JSDoc Utility Formula
|
|
372
|
+
|
|
373
|
+
```
|
|
374
|
+
Utility = (information_invisible_from_types) / (JSDoc_tokens)
|
|
375
|
+
|
|
376
|
+
Enterprise: 60 / 400 = 0.15 ← 85% noise
|
|
377
|
+
Moderate: 80 / 120 = 0.67 ← 33% noise
|
|
378
|
+
AI-optim: 45 / 50 = 0.90 ← 10% noise ← IDEAL
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
---
|
|
382
|
+
|
|
383
|
+
## Checklist: Bring JSDoc to AI Optimum
|
|
384
|
+
|
|
385
|
+
### File Level
|
|
386
|
+
|
|
387
|
+
- [ ] Every file starts with a one-line `/** Category: Name — what it does */`
|
|
388
|
+
- [ ] Category from standard vocabulary (Service, Route, Middleware, ...)
|
|
389
|
+
- [ ] Contains key deps if non-obvious
|
|
390
|
+
|
|
391
|
+
### Functions/Methods
|
|
392
|
+
|
|
393
|
+
- [ ] No `@param {type}` in TypeScript files (types visible from signature)
|
|
394
|
+
- [ ] No `@returns {type}` in TypeScript files
|
|
395
|
+
- [ ] Has `@throws` for every thrown error
|
|
396
|
+
- [ ] Has annotation for side effects (email, logging, cache)
|
|
397
|
+
- [ ] Has annotation for mutations (req.user, state changes)
|
|
398
|
+
- [ ] Everything on a single line where possible
|
|
399
|
+
|
|
400
|
+
### Remove
|
|
401
|
+
|
|
402
|
+
- [ ] No `@author`, `@since`, `@version`, `@copyright`, `@license`
|
|
403
|
+
- [ ] No `@fileoverview` (replaced by 1-line header)
|
|
404
|
+
- [ ] No `@module` (visible from filename)
|
|
405
|
+
- [ ] No `@todo`, `@hack`, `@fixme` (move to issues)
|
|
406
|
+
- [ ] No type duplication in JSDoc
|
|
407
|
+
|
|
408
|
+
---
|
|
409
|
+
|
|
410
|
+
## Full Example: File Before and After
|
|
411
|
+
|
|
412
|
+
### ❌ BEFORE (Enterprise JSDoc) — 55 JSDoc Lines, ~280 tokens
|
|
413
|
+
|
|
414
|
+
```typescript
|
|
415
|
+
/**
|
|
416
|
+
* @fileoverview User Service Module
|
|
417
|
+
*
|
|
418
|
+
* This module provides the UserService class which handles all user-related
|
|
419
|
+
* business logic including creation, retrieval, updating, and deletion of
|
|
420
|
+
* user entities. It also manages password hashing and email verification.
|
|
421
|
+
*
|
|
422
|
+
* @module services/user
|
|
423
|
+
* @requires @prisma/client
|
|
424
|
+
* @requires bcrypt
|
|
425
|
+
* @author John Doe <john@example.com>
|
|
426
|
+
* @since 2024-01-15
|
|
427
|
+
* @version 2.3.1
|
|
428
|
+
* @copyright 2024 Acme Corp
|
|
429
|
+
* @license MIT
|
|
430
|
+
*/
|
|
431
|
+
|
|
432
|
+
import { PrismaClient } from '@prisma/client';
|
|
433
|
+
import bcrypt from 'bcrypt';
|
|
434
|
+
|
|
435
|
+
/**
|
|
436
|
+
* Service class for managing user entities.
|
|
437
|
+
* Provides CRUD operations and authentication helpers.
|
|
438
|
+
*
|
|
439
|
+
* @class UserService
|
|
440
|
+
* @classdesc Handles user business logic
|
|
441
|
+
*/
|
|
442
|
+
export class UserService {
|
|
443
|
+
/**
|
|
444
|
+
* Creates a new user in the database.
|
|
445
|
+
*
|
|
446
|
+
* @async
|
|
447
|
+
* @method create
|
|
448
|
+
* @memberof UserService
|
|
449
|
+
* @param {Object} input - The user creation input
|
|
450
|
+
* @param {string} input.name - The user's display name
|
|
451
|
+
* @param {string} input.email - The user's email address
|
|
452
|
+
* @param {string} input.password - The user's plain text password
|
|
453
|
+
* @returns {Promise<User>} The newly created user object
|
|
454
|
+
* @throws {ConflictError} When a user with the same email already exists
|
|
455
|
+
* @fires user.created
|
|
456
|
+
* @example
|
|
457
|
+
* const user = await userService.create({
|
|
458
|
+
* name: 'John',
|
|
459
|
+
* email: 'john@example.com',
|
|
460
|
+
* password: 'secure123'
|
|
461
|
+
* });
|
|
462
|
+
*/
|
|
463
|
+
async create(input: CreateUserInput): Promise<User> {
|
|
464
|
+
```
|
|
465
|
+
|
|
466
|
+
### ✅ AFTER (AI-Optimized) — 4 JSDoc Lines, ~40 tokens
|
|
467
|
+
|
|
468
|
+
```typescript
|
|
469
|
+
/** Service: UserService — CRUD + auth for users | deps: prisma, bcrypt */
|
|
470
|
+
import { PrismaClient } from '@prisma/client';
|
|
471
|
+
import bcrypt from 'bcrypt';
|
|
472
|
+
|
|
473
|
+
export class UserService {
|
|
474
|
+
/** @throws Conflict(email) | hashes password (bcrypt 12) | sends welcome email */
|
|
475
|
+
async create(input: CreateUserInput): Promise<User> {
|
|
476
|
+
```
|
|
477
|
+
|
|
478
|
+
**Result: 7x fewer tokens, all critical information preserved.**
|
|
479
|
+
Lost: author, date, copyright, example, parameter types — nothing the agent needs.
|
|
480
|
+
|
|
481
|
+
---
|
|
482
|
+
|
|
483
|
+
## Headers for Non-Code Files (MD, YAML, JSON, etc.)
|
|
484
|
+
|
|
485
|
+
JSDoc syntax (`/** */`) only works in JS/TS. But the **concept** of one-line context is needed EVERYWHERE. Here is the format for each file type:
|
|
486
|
+
|
|
487
|
+
### Markdown (.md)
|
|
488
|
+
|
|
489
|
+
Use an HTML comment on line 1 (The First Line Rule), AND a `>` blockquote right after H1. They work in tandem:
|
|
490
|
+
|
|
491
|
+
```markdown
|
|
492
|
+
<!-- FNH: Package — domain entities | EXPORTS: User, Order | DEPS: @project/shared -->
|
|
493
|
+
|
|
494
|
+
# @project/core
|
|
495
|
+
|
|
496
|
+
> Package: Domain entities, services, and repositories | DEPS: @project/shared | ENTRY: src/index.ts
|
|
497
|
+
```
|
|
498
|
+
|
|
499
|
+
The agent reads the first line for rapid parsing, and the blockquote for deeper context.
|
|
500
|
+
|
|
501
|
+
**Categories for Markdown files:**
|
|
502
|
+
|
|
503
|
+
| Format | Purpose | Example |
|
|
504
|
+
| --- | --- | --- |
|
|
505
|
+
| `> Package: ...` | Package README | `> Package: REST API — Express + Zod + Prisma middleware` |
|
|
506
|
+
| `> Guide: ...` | Documentation/guide | `> Guide: API conventions — request/response format, error codes, pagination` |
|
|
507
|
+
| `> Role: ...` | Role prompt | `> Role: Scout — read-only analysis, Gemini Flash, produces scout-report.md` |
|
|
508
|
+
| `> Checklist: ...` | Checklist | `> Checklist: Phase 3 — restructuring steps with build checkpoints` |
|
|
509
|
+
| `> Knowledge: ...` | Knowledge Item | `> Knowledge: Auth flow — JWT lifecycle, bcrypt rounds, role hierarchy` |
|
|
510
|
+
| `> Skill: ...` | Skill desc (frontmatter) | `> Skill: annotate-jsdoc — AI-optimized JSDoc headers for source files` |
|
|
511
|
+
| `> Architecture: ...` | Architectural doc | `> Architecture: migration plan — 12 steps, leaves-first, build checkpoints` |
|
|
512
|
+
| `> Report: ...` | Report | `> Report: scout analysis — 47 files, 3 god-files, no AGENTS.md` |
|
|
513
|
+
|
|
514
|
+
**Examples:**
|
|
515
|
+
|
|
516
|
+
```markdown
|
|
517
|
+
# API Conventions
|
|
518
|
+
|
|
519
|
+
> Knowledge: API response format, error codes, and pagination patterns for all endpoints
|
|
520
|
+
|
|
521
|
+
---
|
|
522
|
+
|
|
523
|
+
# Phase 3: Restructuring
|
|
524
|
+
|
|
525
|
+
> Checklist: 15 migration steps with build checkpoints | Role: Surgeon | Model: Gemini 3.1 Pro
|
|
526
|
+
|
|
527
|
+
---
|
|
528
|
+
|
|
529
|
+
# Scout Report: MyProject
|
|
530
|
+
|
|
531
|
+
> Report: 847 files, 12 packages, 5 god-files, 0 READMEs, no AGENTS.md | estimated 25K tokens waste
|
|
532
|
+
```
|
|
533
|
+
|
|
534
|
+
### YAML (.yml, .yaml)
|
|
535
|
+
|
|
536
|
+
Use a `#` comment on the first line:
|
|
537
|
+
|
|
538
|
+
```yaml
|
|
539
|
+
# Config: GitHub Actions CI — build + test + lint on push/PR | Node 18+
|
|
540
|
+
name: CI
|
|
541
|
+
on: [push, pull_request]
|
|
542
|
+
```
|
|
543
|
+
|
|
544
|
+
```yaml
|
|
545
|
+
# Config: Turbo pipeline — build depends on ^build, test depends on build
|
|
546
|
+
{ "$schema": "https://turbo.build/schema.json", "pipeline": { ... } }
|
|
547
|
+
```
|
|
548
|
+
|
|
549
|
+
### JSON (no comments — use name + description)
|
|
550
|
+
|
|
551
|
+
JSON doesn't support comments. Therefore `name` + `description` in package.json **is** the header:
|
|
552
|
+
|
|
553
|
+
```json
|
|
554
|
+
{
|
|
555
|
+
"name": "@project/core",
|
|
556
|
+
"description": "Domain entities + business logic | deps: prisma, shared"
|
|
557
|
+
}
|
|
558
|
+
```
|
|
559
|
+
|
|
560
|
+
For JSON configs without `description` (tsconfig, etc.) — the agent relies on the file name. That is fine.
|
|
561
|
+
|
|
562
|
+
### Shell scripts (.sh)
|
|
563
|
+
|
|
564
|
+
```bash
|
|
565
|
+
#!/bin/bash
|
|
566
|
+
# Tool: analyze-structure — count files, detect god-files, measure depth | POSIX, read-only
|
|
567
|
+
```
|
|
568
|
+
|
|
569
|
+
### Dockerfiles
|
|
570
|
+
|
|
571
|
+
```dockerfile
|
|
572
|
+
# Config: production Node.js image — multi-stage, node:18-alpine, distroless final
|
|
573
|
+
FROM node:18-alpine AS builder
|
|
574
|
+
```
|
|
575
|
+
|
|
576
|
+
### Format Summary Table
|
|
577
|
+
|
|
578
|
+
| File Type | Header Syntax | Example |
|
|
579
|
+
| --- | --- | --- |
|
|
580
|
+
| `.ts` / `.js` | `/** Category: Name — desc */` | `/** Service: UserService — CRUD + auth */` |
|
|
581
|
+
| `.md` | `> Category: desc` (after H1) | `> Package: REST API — Express + Zod` |
|
|
582
|
+
| `.yml` / `.yaml` | `# Category: desc` | `# Config: CI pipeline — build + test` |
|
|
583
|
+
| `.json` | `"description": "..."` | `"description": "Domain logic"` |
|
|
584
|
+
| `.sh` | `# Category: desc` | `# Tool: analyze — count files` |
|
|
585
|
+
| `Dockerfile` | `# Category: desc` | `# Config: production image` |
|
|
586
|
+
| `.env` | `# Category: desc` | `# Config: local env — API keys, DB URL` |
|
|
587
|
+
| `.sql` | `-- Category: desc` | `-- Migration: add phone to users` |
|
|
588
|
+
| `.py` | `"""Category: desc"""` | `"""Script: seed — 100 users"""` |
|
|
589
|
+
|
|
590
|
+
### Rule: Every File in the Repo MUST Have a Context Header
|
|
591
|
+
|
|
592
|
+
Regardless of format. If the agent opens a file and cannot understand WHAT it is from the first 2 lines — the file is not optimized.
|
|
593
|
+
|
|
594
|
+
---
|
|
595
|
+
|
|
596
|
+
_ai-context-surgeon / strategy | 2026-04-04_
|