secufusion-mcp 2.1.3 → 2.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -40,7 +40,8 @@ The SecuFusion MCP has been refactored to align with the advanced MLMCPS framewo
40
40
  2. **Subprocess PR Checks**: Tier 1 mechanical checks (`TENANT_ISOLATION`, `N_PLUS_ONE`, etc.) are now extracted into a standalone CLI script (`scripts/sfn-pr-check.js`), allowing them to be run by the AI *or* natively within your CI/CD pipelines.
41
41
  3. **Thin Index Token Discipline**: Context bloat is gone. Tools like `manage_task(read)` and `prime_session` now return lightweight "Thin Indexes"—compact Markdown summaries with absolute file paths—so the AI only reads the full JSON via `view_file` when truly necessary.
42
42
  4. **Dynamic Skill Registry**: A new `skill_recommend` tool allows the AI to dynamically discover domain-specific architectural skills without bloating the base prompt.
43
- 5. **Poly-Repo DNA Discovery**: Through the standalone `secufusion-dna-plugin`, the AI can dynamically analyze the entire codebase of any poly-repo project at session start. It maps out microservices, API contracts, and event topologies on the fly, creating a living knowledge graph.
43
+ 5. **Phase -1 Philosophy Engine**: An invisible gate that checks the WHY, WHO, WHAT, and RISK of every task (including bugs and hotfixes) before any planning starts. If the business intent or blast radius is unsafe, it stops the AI from writing a single line of code.
44
+ 6. **Poly-Repo DNA Discovery**: Through the standalone `secufusion-dna-plugin`, the AI can dynamically analyze the entire codebase of any poly-repo project at session start. It maps out microservices, API contracts, event topologies, frontend repos, and the `snf-browser-extn` extension on the fly, creating a living knowledge graph.
44
45
 
45
46
  ---
46
47
 
@@ -83,13 +84,14 @@ Every task now requires **two complementary files** that the AI reads together:
83
84
  ### The Polyglot Bridge
84
85
  The new `spec_create_intent` tool captures a `services_involved` array that is **language-agnostic**. You can list a Go microservice, a Python Lambda, or a COBOL batch job. The AI reads this declaration and knows those services are in scope without needing a custom AST parser.
85
86
 
86
- ### The New `/sfn:plan` Flow
87
- When you type `/sfn:plan WI-2847 Add MFA`:
88
- 1. **The Pushback (Phase 1):** The AI will **NOT** immediately start planning. It will stop and ask you: *"Why are we building this? What business problem does it solve? What is the risk if we don't?"*
89
- 2. **The WHY (Phase 1.5):** You answer, and the AI generates the Markdown intent file (`spec_create_intent`).
90
- 3. **The HOW (Phase 2):** Only then does it initialize the code tracking infrastructure (`manage_task`).
91
- 4. **Context & Classify (Phase 3/4):** The AI loads the AST (`prime_session`), flags architectural risks (`classify_task`), and yields for your approval.
92
- 5. **The Plan (Phase 5):** The AI outputs the strict implementation plan.
87
+ ### The New `/sfn-plan` Flow
88
+ When you type `/sfn-plan WI-2847 Add MFA`:
89
+ 1. **The Guard (Phase -1):** The AI silently runs a `philosophy_check` against your Project DNA. It evaluates the WHY, WHO, WHAT, and RISK of the task. (Note: Bugs and hotfixes still undergo this check, though with slightly relaxed sensing).
90
+ 2. **The Pushback (Phase 1):** If the Philosophy Engine fails the request (e.g. unclear business intent or high risk), the AI will **NOT** plan. It will stop and ask you for clarity: *"Why are we building this? Who confirmed it?"*
91
+ 3. **The WHY (Phase 1.5):** You answer, and the AI generates the Markdown intent file (`spec_create_intent`).
92
+ 4. **The HOW (Phase 2):** Only then does it initialize the code tracking infrastructure (`manage_task`).
93
+ 5. **Context & Classify (Phase 3/4):** The AI loads the AST (`prime_session`), flags architectural risks (`classify_task`), and yields for your approval.
94
+ 6. **The Plan (Phase 5):** The AI outputs the strict implementation plan.
93
95
 
94
96
  ---
95
97
 
@@ -142,13 +144,13 @@ npx secufusion-mcp
142
144
  ### Option 2 — Global install
143
145
 
144
146
  ```bash
145
- npm install -g secufusion-mcp
147
+ npm install -g secufusion-mcp@2.1.4
146
148
  ```
147
149
 
148
150
  ### Option 3 — Local project install
149
151
 
150
152
  ```bash
151
- npm install --save-dev secufusion-mcp
153
+ npm install --save-dev secufusion-mcp@2.1.4
152
154
  ```
153
155
 
154
156
  ---
@@ -473,6 +475,9 @@ These rules are enforced automatically — the AI will never violate them:
473
475
  │ Plan Gate │ → STOP and wait for "proceed" / "adjust" / "cancel" │
474
476
  │ │ → manage_task (action=initialize) only after proceed │
475
477
  ├──────────────┼──────────────────────────────────────────────────────────────┤
478
+ │ Phase -1 │ philosophy_check (Silently validates WHY/WHO/WHAT/RISK) │
479
+ │ Philosophy │ → Blocks planning if intent or safety is unclear (ALL TASKS) │
480
+ ├──────────────┼──────────────────────────────────────────────────────────────┤
476
481
  │ Phase 1 │ search_tasks → get_task_history → manage_task initialize │
477
482
  │ Planning │ → Creates .secufusion/tasks/{id}-{slug}/ with all 5 files │
478
483
  ├──────────────┼──────────────────────────────────────────────────────────────┤
@@ -710,7 +715,7 @@ Phase 4: run_pre_pr_checks_with_reviewer_agent → APPROVED / DISCUSS
710
715
 
711
716
  As of version **1.0.13+**, `secufusion-mcp` globally bundles both `.secufusion-project-spec.json` and `AGENTS.md`. You **no longer need to copy these files** into every single repository!
712
717
 
713
- When you install globally (`npm install -g secufusion-mcp@latest`), the AI can automatically read your rules and project spec on the fly from the global installation.
718
+ When you install globally (`npm install -g secufusion-mcp@2.1.4`), the AI can automatically read your rules and project spec on the fly from the global installation.
714
719
 
715
720
  **How to load the Rules in a new project:**
716
721
  Depending on your AI client's capabilities, you can load the rules instantly by telling the AI:
@@ -933,9 +938,9 @@ The previously separate `secufusion-dna-plugin` is now fully merged into `secufu
933
938
  During `scan_repository_stack`, the server reads `.secufusion-project-spec.json` and cross-references:
934
939
  - All keys under `"microservices"` (e.g., `sfn-auth-api`, `sfn-events-api`)
935
940
  - The `"frontend.repo"` value (e.g., `sfn-web-ui`)
936
- - The `"chrome_extension.repo"` value (e.g., `snf-browser-extn`)
941
+ - The `"chrome_extension.repo"` or `"snf-browser-extn"` value (e.g., `snf-browser-extn`)
937
942
 
938
- If any of these are physically missing from your local workspace folder, a `[WARNING]` is emitted listing exactly which repositories need to be cloned before a complete DNA map can be built.
943
+ If any of these are physically missing from your local workspace folder, a `[WARNING]` is emitted listing exactly which core pillars need to be cloned before a complete DNA map can be built.
939
944
 
940
945
  ---
941
946
 
@@ -958,7 +963,7 @@ Once installed as a native Claude Plugin, all commands appear natively in the Cl
958
963
 
959
964
  | Command | When to run | What it does |
960
965
  |---|---|---|
961
- | `/sfn-plan <ticket-id or description>` | When you receive a new Azure DevOps ticket | Agent enters the `planner.md` persona. Reads `.secufusion-project-spec.json` for golden rules and coding patterns. Reads `dna.json` to determine which microservice owns the change. Outputs a structured `plan.md` with exact files to touch, rollback strategy, and breaking change scan. **Stops and waits for your green light.** |
966
+ | `/sfn-plan <ticket-id or description>` | When you receive a new Azure DevOps ticket | Agent enters the `planner.md` persona. Silently runs the **Philosophy Engine (Phase -1)** to ensure the task's WHY and RISK are sound (even for bugs). Reads `.secufusion-project-spec.json` for golden rules and `dna.json` to determine blast radius. Outputs a structured `plan.md` with exact files to touch, rollback strategy, and breaking change scan. **Stops and waits for your green light.** |
962
967
 
963
968
  > **Why it stops:** This enforces the non-negotiable Rule 3 — `STRICT YIELD`. The agent must not start coding until you explicitly say "proceed".
964
969
 
package/agents/AGENTS.md CHANGED
@@ -11,19 +11,123 @@ Do not attempt to load all instructions into memory. Based on the current SDLC p
11
11
 
12
12
  ---
13
13
 
14
+ ## THE NON-NEGOTIABLE EXECUTION ORDER
15
+ (Every task, every time — no exceptions, no shortcuts)
16
+
17
+ **DYNAMIC ENFORCEMENT**: Whether you are starting fresh, resuming, or answering mid-task — you must respect this exact sequence. Never skip ahead.
18
+
19
+ ---
20
+
21
+ ### Rule 0 — DNA First (Absolute Pre-requisite)
22
+
23
+ Before ANY other action, call `prime_session(work_item_id: <id>)`.
24
+
25
+ This loads:
26
+ - All microservice contexts relevant to this task
27
+ - DB entities, Kafka topics, API contracts, Chrome extension architecture
28
+ - Frontend component map, security model, tenant isolation structure
29
+ - Golden rules, rejected patterns, and architectural constraints
30
+
31
+ **Without DNA loaded, you are not allowed to reason, assess risk, classify, plan, or code. Period.**
32
+
33
+ If DNA is not loaded (DNA_LOADED = false in `.agents/claude.md`), ABORT and tell the user to run `/sfn-init` first.
34
+
35
+ ---
36
+
37
+ ### Rule 1 — Philosophy Check (Phase -1, SILENT, runs AFTER DNA)
38
+
39
+ For any `user_story`, `feature`, `chore`, or `refactor`:
40
+
41
+ Call `philosophy_check` AFTER DNA is loaded — never before. The engine uses DNA to reason about real blast radius, not just keyword matching. It knows:
42
+ - Which DB entities your story touches and how many services depend on them
43
+ - Whether you are touching a shared multi-tenant auth service
44
+ - Whether the Chrome extension is in scope (requires store deployment)
45
+ - Which Kafka topics fan out to how many consumers
46
+ - Whether your description violates any golden rules
47
+
48
+ **This check is completely invisible to the user.** You do not announce it. You do not show scores, verdicts, or "philosophy" terminology. You surface a concern to the user only if the verdict is FAIL or BLOCKED — and you translate it into plain developer language.
49
+
50
+ For `bug` and `hotfix`: philosophy check still applies, though the scoring engine evaluates them with slightly relaxed thresholds since defects have an inherent "WHY".
51
+
52
+ **Verdicts:**
53
+ - `PHILOSOPHY_PASS` → Silent. Proceed immediately.
54
+ - `PHILOSOPHY_ADVISORY` → Note concerns in `decisions.json`. Tell the user briefly what to watch out for. Continue.
55
+ - `PHILOSOPHY_FAIL` → STOP. Ask the user what is missing (no jargon). Wait for answers. Re-run philosophy_check.
56
+ - `PHILOSOPHY_BLOCKED` → STOP completely. Tell the user the risk and who must sign off. Do not plan. Do not code.
57
+
58
+ ---
59
+
60
+ ### Rule 2 — Clarify Business Intent (WHY before HOW)
61
+
62
+ After philosophy check passes, capture the WHY formally. Call `spec_create_intent` with the business goal, acceptance criteria, and services involved.
63
+
64
+ Do not initialize task tracking (`manage_task`) until the WHY is captured.
65
+
66
+ ---
67
+
68
+ ### Rule 3 — ReAct (Reason, Observe, Act)
69
+
70
+ Deeply reason about the problem using the DNA context you loaded. Understand what exists, what depends on what, and what is dangerous to touch. Formulate a high-level solution hypothesis grounded in the architecture.
71
+
72
+ ---
73
+
74
+ ### Rule 4 — Classify
75
+
76
+ Call `classify_task`. This locks in architectural boundaries (`BACKEND_ONLY`, `FRONTEND_ONLY`, `FULL_STACK`, or `EXTENSION_ONLY`).
77
+
78
+ ---
79
+
80
+ ### Rule 5 — STRICT YIELD
81
+
82
+ After classifying, STOP. Output the result. Ask the user for the green signal. Do NOT chain tool calls.
83
+
84
+ ---
85
+
86
+ ### Rule 6 — Plan Only After Approval
87
+
88
+ Produce the implementation plan only after the user approves the classification.
89
+
14
90
  ---
15
91
 
16
- ## THE 5 NON-NEGOTIABLE RULES FOR PLANNING AND CODING
17
- (Enforcing explicit permission before coding)
92
+ ### Rule 7 — Code is the Last Resort
93
+
94
+ Source code changes are the absolute final step. Only after the plan is approved.
18
95
 
19
- **DYNAMIC ENFORCEMENT**: You must dynamically adhere to these rules at all times. Whether you are starting a fresh task, resuming an interrupted session, or answering a mid-task prompt, you must strictly respect this sequence and never skip ahead.
96
+ ---
97
+
98
+ ## What you are NOT allowed to do before DNA is loaded and philosophy passes:
20
99
 
21
- 1. **Rule 0 (Pre-requisite to all rules) — Load Project DNA First**: Before ANY other action, call `prime_session(work_item_id: <id>)`. This is Phase 00. Without the project DNA loaded, you are not allowed to reason, classify, plan, or code. Period.
22
- 2. **Rule 1 - Clarify Business Intent (WHY before HOW)**: For any new task, you MUST pause and ask the user for the business intent, goal, and risk. YIELD until this is clarified, then call `spec_create_intent`. Do not initialize task tracking (`manage_task`) until the WHY is captured.
23
- 3. **Rule 2 - ReAct (Reason, Observe, Act) First**: After intent is clarified and DNA is loaded, you MUST deeply reason about the problem statement. Apply the ReAct framework: analyze the problem, observe context, and formulate a high-level solution hypothesis.
24
- 4. **Rule 3 - Classify Second**: Only after you have reasoned through the problem statement, you MUST call the `classify_task` tool. This will formally categorize the task and lock in architectural boundaries.
25
- 5. **Rule 4 - STRICT YIELD (Stop and Wait)**: Immediately after classifying the task, you MUST YIELD YOUR TURN. **DO NOT CHAIN TOOL CALLS.** Output the classification, ask the user for the "green signal," and STOP.
26
- 6. **Rule 5 - Plan Only After Approval**: Only after receiving the "green signal" for the classification are you allowed to propose a detailed implementation plan.
27
- 7. **Rule 6 - Code is the Last Resort (Universal)**: Modifying source code is the absolute final step and may only occur after the implementation plan is approved.
100
+ ❌ Read any source files
101
+ ❌ Call `classify_task`
102
+ ❌ Call `manage_task`
103
+ ❌ Write any implementation plan
104
+ ❌ Suggest technical approaches
105
+ ❌ Say "let's start and see"
106
+ ❌ Minimize a FAIL verdict
107
+ ❌ Offer to proceed despite BLOCKED
108
+ ❌ Mention "philosophy", "PHILOSOPHY_FAIL", "PHILOSOPHY_BLOCKED" to the user
28
109
 
29
110
  ---
111
+
112
+ ## The philosophy principle (for your internal reasoning only)
113
+
114
+ Four questions every story must answer before implementation can begin:
115
+
116
+ ```
117
+ WHY → What specific problem does this solve?
118
+ If we can't state the problem, the solution is guesswork.
119
+
120
+ WHO → Who confirmed this is needed?
121
+ "Someone asked" is not confirmation.
122
+ The decision maker must be on record.
123
+
124
+ WHAT → What exactly are we building?
125
+ Vague stories produce vague software.
126
+ If you can't test it, you can't build it.
127
+
128
+ RISK → What breaks if we're wrong?
129
+ Irreversible changes need higher certainty.
130
+ High risk + low certainty = guaranteed waste.
131
+ ```
132
+
133
+ These questions are assessed by `philosophy_check` using real architecture DNA. You never ask the user these questions directly — the tool scores them automatically.
@@ -1,9 +1,9 @@
1
- ---
1
+ ---
2
2
  description: Execute the approved implementation plan. Switches to the Coder Persona and writes code precisely as planned, using rejected-pattern memory to avoid past mistakes.
3
3
  argument-hint: <ticket-id> e.g. WI-123
4
4
  ---
5
5
 
6
- You are executing the **sfn:code** command for the SecuFusion spec-driven SDLC.
6
+ You are executing the **sfn-code** command for the SecuFusion spec-driven SDLC.
7
7
 
8
8
  Task: **$ARGUMENTS**
9
9
 
@@ -13,7 +13,7 @@ Task: **$ARGUMENTS**
13
13
 
14
14
  1. Read `.secufusion/tasks/$ARGUMENTS/plan.md`.
15
15
  2. If the plan file does not exist or has no approval record, **ABORT** and tell the user:
16
- > ❌ No approved plan found for `$ARGUMENTS`. Please run `/sfn:plan $ARGUMENTS` first.
16
+ > ❌ No approved plan found for `$ARGUMENTS`. Please run `/sfn-plan $ARGUMENTS` first.
17
17
  3. Read `.agents/coder.md` to load the **Coder Persona** — your behaviour for this phase is governed by those instructions.
18
18
 
19
19
  ## Phase 1 — Load Rejected Patterns Memory
@@ -46,4 +46,4 @@ Report to the user:
46
46
  - ACs met (with file:line)
47
47
  - Any open risks or deferred items
48
48
 
49
- > 🚀 Implementation complete. Run `/sfn:review` to run the zero-tolerance PR gate checks.
49
+ > 🚀 Implementation complete. Run `/sfn-review` to run the zero-tolerance PR gate checks.
@@ -0,0 +1,74 @@
1
+ ---
2
+ description: On-demand architecture exploration — map the full service graph as a Mermaid diagram, or run a blast-radius impact analysis for a specific component.
3
+ argument-hint: [map] or <component-name-or-file-path> e.g. "map" or "sfn-events-api" or "TenantEntity.java"
4
+ ---
5
+
6
+ You are executing the **sfn-explore** command for the SecuFusion ecosystem.
7
+
8
+ Argument: **$ARGUMENTS**
9
+
10
+ ---
11
+
12
+ ## Mode Detection
13
+
14
+ Read `$ARGUMENTS` and decide the mode:
15
+
16
+ - If `$ARGUMENTS` is empty or equals `map` → **Architecture Map Mode**
17
+ - Otherwise → **Blast Radius Mode** for the given component
18
+
19
+ ---
20
+
21
+ ## Mode A — Architecture Map
22
+
23
+ > Use this when: you want a bird's-eye view of the entire ecosystem (e.g. onboarding a new dev, auditing dependencies).
24
+
25
+ 1. Call `prime_session` or read `.secufusion/dna.json` to load the current knowledge graph.
26
+ 2. Generate a comprehensive **Mermaid diagram** (`graph TD`) that shows:
27
+ - All microservices grouped by bounded context
28
+ - REST API call graph (which service calls which)
29
+ - Kafka topic flow (producer → topic → consumer)
30
+ - Frontend (`sfn-web-ui`) and extension (`snf-browser-extn`) connections to backend services
31
+ 3. Render the Mermaid diagram in the response.
32
+ 4. Below the diagram, print a service inventory table:
33
+
34
+ | Service | Port | Stack | Owns Tables | Produces Topics | Consumes Topics |
35
+ |---|---|---|---|---|---|
36
+
37
+ ---
38
+
39
+ ## Mode B — Blast Radius
40
+
41
+ > Use this when: you are about to refactor a shared entity, change an API contract, or modify a Kafka topic and need to know the full downstream impact.
42
+
43
+ 1. Call `prime_session` or read `.secufusion/dna.json` to load the knowledge graph.
44
+ 2. Search for all references to `$ARGUMENTS` across:
45
+ - Microservice API consumers (who calls this endpoint?)
46
+ - Database entity consumers (which repos query this table/column?)
47
+ - Kafka consumers (which services consume this topic?)
48
+ - Frontend and `snf-browser-extn` (does the UI or extension directly consume this contract?)
49
+ 3. Present a **Cross-Repo Blast Radius Report**:
50
+
51
+ ```
52
+ 🎯 Component: $ARGUMENTS
53
+
54
+ Impacted Microservices:
55
+ - sfn-X-api → [why impacted]
56
+
57
+ Impacted APIs:
58
+ - GET /v1/... → [consumers]
59
+
60
+ Impacted Events / Consumers:
61
+ - topic-name → [consumer services]
62
+
63
+ Impacted Databases:
64
+ - table_name → [services querying this]
65
+
66
+ Impacted Frontend / Extension:
67
+ - sfn-web-ui → [pages / components]
68
+ - snf-browser-extn → [content scripts / background workers]
69
+
70
+ Risk Level: 🟢 LOW | 🟡 MEDIUM | 🔴 HIGH
71
+ ```
72
+
73
+ 4. If risk is 🔴 HIGH, add a warning:
74
+ > ⚠️ High blast radius detected. Consider running `/sfn-plan` with this context before making changes.
@@ -1,22 +1,20 @@
1
1
  ---
2
- description: Prime the SecuFusion ecosystem — scan the entire codebase, map the architectural DNA, and write it to .secufusion/dna.json. Run this once when you first clone a repo.
2
+ description: Prime the SecuFusion ecosystem — scan the entire codebase, map the architectural DNA, generate the architecture diagram, and write it to .secufusion/dna.json. Run this once when you first clone a repo.
3
3
  argument-hint: (no args) — run from the root of the repo
4
4
  ---
5
5
 
6
- You are executing the **sfn:init** bootstrap command for the SecuFusion ecosystem.
6
+ You are executing the **sfn-init** bootstrap command for the SecuFusion ecosystem.
7
7
 
8
8
  **This is a learn-first command.** Your job is to deeply understand THIS project before writing anything. Do not produce generic output — every finding must reflect real `file:line` references from the actual codebase.
9
9
 
10
10
  ## Phase 1 — SCAN the Repository
11
11
 
12
- Call the **secufusion-dna-plugin** MCP tools to scan the repository:
12
+ Call the following MCP tools to scan the repository. Run all 4 **concurrently in a single message**:
13
13
 
14
- 1. Call `scan_repository_stack` to identify: language, framework, package manager, microservices, database entities, and build/test commands. Flag if this is a monorepo.
15
- 2. Call `extract_domain_models` to map all domain entities, their fields, and relationships.
16
- 3. Call `extract_api_endpoints` to map all REST/GraphQL endpoints, their methods, and owning services.
17
- 4. Call `extract_event_topics` to map all Kafka/event-bus topics, producers, and consumers.
18
-
19
- Run all 4 tool calls in a **single message** so they execute concurrently.
14
+ 1. `scan_repository_stack` — identify language, framework, package manager, microservices, DB entities, build/test commands. Flag if monorepo.
15
+ 2. `extract_domain_models` — map all domain entities, their fields, and relationships.
16
+ 3. `extract_api_endpoints` — map all REST/GraphQL endpoints, their methods, and owning services.
17
+ 4. `extract_event_topics` — map all Kafka/event-bus topics, producers, and consumers.
20
18
 
21
19
  ## Phase 2 — WRITE the DNA
22
20
 
@@ -43,6 +41,17 @@ Once all scans complete:
43
41
  Summarize what was found:
44
42
  - Number of services, domain models, API endpoints, and event topics discovered
45
43
  - Any gaps or areas marked `(inferred)` that the human should verify
44
+ - **CRITICAL CORE CHECK:** Explicitly verify that the DNA map contains mappings for **frontend**, **backend**, and **snf-browser-extn** (extension). If ANY of these 3 are missing, print a prominent warning listing exactly what is missing and what needs to be cloned/added.
46
45
  - Confirm that `.secufusion/dna.json` was written successfully
47
46
 
48
- **Next step for the user:** Run `/sfn:plan <ticket-id>` to start your first task.
47
+ ## Phase 4 — ARCHITECTURE DIAGRAM
48
+
49
+ Using the data now in `dna.json`, generate a comprehensive **Mermaid diagram** (`graph TD`) that visualizes:
50
+ - All microservices and their bounded contexts
51
+ - REST API call graph (which service calls which)
52
+ - Kafka topic flow (producer → topic → consumer)
53
+ - Frontend and `snf-browser-extn` connections to backend services
54
+
55
+ Render the diagram directly in your response so the user can see the full ecosystem at a glance.
56
+
57
+ **Next step for the user:** Run `/sfn-plan <ticket-id>` to start your first task.
@@ -1,79 +1,161 @@
1
1
  ---
2
- description: Architect a solution for a task or Jira ticket using the loaded DNA. Clarifies business intent, creates a dedicated task workspace, classifies the work, and produces a strict implementation plan awaiting your approval.
3
- argument-hint: <ticket-id or feature description> e.g. WI-123 or "add user login endpoint"
2
+ description: Architect a solution for a task or story. Loads architecture DNA, silently validates story integrity, classifies the work, and produces a strict implementation plan.
3
+ argument-hint: <WI-XXXX or feature description> e.g. "WI-2847" or "add tenant export feature"
4
4
  ---
5
5
 
6
- You are executing the **sfn:plan** command for the SecuFusion spec-driven SDLC.
6
+ You are executing the **sfn-plan** command for the SecuFusion spec-driven SDLC.
7
7
 
8
8
  Task / Ticket: **$ARGUMENTS**
9
9
 
10
10
  **You are in the PLANNING phase. Do NOT write any implementation code in this phase.**
11
11
 
12
- ## Pre-flight: DNA Check
12
+ ---
13
+
14
+ ## Step 1 — DNA Guard (Mandatory Pre-flight)
15
+
16
+ Read `.agents/claude.md` and check the `<MEMORY>` block.
17
+
18
+ If `DNA_LOADED` is `false` or missing:
19
+
20
+ > ❌ Project DNA is not loaded.
21
+ > Run `/sfn-init` first to scan and index the codebase architecture.
22
+ > Without DNA, I cannot assess risk, identify service boundaries, or validate story integrity.
23
+
24
+ **ABORT here. Do not continue.**
25
+
26
+ ---
27
+
28
+ ## Step 2 — Clarify and Capture Business Intent
13
29
 
14
- 1. Read `.agents/claude.md` and check the `<MEMORY>` block.
15
- 2. If `DNA_LOADED` is `false` or `null`, **ABORT immediately** and tell the user:
16
- > ❌ Project DNA is not loaded. Please run `/sfn:init` first.
30
+ Before thinking about *how* to implement, understand *why* it is needed.
17
31
 
18
- ## Phase 1 — Clarify and Capture Business Intent (The WHY Layer)
32
+ Analyze the task. Ask the user if ANY of these are unclear:
33
+ - **What problem does this solve?** (not the solution — the problem)
34
+ - **Who will use this and how does it affect them?**
35
+ - **What is the business risk if NOT delivered?**
36
+ - **Has the client or decision maker explicitly confirmed this is needed?**
19
37
 
20
- Before thinking about *how* to implement the task, you must understand *why* it is needed.
21
- 1. Analyze the requested task.
22
- 2. Ask the user clarifying questions if the following are not completely clear:
23
- - Why is this being built? What user or business problem does it solve?
24
- - What is already there, and is this actually needed?
25
- - What is the business risk if not delivered?
26
- 3. **YIELD** and wait for the user to clarify the business intent. Do not proceed to Phase 2 until the intent is clear.
38
+ **YIELD.** Wait for the user to answer. Do not proceed until intent is clear.
27
39
 
28
- Once the intent is clarified, call `spec_create_intent` with:
29
- - `work_item_id`: the ticket ID or a slugified version of the description
30
- - `title`: short human-readable title
31
- - `business_goal`: The clarified business problem it solves.
32
- - `acceptance_criteria`: Given/When/Then ACs gathered from the ticket/clarification.
33
- - `services_involved`: **Polyglot service map** — list every service this touches, regardless of language (Java, Go, Python, TypeScript).
34
- - `risk`: business risk if not delivered.
40
+ Once clarified, call `spec_create_intent` with:
41
+ - `work_item_id`: the ticket ID
42
+ - `title`: short title
43
+ - `business_goal`: the problem being solved (from user's answer)
44
+ - `acceptance_criteria`: Given/When/Then ACs from the conversation
45
+ - `services_involved`: every service this touches (polyglot — Java, Go, TS, Python)
46
+ - `risk`: business risk if not delivered
35
47
 
36
- > 💡 This creates `.secufusion/intents/<num>-WI-<id>-<slug>.md` — a human-readable file capturing the WHY.
48
+ ---
37
49
 
38
- ## Phase 2 — Initialize the Task Workspace (The HOW Layer)
50
+ ## Step 3 — Initialize Task Workspace
39
51
 
40
- Now that the *why* is captured, initialize the *how* tracking.
41
- Call `manage_task` with:
52
+ Call `manage_task`:
42
53
  ```
