secufusion-mcp 1.0.6 → 1.0.8

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 (3) hide show
  1. package/README.md +64 -205
  2. package/index.js +107 -161
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -14,7 +14,7 @@
14
14
 
15
15
  | Tool | Phase | What it does |
16
16
  |---|---|---|
17
- | `manage_feature_spec` | Planning & Execution | Creates/updates a `.current-task-spec.md` blueprint (works for single-repo or cross-repo tasks) |
17
+ | `manage_branch_state` | Planning & Execution | Manages a `.secufusion-state.json` tracker tied to the active Git branch |
18
18
  | `log_rejected_pattern` | Course Correction | Records bad patterns to `.rejected-patterns.json` so they are never repeated |
19
19
  | `run_pre_pr_checks` | PR Handoff | Discovers modified microservices across the workspace and gates PRs via AST-level linters + structural checks |
20
20
 
@@ -102,69 +102,40 @@ Open Cline settings → MCP Servers → Add:
102
102
 
103
103
  ## Tools Reference
104
104
 
105
- ### 1. `manage_feature_spec`
105
+ ### 1. manage_branch_state
106
106
 
107
- Creates or updates the `.current-task-spec.md` file your single source of truth for every task. The AI reads this before writing any code.
107
+ Manages a structured JSON state file (`.secufusion-state.json`) keyed to the current Git branch. This replaces unstructured Markdown parsing and ensures the AI can resume perfectly.
108
108
 
109
109
  **Parameters:**
110
110
 
111
111
  | Parameter | Type | Required | Description |
112
112
  |---|---|---|---|
113
- | `action` | `"create"` \| `"update"` \| `"read"` | Yes | What to do with the spec |
114
- | `task_description` | string | When `action=create` | Full description of the task/feature |
115
- | `update_content` | string | When `action=update` | Markdown lines to merge (e.g. tick checkboxes) |
116
- | `work_item_id` | string | No | Azure DevOps work item ID |
117
- | `reference_file_path` | string | No | Path to an existing source file to extract coding patterns from |
118
-
119
- **Example — Create a spec:**
120
-
121
- ```
122
- Ask your AI assistant:
123
- "Start working on WI-1042: Add tenant-scoped audit log export to CSV.
124
- Reference file: src/services/AuditService.java"
125
- ```
126
-
127
- The AI will call:
113
+ | `action` | string | Yes | `initialize`, `read`, or `update` |
114
+ | `task_description` | string | No | (For `initialize`) Summary of the work |
115
+ | `pending_acs` | array | No | Array of strings for pending tasks (For `initialize`/`update`) |
116
+ | `completed_acs` | array | No | Array of completed AC strings (For `update`) |
117
+ | `next_step` | string | No | **CRITICAL for `update`**: A clear instruction on what to do next to allow instant resumption. |
118
+ | `reference_file_path` | string | No | Path to a reference file with standard coding patterns |
119
+
120
+ **Example — Starting a new task:**
128
121
  ```json
129
122
  {
130
- "action": "create",
131
- "task_description": "Add tenant-scoped audit log export to CSV...",
132
- "work_item_id": "1042",
133
- "reference_file_path": "src/services/AuditService.java"
123
+ "action": "initialize",
124
+ "task_description": "Implement DeviceActivitySummaryDTO with browserUsage map.",
125
+ "pending_acs": ["Add browserUsage map", "Add unit tests", "Update OpenAPI"]
134
126
  }
135
127
  ```
136
128
 
137
- This generates `.current-task-spec.md` with:
138
- - Task description
139
- - Pre-filled guardrails checklist
140
- - Acceptance criteria placeholders
141
- - Reference code snippet
142
- - Session log
143
-
144
- **Example — Tick off completed work:**
145
-
146
- ```
147
- Ask: "Mark the tenantId scoping and unit tests as done in the spec."
148
- ```
149
-
150
- The AI will call:
129
+ **Example Updating progress:**
151
130
  ```json
152
131
  {
153
132
  "action": "update",
154
- "update_content": "- [x] All DB queries / event payloads are scoped with `tenantId`\n- [x] Unit tests written / updated for new business logic"
133
+ "pending_acs": ["Update OpenAPI"],
134
+ "completed_acs": ["Add browserUsage map", "Add unit tests"],
135
+ "next_step": "Generate the OpenAPI YAML for DeviceActivitySummaryDTO and test generation."
155
136
  }
156
137
  ```
157
138
 
158
- **Example — Read current spec:**
159
-
160
- ```
161
- Ask: "Where did we leave off? Read the current spec."
162
- ```
163
-
164
- ```json
165
- { "action": "read" }
166
- ```
167
-
168
139
  ---
169
140
 
170
141
  ### 2. `log_rejected_pattern`
@@ -219,13 +190,13 @@ This writes to `.rejected-patterns.json`:
219
190
  |---|---|---|---|
220
191
  | `work_item_id` | string | Yes | Azure DevOps work item ID |
221
192
  | `root_dir` | string | No | Directory to scan (defaults to cwd) |
