@imenam/mcp-feature-analyzer 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (111) hide show
  1. package/LICENSE +15 -0
  2. package/README.md +295 -0
  3. package/dist/shared/diagram-geometry.d.ts +45 -0
  4. package/dist/shared/diagram-geometry.js +120 -0
  5. package/dist/shared/diagram-layout.d.ts +98 -0
  6. package/dist/shared/diagram-layout.js +1156 -0
  7. package/dist/shared/diagram-quality.d.ts +30 -0
  8. package/dist/shared/diagram-quality.js +26 -0
  9. package/dist/shared/labels.d.ts +31 -0
  10. package/dist/shared/labels.js +53 -0
  11. package/dist/shared/mindmap-tree.d.ts +28 -0
  12. package/dist/shared/mindmap-tree.js +62 -0
  13. package/dist/shared/prompt.d.ts +17 -0
  14. package/dist/shared/prompt.js +97 -0
  15. package/dist/shared/review-state.d.ts +10 -0
  16. package/dist/shared/review-state.js +17 -0
  17. package/dist/shared/schemas/analysis.schema.d.ts +372 -0
  18. package/dist/shared/schemas/analysis.schema.js +152 -0
  19. package/dist/shared/schemas/api.schema.d.ts +92 -0
  20. package/dist/shared/schemas/api.schema.js +46 -0
  21. package/dist/shared/schemas/diff.schema.d.ts +91 -0
  22. package/dist/shared/schemas/diff.schema.js +37 -0
  23. package/dist/shared/schemas/ipc.schema.d.ts +29 -0
  24. package/dist/shared/schemas/ipc.schema.js +30 -0
  25. package/dist/shared/severity.d.ts +11 -0
  26. package/dist/shared/severity.js +17 -0
  27. package/dist/shared/text.d.ts +12 -0
  28. package/dist/shared/text.js +20 -0
  29. package/dist/src/cli/setup-mcp.d.ts +24 -0
  30. package/dist/src/cli/setup-mcp.js +145 -0
  31. package/dist/src/core/analysis-store.d.ts +95 -0
  32. package/dist/src/core/analysis-store.js +387 -0
  33. package/dist/src/core/data-dir.d.ts +5 -0
  34. package/dist/src/core/data-dir.js +11 -0
  35. package/dist/src/core/diff-parser.d.ts +22 -0
  36. package/dist/src/core/diff-parser.js +225 -0
  37. package/dist/src/core/errors.d.ts +16 -0
  38. package/dist/src/core/errors.js +28 -0
  39. package/dist/src/core/git.d.ts +35 -0
  40. package/dist/src/core/git.js +257 -0
  41. package/dist/src/core/ids.d.ts +16 -0
  42. package/dist/src/core/ids.js +41 -0
  43. package/dist/src/core/invariants.d.ts +24 -0
  44. package/dist/src/core/invariants.js +157 -0
  45. package/dist/src/core/locations.d.ts +30 -0
  46. package/dist/src/core/locations.js +66 -0
  47. package/dist/src/core/log-dir.d.ts +6 -0
  48. package/dist/src/core/log-dir.js +13 -0
  49. package/dist/src/core/migrate.d.ts +24 -0
  50. package/dist/src/core/migrate.js +53 -0
  51. package/dist/src/core/refresh.d.ts +30 -0
  52. package/dist/src/core/refresh.js +113 -0
  53. package/dist/src/core/request-guard.d.ts +32 -0
  54. package/dist/src/core/request-guard.js +72 -0
  55. package/dist/src/core/review-actions.d.ts +27 -0
  56. package/dist/src/core/review-actions.js +99 -0
  57. package/dist/src/gui-worker.d.ts +1 -0
  58. package/dist/src/gui-worker.js +401 -0
  59. package/dist/src/index.d.ts +2 -0
  60. package/dist/src/index.js +658 -0
  61. package/dist/src/tools/add-findings.d.ts +9 -0
  62. package/dist/src/tools/add-findings.js +106 -0
  63. package/dist/src/tools/create-analysis.d.ts +4 -0
  64. package/dist/src/tools/create-analysis.js +36 -0
  65. package/dist/src/tools/delete-analysis.d.ts +4 -0
  66. package/dist/src/tools/delete-analysis.js +11 -0
  67. package/dist/src/tools/delete-diagram.d.ts +4 -0
  68. package/dist/src/tools/delete-diagram.js +22 -0
  69. package/dist/src/tools/delete-findings.d.ts +7 -0
  70. package/dist/src/tools/delete-findings.js +27 -0
  71. package/dist/src/tools/format.d.ts +27 -0
  72. package/dist/src/tools/format.js +92 -0
  73. package/dist/src/tools/get-analysis.d.ts +4 -0
  74. package/dist/src/tools/get-analysis.js +87 -0
  75. package/dist/src/tools/get-diff.d.ts +4 -0
  76. package/dist/src/tools/get-diff.js +67 -0
  77. package/dist/src/tools/get-review-feedback.d.ts +4 -0
  78. package/dist/src/tools/get-review-feedback.js +71 -0
  79. package/dist/src/tools/inputs.d.ts +14 -0
  80. package/dist/src/tools/inputs.js +40 -0
  81. package/dist/src/tools/list-analyses.d.ts +8 -0
  82. package/dist/src/tools/list-analyses.js +71 -0
  83. package/dist/src/tools/refresh-analysis.d.ts +7 -0
  84. package/dist/src/tools/refresh-analysis.js +39 -0
  85. package/dist/src/tools/set-diagram.d.ts +16 -0
  86. package/dist/src/tools/set-diagram.js +207 -0
  87. package/dist/src/tools/types.d.ts +52 -0
  88. package/dist/src/tools/types.js +133 -0
  89. package/dist/src/tools/update-analysis.d.ts +4 -0
  90. package/dist/src/tools/update-analysis.js +121 -0
  91. package/dist/src/tools/update-finding.d.ts +8 -0
  92. package/dist/src/tools/update-finding.js +91 -0
  93. package/dist/src/version.d.ts +1 -0
  94. package/dist/src/version.js +2 -0
  95. package/gui/dist/assets/index-CU9pNYDp.js +72 -0
  96. package/gui/dist/assets/index-Du5eL78F.css +1 -0
  97. package/gui/dist/assets/inter-cyrillic-ext-wght-normal-BOeWTOD4.woff2 +0 -0
  98. package/gui/dist/assets/inter-cyrillic-wght-normal-DqGufNeO.woff2 +0 -0
  99. package/gui/dist/assets/inter-greek-ext-wght-normal-DlzME5K_.woff2 +0 -0
  100. package/gui/dist/assets/inter-greek-wght-normal-CkhJZR-_.woff2 +0 -0
  101. package/gui/dist/assets/inter-latin-ext-wght-normal-DO1Apj_S.woff2 +0 -0
  102. package/gui/dist/assets/inter-latin-wght-normal-Dx4kXJAl.woff2 +0 -0
  103. package/gui/dist/assets/inter-vietnamese-wght-normal-CBcvBZtf.woff2 +0 -0
  104. package/gui/dist/assets/jetbrains-mono-cyrillic-wght-normal-D73BlboJ.woff2 +0 -0
  105. package/gui/dist/assets/jetbrains-mono-greek-wght-normal-Bw9x6K1M.woff2 +0 -0
  106. package/gui/dist/assets/jetbrains-mono-latin-ext-wght-normal-DBQx-q_a.woff2 +0 -0
  107. package/gui/dist/assets/jetbrains-mono-latin-wght-normal-B9CIFXIH.woff2 +0 -0
  108. package/gui/dist/assets/jetbrains-mono-vietnamese-wght-normal-Bt-aOZkq.woff2 +0 -0
  109. package/gui/dist/index.html +13 -0
  110. package/package.json +56 -0
  111. package/scripts/generate-version.js +20 -0