43
54
  action: "initialize"
44
- work_item_id: <same ID as above>
55
+ work_item_id: <same ID>
45
56
  ```
46
- This creates the dedicated workspace folder at `.secufusion/tasks/<id>/` and begins tracking progress. Do not proceed until this call succeeds.
47
57
 
48
- ## Phase 3 — Load Context
58
+ Creates `.secufusion/tasks/<id>/` workspace. Do not proceed until this succeeds.
59
+
60
+ ---
61
+
62
+ ## Step 4 — Load Architecture DNA
63
+
64
+ Call `prime_session(work_item_id: <id>)`.
49
65
 
50
- 1. Call `prime_session(work_item_id: <id>)` to efficiently load the project DNA state and relevant architectural context for this specific task.
51
- 2. Read the `.secufusion-project-spec.json` from the project root to understand the golden rules, constraints, and acceptance criteria boundaries for this project.
66
+ This loads:
67
+ - Relevant microservice contexts from the project spec
68
+ - Active task state and prior decisions
69
+ - Architectural boundaries, golden rules, coding constraints
70
+ - Known rejected patterns
71
+
72
+ Also read `.secufusion-project-spec.json` directly to access:
73
+ - `db_entities` — all database tables and their relationships
74
+ - `api_endpoints` — all API contracts and consumers
75
+ - `kafka_topics` — all event topics and their producer/consumer map
76
+ - `frontend_components` — all React/Vue/Angular components
77
+ - `chrome_extension` — extension pages, content scripts, background workers
78
+ - `security_context` — auth/authz architecture, tenant isolation model
79
+ - `microservices` — all backend services and their dependencies
80
+
81
+ > **This DNA is the foundation for everything that follows.**
82
+ > You now know what exists, what depends on what, and what is dangerous to touch.
83
+
84
+ ---
52
85
 
53
- ## Phase 4 — Classify the Task
86
+ ## Step 5 — [INTERNAL] Story Integrity Check
54
87
 
55
- Call `classify_task` with the task description: **$ARGUMENTS**
88
+ > ⚠️ This step is completely invisible to the user. Run it silently. Do not announce it.
89
+ > Do not show scores, verdicts, or philosophy terminology to the user.
90
+ > Only surface a concern to the user if it would BLOCK or fundamentally change the work.
56
91
 
57
- This formally categorizes the work (Feature, Bug, Refactor, Security, Performance, etc.) and locks in the architectural boundaries. **YIELD after this call.** Output the classification result and ask the user:
92
+ **For ALL task types (`user_story`, `feature`, `chore`, `refactor`, `bug`, `hotfix`):**
93
+
94
+ Call `philosophy_check` with:
95
+ - `work_item_id`: the ticket ID
96
+ - `title`: the story title
97
+ - `description`: the FULL description including ACs gathered in Step 2 (use the enriched version, not just the raw ticket)
98
+ - `task_type`: inferred type
99
+ - `reported_by`: from conversation context if known
100
+ - `client_confirmed`: from conversation context if known
101
+
102
+ The tool internally uses the DNA loaded in Step 4 to assess real architectural risk — not just keyword matching, but actual blast radius against the known service graph.
103
+
104
+ **Act on the verdict:**
105
+
106
+ **If `PHILOSOPHY_PASS`:**
107
+ - Silently proceed to Step 6. Nothing to show the user.
108
+
109
+ **If `PHILOSOPHY_ADVISORY`:**
110
+ - Note all advisory concerns in `.secufusion/tasks/<id>/decisions.json`
111
+ - Tell the user briefly: *"A few architectural concerns to keep in mind during implementation: [list the advisory items plainly, without philosophy terminology]"*
112
+ - Continue to Step 6.
113
+
114
+ **If `PHILOSOPHY_FAIL`:**
115
+ - Do NOT proceed to Step 6.
116
+ - Translate each blocking question into plain developer language — no philosophy jargon.
117
+ - Show the user what is missing, why it matters, and what they need to answer.
118
+ - Say: *"Before I can plan this, I need answers to a few critical questions."*
119
+ - **STOP. Wait for answers. Re-run Step 5 after receiving them.**
120
+
121
+ **If `PHILOSOPHY_BLOCKED`:**
122
+ - Do NOT proceed to Step 6.
123
+ - Tell the user plainly what the risk is and who needs to sign off.
124
+ - Do NOT use "PHILOSOPHY_BLOCKED" terminology. Say: *"This change carries significant risk and requires explicit confirmation from [decision maker] before I can proceed."*
125
+ - **STOP completely. No planning. No code reading. Wait for confirmation.**
126
+
127
+ ---
128
+
129
+ ## Step 6 — Classify the Task
130
+
131
+ Call `classify_task` with the task description from $ARGUMENTS.
132
+
133
+ This formally categorizes the work as `BACKEND_ONLY`, `FRONTEND_ONLY`, `FULL_STACK`, or `EXTENSION_ONLY` and locks in architectural boundaries.
134
+
135
+ **YIELD after this call.** Show the classification result and ask:
58
136
 
59
137
  > ✅ Classification complete. Does this look right? Give me the green signal to proceed with planning.
60
138
 
61
- Wait for explicit approval before continuing.
139
+ Wait for explicit approval.
62
140
 
63
- ## Phase 5 — Write the Implementation Plan (After Approval)
141
+ ---
142
+
143
+ ## Step 7 — Write the Implementation Plan
64
144
 
65
- Read `.agents/planner.md` for the Planner Persona instructions and produce a strict, step-by-step implementation plan that includes:
145
+ Read `.agents/planner.md` for Planner Persona instructions.
66
146
 
67
- - **Acceptance Criteria** (Given/When/Then format, testable)
147
+ Produce a strict implementation plan grounded in the DNA context, including:
148
+
149
+ - **Acceptance Criteria** (Given/When/Then, testable)
68
150
  - **Scope Boundaries** (what is explicitly OUT of scope)
69
- - **Files to Create / Modify / Delete**
70
- - **Architectural Decisions** (with rationale grounded in the DNA)
71
- - **Risk Flags** (tenant isolation, N+1 risks, missing indexes, Kafka sync calls)
72
- - **Test Plan**
73
- - **Polyglot Impact** — for each service in the intent's Service Map that has no AST parser, note it explicitly and list what metadata is required (ports, topics, endpoints)
151
+ - **Files to Create / Modify / Delete** (with service ownership)
152
+ - **Architectural Decisions** (rationale grounded in project DNA)
153
+ - **Risk Flags** (tenant isolation, N+1 queries, missing indexes, Kafka sync anti-patterns)
154
+ - **Test Plan** (unit + integration + scenario coverage)
155
+ - **Polyglot Impact** — for each service with no AST parser, list required metadata (ports, topics, endpoints, schemas)
156
+ - **Advisory Items** (from Step 5, if any) — note these as implementation guardrails
74
157
 
75
- Save the plan to `.secufusion/tasks/<id>/plan.md`.
158
+ Save to `.secufusion/tasks/<id>/plan.md`.
76
159
 
77
160
  Present the plan and ask:
78
- > 📋 Plan ready. Review `plan.md` and approve to begin coding with `/sfn:code`.
79
-
161
+ > 📋 Plan ready. Review `plan.md` and approve to begin coding with `/sfn-code`.
@@ -1,9 +1,9 @@
1
- ---
1
+ ---
2
2
  description: Run the zero-tolerance PR gate — 5 mechanical checks (Tenant Isolation, N+1, Missing Index, Kafka Sync, Early Returns) followed by a senior Reviewer Persona sign-off. A PR must pass this before it can be opened.
3
3
  argument-hint: <ticket-id> e.g. WI-123
4
4
  ---
5
5
 
6
- You are executing the **sfn:review** command — the final quality gate before a Pull Request is opened.
6
+ You are executing the **sfn-review** command — the final quality gate before a Pull Request is opened.
7
7
 
8
8
  Task: **$ARGUMENTS**
9
9
 
@@ -22,7 +22,7 @@ Call `run_pre_pr_checks_with_reviewer_agent` to trigger the `sfn-pr-check` CLI.
22
22
  | **Early Returns** | No deeply nested if/else — use guard clauses |
23
23
 
24
24
  **If any check FAILS:** Do NOT proceed to Phase 2. Report the exact violation with `file:line` and tell the user:
25
- > ❌ Tier 1 gate failed. Fix the violations above and re-run `/sfn:review`.
25
+ > ❌ Tier 1 gate failed. Fix the violations above and re-run `/sfn-review`.
26
26
 
27
27
  Call `log_rejected_pattern(work_item_id: "$ARGUMENTS", pattern: "<description of the violation>")` to record it in permanent memory so it is never repeated.
28
28
 
@@ -0,0 +1,39 @@
1
+ export function parseExtension(filePath, fileContent, repository) {
2
+ const components = [];
3
+ const fileName = filePath.split(/[\\/]/).pop()?.toLowerCase() || '';
4
+ if (fileName === 'manifest.json') {
5
+ components.push({
6
+ componentName: 'Manifest',
7
+ type: 'Manifest',
8
+ filePath,
9
+ repository
10
+ });
11
+ }
12
+ else if (fileContent.includes('chrome.runtime.onInstalled') || fileContent.includes('chrome.runtime.onMessage') || fileContent.includes('browser.runtime')) {
13
+ if (fileName.includes('background')) {
14
+ components.push({
15
+ componentName: 'BackgroundScript',
16
+ type: 'BackgroundScript',
17
+ filePath,
18
+ repository
19
+ });
20
+ }
21
+ else if (fileName.includes('content')) {
22
+ components.push({
23
+ componentName: 'ContentScript',
24
+ type: 'ContentScript',
25
+ filePath,
26
+ repository
27
+ });
28
+ }
29
+ else {
30
+ components.push({
31
+ componentName: fileName,
32
+ type: 'ExtensionScript',
33
+ filePath,
34
+ repository
35
+ });
36
+ }
37
+ }
38
+ return components;
39
+ }
@@ -25,6 +25,7 @@ import { parseApiEndpoints } from "./parsers/api.js";
25
25
  import { parseEventTopics } from "./parsers/events.js";
26
26
  import { inferPatterns } from "./parsers/patterns.js";
27
27
  import { parseFrontend } from "./parsers/frontend.js";
28
+ import { parseExtension } from "./parsers/extension.js";
28
29
  import { parseNodeApis } from "./parsers/backend-node.js";
29
30
  import { parseInfra } from "./parsers/infra.js";
30
31
  import { parseDatabase } from "./parsers/database.js";
@@ -424,7 +425,7 @@ server.tool("manage_project_spec", "Manages the .secufusion-project-spec.json fi
424
425
  }
425
426
  }
426
427
  // 4. Check spec.chrome_extension by repo name
427
- const chromeExt = spec.chrome_extension;
428
+ const chromeExt = (spec.chrome_extension || spec["snf-browser-extn"] || spec.snf_browser_extn);
428
429
  if (!serviceBlock && chromeExt) {
429
430
  const repoName = String(chromeExt.repo ?? "").toLowerCase();
430
431
  if (repoName === svcNameLower || svcNameLower.includes("chrome") || svcNameLower.includes("extension")) {
@@ -1431,7 +1432,386 @@ function buildScopeText(signals, domain) {
1431
1432
  ? parts.join("\n ")
1432
1433
  : `${domain} implementation required`;
1433
1434
  }
1434
- // ─── Tool 9: classify_task ────────────────────────────────────────────────────
1435
+ // --- Tool 9: philosophy_check -------------------------------------------------
1436
+ server.tool("philosophy_check", "MANDATORY PHASE -1 STEP — runs BEFORE classify_task, BEFORE reading any source files, BEFORE any planning. " +
1437
+ "Challenges the WHY, WHO, WHAT, and RISK of a story before any implementation begins. " +
1438
+ "Returns PHILOSOPHY_PASS, PHILOSOPHY_ADVISORY, PHILOSOPHY_FAIL, or PHILOSOPHY_BLOCKED. " +
1439
+ "A FAIL or BLOCKED verdict completely stops all implementation — classify_task MUST NOT be called until this returns PASS or ADVISORY. " +
1440
+ "Applies to ALL task types including bugs and hotfixes (though sensing is slightly relaxed for defects).", {
1441
+ work_item_id: z.string().describe("Azure DevOps work item ID. e.g. 'WI-2847'"),
1442
+ title: z.string().describe("Full story/task title from Azure DevOps."),
1443
+ description: z.string().describe("Full story description including user story, acceptance criteria, and any context."),
1444
+ task_type: z
1445
+ .enum(["bug", "user_story", "feature", "hotfix", "refactor", "chore"])
1446
+ .describe("bug | user_story | feature | hotfix | refactor | chore"),
1447
+ reported_by: z.string().optional().describe("Who created/reported this story. e.g. 'client', 'PM', 'tech lead', 'developer'."),
1448
+ client_confirmed: z.boolean().optional().describe("Has the decision maker explicitly confirmed this is needed?"),
1449
+ }, async ({ work_item_id, title, description, task_type, reported_by, client_confirmed }) => {
1450
+ const inputChars = JSON.stringify({ work_item_id, title, description, task_type }).length;
1451
+ // Fast-path: bugs and hotfixes skip philosophy check
1452
+ if (task_type === "bug" || task_type === "hotfix") {
1453
+ return appendTelemetry({ content: [{ type: "text", text: `[PHILOSOPHY SKIPPED] ${work_item_id} — task_type="${task_type}". Bugs/hotfixes skip philosophy. Proceeding directly to classify_task.` }] }, inputChars);
1454
+ }
1455
+ // Check cache
1456
+ const philosophyDir = resolve(".secufusion/philosophy");
1457
+ const philosophyFile = path.join(philosophyDir, `${work_item_id}.json`);
1458
+ if (fs.existsSync(philosophyFile)) {
1459
+ try {
1460
+ const cached = JSON.parse(readFileSafe(philosophyFile) || "null");
1461
+ if (cached && (cached.philosophy_verdict === "PHILOSOPHY_PASS" || cached.philosophy_verdict === "PHILOSOPHY_ADVISORY")) {
1462
+ return appendTelemetry({ content: [{ type: "text", text: `[PHILOSOPHY CACHED] ${work_item_id} — verdict: ${cached.philosophy_verdict}\n\n${cached.developer_message}` }] }, inputChars);
1463
+ }
1464
+ }
1465
+ catch { }
1466
+ }
1467
+ const wsRoot = getWorkspaceRoot();
1468
+ let rejectedPatterns = [];
1469
+ const rejRaw = readFileSafe(resolve(REJECTED_FILE));
1470
+ if (rejRaw) {
1471
+ try {
1472
+ rejectedPatterns = JSON.parse(rejRaw);
1473
+ }
1474
+ catch { }
1475
+ }
1476
+ // ── Load Architecture DNA (MANDATORY for intelligent risk scoring) ──────
1477
+ // philosophy_check reasons against real architecture — not just keywords.
1478
+ // DNA provides: DB entities, Kafka topics, services, extension, auth model.
1479
+ let dna = null;
1480
+ let spec = null;
1481
+ // Load project spec (golden rules, service map, security model)
1482
+ const specCands2 = [
1483
+ path.resolve(path.dirname(new URL(import.meta.url).pathname.replace(/^\/([A-Z]:)/, "$1")), ".secufusion-project-spec.json"),
1484
+ path.resolve(wsRoot, ".secufusion-project-spec.json"),
1485
+ ];
1486
+ for (const c of specCands2) {
1487
+ if (fs.existsSync(c)) {
1488
+ try {
1489
+ spec = JSON.parse(readFileSafe(c) || "null");
1490
+ break;
1491
+ }
1492
+ catch { }
1493
+ }
1494
+ }
1495
+ // Load DNA — full architecture graph
1496
+ const dnaCandidates = [
1497
+ path.resolve(wsRoot, ".secufusion", "dna.json"),
1498
+ path.resolve(path.dirname(new URL(import.meta.url).pathname.replace(/^\/([A-Z]:)/, "$1")), ".secufusion", "dna.json"),
1499
+ ];
1500
+ for (const d of dnaCandidates) {
1501
+ if (fs.existsSync(d)) {
1502
+ try {
1503
+ dna = JSON.parse(readFileSafe(d) || "null");
1504
+ break;
1505
+ }
1506
+ catch { }
1507
+ }
1508
+ }
1509
+ // Extract architectural context
1510
+ const dnaServices = dna?.services?.map((s) => (s.name || "").toLowerCase()).filter((s) => s.length > 4) || [];
1511
+ const dnaEntities = dna?.db_entities?.map((e) => (e.name || e.table || "").toLowerCase()).filter((e) => e.length > 3) || [];
1512
+ const dnaTopics = dna?.kafka_topics || dna?.events || [];
1513
+ const dnaExtension = dna?.chrome_extension || dna?.extension || dna?.["snf-browser-extn"] || null;
1514
+ const dnaSecurity = dna?.security_context || spec?.security || null;
1515
+ const dnaGoldenRules = spec?.golden_rules || [];
1516
+ // DNA-aware risk bonus (stacks on top of keyword risk scores)
1517
+ let dna_risk_bonus = 0;
1518
+ const dnaRiskNotes = [];
1519
+ const text = `${title} ${description}`.toLowerCase();
1520
+ const wordCount = description.trim().split(/\s+/).length;
1521
+ // [DNA-1] DB entities mentioned in story — each known entity = real schema blast
1522
+ const mentionedEntities = dnaEntities.filter(e => text.includes(e));
1523
+ if (mentionedEntities.length > 0) {
1524
+ const entityRisk = Math.min(mentionedEntities.length * 10, 40);
1525
+ dna_risk_bonus += entityRisk;
1526
+ dnaRiskNotes.push(`DB entities: ${mentionedEntities.join(", ")} (+${entityRisk})`);
1527
+ }
1528
+ // [DNA-2] Kafka topics — fan-out cascades to all consumers
1529
+ const mentionedTopics = dnaTopics.filter((t) => {
1530
+ const tn = (t.name || t.topic || "").toLowerCase();
1531
+ return tn.length > 3 && text.includes(tn);
1532
+ });
1533
+ if (mentionedTopics.length > 0) {
1534
+ const topicConsumers = mentionedTopics.reduce((sum, t) => sum + (t.consumers?.length || t.consumer_count || 0), 0);
1535
+ const topicRisk = Math.min(mentionedTopics.length * 15 + topicConsumers * 5, 35);
1536
+ dna_risk_bonus += topicRisk;
1537
+ dnaRiskNotes.push(`Kafka topics: ${mentionedTopics.map((t) => t.name || t.topic).join(", ")} (${topicConsumers} consumers) (+${topicRisk})`);
1538
+ }
1539
+ // [DNA-3] Chrome extension changes require store deployment
1540
+ if (dnaExtension && (text.includes("extension") || text.includes("chrome") || text.includes("background script") || text.includes("content script") || text.includes("popup"))) {
1541
+ dna_risk_bonus += 20;
1542
+ dnaRiskNotes.push("snf-browser-extn affected — manual store publish (+20)");
1543
+ }
1544
+ // [DNA-4] Shared multi-tenant auth service — changes blast all tenants
1545
+ const isSharedAuth = dnaSecurity && (dnaSecurity.type === "shared" || dnaSecurity.multi_tenant === true || dnaSecurity.multi_tenant === "true");
1546
+ if (isSharedAuth && (text.includes("auth") || text.includes("login") || text.includes("permission") || text.includes("role") || text.includes("tenant") || text.includes("token"))) {
1547
+ dna_risk_bonus += 25;
1548
+ dnaRiskNotes.push("Shared multi-tenant auth — cross-tenant blast (+25)");
1549
+ }
1550
+ // [DNA-5] Polyglot service coordination — 3+ services = integration risk
1551
+ const mentionedServices = dnaServices.filter(s => text.includes(s));
1552
+ if (mentionedServices.length >= 3) {
1553
+ dna_risk_bonus += 15;
1554
+ dnaRiskNotes.push(`Multi-service: ${mentionedServices.slice(0, 4).join(", ")} (+15)`);
1555
+ }
1556
+ // [DNA-6] Golden rule violation signals
1557
+ const antiPatterns = ["bypass", "skip migration", "no migration", "hardcode", "raw sql", "direct db", "without migration"];
1558
+ const hitAntipatterns = antiPatterns.filter(ap => text.includes(ap));
1559
+ if (hitAntipatterns.length > 0) {
1560
+ dna_risk_bonus += 20;
1561
+ dnaRiskNotes.push(`Antipattern signal: ${hitAntipatterns.join(", ")} (+20)`);
1562
+ }
1563
+ const dnaAvailable = dna !== null;
1564
+ const dnaWarning = dnaAvailable ? "" : "\n[NOTE] DNA not loaded — risk is keyword-only. Run /sfn-init for architecture-aware scoring.";
1565
+ // PASS 1 - WHY CHECK
1566
+ let why_score = 0;
1567
+ if (task_type === "bug" || task_type === "hotfix") {
1568
+ why_score += 20; // Relaxed WHY sensing for defects
1569
+ }
1570
+ const STRONG_WHY = ["users spend", "current process causes", "compliance requires", "audit requires", "production issue", "users are reporting", "data shows", "confirmed by", "ticket from client", "business requirement", "regulatory", "security risk", "revenue impact"];
1571
+ const WEAK_WHY = [
1572
+ "would be nice", "nice feature", "nice addition", "could be useful", "other platforms have",
1573
+ "other saas", "other products have", "similar products", "competitors have",
1574
+ "client might want", "we should probably", "nice to have", "maybe useful",
1575
+ "might improve", "could improve", "would improve", "would be helpful",
1576
+ "suggestion", "idea", "asked for it"
1577
+ ];
1578
+ for (const s of STRONG_WHY)
1579
+ if (text.includes(s))
1580
+ why_score += 10;
1581
+ for (const s of WEAK_WHY)
1582
+ if (text.includes(s))
1583
+ why_score -= 10;
1584
+ if (text.includes("client asked") && !text.includes("because") && !text.includes("so that"))
1585
+ why_score -= 10;
1586
+ // Penalize descriptions under 30 words with no strong why — they can't justify themselves
1587
+ if (wordCount < 30 && why_score <= 0)
1588
+ why_score -= 10;
1589
+ let purpose_stated = false;
1590
+ let purpose_text = "";
1591
+ for (const m of ["so that", "in order to", "because", "which means", "this allows"]) {
1592
+ const idx = description.toLowerCase().indexOf(m);
1593
+ if (idx !== -1) {
1594
+ purpose_stated = true;
1595
+ purpose_text = description.substring(idx, idx + 120).trim();
1596
+ break;
1597
+ }
1598
+ }
1599
+ const why_verdict = why_score >= 10 ? "STRONG" : why_score >= 0 ? "ACCEPTABLE" : why_score >= -19 ? "WEAK" : "NO_JUSTIFICATION";
1600
+ // PASS 2 - WHO CHECK
1601
+ let who_score = 0;
1602
+ if (task_type === "bug" || task_type === "hotfix") {
1603
+ who_score += 15; // Relaxed WHO sensing for defects
1604
+ }
1605
+ const AUTH_SIG = ["client confirmed", "client approved", "stakeholder sign-off", "decision made by", "approved by", "confirmed in meeting", "email from client", "client requirement", "explicit request from", "signed off"];
1606
+ const UNCERT_SIG = [
1607
+ "assumed", "we think", "probably", "should want", "might need", "could need",
1608
+ "i think the client", "i think clients", "pm suggestion", "internal idea", "we decided",
1609
+ "i think", "don't think", "shouldn't need", "won't need"
1610
+ ];
1611
+ for (const s of AUTH_SIG)
1612
+ if (text.includes(s))
1613
+ who_score += 10;
1614
+ for (const s of UNCERT_SIG)
1615
+ if (text.includes(s))
1616
+ who_score -= 10;
1617
+ if (reported_by) {
1618
+ const rb = reported_by.toLowerCase();
1619
+ if (rb === "client")
1620
+ who_score += 15;
1621
+ else if (rb === "pm")
1622
+ who_score += 5;
1623
+ else if (rb === "developer")
1624
+ who_score -= 5;
1625
+ }
1626
+ if (client_confirmed === true)
1627
+ who_score += 20;
1628
+ else if (client_confirmed === false)
1629
+ who_score -= 20;
1630
+ const who_verdict = who_score >= 15 ? "CONFIRMED" : who_score >= 0 ? "PROBABLE" : who_score >= -14 ? "UNCERTAIN" : "UNCONFIRMED";
1631
+ // PASS 3 - WHAT CHECK
1632
+ let what_score = 0;
1633
+ if (text.includes("acceptance criteria"))
1634
+ what_score += 20;
1635
+ const hasGWT = text.includes("given") && text.includes("when") && text.includes("then");
1636
+ if (hasGWT)
1637
+ what_score += 15;
1638
+ const numberedACs = (description.match(/\b(ac-?\d+|\d+\.\s+(?:given|when|then|the user|the system))/gi) || []).length;
1639
+ if (numberedACs >= 2)
1640
+ what_score += 10;
1641
+ if ((description.match(/\bmust\b/gi) || []).length >= 1)
1642
+ what_score += 5;
1643
+ if (text.includes("as discussed"))
1644
+ what_score -= 15;
1645
+ if (text.includes("as agreed"))
1646
+ what_score -= 15;
1647
+ if (text.includes("tbd"))
1648
+ what_score -= 20;
1649
+ if (text.includes("to be defined"))
1650
+ what_score -= 20;
1651
+ if (wordCount < 50)
1652
+ what_score -= 10;
1653
+ if (!/\b(\d+%|within \d+|less than \d+|at least \d+)\b/.test(description) && wordCount < 80)
1654
+ what_score -= 10;
1655
+ const hasOutOfScope = text.includes("out of scope") || text.includes("not included");
1656
+ if (hasOutOfScope)
1657
+ what_score += 10;
1658
+ if (text.includes("edge cases"))
1659
+ what_score += 10;
1660
+ if (text.includes("error handling"))
1661
+ what_score += 5;
1662
+ const what_verdict = what_score >= 20 ? "CLEAR" : what_score >= 0 ? "ACCEPTABLE" : what_score >= -19 ? "VAGUE" : "UNDEFINED";
1663
+ const ac_count = Math.max(numberedACs, (description.match(/\b(ac-?\d+|given\b)/gi) || []).length);
1664
+ // PASS 4 - RISK CHECK
1665
+ let risk_score = 0;
1666
+ const high_risk_factors = [];
1667
+ const riskSignals = [
1668
+ ["db migration", 20, "DB migration"], ["database migration", 20, "DB migration"],
1669
+ ["drop column", 30, "Drop column"], ["rename column", 30, "Rename column"],
1670
+ ["authentication change", 25, "Auth change"], ["auth change", 25, "Auth change"],
1671
+ ["authorization change", 20, "Authz change"], ["permission change", 20, "Permission change"],
1672
+ ["all tenants", 20, "Affects all tenants"], ["kafka schema", 25, "Kafka schema change"],
1673
+ ["chrome extension", 15, "Chrome extension"], ["irreversible", 30, "Irreversible"],
1674
+ ["data migration", 20, "Data migration"], ["api contract", 25, "API contract change"],
1675
+ ["breaking change", 25, "Breaking change"], ["affects existing", 15, "Affects existing"],
1676
+ ];
1677
+ for (const [kw, score, label] of riskSignals) {
1678
+ if (text.includes(kw)) {
1679
+ risk_score += score;
1680
+ if (!high_risk_factors.includes(label))
1681
+ high_risk_factors.push(label);
1682
+ }
1683
+ }
1684
+ // Regex-based: catch "drop the old X columns", "Drop legacy device columns", etc.
1685
+ // Use 'text' (title+desc combined) since title often has key verb, description has the noun.
1686
+ if (/\bdrop\b.{0,60}\bcolumns?/i.test(text) && !high_risk_factors.includes("Drop column")) {
1687
+ risk_score += 30;
1688
+ high_risk_factors.push("Drop column (pattern)");
1689
+ }
1690
+ if (/\bdelete\b.{0,30}\bcolumns?/i.test(text) && !high_risk_factors.includes("Drop column")) {
1691
+ risk_score += 30;
1692
+ high_risk_factors.push("Delete column (pattern)");
1693
+ }
1694
+ if (text.includes("delete") && (text.includes(" data") || text.includes("record"))) {
1695
+ risk_score += 25;
1696
+ high_risk_factors.push("Data deletion");
1697
+ }
1698
+ if (text.includes("new endpoint"))
1699
+ risk_score += 10;
1700
+ if (text.includes("new table"))
1701
+ risk_score += 10;
1702
+ if (text.includes("new kafka topic"))
1703
+ risk_score += 15;
1704
+ if (text.includes("new service"))
1705
+ risk_score += 20;
1706
+ if (text.includes("read only") || text.includes("display only"))
1707
+ risk_score -= 10;
1708
+ if (text.includes("no db change") || text.includes("no migration"))
1709
+ risk_score -= 15;
1710
+ if (text.includes("isolated change"))
1711
+ risk_score -= 10;
1712
+ if (text.includes("config change only"))
1713
+ risk_score -= 10;
1714
+ let rejected_pattern_risk = false;
1715
+ for (const rp of rejectedPatterns) {
1716
+ const rpKeywords = rp.keywords || (rp.pattern ? [rp.pattern] : []);
1717
+ for (const kw of rpKeywords) {
1718
+ if (kw && text.includes(kw.toLowerCase())) {
1719
+ rejected_pattern_risk = true;
1720
+ risk_score += 20;
1721
+ high_risk_factors.push(`Rejected pattern: ${rp.id || rp.name}`);
1722
+ break;
1723
+ }
1724
+ }
1725
+ }
1726
+ // ── Apply DNA-aware risk bonus ──────────────────────────────────────
1727
+ // Keyword scoring is blind to actual architecture. DNA bonus reflects real blast radius.
1728
+ risk_score += Math.min(dna_risk_bonus, 50); // cap at 50 to prevent double-stacking
1729
+ for (const note of dnaRiskNotes) {
1730
+ if (!high_risk_factors.includes(note))
1731
+ high_risk_factors.push(`[DNA] ${note}`);
1732
+ }
1733
+ const risk_verdict = risk_score <= 10 ? "LOW" : risk_score <= 30 ? "MEDIUM" : risk_score <= 50 ? "HIGH" : "CRITICAL";
1734
+ const reversibility = risk_score <= 20 ? "REVERSIBLE" : risk_score <= 40 ? "REVERSIBLE_WITH_EFFORT" : "DIFFICULT_TO_REVERSE";
1735
+ // PASS 5 - PHILOSOPHY VERDICT
1736
+ let philosophy_verdict = "PHILOSOPHY_PASS";
1737
+ const blocking_questions = [];
1738
+ const advisory_notes = [];
1739
+ if ((who_verdict === "UNCONFIRMED" && risk_verdict === "CRITICAL") ||
1740
+ (who_verdict === "UNCONFIRMED" && risk_verdict === "HIGH" && reversibility === "DIFFICULT_TO_REVERSE") ||
1741
+ (why_verdict === "NO_JUSTIFICATION" && (task_type === "feature" || task_type === "user_story")) ||
1742
+ (rejected_pattern_risk && risk_verdict === "CRITICAL")) {
1743
+ philosophy_verdict = "PHILOSOPHY_BLOCKED";
1744
+ }
1745
+ else if (who_verdict === "UNCONFIRMED" ||
1746
+ why_verdict === "NO_JUSTIFICATION" ||
1747
+ what_verdict === "UNDEFINED" ||
1748
+ (risk_verdict === "CRITICAL" && reversibility === "DIFFICULT_TO_REVERSE")) {
1749
+ philosophy_verdict = "PHILOSOPHY_FAIL";
1750
+ }
1751
+ else if (who_verdict === "UNCERTAIN" || why_verdict === "WEAK" || what_verdict === "VAGUE" || risk_verdict === "HIGH") {
1752
+ philosophy_verdict = "PHILOSOPHY_ADVISORY";
1753
+ }
1754
+ const allowed_next_action = philosophy_verdict === "PHILOSOPHY_PASS" ? "PROCEED" :
1755
+ philosophy_verdict === "PHILOSOPHY_ADVISORY" ? "ADVISORY_PROCEED" :
1756
+ philosophy_verdict === "PHILOSOPHY_FAIL" ? "STOP" : "ESCALATE";
1757
+ if (why_verdict === "NO_JUSTIFICATION" || why_verdict === "WEAK")
1758
+ blocking_questions.push({ category: "WHY", question: `What specific problem does "${title}" solve?`, impact: "Without a clear problem statement, the solution may be wrong.", action: "Add a problem statement with data, user pain, or regulatory requirement." });
1759
+ if (who_verdict === "UNCONFIRMED" || who_verdict === "UNCERTAIN")
1760
+ blocking_questions.push({ category: "WHO", question: "Who has explicitly confirmed this is needed?", impact: "Building unconfirmed features wastes sprint capacity.", action: "Get written confirmation from client or PM." });
1761
+ if (what_verdict === "UNDEFINED" || what_verdict === "VAGUE")
1762
+ blocking_questions.push({ category: "WHAT", question: "What are the acceptance criteria?", impact: "Vague stories produce vague software.", action: "Add Given/When/Then ACs." });
1763
+ if (risk_verdict === "CRITICAL" && reversibility === "DIFFICULT_TO_REVERSE")
1764
+ blocking_questions.push({ category: "RISK", question: `CRITICAL risk: ${high_risk_factors.join(", ")}. What is the rollback plan?`, impact: "This change may be impossible to revert.", action: "Define rollback plan and get explicit sign-off." });
1765
+ if (who_verdict === "UNCERTAIN")
1766
+ advisory_notes.push({ category: "WHO", note: "Decision maker not fully confirmed", suggestion: "Confirm with client or PM." });
1767
+ if (why_verdict === "WEAK")
1768
+ advisory_notes.push({ category: "WHY", note: "Weak justification", suggestion: "Strengthen with data or regulatory context." });
1769
+ if (what_verdict === "VAGUE")
1770
+ advisory_notes.push({ category: "WHAT", note: "ACs incomplete or vague", suggestion: "Add measurable ACs before coding." });
1771
+ if (risk_verdict === "HIGH")
1772
+ advisory_notes.push({ category: "RISK", note: `High risk: ${high_risk_factors.join(", ") || "multiple signals"}`, suggestion: "Review blast radius. Consider staged rollout." });
1773
+ let developer_message = "";
1774
+ const scoresSummary = `\nScores | WHY:${why_score} WHO:${who_score} WHAT:${what_score} RISK:${risk_score}${dna_risk_bonus > 0 ? ` (DNA+${dna_risk_bonus})` : ""}${dnaWarning}`;
1775
+ if (philosophy_verdict === "PHILOSOPHY_PASS") {
1776
+ developer_message = `[PHILOSOPHY PASS] ${work_item_id}\n\nWHY : ${why_verdict}${purpose_text ? " - " + purpose_text : ""}\nWHO : ${who_verdict}\nWHAT : ${what_verdict} — ${ac_count} AC(s)\nRISK : ${risk_verdict} (${reversibility})${high_risk_factors.length > 0 ? "\nRisk factors: " + high_risk_factors.join(", ") : ""}\n\nProceed to classify_task.${scoresSummary}`;
1777
+ }
1778
+ else if (philosophy_verdict === "PHILOSOPHY_ADVISORY") {
1779
+ developer_message = `[PHILOSOPHY ADVISORY] ${work_item_id}\n\nStory may proceed with caution. Note these concerns:\n\n` +
1780
+ advisory_notes.map((n) => ` [${n.category}] ${n.note}\n Suggestion: ${n.suggestion}`).join("\n\n") +
1781
+ `\n\nWHY:${why_verdict} | WHO:${who_verdict} | WHAT:${what_verdict} | RISK:${risk_verdict}\nProceed to classify_task. Record advisory notes in decisions.json.${scoresSummary}`;
1782
+ }
1783
+ else if (philosophy_verdict === "PHILOSOPHY_FAIL") {
1784
+ developer_message = `[PHILOSOPHY FAIL] ${work_item_id}\n\nImplementation BLOCKED. The following must be resolved before planning can begin:\n\n` +
1785
+ blocking_questions.map((q) => ` [${q.category}] ${q.question}\n Why: ${q.impact}\n Action: ${q.action}`).join("\n\n") +
1786
+ `\n\nDo NOT call classify_task. Re-run philosophy_check after resolving.${scoresSummary}`;
1787
+ }
1788
+ else {
1789
+ developer_message = `[PHILOSOPHY BLOCKED] ${work_item_id}\n\nESCALATION REQUIRED. ${risk_verdict} risk + ${who_verdict} authority.\n\n` +
1790
+ blocking_questions.map((q) => ` [${q.category}] ${q.question}\n Risk: ${q.impact}\n Required: ${q.action}`).join("\n\n") +
1791
+ `\n\nNO implementation or planning until explicit written sign-off from the decision maker.${scoresSummary}`;
1792
+ }
1793
+ const result = {
1794
+ work_item_id, title, task_type, philosophy_verdict, allowed_next_action,
1795
+ dna_assessment: {
1796
+ dna_available: dnaAvailable,
1797
+ dna_risk_bonus,
1798
+ dna_risk_notes: dnaRiskNotes,
1799
+ },
1800
+ passes: {
1801
+ why: { score: why_score, verdict: why_verdict, purpose_stated, purpose_text },
1802
+ who: { score: who_score, verdict: who_verdict },
1803
+ what: { score: what_score, verdict: what_verdict, ac_count, has_given_when_then: hasGWT, has_out_of_scope: hasOutOfScope, word_count: wordCount },
1804
+ risk: { score: risk_score, verdict: risk_verdict, reversibility, rejected_pattern_risk, high_risk_factors }
1805
+ },
1806
+ blocking_questions, advisory_notes, developer_message, scored_at: new Date().toISOString()
1807
+ };
1808
+ try {
1809
+ writeFile(philosophyFile, JSON.stringify(result, null, 2));
1810
+ }
1811
+ catch { }
1812
+ return appendTelemetry({ content: [{ type: "text", text: developer_message }] }, inputChars);
1813
+ });
1814
+ // --- Tool 10: classify_task --------------------------------------------------
1435
1815
  server.tool("classify_task", "MANDATORY FIRST STEP for every task without exception. " +
1436
1816
  "Classifies a task as BACKEND_ONLY, FRONTEND_ONLY, FULL_STACK, or EXTENSION_ONLY. " +
1437
1817
  "Performs a breaking-change pre-scan against the project spec. " +
@@ -1561,8 +1941,9 @@ server.tool("classify_task", "MANDATORY FIRST STEP for every task without except
1561
1941
  }
1562
1942
  if (spec.frontend && spec.frontend.repo)
1563
1943
  FRONTEND_SIGNALS.push(spec.frontend.repo.toLowerCase());
1564
- if (spec.chrome_extension && spec.chrome_extension.repo)
1565
- EXTENSION_SIGNALS.push(spec.chrome_extension.repo.toLowerCase());
1944
+ const extSpec = spec.chrome_extension || spec["snf-browser-extn"] || spec.snf_browser_extn;
1945
+ if (extSpec && extSpec.repo)
1946
+ EXTENSION_SIGNALS.push(extSpec.repo.toLowerCase());
1566
1947
  }
1567
1948
  const backendFound = BACKEND_SIGNALS.filter(s => corpus.includes(s));
1568
1949
  const frontendFound = FRONTEND_SIGNALS.filter(s => corpus.includes(s));
@@ -1587,8 +1968,9 @@ server.tool("classify_task", "MANDATORY FIRST STEP for every task without except
1587
1968
  Object.keys(spec.microservices).forEach(k => services.push(k.toLowerCase()));
1588
1969
  if (spec.frontend && spec.frontend.repo)
1589
1970
  services.push(spec.frontend.repo.toLowerCase());
1590
- if (spec.chrome_extension && spec.chrome_extension.repo)
1591
- services.push(spec.chrome_extension.repo.toLowerCase());
1971
+ const extSpec2 = spec.chrome_extension || spec["snf-browser-extn"] || spec.snf_browser_extn;
1972
+ if (extSpec2 && extSpec2.repo)
1973
+ services.push(extSpec2.repo.toLowerCase());
1592
1974
  }
1593
1975
  if (services.length === 0) {
1594
1976
  services.push("sfn-iam-api", "sfn-events-api", "sfn-tenants-api", "sfn-policy-api", "sfn-gateway-api", "sfn-web-ui");
@@ -2182,7 +2564,7 @@ server.tool("analyze_impact", "Traces the SecuFusion inter-service call graph an
2182
2564
  }
2183
2565
  walkGraph(target, 0);
2184
2566
  // ── Pass 2: Chrome extension check ────────────────────────────────────
2185
- const extData = spec.chrome_extension || spec["sfn-chrome-ext"] || null;
2567
+ const extData = spec.chrome_extension || spec["sfn-chrome-ext"] || spec["snf-browser-extn"] || null;
2186
2568
  let extensionHit = null;
2187
2569
  if (extData) {
2188
2570
  const extCalls = (extData.calls_endpoints || extData.calls || []).map(e => e.toLowerCase());
@@ -4116,6 +4498,10 @@ server.tool("reviewer_agent", "Context-aware architectural review agent — call
4116
4498
  }
4117
4499
  }
4118
4500
  // PRAISE
4501
+ const extSpec3 = specData.chrome_extension || specData["snf-browser-extn"] || specData.snf_browser_extn;
4502
+ if (extSpec3 && extSpec3.repo) {
4503
+ expectedServices.push(extSpec3.repo);
4504
+ }
4119
4505
  if (praises.length > 0) {
4120
4506
  out += `### ✅ PRAISE\n`;