222
- | `skip_checks` | array | No | `spec_boxes`, `console_logs`, `hardcoded_urls`, `flyway_migrations` |
193
+ | `skip_checks` | array | No | `branch_state`, `console_logs`, `tenant_isolation`, `hardcoded_urls`, `flyway_migrations` |
223
194
 
224
195
  **Guardrail checks:**
225
196
 
226
197
  | Check | Fails when |
227
198
  |---|---|
228
- | **SPEC** | `.current-task-spec.md` is missing or has unchecked `- [ ]` boxes |
199
+ | **STATE** | `.secufusion-state.json` has pending ACs for the active branch |
229
200
  | **LINTING** | AST linters (ESLint, Checkstyle) fail in any discovered microservice. Fix natively, do not suppress! (Falls back to regex if no linters exist) |
230
201
  | **SECURITY** | Hardcoded IPs or `uat.*` / `prod.*` / `staging.*` URLs in source or config files |
231
202
  | **TENANT ISOLATION** | `*Repository.java` files contain query methods or `@Query` annotations that do NOT include `tenant` filtering |
@@ -248,14 +219,14 @@ The AI will call:
248
219
  ```
249
220
  # ✅ Pre-PR Checks PASSED — Work Item #1042
250
221
 
251
- ✅ [SPEC] All spec checkboxes are checked.
222
+ ✅ [STATE] All branch tasks completed.
252
223
  ✅ [LOGGING] No console.log / System.out.println found.
253
224
  ✅ [SECURITY] No hardcoded UAT/Prod IPs or environment URLs found.
254
225
  ✅ [FLYWAY] Flyway migration coverage looks good.
255
226
 
256
227
  ## PR Summary
257
228
  - Work Item: #1042
258
- - Spec: All acceptance criteria verified
229
+ - State: All pending ACs resolved
259
230
  - Ready to raise PR 🚀
260
231
  ```
261
232
 
@@ -263,7 +234,7 @@ The AI will call:
263
234
  ```
264
235
  # ❌ Pre-PR Checks FAILED — Work Item #1042
265
236
 
266
- ❌ [SPEC] 3 unchecked item(s) in the spec:
237
+ ❌ [STATE] 3 pending AC(s) remain in .secufusion-state.json:
267
238
  • Flyway SQL migration created for every modified JPA @Entity
268
239
  • Unit tests written / updated for new business logic
269
240
  • API contract updated if endpoints changed
@@ -284,7 +255,7 @@ These rules are enforced automatically — the AI will never violate them:
284
255
  ✅ No console.log() or System.out.println() in any source file
285
256
  ✅ No hardcoded UAT/Prod IPs or environment URLs
286
257
  ✅ Every JPA @Entity change accompanied by a Flyway .sql migration
287
- Spec must be fully checked before PR is raised
258
+ State in .secufusion-state.json must be fully resolved before PR is raised
288
259
  ```
289
260
 
290
261
  ---
@@ -293,7 +264,7 @@ These rules are enforced automatically — the AI will never violate them:
293
264
 
294
265
  | File | Description |
295
266
  |---|---|
296
- | `.current-task-spec.md` | Living task blueprint — created per feature, updated as work progresses |
267
+ | `.secufusion-state.json` | Living task blueprint — tracks pending/completed ACs per branch |
297
268
  | `.rejected-patterns.json` | Cumulative log of all rejected patterns across sessions |
298
269
 
299
270
  > **Tip:** Commit both files to your repo so the entire team benefits from the shared knowledge.
@@ -306,11 +277,11 @@ These rules are enforced automatically — the AI will never violate them:
306
277
  ┌─────────────────────────────────────────────────────┐
307
278
  │ SecuFusion MCP Workflow │
308
279
  ├──────────────┬──────────────────────────────────────┤
309
- │ Phase 1 │ manage_feature_spec (action=create)
310
- │ Planning │ → Generates .current-task-spec.md
280
+ │ Phase 1 │ manage_branch_state (action=init)
281
+ │ Planning │ → Initializes .secufusion-state.json
311
282
  ├──────────────┼──────────────────────────────────────┤
312
- │ Phase 2 │ manage_feature_spec (action=update) │
313
- │ Execution │ → Tick off ACs as you complete them
283
+ │ Phase 2 │ manage_branch_state (action=update) │
284
+ │ Execution │ → Resolve ACs & define next_step
314
285
  ├──────────────┼──────────────────────────────────────┤
315
286
  │ Phase 3 │ log_rejected_pattern │
316
287
  │ Correction │ → Record mistakes to avoid repeat │
@@ -373,46 +344,14 @@ Admin users must be forced through TOTP verification before
373
344
  accessing any dashboard route. Exempt service accounts.
