@ema.co/mcp-toolkit 2026.1.25 → 2026.1.26-4
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.
Potentially problematic release.
This version of @ema.co/mcp-toolkit might be problematic. Click here for more details.
- package/README.md +10 -2
- package/dist/mcp/handlers/action/index.js +3 -18
- package/dist/mcp/handlers/data/index.js +385 -41
- package/dist/mcp/handlers/data/templates.js +107 -0
- package/dist/mcp/handlers/deprecation.js +50 -0
- package/dist/mcp/handlers/env/index.js +8 -4
- package/dist/mcp/handlers/knowledge/index.js +44 -237
- package/dist/mcp/handlers/persona/create.js +47 -18
- package/dist/mcp/handlers/persona/index.js +14 -11
- package/dist/mcp/handlers/persona/update.js +4 -2
- package/dist/mcp/handlers/persona/version.js +234 -0
- package/dist/mcp/handlers/sync/index.js +3 -18
- package/dist/mcp/handlers/template/index.js +75 -10
- package/dist/mcp/handlers/workflow/analyze.js +171 -0
- package/dist/mcp/handlers/workflow/compare.js +70 -0
- package/dist/mcp/handlers/workflow/deploy.js +73 -0
- package/dist/mcp/handlers/workflow/generate.js +350 -0
- package/dist/mcp/handlers/workflow/index.js +294 -0
- package/dist/mcp/handlers/workflow/modify.js +456 -0
- package/dist/mcp/handlers/workflow/optimize.js +136 -0
- package/dist/mcp/handlers/workflow/types.js +4 -0
- package/dist/mcp/handlers/workflow/utils.js +30 -0
- package/dist/mcp/handlers-consolidated.js +73 -2696
- package/dist/mcp/prompts.js +83 -43
- package/dist/mcp/resources.js +382 -57
- package/dist/mcp/server.js +199 -391
- package/dist/mcp/{tools-v2.js → tools.js} +20 -54
- package/dist/mcp/workflow-operations.js +2 -2
- package/dist/sdk/client-adapter.js +267 -32
- package/dist/sdk/client.js +45 -16
- package/dist/sdk/ema-client.js +183 -0
- package/dist/sdk/generated/deprecated-actions.js +171 -0
- package/dist/sdk/generated/template-fallbacks.js +123 -0
- package/dist/sdk/guidance.js +65 -11
- package/dist/sdk/index.js +3 -1
- package/dist/sdk/knowledge.js +139 -86
- package/dist/sdk/workflow-intent.js +27 -0
- package/dist/sdk/workflow-transformer.js +0 -342
- package/docs/mcp-tools-guide.md +37 -45
- package/package.json +10 -4
- package/dist/mcp/handlers/persona/analyze.js +0 -275
- package/dist/mcp/handlers/persona/compare.js +0 -32
- package/dist/mcp/tools-consolidated.js +0 -875
- package/dist/mcp/tools-legacy.js +0 -736
- package/docs/CODEBASE-ANALYSIS-2026-01-23.md +0 -936
- package/docs/CODEBASE-ANALYSIS-PRIORITIZED.md +0 -774
- package/docs/api-contracts.md +0 -216
- package/docs/auto-builder-analysis.md +0 -271
- package/docs/blog/mcp-tool-design-lessons.md +0 -309
- package/docs/data-architecture.md +0 -166
- package/docs/demos/ap-invoice-generation.md +0 -347
- package/docs/demos/ap-invoice-processing.md +0 -271
- package/docs/ema-auto-builder-guide.html +0 -394
- package/docs/lessons-learned.md +0 -209
- package/docs/llm-native-workflow-design.md +0 -252
- package/docs/local-generation.md +0 -508
- package/docs/mcp-flow-diagram.md +0 -135
- package/docs/migration/action-composition-migration.md +0 -270
- package/docs/naming-conventions.md +0 -278
- package/docs/proposals/HANDOFF-tool-restructure.md +0 -526
- package/docs/proposals/action-composition.md +0 -490
- package/docs/proposals/explicit-method-restructure.md +0 -328
- package/docs/proposals/mcp-tool-restructure-2026-01.md +0 -366
- package/docs/proposals/self-contained-guidance.md +0 -427
- package/docs/proto-sdk-generation.md +0 -242
- package/docs/release-impact.md +0 -102
- package/docs/release-process.md +0 -157
- package/docs/staging.RULE.md +0 -142
- package/docs/test-persona-creation.md +0 -196
- package/docs/tool-consolidation-v2.md +0 -225
- package/docs/tool-response-standards.md +0 -256
- package/resources/demo-kits/README.md +0 -175
- package/resources/demo-kits/finance-ap/manifest.json +0 -150
- package/resources/demo-kits/tags.json +0 -91
- package/resources/docs/getting-started.md +0 -97
- package/resources/templates/auto-builder-rules.md +0 -224
- package/resources/templates/chat-ai/README.md +0 -119
- package/resources/templates/chat-ai/persona-config.json +0 -111
- package/resources/templates/dashboard-ai/README.md +0 -156
- package/resources/templates/dashboard-ai/persona-config.json +0 -180
- package/resources/templates/demo-scenarios/README.md +0 -63
- package/resources/templates/demo-scenarios/test-published-package.md +0 -116
- package/resources/templates/document-gen-ai/README.md +0 -132
- package/resources/templates/document-gen-ai/persona-config.json +0 -316
- package/resources/templates/voice-ai/README.md +0 -123
- package/resources/templates/voice-ai/persona-config.json +0 -74
- package/resources/templates/voice-ai/workflow-prompt.md +0 -121
|
@@ -1,774 +0,0 @@
|
|
|
1
|
-
# Prioritized Codebase Issues
|
|
2
|
-
|
|
3
|
-
**Date**: January 23, 2026
|
|
4
|
-
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
## Impact vs Effort Matrix
|
|
8
|
-
|
|
9
|
-
```
|
|
10
|
-
HIGH IMPACT
|
|
11
|
-
│
|
|
12
|
-
┌────────────────────┼────────────────────┐
|
|
13
|
-
│ │ │
|
|
14
|
-
│ QUICK WINS │ BIG BETS │
|
|
15
|
-
│ (Do First) │ (Plan Carefully) │
|
|
16
|
-
│ │ │
|
|
17
|
-
LOW ├────────────────────┼────────────────────┤ HIGH
|
|
18
|
-
EFFORT │ EFFORT
|
|
19
|
-
│ │ │
|
|
20
|
-
│ FILL-INS │ MONEY PITS │
|
|
21
|
-
│ (If Time) │ (Avoid/Defer) │
|
|
22
|
-
│ │ │
|
|
23
|
-
└────────────────────┼────────────────────┘
|
|
24
|
-
│
|
|
25
|
-
LOW IMPACT
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
---
|
|
29
|
-
|
|
30
|
-
## Section 1: Quick Wins (High Impact, Low Effort)
|
|
31
|
-
|
|
32
|
-
These deliver immediate value with minimal risk. Do these first.
|
|
33
|
-
|
|
34
|
-
### QW-1: Add Graceful Shutdown Handler
|
|
35
|
-
|
|
36
|
-
**Effort**: 30 min | **Impact**: Prevents data corruption, resource leaks
|
|
37
|
-
|
|
38
|
-
```typescript
|
|
39
|
-
// src/mcp/server.ts - Add near server initialization
|
|
40
|
-
process.on("SIGTERM", () => {
|
|
41
|
-
server.close();
|
|
42
|
-
process.exit(0);
|
|
43
|
-
});
|
|
44
|
-
process.on("SIGINT", () => {
|
|
45
|
-
server.close();
|
|
46
|
-
process.exit(0);
|
|
47
|
-
});
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
---
|
|
51
|
-
|
|
52
|
-
### QW-2: Extract Shared EmaApiError Class
|
|
53
|
-
|
|
54
|
-
**Effort**: 30 min | **Impact**: Eliminates duplicate code, single source of truth
|
|
55
|
-
|
|
56
|
-
**Files to change**:
|
|
57
|
-
|
|
58
|
-
- Create `src/sdk/errors.ts`
|
|
59
|
-
- Update `src/sdk/client.ts`
|
|
60
|
-
- Update `src/sdk/ema-client.ts`
|
|
61
|
-
|
|
62
|
-
```typescript
|
|
63
|
-
// src/sdk/errors.ts
|
|
64
|
-
export class EmaApiError extends Error {
|
|
65
|
-
constructor(
|
|
66
|
-
message: string,
|
|
67
|
-
public readonly statusCode: number,
|
|
68
|
-
public readonly body: unknown,
|
|
69
|
-
) {
|
|
70
|
-
super(message);
|
|
71
|
-
this.name = "EmaApiError";
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
```
|
|
75
|
-
|
|
76
|
-
---
|
|
77
|
-
|
|
78
|
-
### QW-3: Add Coverage Thresholds
|
|
79
|
-
|
|
80
|
-
**Effort**: 15 min | **Impact**: Prevents test coverage regression
|
|
81
|
-
|
|
82
|
-
```typescript
|
|
83
|
-
// vitest.config.ts - Add to coverage section
|
|
84
|
-
coverage: {
|
|
85
|
-
thresholds: {
|
|
86
|
-
lines: 70,
|
|
87
|
-
functions: 70,
|
|
88
|
-
branches: 60,
|
|
89
|
-
statements: 70
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
```
|
|
93
|
-
|
|
94
|
-
---
|
|
95
|
-
|
|
96
|
-
### QW-4: Use structuredClone Instead of JSON.parse/stringify
|
|
97
|
-
|
|
98
|
-
**Effort**: 1 hour | **Impact**: 30-50% faster cloning, lower memory
|
|
99
|
-
|
|
100
|
-
**Files**: `src/sdk/client.ts:494`, `src/mcp/handlers-consolidated.ts:1137`, `src/sync.ts:149`
|
|
101
|
-
|
|
102
|
-
```typescript
|
|
103
|
-
// Before
|
|
104
|
-
const cloned = JSON.parse(JSON.stringify(workflow));
|
|
105
|
-
|
|
106
|
-
// After
|
|
107
|
-
const cloned = structuredClone(workflow);
|
|
108
|
-
```
|
|
109
|
-
|
|
110
|
-
---
|
|
111
|
-
|
|
112
|
-
### QW-5: Consolidate checkDeprecatedParams
|
|
113
|
-
|
|
114
|
-
**Effort**: 45 min | **Impact**: DRY, single place to update
|
|
115
|
-
|
|
116
|
-
**Current locations** (delete from):
|
|
117
|
-
|
|
118
|
-
- `src/mcp/handlers-consolidated.ts:219`
|
|
119
|
-
- `src/mcp/handlers/sync/index.ts:16`
|
|
120
|
-
- `src/mcp/handlers/action/index.ts:20`
|
|
121
|
-
|
|
122
|
-
**Move to**: `src/mcp/handlers/utils.ts` (already exists)
|
|
123
|
-
|
|
124
|
-
---
|
|
125
|
-
|
|
126
|
-
### QW-6: Fix Unknown Action Type Silent Fallback
|
|
127
|
-
|
|
128
|
-
**Effort**: 30 min | **Impact**: Prevents silent runtime errors
|
|
129
|
-
|
|
130
|
-
```typescript
|
|
131
|
-
// src/sdk/workflow-transformer.ts:392-415
|
|
132
|
-
function mapToActionType(rawName: string): ActionType | 'unknown' {
|
|
133
|
-
const mapping: Record<string, ActionType> = { ... };
|
|
134
|
-
const result = mapping[rawName];
|
|
135
|
-
if (!result) {
|
|
136
|
-
console.warn(`Unknown action type: ${rawName}, preserving as-is`);
|
|
137
|
-
return 'unknown';
|
|
138
|
-
}
|
|
139
|
-
return result;
|
|
140
|
-
}
|
|
141
|
-
```
|
|
142
|
-
|
|
143
|
-
---
|
|
144
|
-
|
|
145
|
-
### QW-7: Add Workflow Namespace Validation
|
|
146
|
-
|
|
147
|
-
**Effort**: 30 min | **Impact**: Prevents silent deployment failures
|
|
148
|
-
|
|
149
|
-
```typescript
|
|
150
|
-
// src/sdk/workflow-transformer.ts - Add before line 552
|
|
151
|
-
function validateWorkflowNamespace(ns: unknown): boolean {
|
|
152
|
-
if (!ns || typeof ns !== "object") return false;
|
|
153
|
-
const namespace = ns as { namespaces?: unknown[]; name?: string };
|
|
154
|
-
return (
|
|
155
|
-
Array.isArray(namespace.namespaces) && typeof namespace.name === "string"
|
|
156
|
-
);
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
// Then use it
|
|
160
|
-
if (!validateWorkflowNamespace(originalDef.workflowName)) {
|
|
161
|
-
throw new Error("Invalid workflow namespace structure");
|
|
162
|
-
}
|
|
163
|
-
compiled.workflow_def.workflowName = originalDef.workflowName;
|
|
164
|
-
```
|
|
165
|
-
|
|
166
|
-
---
|
|
167
|
-
|
|
168
|
-
### Quick Wins Summary
|
|
169
|
-
|
|
170
|
-
| ID | Task | Effort | Impact |
|
|
171
|
-
| ---- | ---------------------------- | ------ | ----------------- |
|
|
172
|
-
| QW-1 | Graceful shutdown | 30 min | Data safety |
|
|
173
|
-
| QW-2 | Extract EmaApiError | 30 min | DRY |
|
|
174
|
-
| QW-3 | Coverage thresholds | 15 min | Quality gate |
|
|
175
|
-
| QW-4 | Use structuredClone | 1 hour | Performance |
|
|
176
|
-
| QW-5 | Consolidate deprecated check | 45 min | DRY |
|
|
177
|
-
| QW-6 | Fix action type fallback | 30 min | Error prevention |
|
|
178
|
-
| QW-7 | Namespace validation | 30 min | Deployment safety |
|
|
179
|
-
|
|
180
|
-
**Total Quick Wins**: ~4 hours for 7 high-impact fixes
|
|
181
|
-
|
|
182
|
-
---
|
|
183
|
-
|
|
184
|
-
## Section 2: Security Fixes (Must Do)
|
|
185
|
-
|
|
186
|
-
Security issues grouped by attack surface.
|
|
187
|
-
|
|
188
|
-
### SEC-1: Input Validation (HIGH)
|
|
189
|
-
|
|
190
|
-
**Effort**: 4 hours | **Impact**: Prevents injection, corruption
|
|
191
|
-
|
|
192
|
-
**Add Zod validation at handler entry points**:
|
|
193
|
-
|
|
194
|
-
```typescript
|
|
195
|
-
// src/mcp/handlers/utils.ts - Add
|
|
196
|
-
import { z } from "zod";
|
|
197
|
-
|
|
198
|
-
export const PersonaIdSchema = z.string().uuid();
|
|
199
|
-
export const FilePathSchema = z
|
|
200
|
-
.string()
|
|
201
|
-
.refine((p) => !p.includes("..") && !p.startsWith("/"), "Invalid file path");
|
|
202
|
-
|
|
203
|
-
// Use in handlers
|
|
204
|
-
const id = PersonaIdSchema.parse(args.id);
|
|
205
|
-
```
|
|
206
|
-
|
|
207
|
-
**Priority handlers**:
|
|
208
|
-
|
|
209
|
-
1. `handlePersona` - persona CRUD
|
|
210
|
-
2. `handleData` - file operations
|
|
211
|
-
3. `handleKnowledge` - file uploads
|
|
212
|
-
|
|
213
|
-
---
|
|
214
|
-
|
|
215
|
-
### SEC-2: Path Traversal Fix (CRITICAL)
|
|
216
|
-
|
|
217
|
-
**Effort**: 1 hour | **Impact**: Prevents unauthorized file access
|
|
218
|
-
|
|
219
|
-
```typescript
|
|
220
|
-
// src/mcp/handlers/utils.ts - Add
|
|
221
|
-
export function validateAndResolvePath(
|
|
222
|
-
userPath: string,
|
|
223
|
-
baseDir: string,
|
|
224
|
-
): string {
|
|
225
|
-
const resolved = path.resolve(baseDir, userPath);
|
|
226
|
-
const normalized = path.normalize(resolved);
|
|
227
|
-
|
|
228
|
-
if (!normalized.startsWith(path.resolve(baseDir))) {
|
|
229
|
-
throw new Error("Path traversal detected");
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
return normalized;
|
|
233
|
-
}
|
|
234
|
-
```
|
|
235
|
-
|
|
236
|
-
**Apply to**:
|
|
237
|
-
|
|
238
|
-
- `src/mcp/server.ts:3930-3937` (file upload)
|
|
239
|
-
- `src/mcp/server.ts:4140-4149` (file operations)
|
|
240
|
-
|
|
241
|
-
---
|
|
242
|
-
|
|
243
|
-
### SEC-3: Sanitize Error Messages (HIGH)
|
|
244
|
-
|
|
245
|
-
**Effort**: 2 hours | **Impact**: Prevents information disclosure
|
|
246
|
-
|
|
247
|
-
```typescript
|
|
248
|
-
// src/sdk/errors.ts - Add
|
|
249
|
-
export function sanitizeErrorForResponse(error: unknown): string {
|
|
250
|
-
if (error instanceof EmaApiError) {
|
|
251
|
-
// Log full details internally
|
|
252
|
-
console.error("API Error", { status: error.statusCode, body: error.body });
|
|
253
|
-
// Return sanitized message
|
|
254
|
-
return `API error (${error.statusCode}): Operation failed`;
|
|
255
|
-
}
|
|
256
|
-
return error instanceof Error ? error.message : "Unknown error";
|
|
257
|
-
}
|
|
258
|
-
```
|
|
259
|
-
|
|
260
|
-
**Apply to**:
|
|
261
|
-
|
|
262
|
-
- `src/mcp/server.ts:5829`
|
|
263
|
-
- `src/sdk/client.ts:532-613`
|
|
264
|
-
|
|
265
|
-
---
|
|
266
|
-
|
|
267
|
-
### SEC-4: Debug Logging Token Safety (MEDIUM)
|
|
268
|
-
|
|
269
|
-
**Effort**: 1 hour | **Impact**: Prevents token exposure
|
|
270
|
-
|
|
271
|
-
```typescript
|
|
272
|
-
// src/sdk/logging.ts - Add
|
|
273
|
-
export function sanitizeForLogging(obj: unknown): unknown {
|
|
274
|
-
if (typeof obj !== "object" || obj === null) return obj;
|
|
275
|
-
const sanitized = { ...obj } as Record<string, unknown>;
|
|
276
|
-
const sensitiveKeys = [
|
|
277
|
-
"token",
|
|
278
|
-
"bearer",
|
|
279
|
-
"authorization",
|
|
280
|
-
"api_key",
|
|
281
|
-
"password",
|
|
282
|
-
];
|
|
283
|
-
for (const key of Object.keys(sanitized)) {
|
|
284
|
-
if (sensitiveKeys.some((k) => key.toLowerCase().includes(k))) {
|
|
285
|
-
sanitized[key] = "[REDACTED]";
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
return sanitized;
|
|
289
|
-
}
|
|
290
|
-
```
|
|
291
|
-
|
|
292
|
-
---
|
|
293
|
-
|
|
294
|
-
### Security Fixes Summary
|
|
295
|
-
|
|
296
|
-
| ID | Task | Effort | Severity |
|
|
297
|
-
| ----- | ------------------ | ------- | -------- |
|
|
298
|
-
| SEC-1 | Input validation | 4 hours | HIGH |
|
|
299
|
-
| SEC-2 | Path traversal fix | 1 hour | CRITICAL |
|
|
300
|
-
| SEC-3 | Sanitize errors | 2 hours | HIGH |
|
|
301
|
-
| SEC-4 | Token safety | 1 hour | MEDIUM |
|
|
302
|
-
|
|
303
|
-
**Total Security**: ~8 hours
|
|
304
|
-
|
|
305
|
-
---
|
|
306
|
-
|
|
307
|
-
## Section 3: Performance Fixes
|
|
308
|
-
|
|
309
|
-
Issues ordered by user-visible impact.
|
|
310
|
-
|
|
311
|
-
### PERF-1: Parallelize Sync Operations (CRITICAL)
|
|
312
|
-
|
|
313
|
-
**Effort**: 2 hours | **Impact**: 3-10x faster sync
|
|
314
|
-
|
|
315
|
-
**N+1 Query Fix** (`src/sync.ts:259-273`):
|
|
316
|
-
|
|
317
|
-
```typescript
|
|
318
|
-
// Before: Sequential
|
|
319
|
-
for (let p of personas) {
|
|
320
|
-
if (!p.workflow_def) {
|
|
321
|
-
const full = await masterClient.getPersonaById(p.id);
|
|
322
|
-
}
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
// After: Parallel batches
|
|
326
|
-
const missingWorkflow = personas.filter((p) => !p.workflow_def);
|
|
327
|
-
const batches = chunk(missingWorkflow, 10); // 10 at a time
|
|
328
|
-
for (const batch of batches) {
|
|
329
|
-
const results = await Promise.all(
|
|
330
|
-
batch.map((p) => masterClient.getPersonaById(p.id)),
|
|
331
|
-
);
|
|
332
|
-
// Merge results...
|
|
333
|
-
}
|
|
334
|
-
```
|
|
335
|
-
|
|
336
|
-
**Target Sync Fix** (`src/sync.ts:316-334`):
|
|
337
|
-
|
|
338
|
-
```typescript
|
|
339
|
-
// Before: Sequential
|
|
340
|
-
for (const target of targets) {
|
|
341
|
-
await syncToTarget(persona, target);
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
// After: Parallel
|
|
345
|
-
const results = await Promise.allSettled(
|
|
346
|
-
targets.map((target) => syncToTarget(persona, target)),
|
|
347
|
-
);
|
|
348
|
-
```
|
|
349
|
-
|
|
350
|
-
---
|
|
351
|
-
|
|
352
|
-
### PERF-2: Async File I/O (HIGH)
|
|
353
|
-
|
|
354
|
-
**Effort**: 4 hours | **Impact**: Unblocks event loop
|
|
355
|
-
|
|
356
|
-
**File**: `src/sdk/version-storage.ts`
|
|
357
|
-
|
|
358
|
-
Convert all sync operations:
|
|
359
|
-
|
|
360
|
-
```typescript
|
|
361
|
-
// Before
|
|
362
|
-
const content = fs.readFileSync(path, 'utf8');
|
|
363
|
-
fs.writeFileSync(path, data);
|
|
364
|
-
if (fs.existsSync(path)) { ... }
|
|
365
|
-
|
|
366
|
-
// After
|
|
367
|
-
import { readFile, writeFile, access } from 'fs/promises';
|
|
368
|
-
|
|
369
|
-
const content = await readFile(path, 'utf8');
|
|
370
|
-
await writeFile(path, data);
|
|
371
|
-
try {
|
|
372
|
-
await access(path);
|
|
373
|
-
// exists
|
|
374
|
-
} catch {
|
|
375
|
-
// doesn't exist
|
|
376
|
-
}
|
|
377
|
-
```
|
|
378
|
-
|
|
379
|
-
**Methods to update** (15 total):
|
|
380
|
-
|
|
381
|
-
- `getLatestSnapshot` → `getLatestSnapshotAsync`
|
|
382
|
-
- `saveSnapshot` → `saveSnapshotAsync`
|
|
383
|
-
- etc.
|
|
384
|
-
|
|
385
|
-
---
|
|
386
|
-
|
|
387
|
-
### PERF-3: Cache Prepared Statements (MEDIUM)
|
|
388
|
-
|
|
389
|
-
**Effort**: 1 hour | **Impact**: Faster SQLite queries
|
|
390
|
-
|
|
391
|
-
```typescript
|
|
392
|
-
// src/sdk/state.ts - Change pattern
|
|
393
|
-
class StateStore {
|
|
394
|
-
// Cache statements at class level
|
|
395
|
-
private readonly getMappingStmt: Statement;
|
|
396
|
-
private readonly upsertMappingStmt: Statement;
|
|
397
|
-
|
|
398
|
-
constructor(dbPath: string) {
|
|
399
|
-
this.db = new Database(dbPath);
|
|
400
|
-
// Prepare once
|
|
401
|
-
this.getMappingStmt = this.db.prepare(`SELECT ...`);
|
|
402
|
-
this.upsertMappingStmt = this.db.prepare(`INSERT ...`);
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
getMapping(id: string) {
|
|
406
|
-
return this.getMappingStmt.get(id); // Use cached
|
|
407
|
-
}
|
|
408
|
-
}
|
|
409
|
-
```
|
|
410
|
-
|
|
411
|
-
---
|
|
412
|
-
|
|
413
|
-
### PERF-4: Eliminate Double API Call (MEDIUM)
|
|
414
|
-
|
|
415
|
-
**Effort**: 1 hour | **Impact**: 50% fewer update API calls
|
|
416
|
-
|
|
417
|
-
```typescript
|
|
418
|
-
// src/sdk/client.ts:476-550
|
|
419
|
-
// Before: Always fetch existing persona
|
|
420
|
-
async updateAiEmployee(req: UpdateRequest) {
|
|
421
|
-
const existing = await this.getPersonaById(req.id); // Extra call!
|
|
422
|
-
// ...fix namespace...
|
|
423
|
-
return this.doUpdate(req);
|
|
424
|
-
}
|
|
425
|
-
|
|
426
|
-
// After: Only fetch if namespace missing
|
|
427
|
-
async updateAiEmployee(req: UpdateRequest) {
|
|
428
|
-
if (req.workflow && !hasValidNamespace(req.workflow)) {
|
|
429
|
-
const existing = await this.getPersonaById(req.id);
|
|
430
|
-
copyNamespace(existing.workflow_def, req.workflow);
|
|
431
|
-
}
|
|
432
|
-
return this.doUpdate(req);
|
|
433
|
-
}
|
|
434
|
-
```
|
|
435
|
-
|
|
436
|
-
---
|
|
437
|
-
|
|
438
|
-
### Performance Fixes Summary
|
|
439
|
-
|
|
440
|
-
| ID | Task | Effort | Speedup |
|
|
441
|
-
| ------ | --------------------- | ------- | --------- |
|
|
442
|
-
| PERF-1 | Parallelize sync | 2 hours | 3-10x |
|
|
443
|
-
| PERF-2 | Async file I/O | 4 hours | Unblocks |
|
|
444
|
-
| PERF-3 | Cache statements | 1 hour | ~20% |
|
|
445
|
-
| PERF-4 | Eliminate double call | 1 hour | 50% fewer |
|
|
446
|
-
|
|
447
|
-
**Total Performance**: ~8 hours
|
|
448
|
-
|
|
449
|
-
---
|
|
450
|
-
|
|
451
|
-
## Section 4: Architecture Fixes
|
|
452
|
-
|
|
453
|
-
Structural issues that compound over time.
|
|
454
|
-
|
|
455
|
-
### ARCH-1: Fix Circular Dependency (CRITICAL)
|
|
456
|
-
|
|
457
|
-
**Effort**: 2 hours | **Impact**: Prevents module failures
|
|
458
|
-
|
|
459
|
-
**Problem**:
|
|
460
|
-
|
|
461
|
-
```
|
|
462
|
-
src/sync.ts → imports → src/sdk/config.ts
|
|
463
|
-
src/sdk/sync.ts → imports → src/sync.ts (circular!)
|
|
464
|
-
```
|
|
465
|
-
|
|
466
|
-
**Solution**:
|
|
467
|
-
|
|
468
|
-
1. Create `src/sdk/sync-engine.ts` with core logic
|
|
469
|
-
2. Move `fingerprintPersona`, `syncOnce`, `transformWorkflowForTarget`
|
|
470
|
-
3. Have `src/sdk/sync.ts` re-export
|
|
471
|
-
4. Make `src/sync.ts` a thin wrapper or delete
|
|
472
|
-
|
|
473
|
-
```
|
|
474
|
-
src/sdk/sync-engine.ts ← NEW: core logic
|
|
475
|
-
src/sdk/sync.ts ← re-exports sync-engine
|
|
476
|
-
src/sync.ts ← DELETE or thin wrapper
|
|
477
|
-
```
|
|
478
|
-
|
|
479
|
-
---
|
|
480
|
-
|
|
481
|
-
### ARCH-2: Complete Handler Modularization (HIGH)
|
|
482
|
-
|
|
483
|
-
**Effort**: 8 hours | **Impact**: Maintainability, testability
|
|
484
|
-
|
|
485
|
-
**Current state**:
|
|
486
|
-
|
|
487
|
-
- `handlers-consolidated.ts`: 3,381 lines
|
|
488
|
-
- `server.ts`: 5,914 lines
|
|
489
|
-
|
|
490
|
-
**Target state**:
|
|
491
|
-
|
|
492
|
-
```
|
|
493
|
-
src/mcp/handlers/
|
|
494
|
-
├── persona/ ✅ Done
|
|
495
|
-
├── data/ ✅ Done
|
|
496
|
-
├── action/ ✅ Done
|
|
497
|
-
├── sync/ ✅ Done
|
|
498
|
-
├── workflow/ ❌ NEW - Extract from handlers-consolidated
|
|
499
|
-
├── version/ ❌ NEW - Extract version_* modes
|
|
500
|
-
└── utils.ts ✅ Done
|
|
501
|
-
```
|
|
502
|
-
|
|
503
|
-
**Steps**:
|
|
504
|
-
|
|
505
|
-
1. Create `src/mcp/handlers/workflow/index.ts`
|
|
506
|
-
2. Move `handleWorkflow` (962 lines) to workflow handler
|
|
507
|
-
3. Create `src/mcp/handlers/version/index.ts`
|
|
508
|
-
4. Move version modes (330 lines)
|
|
509
|
-
5. Reduce `handlers-consolidated.ts` to dispatch only
|
|
510
|
-
|
|
511
|
-
---
|
|
512
|
-
|
|
513
|
-
### ARCH-3: Split server.ts (MEDIUM)
|
|
514
|
-
|
|
515
|
-
**Effort**: 4 hours | **Impact**: Readability, maintainability
|
|
516
|
-
|
|
517
|
-
**Current**: 5,914 lines doing many things
|
|
518
|
-
|
|
519
|
-
**Target**:
|
|
520
|
-
|
|
521
|
-
```
|
|
522
|
-
src/mcp/
|
|
523
|
-
├── server.ts ← 500 lines: init, routing only
|
|
524
|
-
├── tools/
|
|
525
|
-
│ ├── index.ts ← tool registration
|
|
526
|
-
│ └── helpers.ts ← tool helpers
|
|
527
|
-
├── middleware/
|
|
528
|
-
│ └── error-handler.ts
|
|
529
|
-
└── lifecycle.ts ← startup, shutdown
|
|
530
|
-
```
|
|
531
|
-
|
|
532
|
-
---
|
|
533
|
-
|
|
534
|
-
### Architecture Fixes Summary
|
|
535
|
-
|
|
536
|
-
| ID | Task | Effort | Impact |
|
|
537
|
-
| ------ | ---------------- | ------- | --------------- |
|
|
538
|
-
| ARCH-1 | Fix circular dep | 2 hours | Stability |
|
|
539
|
-
| ARCH-2 | Extract handlers | 8 hours | Maintainability |
|
|
540
|
-
| ARCH-3 | Split server.ts | 4 hours | Readability |
|
|
541
|
-
|
|
542
|
-
**Total Architecture**: ~14 hours
|
|
543
|
-
|
|
544
|
-
---
|
|
545
|
-
|
|
546
|
-
## Section 5: Test Coverage
|
|
547
|
-
|
|
548
|
-
Focus on highest-risk untested code.
|
|
549
|
-
|
|
550
|
-
### TEST-1: SDK Client Tests (HIGH)
|
|
551
|
-
|
|
552
|
-
**Effort**: 8 hours | **Impact**: Core API client coverage
|
|
553
|
-
|
|
554
|
-
**Untested files** (highest risk):
|
|
555
|
-
|
|
556
|
-
- `src/sdk/client.ts` (2,400 lines)
|
|
557
|
-
- `src/sdk/ema-client.ts` (405 lines)
|
|
558
|
-
|
|
559
|
-
**Test approach**:
|
|
560
|
-
|
|
561
|
-
```typescript
|
|
562
|
-
// test/sdk/ema-client.test.ts
|
|
563
|
-
import { vi } from "vitest";
|
|
564
|
-
import { EmaClientV2 } from "../src/sdk/ema-client";
|
|
565
|
-
|
|
566
|
-
vi.mock("../src/sdk/generated/api-client", () => ({
|
|
567
|
-
getPersonas: vi.fn(),
|
|
568
|
-
updatePersona: vi.fn(),
|
|
569
|
-
}));
|
|
570
|
-
|
|
571
|
-
describe("EmaClientV2", () => {
|
|
572
|
-
it("handles API errors correctly", async () => {
|
|
573
|
-
// Mock 404 response
|
|
574
|
-
// Assert EmaApiError thrown
|
|
575
|
-
});
|
|
576
|
-
|
|
577
|
-
it("preserves workflow namespace on update", async () => {
|
|
578
|
-
// Critical business logic
|
|
579
|
-
});
|
|
580
|
-
});
|
|
581
|
-
```
|
|
582
|
-
|
|
583
|
-
---
|
|
584
|
-
|
|
585
|
-
### TEST-2: Workflow Validator/Optimizer Tests (MEDIUM)
|
|
586
|
-
|
|
587
|
-
**Effort**: 4 hours | **Impact**: Validation logic coverage
|
|
588
|
-
|
|
589
|
-
**Untested**:
|
|
590
|
-
|
|
591
|
-
- `src/sdk/workflow-validator.ts`
|
|
592
|
-
- `src/sdk/workflow-optimizer.ts`
|
|
593
|
-
|
|
594
|
-
---
|
|
595
|
-
|
|
596
|
-
### TEST-3: Error Path Tests (MEDIUM)
|
|
597
|
-
|
|
598
|
-
**Effort**: 4 hours | **Impact**: Resilience coverage
|
|
599
|
-
|
|
600
|
-
Add tests for:
|
|
601
|
-
|
|
602
|
-
- Network failures
|
|
603
|
-
- Timeout scenarios
|
|
604
|
-
- Malformed responses
|
|
605
|
-
- Concurrent operations
|
|
606
|
-
|
|
607
|
-
---
|
|
608
|
-
|
|
609
|
-
### Test Coverage Summary
|
|
610
|
-
|
|
611
|
-
| ID | Task | Effort | Coverage Gain |
|
|
612
|
-
| ------ | ---------------- | ------- | ------------- |
|
|
613
|
-
| TEST-1 | SDK client tests | 8 hours | +15% |
|
|
614
|
-
| TEST-2 | Validator tests | 4 hours | +5% |
|
|
615
|
-
| TEST-3 | Error path tests | 4 hours | +5% |
|
|
616
|
-
|
|
617
|
-
**Total Testing**: ~16 hours
|
|
618
|
-
|
|
619
|
-
---
|
|
620
|
-
|
|
621
|
-
## Section 6: Code Quality
|
|
622
|
-
|
|
623
|
-
Technical debt that slows development.
|
|
624
|
-
|
|
625
|
-
### QUAL-1: Reduce Type Assertions (HIGH)
|
|
626
|
-
|
|
627
|
-
**Effort**: 8 hours | **Impact**: Type safety
|
|
628
|
-
|
|
629
|
-
**Focus files** (highest assertion count):
|
|
630
|
-
|
|
631
|
-
1. `src/sdk/workflow-fixer.ts` - 4 `as unknown` casts
|
|
632
|
-
2. `src/sdk/intent-architect.ts` - 1 unsafe cast
|
|
633
|
-
3. `src/mcp/handlers-consolidated.ts` - Many `as Record<...>`
|
|
634
|
-
|
|
635
|
-
**Strategy**: Add type guards:
|
|
636
|
-
|
|
637
|
-
```typescript
|
|
638
|
-
// src/sdk/type-guards.ts
|
|
639
|
-
export function isWorkflowDef(obj: unknown): obj is WorkflowDef {
|
|
640
|
-
return (
|
|
641
|
-
typeof obj === "object" &&
|
|
642
|
-
obj !== null &&
|
|
643
|
-
"actions" in obj &&
|
|
644
|
-
Array.isArray((obj as { actions: unknown }).actions)
|
|
645
|
-
);
|
|
646
|
-
}
|
|
647
|
-
|
|
648
|
-
// Usage
|
|
649
|
-
if (!isWorkflowDef(workflowDef)) {
|
|
650
|
-
throw new Error("Invalid workflow definition");
|
|
651
|
-
}
|
|
652
|
-
// Now TypeScript knows it's WorkflowDef
|
|
653
|
-
```
|
|
654
|
-
|
|
655
|
-
---
|
|
656
|
-
|
|
657
|
-
### QUAL-2: Remove Dead Code (LOW)
|
|
658
|
-
|
|
659
|
-
**Effort**: 2 hours | **Impact**: Cleaner codebase
|
|
660
|
-
|
|
661
|
-
- Remove 100+ lines of commented code in `server.ts`
|
|
662
|
-
- Run `npm run lint:unused` to find unused exports
|
|
663
|
-
- Delete or extract to separate "legacy" file
|
|
664
|
-
|
|
665
|
-
---
|
|
666
|
-
|
|
667
|
-
### QUAL-3: Address Critical TODOs (MEDIUM)
|
|
668
|
-
|
|
669
|
-
**Effort**: Varies | **Impact**: Completes incomplete features
|
|
670
|
-
|
|
671
|
-
**High-priority TODOs**:
|
|
672
|
-
|
|
673
|
-
```typescript
|
|
674
|
-
// src/mcp/server.ts:1624
|
|
675
|
-
"TODO: Add support for 3rd party data sources";
|
|
676
|
-
|
|
677
|
-
// src/mcp/handlers-consolidated.ts:359
|
|
678
|
-
"TODO: Deprecate handleWorkflow and move remaining logic";
|
|
679
|
-
```
|
|
680
|
-
|
|
681
|
-
---
|
|
682
|
-
|
|
683
|
-
### Code Quality Summary
|
|
684
|
-
|
|
685
|
-
| ID | Task | Effort | Impact |
|
|
686
|
-
| ------ | ---------------- | ------- | ------------ |
|
|
687
|
-
| QUAL-1 | Type guards | 8 hours | Safety |
|
|
688
|
-
| QUAL-2 | Remove dead code | 2 hours | Cleanliness |
|
|
689
|
-
| QUAL-3 | Address TODOs | Varies | Completeness |
|
|
690
|
-
|
|
691
|
-
---
|
|
692
|
-
|
|
693
|
-
## Recommended Execution Order
|
|
694
|
-
|
|
695
|
-
### Sprint 1: Quick Wins + Critical Security (1 week)
|
|
696
|
-
|
|
697
|
-
| Day | Tasks | Hours |
|
|
698
|
-
| --- | -------------------------- | ----- |
|
|
699
|
-
| 1 | QW-1, QW-2, QW-3 | 1.25h |
|
|
700
|
-
| 1 | SEC-2 (path traversal) | 1h |
|
|
701
|
-
| 2 | QW-4, QW-5, QW-6, QW-7 | 2.75h |
|
|
702
|
-
| 2 | SEC-3 (error sanitization) | 2h |
|
|
703
|
-
| 3 | ARCH-1 (circular dep) | 2h |
|
|
704
|
-
| 3 | SEC-1 (input validation) | 4h |
|
|
705
|
-
| 4 | PERF-1 (parallelize sync) | 2h |
|
|
706
|
-
| 5 | Buffer / PR review | - |
|
|
707
|
-
|
|
708
|
-
**Sprint 1 Total**: ~15 hours of work
|
|
709
|
-
|
|
710
|
-
### Sprint 2: Performance + Architecture (1 week)
|
|
711
|
-
|
|
712
|
-
| Day | Tasks | Hours |
|
|
713
|
-
| --- | --------------------------- | ----- |
|
|
714
|
-
| 1-2 | PERF-2 (async file I/O) | 4h |
|
|
715
|
-
| 2 | PERF-3, PERF-4 | 2h |
|
|
716
|
-
| 3-4 | ARCH-2 (handler extraction) | 8h |
|
|
717
|
-
| 5 | Buffer / PR review | - |
|
|
718
|
-
|
|
719
|
-
**Sprint 2 Total**: ~14 hours of work
|
|
720
|
-
|
|
721
|
-
### Sprint 3: Testing + Quality (1 week)
|
|
722
|
-
|
|
723
|
-
| Day | Tasks | Hours |
|
|
724
|
-
| --- | ------------------------- | ----- |
|
|
725
|
-
| 1-2 | TEST-1 (SDK client tests) | 8h |
|
|
726
|
-
| 3 | TEST-2, TEST-3 | 8h |
|
|
727
|
-
| 4-5 | QUAL-1 (type guards) | 8h |
|
|
728
|
-
|
|
729
|
-
**Sprint 3 Total**: ~24 hours of work
|
|
730
|
-
|
|
731
|
-
---
|
|
732
|
-
|
|
733
|
-
## Quick Reference Card
|
|
734
|
-
|
|
735
|
-
### Do Today (< 2 hours total)
|
|
736
|
-
|
|
737
|
-
1. ✅ Add graceful shutdown (30 min)
|
|
738
|
-
2. ✅ Add coverage thresholds (15 min)
|
|
739
|
-
3. ✅ Fix action type fallback (30 min)
|
|
740
|
-
4. ✅ Add namespace validation (30 min)
|
|
741
|
-
|
|
742
|
-
### Do This Week
|
|
743
|
-
|
|
744
|
-
1. 🔒 Fix path traversal
|
|
745
|
-
2. 🔒 Add input validation
|
|
746
|
-
3. 🔒 Sanitize error messages
|
|
747
|
-
4. 🏗️ Fix circular dependency
|
|
748
|
-
5. ⚡ Parallelize sync operations
|
|
749
|
-
|
|
750
|
-
### Do This Month
|
|
751
|
-
|
|
752
|
-
1. ⚡ Async file I/O migration
|
|
753
|
-
2. 🏗️ Complete handler extraction
|
|
754
|
-
3. 🧪 Add SDK client tests
|
|
755
|
-
4. 🔧 Add type guards
|
|
756
|
-
|
|
757
|
-
---
|
|
758
|
-
|
|
759
|
-
## Metrics to Track
|
|
760
|
-
|
|
761
|
-
After implementing fixes:
|
|
762
|
-
|
|
763
|
-
| Metric | Current | Target |
|
|
764
|
-
| ------------------------ | ------- | ------ |
|
|
765
|
-
| Test coverage | ~45% | 70% |
|
|
766
|
-
| `any` types | 102 | <20 |
|
|
767
|
-
| Type assertions | 2000+ | <500 |
|
|
768
|
-
| Sync time (100 personas) | ~30s | ~5s |
|
|
769
|
-
| server.ts lines | 5,914 | <1,000 |
|
|
770
|
-
| Critical issues | 8 | 0 |
|
|
771
|
-
|
|
772
|
-
---
|
|
773
|
-
|
|
774
|
-
_Generated: January 23, 2026_
|