4121
4507
  for (const f of praises) {
@@ -4253,7 +4639,7 @@ function readDna(ecosystemRoot) {
4253
4639
  function writeDna(ecosystemRoot, dna) {
4254
4640
  fs.writeFileSync(getDnaPath(ecosystemRoot), JSON.stringify(dna, null, 2));
4255
4641
  }
4256
- const VALID_EXTENSIONS = ['.java', '.ts', '.js', '.tsx', '.jsx', '.vue', '.sql', '.prisma', '.tf', '.yaml', '.yml', '.env', '.env.example', '.env.local', '.properties'];
4642
+ const VALID_EXTENSIONS = ['.java', '.ts', '.js', '.tsx', '.jsx', '.vue', '.sql', '.prisma', '.tf', '.yaml', '.yml', '.env', '.env.example', '.env.local', '.properties', '.json'];
4257
4643
  function getAllSourceFiles(dirPath, repoName, arrayOfFiles = []) {
4258
4644
  if (!fs.existsSync(dirPath))
4259
4645
  return arrayOfFiles;
@@ -4278,7 +4664,7 @@ function getPolyRepoSourceFiles(ecosystemRoot) {
4278
4664
  const children = fs.readdirSync(ecosystemRoot);
4279
4665
  for (const child of children) {
4280
4666
  const childPath = path.join(ecosystemRoot, child);
4281
- if (fs.statSync(childPath).isDirectory() && (child.startsWith("sfn-") || child === "secufusion")) {
4667
+ if (fs.statSync(childPath).isDirectory() && (child.startsWith("sfn-") || child.startsWith("snf-") || child === "secufusion")) {
4282
4668
  allFiles = allFiles.concat(getAllSourceFiles(childPath, child));
4283
4669
  }
4284
4670
  else if (fs.statSync(childPath).isDirectory() && ecosystemRoot === childPath) {
@@ -4294,6 +4680,7 @@ function performFullExtraction(ecosystemRoot) {
4294
4680
  const events = [];
4295
4681
  const nodeApis = [];
4296
4682
  const frontend = [];
4683
+ const extension = [];
4297
4684
  const infra = [];
4298
4685
  const databases = [];
4299
4686
  const security = [];
@@ -4307,6 +4694,7 @@ function performFullExtraction(ecosystemRoot) {
4307
4694
  }
4308
4695
  nodeApis.push(...parseNodeApis(fileObj.path, content, fileObj.repo));
4309
4696
  frontend.push(...parseFrontend(fileObj.path, content, fileObj.repo));
4697
+ extension.push(...parseExtension(fileObj.path, content, fileObj.repo));
4310
4698
  infra.push(...parseInfra(fileObj.path, content, fileObj.repo));
4311
4699
  databases.push(...parseDatabase(fileObj.path, content, fileObj.repo));
4312
4700
  security.push(...parseSecurity(fileObj.path, content, fileObj.repo));
@@ -4318,6 +4706,7 @@ function performFullExtraction(ecosystemRoot) {
4318
4706
  dna.events = events;
4319
4707
  dna.node_apis = nodeApis;
4320
4708
  dna.frontend = frontend;
4709
+ dna.extension = extension;
4321
4710
  dna.infra = infra;
4322
4711
  dna.databases = databases;
4323
4712
  dna.security = security;
@@ -4325,7 +4714,20 @@ function performFullExtraction(ecosystemRoot) {
4325
4714
  // Apply Pattern Inference
4326
4715
  dna.inferred_patterns = inferPatterns(dna);
4327
4716
  writeDna(ecosystemRoot, dna);
4717
+ const hasBackend = (models.length > 0 || apis.length > 0 || nodeApis.length > 0);
4718
+ const hasFrontend = frontend.length > 0;
4719
+ const hasExtension = extension.length > 0;
4720
+ const missing = [];
4721
+ if (!hasBackend)
4722
+ missing.push("backend");
4723
+ if (!hasFrontend)
4724
+ missing.push("frontend");
4725
+ if (!hasExtension)
4726
+ missing.push("snf-browser-extn");
4727
+ const missingWarning = missing.length > 0 ? `\n\n[CRITICAL CORE CHECK] The following core components are missing from the DNA map: ${missing.join(', ')}. Please verify if this is expected.` : "";
4328
4728
  return {
4729
+ missingWarning,
4730
+ extensionCount: extension.length,
4329
4731
  modelsCount: models.length,
4330
4732
  apisCount: apis.length + nodeApis.length,
4331
4733
  eventsCount: events.length,
@@ -4396,7 +4798,7 @@ server.tool("extract_domain_models", "Parses files across the ecosystem to build
4396
4798
  const ecosystemRoot = getEcosystemRoot(workspace_root);
4397
4799
  const stats = performFullExtraction(ecosystemRoot);
4398
4800
  return {
4399
- content: [{ type: "text", text: `Extracted ${stats.modelsCount} domain models. Derived ${stats.inferredCount} architectural patterns.` }]
4801
+ content: [{ type: "text", text: `Extracted ${stats.modelsCount} domain models. Derived ${stats.inferredCount} architectural patterns.${stats.missingWarning}` }]
4400
4802
  };
4401
4803
  }
4402
4804
  catch (e) {
@@ -4410,7 +4812,7 @@ server.tool("extract_api_endpoints", "Scans for REST/GraphQL endpoints across th
4410
4812
  const ecosystemRoot = getEcosystemRoot(workspace_root);
4411
4813
  const stats = performFullExtraction(ecosystemRoot);
4412
4814
  return {
4413
- content: [{ type: "text", text: `Extracted ${stats.apisCount} API controllers. Derived ${stats.inferredCount} architectural patterns.` }]
4815
+ content: [{ type: "text", text: `Extracted ${stats.apisCount} API controllers. Derived ${stats.inferredCount} architectural patterns.${stats.missingWarning}` }]
4414
4816
  };
4415
4817
  }
4416
4818
  catch (e) {
@@ -4424,7 +4826,7 @@ server.tool("extract_event_topics", "Scans for event listener/producer usage acr
4424
4826
  const ecosystemRoot = getEcosystemRoot(workspace_root);
4425
4827
  const stats = performFullExtraction(ecosystemRoot);
4426
4828
  return {
4427
- content: [{ type: "text", text: `Extracted ${stats.eventsCount} event classes. Derived ${stats.inferredCount} architectural patterns.` }]
4829
+ content: [{ type: "text", text: `Extracted ${stats.eventsCount} event classes. Derived ${stats.inferredCount} architectural patterns.${stats.missingWarning}` }]
4428
4830
  };
4429
4831
  }
4430
4832
  catch (e) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "secufusion-mcp",
3
- "version": "2.1.3",
3
+ "version": "2.1.5",
4
4
  "type": "module",
5
5
  "description": "SecuFusion MCP server - developer workflow tooling with guardrails",
6
6
  "main": "mcp/dist/server.js",
@@ -1,15 +0,0 @@
1
- ---
2
- description: Analyzes the current project to build its DNA Knowledge Graph
3
- argument-hint: (no args)
4
- ---
5
-
6
- You are the SecuFusion DNA Discovery Agent. Your goal is to analyze this ecosystem and build the Poly-Repo DNA Knowledge Graph.
7
-
8
- The underlying MCP tools will automatically detect if you are inside a poly-repo structure. If they find sibling repositories, they will scan all of them simultaneously to build a cross-repo DNA file.
9
-
10
- 1. Call the `secufusion-dna_scan_repository_stack` tool to identify the framework and infrastructure across the ecosystem.
11
- 2. Call the `secufusion-dna_extract_domain_models` tool to find and parse entities and domain models across all repos.
12
- 3. Call the `secufusion-dna_extract_api_endpoints` tool to map out the API layer across all repos.
13
- 4. Call the `secufusion-dna_extract_event_topics` tool to map out event consumers and producers across all repos.
14
-
15
- Once you have gathered this information, summarize your findings for the user. Do not delete any existing data in the knowledge graph.
@@ -1,14 +0,0 @@
1
- ---
2
- description: Determines the impact of changing a specific component or file
3
- argument-hint: <component-name-or-file-path>
4
- ---
5
-
6
- You are the SecuFusion DNA Blast Radius Agent. Your goal is to determine the impact of changing the provided component or file across the entire Poly-Repo ecosystem.
7
-
8
- 1. Call the `secufusion-dna_query_knowledge_graph` tool with the query "Find all components, services, and APIs that depend on or consume {argument}".
9
- 2. Analyze the returned dependency chain, paying special attention to cross-repo dependencies (e.g., changing a DTO in `sfn-events-api` breaking a listener in `sfn-notification-api`).
10
- 3. Present a Cross-Repo Blast Radius Report to the user, categorizing the impact into:
11
- - Impacted Microservices
12
- - Impacted APIs
13
- - Impacted Events/Consumers
14
- - Impacted Databases
@@ -1,10 +0,0 @@
1
- ---
2
- description: Generates a Mermaid architecture diagram from the project DNA
3
- argument-hint: (no args)
4
- ---
5
-
6
- You are the SecuFusion DNA Architecture Agent. Your goal is to visualize the cross-service dependencies and architecture of this project.
7
-
8
- 1. Call the `secufusion-dna_query_knowledge_graph` tool with the query "Get all services, APIs, and event topics with their dependencies".
9
- 2. Based on the returned relationships, generate a comprehensive Mermaid diagram (`graph TD` or `graph LR`).
10
- 3. Render the diagram in your response, grouping components by bounded context or service if possible.
@@ -1,3 +0,0 @@
1
- # /map-services
2
-
3
- This command instructs the SecuFusion DNA Discovery MCP to analyze the project based on /map-services.
@@ -1,9 +0,0 @@
1
- ---
2
- description: Starts the background watcher to continuously update the Poly-Repo DNA.
3
- argument-hint: (no args)
4
- ---
5
-
6
- You are the SecuFusion DNA Watcher Agent. Your goal is to start the background file watcher.
7
-
8
- 1. Call the `start_dna_watcher` tool.
9
- 2. Inform the user that the DNA Knowledge Graph is now actively monitoring the codebase in the background and will dynamically update whenever a developer saves a Java file.