374
345
  ```
375
346
 
376
- **The AI automatically calls `manage_feature_spec` and creates `.current-task-spec.md`:**
377
- ```markdown
378
- # SecuFusion Feature Spec
379
-
380
- **Generated:** 2026-08-26T14:35:00.000Z
381
- **Azure DevOps Work Item:** 2847 → https://dev.azure.com/secufusion/_workitems/edit/2847
382
-
383
- ## Task Description
384
- Add MFA enforcement for admin users on login...
385
-
386
- ## Guardrails Checklist
387
- - [ ] All DB queries / event payloads are scoped with `tenantId`
388
- - [ ] No `console.log` / `System.out.println` left in source files
389
- - [ ] No hardcoded UAT/Prod IPs or environment URLs
390
- - [ ] Flyway SQL migration created for every modified JPA `@Entity`
391
- - [ ] Unit tests written / updated for new business logic
392
- - [ ] API contract updated if endpoints changed
393
-
394
- ## Acceptance Criteria
395
- - [ ] AC-1: (fill in from ticket)
396
- - [ ] AC-2: (fill in from ticket)
397
-
398
- ## Session Log
399
- | 2026-08-26T14:35:00Z | Spec created |
400
- ```
401
-
402
- You can paste as little or as much as you want:
403
-
404
- ```
405
- # Minimal — one liner
406
- WI-2847: MFA for admin login with TOTP.
407
-
408
- # Full ticket paste — straight from Azure
409
- WI-2847
410
- Title: Add MFA enforcement for admin users
411
- Description: Admin users must complete TOTP verification...
412
- Acceptance Criteria:
413
- - Given admin logs in, When MFA not done, Then redirect to /mfa
414
- - Service accounts in GROUP_SERVICE_ACCOUNTS are exempt
415
- Priority: High
347
+ **The AI automatically calls `manage_branch_state` and creates/initializes `.secufusion-state.json`:**
348
+ ```json
349
+ {
350
+ "task": "WI-2847: Add MFA enforcement",
351
+ "pending_acs": ["AC-1: Auth flow", "AC-2: Redirects", "AC-3: Exemptions"],
352
+ "completed_acs": [],
353
+ "next_step": "Implement MFA logic in AuthController"
354
+ }
416
355
  ```
417
356
 
418
357
  ---
@@ -435,23 +374,20 @@ As you finish pieces of the feature, tell the AI:
435
374
 
436
375
  ```
437
376
  I've finished the tenantId scoping on all queries and written the unit tests.
438
- Update the spec.
377
+ Update the state.
439
378
  ```
440
379
 
441
- The AI calls `manage_feature_spec` with `action=update` and the spec updates:
442
-
443
- ```markdown
444
- # Before
445
- - [ ] All DB queries / event payloads are scoped with `tenantId`
446
- - [ ] Unit tests written / updated for new business logic
380
+ The AI calls `manage_branch_state` with `action=update` and the state updates:
447
381
 
448
- # After
449
- - [x] All DB queries / event payloads are scoped with `tenantId`
450
- - [x] Unit tests written / updated for new business logic
382
+ ```json
383
+ {
384
+ "task": "WI-2847: Add MFA enforcement",
385
+ "pending_acs": ["AC-3: Exemptions"],
386
+ "completed_acs": ["Add tenantId scoping", "Add unit tests"],
387
+ "next_step": "Implement exemption logic for service accounts"
388
+ }
451
389
  ```
452
390
 
453
- A new row is also appended to the Session Log automatically, so you always have an audit trail of progress across sessions.
454
-
455
391
  ---
456
392
 
457
393
  ### Step 5 — Course correction (if the AI does something wrong)
@@ -474,23 +410,6 @@ The AI **immediately** calls `log_rejected_pattern`:
474
410
  }
475
411
  ```
476
412
 
477
- This gets appended to `.rejected-patterns.json`:
478
-
479
- ```json
480
- [
481
- {
482
- "id": 1,
483
- "timestamp": "2026-08-26T15:10:00.000Z",
484
- "category": "security",
485
- "pattern": "Hardcoded staging URL https://staging.secufusion.io in source files",
486
- "reason": "Must use @Value from application.properties...",
487
- "file_context": "src/services/NotificationService.java"
488
- }
489
- ]
490
- ```
491
-
492
- From this point on, the AI checks this file before every suggestion — the mistake will never be repeated, even in future sessions.
493
-
494
413
  ---
495
414
 
496
415
  ### Step 6 — Pre-PR checks (PR Handoff phase)
@@ -508,101 +427,41 @@ The AI scans your entire repo and produces a report.
508
427
  # ✅ Pre-PR Checks PASSED — Work Item #2847
509
428
 
510
429
  Scanned directory: C:\projects\secufusion-backend
511
- Timestamp: 2026-08-26T16:00:00.000Z
512
430
 
513
- ✅ [SPEC] All spec checkboxes are checked.
431
+ ✅ [STATE] All tasks resolved.
514
432
  ✅ [LOGGING] No console.log / System.out.println found.
515
433
  ✅ [SECURITY] No hardcoded UAT/Prod IPs or environment URLs found.
516
434
  ✅ [FLYWAY] Flyway migration coverage looks good.
517
435
 
518
436
  ## PR Summary
519
437
  - Work Item: #2847
520
- - Spec: All acceptance criteria verified
438
+ - State: All pending ACs resolved
521
439
  - Guardrails: tenant isolation secured, no debug logs, no hardcoded URLs, Flyway covered ✅
522
440
  - Ready to raise PR 🚀
