secufusion-mcp 2.2.7 → 2.2.9
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/.claude-plugin/plugin.json +1 -1
- package/agents/AGENTS.md +2 -2
- package/mcp/dist/server.js +17 -10
- package/package.json +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "secufusion-mcp",
|
|
3
3
|
"description": "SecuFusion MSSP platform dev agent — project-level spec driven, tenant-isolation enforced, zero-trust guardrails. 5 Core Slash Commands: /sfn-init (dynamic DNA + architecture diagram + watcher), /sfn-plan (philosophy check + intent WHY + classify + plan), /sfn-code (spec-driven implementation), /sfn-review (zero-tolerance 3-tier PR gate), /sfn-explore (on-demand service graph or blast-radius analysis).",
|
|
4
|
-
"version": "2.2.
|
|
4
|
+
"version": "2.2.9",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Motivity Labs"
|
|
7
7
|
},
|
package/agents/AGENTS.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
# SecuFusion MCP Workflow Router
|
|
2
2
|
|
|
3
3
|
You are an elite Senior Developer and Architect. You prioritize robust cross-service architecture, zero-trust security, and flawless state management.
|
|
4
4
|
|
|
@@ -47,7 +47,7 @@ Call `philosophy_check` AFTER DNA is loaded — never before. The engine us
|
|
|
47
47
|
|
|
48
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
49
|
|
|
50
|
-
For `bug` and `hotfix`: philosophy check
|
|
50
|
+
For `bug` and `hotfix`: philosophy check **fully runs** — no skip. The scoring engine applies relaxed thresholds: WHY gets a +20 head-start (something is broken = implicit justification), WHO gets a +15 head-start (reporter = implicit authority), and `NO_JUSTIFICATION` is not a blocking verdict. However, ADVISORY and FAIL still fire normally — a high-risk bug fix (auth regression, data-loss, multi-tenant blast) will still be challenged.
|
|
51
51
|
|
|
52
52
|
**Verdicts:**
|
|
53
53
|
- `PHILOSOPHY_PASS` → Silent. Proceed immediately.
|
package/mcp/dist/server.js
CHANGED
|
@@ -897,14 +897,15 @@ server.tool("manage_task", "Manages structured task records in .secufusion/tasks
|
|
|
897
897
|
completed_acs: z.array(z.string()).optional().describe("Completed AC list. Used with 'update_spec'."),
|
|
898
898
|
next_step: z.string().optional().describe("Next actionable step. Required for 'update_spec'."),
|
|
899
899
|
tags: z.array(z.string()).optional().describe("Tags for searchability, e.g. ['tenant', 'iam', 'security']."),
|
|
900
|
+
task_type: z.enum(["bug", "user_story", "feature", "hotfix", "refactor", "chore"]).optional().describe("Type of work item. Persisted to spec.json so search_tasks and filter_type work correctly. Pass on initialize and wherever classify_task supplies it."),
|
|
900
901
|
file_path: z.string().optional().describe("File path to log. Used with 'log_file_touched'."),
|
|
901
902
|
change_summary: z.string().optional().describe("One-line summary of the change. Used with 'log_file_touched'."),
|
|
902
903
|
decision: z.string().optional().describe("Architectural decision to record. Used with 'log_decision'."),
|
|
903
904
|
rationale: z.string().optional().describe("Why this decision was made. Used with 'log_decision'."),
|
|
904
905
|
scenario: z.string().optional().describe("Test scenario description. Used with 'add_scenario'."),
|
|
905
906
|
scenario_type: z.enum(["unit", "integration", "e2e", "manual"]).optional().describe("Test scenario type. Used with 'add_scenario'."),
|
|
906
|
-
}, async ({ action, work_item_id, title, description, acceptance_criteria, pending_acs, completed_acs, next_step, tags, file_path, change_summary, decision, rationale, scenario, scenario_type }) => {
|
|
907
|
-
const inputChars = JSON.stringify({ action, work_item_id, title, description, acceptance_criteria, pending_acs, completed_acs, next_step, tags, file_path, change_summary, decision, rationale, scenario, scenario_type }).length;
|
|
907
|
+
}, async ({ action, work_item_id, title, description, acceptance_criteria, pending_acs, completed_acs, next_step, tags, task_type, file_path, change_summary, decision, rationale, scenario, scenario_type }) => {
|
|
908
|
+
const inputChars = JSON.stringify({ action, work_item_id, title, description, acceptance_criteria, pending_acs, completed_acs, next_step, tags, task_type, file_path, change_summary, decision, rationale, scenario, scenario_type }).length;
|
|
908
909
|
const tasksRoot = resolve(TASKS_DIR);
|
|
909
910
|
let dir = resolveTaskFolder(work_item_id, tasksRoot);
|
|
910
911
|
if (action === "initialize") {
|
|
@@ -926,7 +927,7 @@ server.tool("manage_task", "Manages structured task records in .secufusion/tasks
|
|
|
926
927
|
if (!title)
|
|
927
928
|
return appendTelemetry({ isError: true, content: [{ type: "text", text: "ERROR: 'title' is required for action=initialize." }] }, inputChars);
|
|
928
929
|
const now = new Date().toISOString();
|
|
929
|
-
const spec = { work_item_id, title, description: description || "", acceptance_criteria: acceptance_criteria || [], tags: tags || [], created_at: now, status: "active" };
|
|
930
|
+
const spec = { work_item_id, title, description: description || "", acceptance_criteria: acceptance_criteria || [], tags: tags || [], task_type: task_type || "unknown", created_at: now, status: "active" };
|
|
930
931
|
const progress = { pending_acs: acceptance_criteria || [], completed_acs: [], next_step: "Review spec and begin implementation.", last_updated: now };
|
|
931
932
|
if (!fs.existsSync(specPath)) {
|
|
932
933
|
writeFile(specPath, JSON.stringify(spec, null, 2));
|
|
@@ -935,8 +936,8 @@ server.tool("manage_task", "Manages structured task records in .secufusion/tasks
|
|
|
935
936
|
writeFile(filesPath, JSON.stringify([], null, 2));
|
|
936
937
|
writeFile(scenariosPath, JSON.stringify([], null, 2));
|
|
937
938
|
}
|
|
938
|
-
upsertRegistry({ work_item_id, title, status: "active", created_at: now, tags: tags || [], folder: path.basename(dir) });
|
|
939
|
-
return appendTelemetry({ content: [{ type: "text", text: `✅ Task WI-${work_item_id} initialized.\n\n**Folder:** ${dir}\n**Title:** ${title}\n**ACs:** ${(acceptance_criteria || []).length}\n\n${JSON.stringify(spec, null, 2)}` }] }, inputChars);
|
|
939
|
+
upsertRegistry({ work_item_id, title, status: "active", created_at: now, tags: tags || [], task_type: task_type || "unknown", folder: path.basename(dir) });
|
|
940
|
+
return appendTelemetry({ content: [{ type: "text", text: `✅ Task WI-${work_item_id} initialized.\n\n**Folder:** ${dir}\n**Title:** ${title}\n**Type:** ${task_type || "unknown"}\n**ACs:** ${(acceptance_criteria || []).length}\n\n${JSON.stringify(spec, null, 2)}` }] }, inputChars);
|
|
940
941
|
}
|
|
941
942
|
if (!fs.existsSync(specPath)) {
|
|
942
943
|
return appendTelemetry({ isError: true, content: [{ type: "text", text: `ERROR: Task WI-${work_item_id} not found. Call action=initialize first.\n\nExpected folder: ${dir}` }] }, inputChars);
|
|
@@ -967,7 +968,7 @@ server.tool("manage_task", "Manages structured task records in .secufusion/tasks
|
|
|
967
968
|
if (!next_step)
|
|
968
969
|
return appendTelemetry({ isError: true, content: [{ type: "text", text: "ERROR: 'next_step' is required for action=update_spec." }] }, inputChars);
|
|
969
970
|
const now = new Date().toISOString();
|
|
970
|
-
if (description !== undefined || acceptance_criteria !== undefined || tags !== undefined) {
|
|
971
|
+
if (description !== undefined || acceptance_criteria !== undefined || tags !== undefined || task_type !== undefined) {
|
|
971
972
|
const spec = readJson(specPath) || {};
|
|
972
973
|
if (description !== undefined)
|
|
973
974
|
spec["description"] = description;
|
|
@@ -975,6 +976,10 @@ server.tool("manage_task", "Manages structured task records in .secufusion/tasks
|
|
|
975
976
|
spec["acceptance_criteria"] = acceptance_criteria;
|
|
976
977
|
if (tags !== undefined)
|
|
977
978
|
spec["tags"] = tags;
|
|
979
|
+
if (task_type !== undefined) {
|
|
980
|
+
spec["task_type"] = task_type;
|
|
981
|
+
upsertRegistry({ work_item_id, task_type });
|
|
982
|
+
}
|
|
978
983
|
writeFile(specPath, JSON.stringify(spec, null, 2));
|
|
979
984
|
}
|
|
980
985
|
const progress = readJson(progressPath) || {};
|
|
@@ -1542,10 +1547,12 @@ server.tool("philosophy_check", "MANDATORY PHASE -1 STEP — runs BEFORE classif
|
|
|
1542
1547
|
client_confirmed: z.boolean().optional().describe("Has the decision maker explicitly confirmed this is needed?"),
|
|
1543
1548
|
}, async ({ work_item_id, title, description, task_type, reported_by, client_confirmed }) => {
|
|
1544
1549
|
const inputChars = JSON.stringify({ work_item_id, title, description, task_type }).length;
|
|
1545
|
-
//
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1550
|
+
// Bugs and hotfixes run through the full philosophy engine with relaxed scoring:
|
|
1551
|
+
// WHY → +20 head-start (defects have an inherent "WHY": something is broken)
|
|
1552
|
+
// WHO → +15 head-start (reporter is implicit authority for a defect)
|
|
1553
|
+
// RISK → NO_JUSTIFICATION block exempted for bug/hotfix (see Pass 5)
|
|
1554
|
+
// This ensures high-risk bug fixes (auth regressions, data-loss fixes, multi-tenant
|
|
1555
|
+
// defects) still surface ADVISORY or FAIL when the blast radius warrants it.
|
|
1549
1556
|
// Check cache
|
|
1550
1557
|
const philosophyDir = resolve(".secufusion/philosophy");
|
|
1551
1558
|
const philosophyFile = path.join(philosophyDir, `${work_item_id}.json`);
|
package/package.json
CHANGED