@@ -0,0 +1,121 @@
1
+ import { has, nullableString, optionalString, rejectUnknownFields, requireString, requireStringArray, textResult, } from "./types.js";
2
+ const EDITABLE = [
3
+ "title",
4
+ "project",
5
+ "summary",
6
+ "objective",
7
+ "approach",
8
+ "attention_points",
9
+ "request_text",
10
+ "request_source",
11
+ ];
12
+ /**
13
+ * Lit `objective`, `approach` et `attention_points`. `objective: null` retire
14
+ * toute la vue d'ensemble et exclut les deux autres champs.
15
+ */
16
+ function readOverview(args) {
17
+ const objective = nullableString(args, "objective");
18
+ const approach = optionalString(args, "approach");
19
+ const attentionPoints = has(args, "attention_points") ? requireStringArray(args, "attention_points") : undefined;
20
+ if (objective === null) {
21
+ if (approach !== undefined || attentionPoints !== undefined) {
22
+ throw new Error(`"objective" is null (overview removed), so "approach" and "attention_points" cannot be set.`);
23
+ }
24
+ return { remove: true };
25
+ }
26
+ if (objective === undefined && approach === undefined && attentionPoints === undefined)
27
+ return undefined;
28
+ return { remove: false, objective, approach, attentionPoints };
29
+ }
30
+ /**
31
+ * Applique la modification de la vue d'ensemble : sans vue d'ensemble existante,
32
+ * `objective` et `approach` sont requis pour la créer ; sinon chaque champ donné
33
+ * remplace le précédent et les autres sont conservés.
34
+ */
35
+ function nextOverview(id, current, input) {
36
+ if (input.remove)
37
+ return null;
38
+ if (current === null) {
39
+ const missing = ["objective", "approach"].filter((field) => input[field] === undefined);
40
+ if (missing.length > 0) {
41
+ throw new Error(`Analysis "${id}" has no overview yet: give ${missing.map((field) => `"${field}"`).join(" and ")} too ` +
42
+ `to create it ("attention_points" is optional and defaults to an empty list).`);
43
+ }
44
+ return { objective: input.objective, approach: input.approach, attentionPoints: input.attentionPoints ?? [] };
45
+ }
46
+ return {
47
+ objective: input.objective ?? current.objective,
48
+ approach: input.approach ?? current.approach,
49
+ attentionPoints: input.attentionPoints ?? current.attentionPoints,
50
+ };
51
+ }
52
+ /** Met à jour le titre, le projet, la vue d'ensemble, le résumé et la demande initiale d'une analyse. */
53
+ export function updateAnalysis(store, args) {
54
+ rejectUnknownFields(args, ["analysis_id", ...EDITABLE]);
55
+ const id = requireString(args, "analysis_id");
56
+ const given = EDITABLE.filter((field) => has(args, field));
57
+ if (given.length === 0) {
58
+ throw new Error(`Give at least one field to change: ${EDITABLE.join(", ")}.`);
59
+ }
60
+ const title = optionalString(args, "title");
61
+ const project = optionalString(args, "project");
62
+ const summary = has(args, "summary") ? requireStringArray(args, "summary") : undefined;
63
+ const overview = readOverview(args);
64
+ const requestText = nullableString(args, "request_text");
65
+ const requestSource = nullableString(args, "request_source");
66
+ if (requestText === null && typeof requestSource === "string") {
67
+ throw new Error(`"request_text" is null (request removed), so "request_source" cannot be set.`);
68
+ }
69
+ let previousProject = "";
70
+ const analysis = store.mutate(id, "agent", (draft) => {
71
+ previousProject = draft.project;
72
+ if (title !== undefined)
73
+ draft.title = title;
74
+ if (project !== undefined)
75
+ draft.project = project;
76
+ if (summary !== undefined)
77
+ draft.summary = summary;
78
+ if (overview !== undefined)
79
+ draft.overview = nextOverview(id, draft.overview, overview);
80
+ if (requestText === null) {
81
+ draft.request = null;
82
+ }
83
+ else if (requestText !== undefined) {
84
+ draft.request = { text: requestText, source: requestSource !== undefined ? requestSource : (draft.request?.source ?? null) };
85
+ }
86
+ else if (requestSource !== undefined) {
87
+ if (draft.request === null) {
88
+ throw new Error(`Analysis "${id}" has no initial request to attach a source to: give "request_text" too.`);
89
+ }
90
+ draft.request = { ...draft.request, source: requestSource };
91
+ }
92
+ });
93
+ const changes = [];
94
+ if (title !== undefined)
95
+ changes.push(`title "${analysis.title}"`);
96
+ if (project !== undefined) {
97
+ changes.push(project === previousProject ? `project "${project}" (unchanged)` : `project "${previousProject}" -> "${project}"`);
98
+ }
99
+ if (summary !== undefined)
100
+ changes.push(`summary (${analysis.summary.length} bullet(s))`);
101
+ if (overview !== undefined) {
102
+ changes.push(analysis.overview === null
103
+ ? "overview removed"
104
+ : `overview (${analysis.overview.attentionPoints.length} attention point(s))`);
105
+ }
106
+ if (requestText !== undefined || requestSource !== undefined) {
107
+ changes.push(analysis.request === null ? "initial request removed" : "initial request");
108
+ }
109
+ const missing = [];
110
+ if (analysis.overview === null)
111
+ missing.push("the overview (objective, approach, attention_points)");
112
+ if (analysis.summary.length === 0)
113
+ missing.push("the summary");
114
+ const next = missing.length > 0
115
+ ? `Next: write ${missing.join(" and ")} with update_analysis, then record problems and missing requirements with add_findings.`
116
+ : `Next: record problems and missing requirements with add_findings.`;
117
+ return {
118
+ result: textResult(`Updated analysis ${analysis.id}: ${changes.join(", ")}. Revision ${analysis.revision}.\n${next}`),
119
+ analysisId: analysis.id,
120
+ };
121
+ }
@@ -0,0 +1,8 @@
1
+ import type { AnalysisStore } from "../core/analysis-store.js";
2
+ import { type Args, type MutationResult } from "./types.js";
3
+ /**
4
+ * Modifie les champs de l'agent d'un constat. Un nouvel emplacement est résolu
5
+ * sur le snapshot ; un nouvel emplacement ou son retrait rouvre un constat
6
+ * `outdated`. Le statut `ignored` relève du relecteur et n'est pas modifié.
7
+ */
8
+ export declare function updateFinding(store: AnalysisStore, args: Args): MutationResult;
@@ -0,0 +1,91 @@
1
+ import { AnalysisError } from "../core/errors.js";
2
+ import { resolveLocation } from "../core/locations.js";
3
+ import { FINDING_KINDS, SEVERITIES } from "../../shared/schemas/analysis.schema.js";
4
+ import { findingLine } from "./format.js";
5
+ import { readLocation } from "./inputs.js";
6
+ import { has, nullableText, optionalEnum, optionalString, rejectUnknownFields, requireString, requireText, textResult, } from "./types.js";
7
+ const EDITABLE = ["severity", "kind", "title", "body", "path", "start_line", "end_line", "suggestion", "prompt"];
8
+ /**
9
+ * Modifie les champs de l'agent d'un constat. Un nouvel emplacement est résolu
10
+ * sur le snapshot ; un nouvel emplacement ou son retrait rouvre un constat
11
+ * `outdated`. Le statut `ignored` relève du relecteur et n'est pas modifié.
12
+ */
13
+ export function updateFinding(store, args) {
14
+ rejectUnknownFields(args, ["analysis_id", "finding_id", ...EDITABLE]);
15
+ const id = requireString(args, "analysis_id");
16
+ const findingId = requireString(args, "finding_id");
17
+ const given = EDITABLE.filter((field) => has(args, field));
18
+ if (given.length === 0) {
19
+ throw new Error(`Give at least one field to change: ${EDITABLE.join(", ")}.`);
20
+ }
21
+ const severity = optionalEnum(args, "severity", SEVERITIES);
22
+ const kind = optionalEnum(args, "kind", FINDING_KINDS);
23
+ const title = optionalString(args, "title");
24
+ const body = has(args, "body") ? requireText(args, "body") : undefined;
25
+ const suggestion = nullableText(args, "suggestion", "", true);
26
+ const prompt = nullableText(args, "prompt");
27
+ const location = readLocation(args);
28
+ const analysis = store.get(id);
29
+ const current = analysis.findings.find((finding) => finding.id === findingId);
30
+ if (!current) {
31
+ const known = analysis.findings.map((finding) => finding.id).join(", ") || "none";
32
+ throw new AnalysisError(`Finding "${findingId}" not found in analysis "${id}". Existing findings: ${known}.`);
33
+ }
34
+ const nextKind = kind ?? current.kind;
35
+ const nextHasLocation = location === undefined ? current.location !== null : location !== null;
36
+ const nextSuggestion = suggestion === undefined ? current.suggestion : suggestion;
37
+ if (!nextHasLocation && nextKind === "issue") {
38
+ throw new AnalysisError(`Finding "${findingId}" would be an issue without location; only requirement_gap findings may have none. Give "path" and "start_line", or set kind to requirement_gap.`);
39
+ }
40
+ if (!nextHasLocation && nextSuggestion !== null) {
41
+ throw new AnalysisError(`Finding "${findingId}" would have a suggestion but no location to replace. Clear it with "suggestion": null, or keep a location.`);
42
+ }
43
+ let resolved = null;
44
+ if (location)
45
+ resolved = resolveLocation(store.getSnapshot(id), analysis.files, location);
46
+ const previousStatus = current.status;
47
+ const updated = store.mutate(id, "agent", (draft) => {
48
+ if (draft.snapshotAt !== analysis.snapshotAt) {
49
+ throw new AnalysisError(`The diff of analysis "${id}" was recomputed while the finding was validated. Send the update again.`);
50
+ }
51
+ const finding = draft.findings.find((entry) => entry.id === findingId);
52
+ if (!finding)
53
+ throw new AnalysisError(`Finding "${findingId}" was deleted in the meantime from analysis "${id}".`);
54
+ if (severity !== undefined)
55
+ finding.severity = severity;
56
+ if (kind !== undefined)
57
+ finding.kind = kind;
58
+ if (title !== undefined)
59
+ finding.title = title;
60
+ if (body !== undefined)
61
+ finding.body = body;
62
+ if (suggestion !== undefined)
63
+ finding.suggestion = suggestion;
64
+ if (prompt !== undefined)
65
+ finding.prompt = prompt;
66
+ if (location === null) {
67
+ finding.location = null;
68
+ finding.anchorText = null;
69
+ }
70
+ else if (resolved) {
71
+ finding.location = { path: resolved.path, startLine: resolved.startLine, endLine: resolved.endLine };
72
+ finding.anchorText = resolved.anchorText;
73
+ }
74
+ if (location !== undefined && finding.status === "outdated")
75
+ finding.status = "open";
76
+ });
77
+ const finding = updated.findings.find((entry) => entry.id === findingId);
78
+ const lines = [`Updated finding ${findingId} (${given.join(", ")}):`, ` ${findingLine(finding)}`];
79
+ if (previousStatus === "outdated" && finding.status === "open") {
80
+ lines.push(location === null
81
+ ? "It was outdated; removing its location reopened it."
82
+ : "It was outdated; the new location reopened it.");
83
+ }
84
+ else if (finding.status === "outdated") {
85
+ lines.push("It is still outdated: give a new location (path and start_line, from get_diff) to reopen it, or delete it with delete_findings if it is solved.");
86
+ }
87
+ else if (finding.status === "ignored") {
88
+ lines.push("It stays ignored: only the reviewer can reopen it in the GUI.");
89
+ }
90
+ return { result: textResult(lines.join("\n")), analysisId: updated.id };
91
+ }
@@ -0,0 +1 @@
1
+ export declare const APP_VERSION = "1.0.0";
@@ -0,0 +1,2 @@
1
+ // Auto-generated version file - do not edit manually
2
+ export const APP_VERSION = '1.0.0';