523
-
524
- 🚫 Rejected Patterns Reminder (1 on record)
525
- - [security] Hardcoded staging URL https://staging.secufusion.io in source files
526
- ```
527
-
528
- **❌ Checks fail — you must fix before PR:**
529
- ```
530
- # ❌ Pre-PR Checks FAILED — Work Item #2847
531
-
532
- ## Errors (must fix before PR)
533
-
534
- ❌ [SPEC] 2 unchecked item(s) in the spec:
535
- • Flyway SQL migration created for every modified JPA @Entity
536
- • API contract (OpenAPI / TS types) updated if endpoints changed
537
-
538
- ❌ [LINTING] 2 linter error(s) across workspace — fix natively in their respective microservices:
539
- • [ESLint] apps/admin-dashboard/src/components/MfaSetup.tsx:47 — Unexpected console statement (no-console)
540
- • [Checkstyle/Maven] Build failed: [ERROR] AuditService.java:[112] Line contains System.out.println
541
-
542
- ## Passed
543
- ✅ [SECURITY] No hardcoded UAT/Prod IPs or environment URLs found.
544
- ✅ [FLYWAY] Flyway migration coverage looks good.
545
441
  ```
546
442
 
547
- Fix the issues, run checks again, and only raise the PR once it's fully green.
548
-
549
- ---
550
-
551
- ### Quick cheat sheet
552
-
553
- | What you want to do | What to say to the AI |
554
- |---|---|
555
- | Start a new task | `WI-XXXX: [paste description from Azure]` |
556
- | Check where you left off | `Read the current spec` |
557
- | Mark work as done | `Mark the tenantId scoping as complete in the spec` |
558
- | Record a mistake | `Never do [X] again because [Y]` |
559
- | Gate the PR | `Run pre-PR checks for WI-XXXX` |
560
- | Resume after a break | `What's left on the current task?` |
561
- | Use a reference file | `WI-XXXX: [desc]. Reference: src/services/MyService.java` |
562
-
563
443
  ---
564
444
 
565
- ## How It Actually Works The Invoker
566
-
567
- There are two layers that need to be in place for the MCP server to work automatically.
568
-
569
- ### Layer 1 — `mcp_config.json` (makes tools available)
570
-
571
- This tells the IDE to start the MCP server process when it launches. The tools become registered and ready, but nothing calls them yet.
572
-
573
- ```
574
- IDE starts → reads mcp_config.json → spawns node index.js → tools registered
575
- ```
576
-
577
- ### Layer 2 — `AGENTS.md` (the invoker — tells AI when to call each tool)
578
-
579
- Without this, the tools sit idle. The AI doesn't know when to invoke them.
580
- Create `.agents/AGENTS.md` in your project root:
445
+ ## How It Works (The 2 Layers)
581
446
 
582
- ```markdown
583
- # SecuFusion MCP Workflow Rules
447
+ To prevent AI amnesia or generic bad habits across your projects, the SecuFusion MCP relies on structured branch-aware JSON and native AST tooling.
584
448
 
585
- You are an elite Senior Developer and Architect working on the SecuFusion workspace (containing multiple microservice repositories). You prioritize robust cross-service architecture, zero-trust security (tenant isolation), and flawless state management. You rely on standard AST-aware build tools (ESLint/Checkstyle) for code hygiene. You strictly follow project standards and always use the custom MCP tools provided.
449
+ ## Phase 0 Resume (TRIGGER: new session, switching branches, or user says "resume" or "continue")
450
+ - Call `manage_branch_state` with `action: "read"`. The tool will automatically detect the current Git branch and return the structured JSON state for that specific branch. Do not re-read requirements; immediately begin executing the item explicitly listed in the `next_step` field.
586
451
 
587
452
  ## Phase 1 — Planning (TRIGGER: user assigns a task or work item)
588
- - Do NOT write code immediately. First, call `manage_feature_spec`.
589
- - Determine which microservices are likely affected. Pass a `reference_file_path` from each to observe exact coding patterns.
590
- - Pass the user's requirements into `task_description` to generate the workspace-level `.current-task-spec.md` blueprint.
591
- - Wait for the spec to be generated before writing any code.
453
+ - Call `manage_branch_state` with `action: "initialize"`. Pass the `task_description` and `reference_file_path`. The tool will generate a branch-bound JSON state file tracking the Acceptance Criteria (ACs) as a structured array of pending tasks, keyed to your active Git branch.
592
454
 
593
- ## Phase 2 — Execution (TRIGGER: as you complete work)
594
- - Keep the `.current-task-spec.md` file updated as your source of truth.
595
- - Whenever you finish a logical chunk, call `manage_feature_spec` with `update_content` to check off the `[ ]` boxes to `[x]`.
596
- - If you are resuming a session, always call `manage_feature_spec` with `action=read` first to know exactly where you left off.
455
+ ## Phase 2 — Execution (TRIGGER: as you complete ACs, or before ending a session/response)
456
+ - Call `manage_branch_state` with `action: "update"`. Move completed items from `pending_acs` to `completed_acs`.
457
+ - CRITICAL: You must explicitly write a clear, actionable instruction into the `next_step` parameter (e.g., "Implement browserUsage map in DeviceActivitySummaryDTO"). This ensures your future self can resume instantly without parsing the full spec.
597
458
 
598
459
  ## Phase 3 — Course Correction (TRIGGER: user corrects you or rejects an approach)
599
- - Immediately call `log_rejected_pattern`.
600
- - Pass the bad `pattern` you used and the `reason`/correction the user provided.
601
- - Always check `.rejected-patterns.json` implicitly before suggesting architectural choices to ensure you never repeat past mistakes.
460
+ - Immediately call `log_rejected_pattern`. Pass the bad `pattern` and the `reason`. Always check `.rejected-patterns.json` implicitly before suggesting architectural choices.
602
461
 
603
- ## Phase 4 — PR Handoff (TRIGGER: user says "prepare PR", "finish up", or "run checks")
604
- - Call `run_pre_pr_checks` with the Azure DevOps `work_item_id`. The tool will automatically discover all modified microservices in the workspace and run native linters, database script checks, and strict tenant-isolation scanners.
605
- - If the tool throws an error for a specific repository (e.g., missing Flyway SQL migration, missing `tenantId` in a query, or a linter failing), YOU MUST navigate to that specific microservice, FIX THE ERROR in the codebase natively, and run the tool again until the entire workspace passes. Do not suppress warnings.
462
+ ## Phase 4 — PR Handoff (TRIGGER: user says "prepare PR" or "run checks")
463
+ - Call `run_pre_pr_checks` with the Azure DevOps `workItemId`. The tool checks the structured branch state to ensure `pending_acs` is empty, then discovers modified microservices to run native linters, Flyway checks, and the Tenant-Isolation scanner.
464
+ - If an error is thrown, YOU MUST navigate to that microservice, FIX THE ERROR natively, and rerun until the workspace passes.
606
465
 
607
466
  ## Guardrails (enforce always, no exceptions)
608
467
  - TENANT SAFETY IS AUTOMATED: The PR Gatekeeper actively scans all `*Repository.java` files. If you write a database query (derived method or `@Query`) that does not explicitly filter by `tenantId` or contain the word `tenant`, the PR will be blocked. Write secure, tenant-isolated queries on your first attempt.
@@ -620,9 +479,9 @@ mcp_config.json → starts the server (tools available)
620
479
 
621
480
  You say: "WI-1042: Add audit log export"
622
481
 
623
- AI reads AGENTS.md → Phase 1 triggered → calls manage_feature_spec
482
+ AI reads AGENTS.md → Phase 1 triggered → calls manage_branch_state
624
483
 
625
- .current-task-spec.md created in your project root
484
+ .secufusion-state.json initialized for your Git branch
626
485
  ```
627
486
 
628
487
  ### Reusing across projects
@@ -648,14 +507,14 @@ Once both layers are in place, you interact completely naturally:
648
507
  | Situation | What you say |
649
508
  |---|---|
650
509
  | 🆕 New task | `WI-XXXX: [paste description from Azure]` |
651
- | ✅ Done a chunk | `Done with the tenantId scoping, update the spec` |
510
+ | ✅ Done a chunk | `Done with the tenantId scoping, update the state` |
652
511
  | ❌ AI did something wrong | `Don't do X, do Y instead` |
653
512
  | 🚀 Ready for PR | `Run checks for WI-XXXX` or `Prepare PR` |
654
513
  | 🔄 Resuming after a break | `What's left?` or `Resume the current task` |
655
514
 
656
515
  **Before `AGENTS.md`:** You had to remember which tool to invoke and when.
657
516
 
658
- **After `AGENTS.md`:** You just describe work. The AI follows the 4-phase workflow automatically — no commands, no syntax, no manual tool calls.
517
+ **After `AGENTS.md`:** You just describe work. The AI follows the 5-phase workflow automatically — no commands, no syntax, no manual tool calls.
659
518
 
660
519
  ---
661
520
 
package/index.js CHANGED
@@ -22,7 +22,7 @@ import { execSync } from "child_process";
22
22
  // ─────────────────────────────────────────────
23
23
  // Constants / helpers
24
24
  // ─────────────────────────────────────────────
25
- const SPEC_FILE = ".current-task-spec.md";
25
+ const STATE_FILE = ".secufusion-state.json";
26
26
  const REJECTED_FILE = ".rejected-patterns.json";
27
27
  /** Resolve a path relative to cwd (where the MCP server is invoked). */
28
28
  function resolve(file) {
@@ -40,56 +40,13 @@ function writeFile(filePath, content) {
40
40
  fs.mkdirSync(path.dirname(filePath), { recursive: true });
41
41
  fs.writeFileSync(filePath, content, "utf-8");
42
42
  }
43
- // ─────────────────────────────────────────────
44
- // manage_feature_spec helpers
45
- // ─────────────────────────────────────────────
46
- function buildInitialSpec(taskDescription, workItemId, referenceSnippet) {
47
- const now = new Date().toISOString();
48
- const wiLine = workItemId
49
- ? `**Azure DevOps Work Item:** [${workItemId}](https://dev.azure.com/secufusion/_workitems/edit/${workItemId})\n`
50
- : "";
51
- const refSection = referenceSnippet
52
- ? `\n## Reference Code Pattern\n\n> Extracted from the provided reference file to guide implementation style.\n\n\`\`\`\n${referenceSnippet.slice(0, 800)}\n\`\`\`\n`
53
- : "";
54
- return `# SecuFusion Feature Spec
55
- <!-- AUTO-GENERATED — do not remove the checkboxes; they are used by run_pre_pr_checks -->
56
-
57
- **Generated:** ${now}
58
- ${wiLine}
59
- ## Task Description
60
-
61
- ${taskDescription}
62
- ${refSection}
63
- ## Guardrails Checklist
64
-
65
- - [ ] All DB queries / event payloads are scoped with \`tenantId\`
66
- - [ ] No \`console.log\` / \`System.out.println\` left in source files
67
- - [ ] No hardcoded UAT/Prod IPs or environment URLs
68
- - [ ] Flyway SQL migration created for every modified JPA \`@Entity\`
69
- - [ ] Unit tests written / updated for new business logic
70
- - [ ] API contract (OpenAPI / TS types) updated if endpoints changed
71
-
72
- ## Acceptance Criteria
73
-
74
- - [ ] AC-1: (fill in from ticket)
75
- - [ ] AC-2: (fill in from ticket)
76
- - [ ] AC-3: (fill in from ticket)
77
-
78
- ## Implementation Notes
79
-
80
- > Add architecture decisions, edge-cases, and external dependency notes here.
81
-
82
- ## Session Log
83
-
84
- | Timestamp | Update |
85
- |-----------|--------|
86
- | ${now} | Spec created |
87
- `;
88
- }
89
- function appendSessionLog(existing, update) {
90
- const ts = new Date().toISOString();
91
- const logRow = `| ${ts} | ${update} |`;
92
- return existing.replace(/(\| [^\n]+ \|)\s*$/, `$1\n${logRow}`);
43
+ function getCurrentBranch(cwd) {
44
+ try {
45
+ return execSync("git rev-parse --abbrev-ref HEAD", { cwd, stdio: "pipe" }).toString().trim();
46
+ }
47
+ catch {
48
+ return "unknown-branch";
49
+ }
93
50
  }
94
51
  // ─────────────────────────────────────────────
95
52
  // run_pre_pr_checks helpers
@@ -100,34 +57,29 @@ const CONSOLE_LOG_REGEX = [
100
57
  ];
101
58
  const HARDCODED_URL_PATTERN = /(?:https?:\/\/)?(?:\d{1,3}\.){3}\d{1,3}(?::\d+)?|(?:uat|prod|staging|preprod)\.[a-z0-9.-]+\.[a-z]{2,}/gi;
102
59
  function walkDir(dir, exts) {
103
- const results = [];
104
- if (!fs.existsSync(dir))
105
- return results;
106
- for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
107
- const full = path.join(dir, entry.name);
108
- if (entry.isDirectory()) {
109
- if (["node_modules", ".git", "dist", "build", "target", ".idea"].includes(entry.name))
60
+ let results = [];
61
+ try {
62
+ const list = fs.readdirSync(dir);
63
+ for (const file of list) {
64
+ if (file === "node_modules" || file === ".git" || file === "dist" || file === "target")
110
65
  continue;
111
- results.push(...walkDir(full, exts));
112
- }
113
- else if (exts.some((e) => entry.name.endsWith(e))) {
114
- results.push(full);
66
+ const filePath = path.join(dir, file);
67
+ const stat = fs.statSync(filePath);
68
+ if (stat && stat.isDirectory()) {
69
+ results = results.concat(walkDir(filePath, exts));
70
+ }
71
+ else {
72
+ if (exts.some(ext => file.endsWith(ext))) {
73
+ results.push(filePath);
74
+ }
75
+ }
115
76
  }
116
77
  }
78
+ catch (e) {
79
+ /* ignore */
80
+ }
117
81
  return results;
118
82
  }
119
- function checkSpecFile() {
120
- const content = readFileSafe(resolve(SPEC_FILE));
121
- if (!content)
122
- return { unchecked: [], missing: true };
123
- const unchecked = [];
124
- for (const line of content.split("\n")) {
125
- const match = line.match(/^- \[ \] (.+)/);
126
- if (match)
127
- unchecked.push(match[1].trim());
128
- }
129
- return { unchecked, missing: false };
130
- }
131
83
  // ── AST-level linting via ESLint (preferred over regex for JS/TS) ─────────────
132
84
  function runEslint(rootDir) {
133
85
  // Check if ESLint is configured in the project
@@ -304,128 +256,113 @@ const server = new McpServer({
304
256
  name: "secufusion-mcp",
305
257
  version: "1.0.0",
306
258
  });
307
- // ─── Tool 1: manage_feature_spec ─────────────────────────────────────────────
308
- server.tool("manage_feature_spec", "Create or update the .current-task-spec.md blueprint for the current feature. " +
309
- "Use this during the Planning and Execution phases. " +
310
- "Works for both single-repo and cross-repo workspace tasks.", {
259
+ // ─── Tool 1: manage_branch_state ─────────────────────────────────────────────
260
+ server.tool("manage_branch_state", "Manage the structured JSON state for the current Git branch. Use to initialize new tasks, track pending/completed ACs, and leave explicit next steps for resuming.", {
261
+ action: z
262
+ .enum(["initialize", "read", "update"])
263
+ .describe("Action to perform on the branch state."),
311
264
  task_description: z
312
265
  .string()
313
266
  .optional()
314
- .describe("Full description of the new feature/task (used when creating a spec from scratch)."),
315
- update_content: z
267
+ .describe("Used with 'initialize' to describe the task."),
268
+ reference_file_path: z
316
269
  .string()
317
270
  .optional()
318
- .describe("Partial markdown update / session-log entry to merge into the existing spec. " +
319
- "Use to tick checkboxes: replace '- [ ] AC-1' with '- [x] AC-1'."),
320
- work_item_id: z
321
- .string()
271
+ .describe("Used with 'initialize' to note a reference file."),
272
+ pending_acs: z
273
+ .array(z.string())
322
274
  .optional()
323
- .describe("Azure DevOps work item ID to embed in the spec header."),
324
- reference_file_path: z
275
+ .describe("Array of ACs. Used with 'initialize' or 'update' to set pending tasks."),
276
+ completed_acs: z
277
+ .array(z.string())
278
+ .optional()
279
+ .describe("Array of completed ACs. Used with 'update'."),
280
+ next_step: z
325
281
  .string()
326
282
  .optional()
327
- .describe("Absolute or cwd-relative path to an existing source file whose coding patterns should " +
328
- "be embedded as a reference snippet in the new spec."),
329
- action: z
330
- .enum(["create", "update", "read"])
331
- .default("create")
332
- .describe("'create' generates a new spec (overwrites if one exists), " +
333
- "'update' patches the existing spec, " +
334
- "'read' returns the current spec content without modification."),
335
- }, async ({ task_description, update_content, work_item_id, reference_file_path, action }) => {
336
- const specPath = resolve(SPEC_FILE);
337
- if (action === "read") {
338
- const content = readFileSafe(specPath);
339
- if (!content) {
340
- return {
341
- content: [
342
- {
343
- type: "text",
344
- text: `No spec file found at ${SPEC_FILE}. Run with action='create' to generate one.`,
345
- },
346
- ],
347
- };
283
+ .describe("Explicit actionable instruction for resuming. Required for 'update'."),
284
+ }, async ({ action, task_description, reference_file_path, pending_acs, completed_acs, next_step }) => {
285
+ const cwd = process.cwd();
286
+ const branch = getCurrentBranch(cwd);
287
+ const statePath = path.resolve(STATE_FILE);
288
+ let state = {};
289
+ if (fs.existsSync(statePath)) {
290
+ try {
291
+ state = JSON.parse(readFileSafe(statePath) || "{}");
292
+ }
293
+ catch {
294
+ state = {};
348
295
  }
349
- return { content: [{ type: "text", text: content }] };
350
296
  }
351
- if (action === "create") {
352
- if (!task_description) {
297
+ if (action === "read") {
298
+ const branchState = state[branch];
299
+ if (!branchState) {
353
300
  return {
354
301
  content: [
355
302
  {
356
303
  type: "text",
357
- text: "ERROR: `task_description` is required when action='create'.",
304
+ text: `No state found for branch '${branch}'. Please initialize first.`,
358
305
  },
359
306
  ],
360
- isError: true,
361
307
  };
362
308
  }
363
- let refSnippet = null;
364
- if (reference_file_path) {
365
- refSnippet = readFileSafe(path.isAbsolute(reference_file_path)
366
- ? reference_file_path
367
- : resolve(reference_file_path));
368
- }
369
- const spec = buildInitialSpec(task_description, work_item_id, refSnippet);
370
- writeFile(specPath, spec);
309
+ return {
310
+ content: [{ type: "text", text: JSON.stringify(branchState, null, 2) }],
311
+ };
312
+ }
313
+ if (action === "initialize") {
314
+ state[branch] = {
315
+ task_description: task_description || "",
316
+ reference_file_path: reference_file_path || "",
317
+ pending_acs: pending_acs || [],
318
+ completed_acs: [],
319
+ next_step: "Review requirements and begin implementation.",
320
+ last_updated: new Date().toISOString()
321
+ };
322
+ writeFile(statePath, JSON.stringify(state, null, 2));
371
323
  return {
372
324
  content: [
373
325
  {
374
326
  type: "text",
375
- text: `✅ Spec created at \`${SPEC_FILE}\`.\n\n` +
376
- `Review and fill in the Acceptance Criteria before starting implementation.\n\n` +
377
- `---\n\n${spec}`,
327
+ text: `✅ Branch state initialized for '${branch}'.\n\nState:\n${JSON.stringify(state[branch], null, 2)}`,
378
328
  },
379
329
  ],
380
330
  };
381
331
  }
382
332
  if (action === "update") {
383
- if (!update_content) {
333
+ if (!state[branch]) {
384
334
  return {
335
+ isError: true,
385
336
  content: [
386
- {
387
- type: "text",
388
- text: "ERROR: `update_content` is required when action='update'.",
389
- },
337
+ { type: "text", text: `No state found for branch '${branch}'. Initialize first.` },
390
338
  ],
391
- isError: true,
392
339
  };
393
340
  }
394
- const existing = readFileSafe(specPath);
395
- if (!existing) {
341
+ if (!next_step) {
396
342
  return {
343
+ isError: true,
397
344
  content: [
398
- {
399
- type: "text",
400
- text: `ERROR: No spec file found at ${SPEC_FILE}. Create one first with action='create'.`,
401
- },
345
+ { type: "text", text: "ERROR: 'next_step' is required when updating." },
402
346
  ],
403
- isError: true,
404
347
  };
405
348
  }
406
- let updated = existing;
407
- for (const line of update_content.split("\n")) {
408
- const checkedMatch = line.match(/^- \[x\] (.+)/);
409
- if (checkedMatch) {
410
- const label = checkedMatch[1].trim().replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
411
- updated = updated.replace(new RegExp(`- \\[ \\] ${label}`, "g"), `- [x] ${checkedMatch[1].trim()}`);
412
- }
413
- }
414
- updated = appendSessionLog(updated, update_content.replace(/\n/g, " ").slice(0, 120));
415
- writeFile(specPath, updated);
349
+ if (pending_acs)
350
+ state[branch].pending_acs = pending_acs;
351
+ if (completed_acs)
352
+ state[branch].completed_acs = completed_acs;
353
+ state[branch].next_step = next_step;
354
+ state[branch].last_updated = new Date().toISOString();
355
+ writeFile(statePath, JSON.stringify(state, null, 2));
416
356
  return {
417
357
  content: [
418
358
  {
419
359
  type: "text",
420
- text: `✅ Spec updated at \`${SPEC_FILE}\`.\n\n---\n\n${updated}`,
360
+ text: `✅ Branch state updated for '${branch}'. Next step recorded:\n> ${next_step}`,
421
361
  },
422
362
  ],
423
363
  };
424
364
  }
425
- return {
426
- content: [{ type: "text", text: "Unknown action." }],
427
- isError: true,
428
- };
365
+ return { content: [{ type: "text", text: "Invalid action." }] };
429
366
  });
430
367
  // ─── Tool 2: log_rejected_pattern ────────────────────────────────────────────
431
368
  server.tool("log_rejected_pattern", "Record a coding pattern that was rejected by the team so it is never repeated. " +
@@ -515,23 +452,32 @@ server.tool("run_pre_pr_checks", "Run all SecuFusion pre-PR guardrail checks acr
515
452
  const errors = [];
516
453
  const warnings = [];
517
454
  const passed = [];
518
- // ── 1. Spec checkbox check ─────────────────────────────────────────────
455
+ // ── 1. Branch state check ─────────────────────────────────────────────
519
456
  if (!skip_checks.includes("spec_boxes")) {
520
- const { unchecked, missing } = checkSpecFile();
521
- if (missing) {
522
- errors.push(`❌ [SPEC] No \`.current-task-spec.md\` found. ` +
523
- `Call \`manage_feature_spec\` with action='create' before raising a PR.`);
457
+ const branch = getCurrentBranch(scanRoot);
458
+ const statePath = path.resolve(scanRoot, STATE_FILE);
459
+ let branchState = null;
460
+ if (fs.existsSync(statePath)) {
461
+ try {
462
+ const stateData = JSON.parse(readFileSafe(statePath) || "{}");
463
+ branchState = stateData[branch];
464
+ }
465
+ catch { }
466
+ }
467
+ if (!branchState) {
468
+ errors.push(`❌ [STATE] No branch state found for '${branch}' in \`${STATE_FILE}\`. ` +
469
+ `Call \`manage_branch_state\` with action='initialize' before raising a PR.`);
524
470
  }
525
- else if (unchecked.length > 0) {
526
- errors.push(`❌ [SPEC] ${unchecked.length} unchecked item(s) in the spec:\n` +
527
- unchecked.map((u) => ` • ${u}`).join("\n"));
471
+ else if (branchState.pending_acs && branchState.pending_acs.length > 0) {
472
+ errors.push(`❌ [STATE] ${branchState.pending_acs.length} pending AC(s) remain for branch '${branch}':\n` +
473
+ branchState.pending_acs.map((u) => ` • ${u}`).join("\n"));
528
474
  }
529
475
  else {
530
- passed.push("✅ [SPEC] All spec checkboxes are checked.");
476
+ passed.push(`✅ [STATE] Branch state for '${branch}' is clear (no pending ACs).`);
531
477
  }
532
478
  }
533
479
  else {
534
- warnings.push("⚠️ [SPEC] Spec checkbox check SKIPPED (manually bypassed).");
480
+ warnings.push("⚠️ [STATE] Branch state check SKIPPED (manually bypassed).");
535
481
  }
536
482
  // ── 2. AST-level linting (Workspace Discovery → ESLint/Checkstyle → regex fallback)
537
483
  if (!skip_checks.includes("console_logs")) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "secufusion-mcp",
3
- "version": "1.0.6",
3
+ "version": "1.0.8",
4
4
  "type": "module",
5
5
  "description": "SecuFusion MCP server - developer workflow tooling with guardrails",
6
6
  "main": "index.js",