engimcp 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 (134) hide show
  1. package/CHANGELOG.md +43 -0
  2. package/LICENSE +21 -0
  3. package/README.md +345 -0
  4. package/dist/audit/auditLog.d.ts +9 -0
  5. package/dist/audit/auditLog.js +20 -0
  6. package/dist/audit/auditLog.js.map +1 -0
  7. package/dist/bom/bomService.d.ts +23 -0
  8. package/dist/bom/bomService.js +44 -0
  9. package/dist/bom/bomService.js.map +1 -0
  10. package/dist/config/projectConfig.d.ts +16 -0
  11. package/dist/config/projectConfig.js +16 -0
  12. package/dist/config/projectConfig.js.map +1 -0
  13. package/dist/config/schema.d.ts +16 -0
  14. package/dist/config/schema.js +21 -0
  15. package/dist/config/schema.js.map +1 -0
  16. package/dist/context/contextPack.d.ts +31 -0
  17. package/dist/context/contextPack.js +142 -0
  18. package/dist/context/contextPack.js.map +1 -0
  19. package/dist/context/tokenBudget.d.ts +1 -0
  20. package/dist/context/tokenBudget.js +4 -0
  21. package/dist/context/tokenBudget.js.map +1 -0
  22. package/dist/decisions/decisionService.d.ts +21 -0
  23. package/dist/decisions/decisionService.js +62 -0
  24. package/dist/decisions/decisionService.js.map +1 -0
  25. package/dist/dev/smokeProjectStatus.d.ts +1 -0
  26. package/dist/dev/smokeProjectStatus.js +9 -0
  27. package/dist/dev/smokeProjectStatus.js.map +1 -0
  28. package/dist/documents/documentService.d.ts +83 -0
  29. package/dist/documents/documentService.js +371 -0
  30. package/dist/documents/documentService.js.map +1 -0
  31. package/dist/documents/frontmatter.d.ts +14 -0
  32. package/dist/documents/frontmatter.js +30 -0
  33. package/dist/documents/frontmatter.js.map +1 -0
  34. package/dist/documents/headings.d.ts +6 -0
  35. package/dist/documents/headings.js +15 -0
  36. package/dist/documents/headings.js.map +1 -0
  37. package/dist/documents/markdownParser.d.ts +2 -0
  38. package/dist/documents/markdownParser.js +3 -0
  39. package/dist/documents/markdownParser.js.map +1 -0
  40. package/dist/documents/sectionPatch.d.ts +7 -0
  41. package/dist/documents/sectionPatch.js +73 -0
  42. package/dist/documents/sectionPatch.js.map +1 -0
  43. package/dist/documents/templates.d.ts +1 -0
  44. package/dist/documents/templates.js +62 -0
  45. package/dist/documents/templates.js.map +1 -0
  46. package/dist/filesystem/filesystemService.d.ts +168 -0
  47. package/dist/filesystem/filesystemService.js +606 -0
  48. package/dist/filesystem/filesystemService.js.map +1 -0
  49. package/dist/git/gitAdapter.d.ts +25 -0
  50. package/dist/git/gitAdapter.js +99 -0
  51. package/dist/git/gitAdapter.js.map +1 -0
  52. package/dist/graph/graphBuilder.d.ts +27 -0
  53. package/dist/graph/graphBuilder.js +126 -0
  54. package/dist/graph/graphBuilder.js.map +1 -0
  55. package/dist/graph/impact.d.ts +18 -0
  56. package/dist/graph/impact.js +53 -0
  57. package/dist/graph/impact.js.map +1 -0
  58. package/dist/graph/relations.d.ts +7 -0
  59. package/dist/graph/relations.js +28 -0
  60. package/dist/graph/relations.js.map +1 -0
  61. package/dist/index.d.ts +2 -0
  62. package/dist/index.js +16 -0
  63. package/dist/index.js.map +1 -0
  64. package/dist/mcp/errors.d.ts +5 -0
  65. package/dist/mcp/errors.js +11 -0
  66. package/dist/mcp/errors.js.map +1 -0
  67. package/dist/mcp/prompts.d.ts +2 -0
  68. package/dist/mcp/prompts.js +39 -0
  69. package/dist/mcp/prompts.js.map +1 -0
  70. package/dist/mcp/resources.d.ts +2 -0
  71. package/dist/mcp/resources.js +36 -0
  72. package/dist/mcp/resources.js.map +1 -0
  73. package/dist/mcp/tools.d.ts +2 -0
  74. package/dist/mcp/tools.js +431 -0
  75. package/dist/mcp/tools.js.map +1 -0
  76. package/dist/project/pathSafety.d.ts +6 -0
  77. package/dist/project/pathSafety.js +137 -0
  78. package/dist/project/pathSafety.js.map +1 -0
  79. package/dist/project/projectInit.d.ts +11 -0
  80. package/dist/project/projectInit.js +81 -0
  81. package/dist/project/projectInit.js.map +1 -0
  82. package/dist/project/projectService.d.ts +36 -0
  83. package/dist/project/projectService.js +60 -0
  84. package/dist/project/projectService.js.map +1 -0
  85. package/dist/project/writeGuards.d.ts +3 -0
  86. package/dist/project/writeGuards.js +46 -0
  87. package/dist/project/writeGuards.js.map +1 -0
  88. package/dist/requirements/requirementService.d.ts +19 -0
  89. package/dist/requirements/requirementService.js +72 -0
  90. package/dist/requirements/requirementService.js.map +1 -0
  91. package/dist/runtime/options.d.ts +7 -0
  92. package/dist/runtime/options.js +34 -0
  93. package/dist/runtime/options.js.map +1 -0
  94. package/dist/search/ftsIndex.d.ts +29 -0
  95. package/dist/search/ftsIndex.js +96 -0
  96. package/dist/search/ftsIndex.js.map +1 -0
  97. package/dist/search/searchService.d.ts +20 -0
  98. package/dist/search/searchService.js +17 -0
  99. package/dist/search/searchService.js.map +1 -0
  100. package/dist/server.d.ts +2 -0
  101. package/dist/server.js +16 -0
  102. package/dist/server.js.map +1 -0
  103. package/dist/storage/sqlite.d.ts +15 -0
  104. package/dist/storage/sqlite.js +80 -0
  105. package/dist/storage/sqlite.js.map +1 -0
  106. package/dist/tasks/taskService.d.ts +17 -0
  107. package/dist/tasks/taskService.js +57 -0
  108. package/dist/tasks/taskService.js.map +1 -0
  109. package/dist/utils/atomicWrite.d.ts +1 -0
  110. package/dist/utils/atomicWrite.js +10 -0
  111. package/dist/utils/atomicWrite.js.map +1 -0
  112. package/dist/utils/errors.d.ts +1 -0
  113. package/dist/utils/errors.js +2 -0
  114. package/dist/utils/errors.js.map +1 -0
  115. package/dist/utils/ids.d.ts +3 -0
  116. package/dist/utils/ids.js +25 -0
  117. package/dist/utils/ids.js.map +1 -0
  118. package/dist/validation/checks.d.ts +1 -0
  119. package/dist/validation/checks.js +2 -0
  120. package/dist/validation/checks.js.map +1 -0
  121. package/dist/validation/validator.d.ts +18 -0
  122. package/dist/validation/validator.js +131 -0
  123. package/dist/validation/validator.js.map +1 -0
  124. package/dist/verification/testReportService.d.ts +19 -0
  125. package/dist/verification/testReportService.js +42 -0
  126. package/dist/verification/testReportService.js.map +1 -0
  127. package/dist/version.d.ts +1 -0
  128. package/dist/version.js +2 -0
  129. package/dist/version.js.map +1 -0
  130. package/package.json +49 -0
  131. package/templates/design_doc.md +24 -0
  132. package/templates/edr.md +58 -0
  133. package/templates/requirement.md +30 -0
  134. package/templates/task.md +22 -0
@@ -0,0 +1,81 @@
1
+ import { access, mkdir } from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { atomicWrite } from "../utils/atomicWrite.js";
4
+ import { assertAbsoluteRoot } from "./pathSafety.js";
5
+ import { EngiMcpError } from "../mcp/errors.js";
6
+ export async function initProject(input) {
7
+ const root = assertAbsoluteRoot(input.root);
8
+ const createdPaths = [];
9
+ const warnings = [];
10
+ await mkdir(root, { recursive: true });
11
+ const projectConfigPath = path.join(root, "project.yaml");
12
+ if ((await exists(projectConfigPath)) && !input.force) {
13
+ throw new EngiMcpError("PROJECT_EXISTS", "project.yaml already exists.");
14
+ }
15
+ const files = [
16
+ {
17
+ relativePath: "project.yaml",
18
+ content: `project:
19
+ id: ${path.basename(root)}
20
+ name: ${path.basename(root)}
21
+ schema_version: 1.0.0
22
+ source_of_truth: markdown
23
+ paths:
24
+ docs: docs
25
+ templates: templates
26
+ `
27
+ },
28
+ {
29
+ relativePath: "docs/README.md",
30
+ content: `---
31
+ id: DOC-PROJECT-README
32
+ kind: overview
33
+ status: draft
34
+ version: 0.1.0
35
+ ---
36
+
37
+ # Project Overview
38
+ `
39
+ },
40
+ {
41
+ relativePath: "templates/design_doc.md",
42
+ content: `---
43
+ id: DOC-EXAMPLE
44
+ kind: design_doc
45
+ status: draft
46
+ version: 0.1.0
47
+ ---
48
+
49
+ # Document Title
50
+
51
+ ## Purpose
52
+ `
53
+ }
54
+ ];
55
+ for (const file of files) {
56
+ const target = path.join(root, file.relativePath);
57
+ if ((await exists(target)) && !input.force) {
58
+ warnings.push(`Skipped existing file: ${file.relativePath}`);
59
+ continue;
60
+ }
61
+ await atomicWrite(target, file.content);
62
+ createdPaths.push(file.relativePath);
63
+ }
64
+ await mkdir(path.join(root, ".engimcp"), { recursive: true });
65
+ createdPaths.push(".engimcp/");
66
+ return {
67
+ ok: true,
68
+ created_paths: createdPaths,
69
+ warnings
70
+ };
71
+ }
72
+ async function exists(filePath) {
73
+ try {
74
+ await access(filePath);
75
+ return true;
76
+ }
77
+ catch {
78
+ return false;
79
+ }
80
+ }
81
+ //# sourceMappingURL=projectInit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"projectInit.js","sourceRoot":"","sources":["../../src/project/projectInit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAchD,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,KAAuB;IACvD,MAAM,IAAI,GAAG,kBAAkB,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC5C,MAAM,YAAY,GAAa,EAAE,CAAC;IAClC,MAAM,QAAQ,GAAa,EAAE,CAAC;IAE9B,MAAM,KAAK,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAEvC,MAAM,iBAAiB,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,cAAc,CAAC,CAAC;IAC1D,IAAI,CAAC,MAAM,MAAM,CAAC,iBAAiB,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QACtD,MAAM,IAAI,YAAY,CAAC,gBAAgB,EAAE,8BAA8B,CAAC,CAAC;IAC3E,CAAC;IAED,MAAM,KAAK,GAAqD;QAC9D;YACE,YAAY,EAAE,cAAc;YAC5B,OAAO,EAAE;QACP,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;UACjB,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;;;;;;CAM5B;SACI;QACD;YACE,YAAY,EAAE,gBAAgB;YAC9B,OAAO,EAAE;;;;;;;;CAQd;SACI;QACD;YACE,YAAY,EAAE,yBAAyB;YACvC,OAAO,EAAE;;;;;;;;;;CAUd;SACI;KACF,CAAC;IAEF,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC;QAClD,IAAI,CAAC,MAAM,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;YAC3C,QAAQ,CAAC,IAAI,CAAC,0BAA0B,IAAI,CAAC,YAAY,EAAE,CAAC,CAAC;YAC7D,SAAS;QACX,CAAC;QACD,MAAM,WAAW,CAAC,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;QACxC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IACvC,CAAC;IAED,MAAM,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,UAAU,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC9D,YAAY,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IAE/B,OAAO;QACL,EAAE,EAAE,IAAI;QACR,aAAa,EAAE,YAAY;QAC3B,QAAQ;KACT,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,MAAM,CAAC,QAAgB;IACpC,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,QAAQ,CAAC,CAAC;QACvB,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC"}
@@ -0,0 +1,36 @@
1
+ export interface ProjectStatusInput {
2
+ root: string;
3
+ include_validation_summary?: boolean;
4
+ include_git_status?: boolean;
5
+ }
6
+ export interface ProjectStatus {
7
+ project_id: string;
8
+ documents: number;
9
+ requirements: number;
10
+ decisions: number;
11
+ tasks_open: number;
12
+ validation?: {
13
+ errors: number;
14
+ warnings: number;
15
+ };
16
+ git?: {
17
+ is_git_repo: boolean;
18
+ dirty: boolean;
19
+ summary: string;
20
+ };
21
+ }
22
+ export interface ProjectMapInput {
23
+ root: string;
24
+ kind?: string[];
25
+ max_depth?: number;
26
+ }
27
+ export interface ProjectMapItem {
28
+ id?: string;
29
+ path: string;
30
+ kind?: string;
31
+ status?: string;
32
+ }
33
+ export declare function getProjectStatus(input: ProjectStatusInput): Promise<ProjectStatus>;
34
+ export declare function getProjectMap(input: ProjectMapInput): Promise<{
35
+ items: ProjectMapItem[];
36
+ }>;
@@ -0,0 +1,60 @@
1
+ import path from "node:path";
2
+ import { readProjectConfig } from "../config/projectConfig.js";
3
+ import { buildDocumentRegistry } from "../documents/documentService.js";
4
+ import { getGitStatus } from "../git/gitAdapter.js";
5
+ import { ensureIndex } from "../storage/sqlite.js";
6
+ import { validateProject } from "../validation/validator.js";
7
+ import { assertAbsoluteRoot } from "./pathSafety.js";
8
+ export async function getProjectStatus(input) {
9
+ const root = assertAbsoluteRoot(input.root);
10
+ const projectConfig = await readProjectConfig(root);
11
+ await ensureIndex(root);
12
+ const registry = await buildDocumentRegistry(root);
13
+ const status = {
14
+ project_id: projectConfig.project.id ?? path.basename(root),
15
+ documents: registry.documents.length,
16
+ requirements: registry.documents.filter((document) => isRequirement(document.kind, document.id))
17
+ .length,
18
+ decisions: registry.documents.filter((document) => isDecision(document.kind, document.id))
19
+ .length,
20
+ tasks_open: registry.documents.filter((document) => document.kind === "task" && document.status !== "done" && document.status !== "cancelled").length
21
+ };
22
+ if (input.include_validation_summary ?? true) {
23
+ const validation = await validateProject({ root, severity: "warning" });
24
+ status.validation = {
25
+ errors: validation.errors.length,
26
+ warnings: validation.warnings.length
27
+ };
28
+ }
29
+ if (input.include_git_status ?? true) {
30
+ status.git = await getGitStatus(root);
31
+ }
32
+ return status;
33
+ }
34
+ export async function getProjectMap(input) {
35
+ const root = assertAbsoluteRoot(input.root);
36
+ const registry = await buildDocumentRegistry(root);
37
+ const allowedKinds = input.kind && input.kind.length > 0 ? new Set(input.kind) : undefined;
38
+ const maxDepth = input.max_depth;
39
+ const items = registry.documents
40
+ .filter((document) => !allowedKinds || (document.kind && allowedKinds.has(document.kind)))
41
+ .filter((document) => maxDepth === undefined || pathDepth(document.path) <= maxDepth)
42
+ .map((document) => ({
43
+ id: document.id,
44
+ path: document.path,
45
+ kind: document.kind,
46
+ status: document.status
47
+ }))
48
+ .sort((left, right) => left.path.localeCompare(right.path));
49
+ return { items };
50
+ }
51
+ function isRequirement(kind, id) {
52
+ return kind === "requirement" || kind === "requirements" || /^(FR|NFR|SEC|AC)-\d+/.test(id ?? "");
53
+ }
54
+ function isDecision(kind, id) {
55
+ return kind === "decision" || kind === "decision-log" || /^EDR-\d+/.test(id ?? "");
56
+ }
57
+ function pathDepth(relativePath) {
58
+ return relativePath.split(/[\\/]+/).filter(Boolean).length;
59
+ }
60
+ //# sourceMappingURL=projectService.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"projectService.js","sourceRoot":"","sources":["../../src/project/projectService.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export declare function assertProjectWritable(root: string): Promise<void>;
2
+ export declare function assertNoGitConflictMarkers(content: string, displayPath: string): void;
3
+ export declare function assertPathHasNoGitConflictMarkers(absolutePath: string, displayPath: string): Promise<void>;
@@ -0,0 +1,46 @@
1
+ import { lstat, readFile, readdir } from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { readProjectConfig } from "../config/projectConfig.js";
4
+ import { EngiMcpError } from "../mcp/errors.js";
5
+ import { getRuntimeOptions } from "../runtime/options.js";
6
+ export async function assertProjectWritable(root) {
7
+ if (getRuntimeOptions().readOnly) {
8
+ throw new EngiMcpError("READ_ONLY", "Project is in read-only mode.");
9
+ }
10
+ try {
11
+ const config = await readProjectConfig(root);
12
+ if (config.mcp?.read_only_mode) {
13
+ throw new EngiMcpError("READ_ONLY", "Project is in read-only mode.");
14
+ }
15
+ }
16
+ catch (error) {
17
+ if (error instanceof EngiMcpError) {
18
+ throw error;
19
+ }
20
+ }
21
+ }
22
+ export function assertNoGitConflictMarkers(content, displayPath) {
23
+ if (/^<<<<<<< .*\r?\n[\s\S]*?^=======\r?\n[\s\S]*?^>>>>>>> .*$/m.test(content)) {
24
+ throw new EngiMcpError("GIT_CONFLICT_PRESENT", `Refusing to overwrite ${displayPath} because it contains Git conflict markers.`);
25
+ }
26
+ }
27
+ export async function assertPathHasNoGitConflictMarkers(absolutePath, displayPath) {
28
+ let fileStat;
29
+ try {
30
+ fileStat = await lstat(absolutePath);
31
+ }
32
+ catch {
33
+ return;
34
+ }
35
+ if (fileStat.isDirectory()) {
36
+ for (const entry of await readdir(absolutePath, { withFileTypes: true })) {
37
+ await assertPathHasNoGitConflictMarkers(path.join(absolutePath, entry.name), path.posix.join(displayPath, entry.name));
38
+ }
39
+ return;
40
+ }
41
+ if (!fileStat.isFile()) {
42
+ return;
43
+ }
44
+ assertNoGitConflictMarkers(await readFile(absolutePath, "utf8"), displayPath);
45
+ }
46
+ //# sourceMappingURL=writeGuards.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"writeGuards.js","sourceRoot":"","sources":["../../src/project/writeGuards.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAC5D,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAC/D,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAE1D,MAAM,CAAC,KAAK,UAAU,qBAAqB,CAAC,IAAY;IACtD,IAAI,iBAAiB,EAAE,CAAC,QAAQ,EAAE,CAAC;QACjC,MAAM,IAAI,YAAY,CAAC,WAAW,EAAE,+BAA+B,CAAC,CAAC;IACvE,CAAC;IAED,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC,IAAI,CAAC,CAAC;QAC7C,IAAI,MAAM,CAAC,GAAG,EAAE,cAAc,EAAE,CAAC;YAC/B,MAAM,IAAI,YAAY,CAAC,WAAW,EAAE,+BAA+B,CAAC,CAAC;QACvE,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,YAAY,EAAE,CAAC;YAClC,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;AACH,CAAC;AAED,MAAM,UAAU,0BAA0B,CAAC,OAAe,EAAE,WAAmB;IAC7E,IAAI,4DAA4D,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QAC/E,MAAM,IAAI,YAAY,CACpB,sBAAsB,EACtB,yBAAyB,WAAW,4CAA4C,CACjF,CAAC;IACJ,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,iCAAiC,CACrD,YAAoB,EACpB,WAAmB;IAEnB,IAAI,QAAQ,CAAC;IACb,IAAI,CAAC;QACH,QAAQ,GAAG,MAAM,KAAK,CAAC,YAAY,CAAC,CAAC;IACvC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO;IACT,CAAC;IAED,IAAI,QAAQ,CAAC,WAAW,EAAE,EAAE,CAAC;QAC3B,KAAK,MAAM,KAAK,IAAI,MAAM,OAAO,CAAC,YAAY,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;YACzE,MAAM,iCAAiC,CACrC,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,KAAK,CAAC,IAAI,CAAC,EACnC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,WAAW,EAAE,KAAK,CAAC,IAAI,CAAC,CACzC,CAAC;QACJ,CAAC;QACD,OAAO;IACT,CAAC;IAED,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC;QACvB,OAAO;IACT,CAAC;IAED,0BAA0B,CAAC,MAAM,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC,EAAE,WAAW,CAAC,CAAC;AAChF,CAAC"}
@@ -0,0 +1,19 @@
1
+ export interface CreateRequirementInput {
2
+ root: string;
3
+ requirement_type: "functional" | "non_functional" | "security" | "acceptance";
4
+ title: string;
5
+ statement: string;
6
+ priority: "must" | "should" | "could" | "wont";
7
+ rationale?: string;
8
+ related?: string[];
9
+ dry_run?: boolean;
10
+ }
11
+ export declare function createRequirement(input: CreateRequirementInput): Promise<{
12
+ id: string;
13
+ path: string;
14
+ content: string;
15
+ } | {
16
+ id: string;
17
+ path: string;
18
+ content?: undefined;
19
+ }>;
@@ -0,0 +1,72 @@
1
+ import { writeAuditLog } from "../audit/auditLog.js";
2
+ import { buildDocumentRegistry } from "../documents/documentService.js";
3
+ import { serializeDocument } from "../documents/frontmatter.js";
4
+ import { assertAbsoluteRoot, resolveSafePath } from "../project/pathSafety.js";
5
+ import { assertProjectWritable } from "../project/writeGuards.js";
6
+ import { atomicWrite } from "../utils/atomicWrite.js";
7
+ import { nextSequentialId, slugify } from "../utils/ids.js";
8
+ export async function createRequirement(input) {
9
+ const root = assertAbsoluteRoot(input.root);
10
+ await assertProjectWritable(root);
11
+ const registry = await buildDocumentRegistry(root);
12
+ const id = nextSequentialId(registry.byId.keys(), requirementPrefix(input.requirement_type));
13
+ const relativePath = `docs/requirements/${id}-${slugify(input.title)}.md`;
14
+ const frontmatter = {
15
+ id,
16
+ kind: "requirement",
17
+ requirement_type: input.requirement_type,
18
+ status: "draft",
19
+ priority: input.priority,
20
+ version: "0.1.0",
21
+ statement: input.statement,
22
+ rationale: input.rationale,
23
+ relates_to: input.related ?? [],
24
+ verified_by: [],
25
+ decided_by: []
26
+ };
27
+ const body = `# ${id}: ${input.title}
28
+
29
+ ## Statement
30
+
31
+ ${input.statement}
32
+
33
+ ## Rationale
34
+
35
+ ${input.rationale ?? ""}
36
+
37
+ ## Acceptance Criteria
38
+
39
+ - [ ] Define verification.
40
+
41
+ ## Links
42
+
43
+ - Related: ${(input.related ?? []).join(", ")}
44
+ `;
45
+ const content = serializeDocument(frontmatter, body);
46
+ if (input.dry_run) {
47
+ return { id, path: relativePath, content };
48
+ }
49
+ await atomicWrite(await resolveSafePath(root, relativePath), content);
50
+ await writeAuditLog({
51
+ root,
52
+ tool: "engi_requirement_create",
53
+ target: id,
54
+ operation: "create",
55
+ result: "ok",
56
+ diff_summary: "requirement created"
57
+ });
58
+ return { id, path: relativePath };
59
+ }
60
+ function requirementPrefix(type) {
61
+ if (type === "non_functional") {
62
+ return "NFR";
63
+ }
64
+ if (type === "security") {
65
+ return "SEC";
66
+ }
67
+ if (type === "acceptance") {
68
+ return "AC";
69
+ }
70
+ return "FR";
71
+ }
72
+ //# sourceMappingURL=requirementService.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"requirementService.js","sourceRoot":"","sources":["../../src/requirements/requirementService.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,qBAAqB,EAAE,MAAM,iCAAiC,CAAC;AACxE,OAAO,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAC/E,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAa5D,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,KAA6B;IACnE,MAAM,IAAI,GAAG,kBAAkB,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC5C,MAAM,qBAAqB,CAAC,IAAI,CAAC,CAAC;IAClC,MAAM,QAAQ,GAAG,MAAM,qBAAqB,CAAC,IAAI,CAAC,CAAC;IACnD,MAAM,EAAE,GAAG,gBAAgB,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,iBAAiB,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC,CAAC;IAC7F,MAAM,YAAY,GAAG,qBAAqB,EAAE,IAAI,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC;IAC1E,MAAM,WAAW,GAAG;QAClB,EAAE;QACF,IAAI,EAAE,aAAa;QACnB,gBAAgB,EAAE,KAAK,CAAC,gBAAgB;QACxC,MAAM,EAAE,OAAO;QACf,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,OAAO,EAAE,OAAO;QAChB,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,UAAU,EAAE,KAAK,CAAC,OAAO,IAAI,EAAE;QAC/B,WAAW,EAAE,EAAE;QACf,UAAU,EAAE,EAAE;KACf,CAAC;IACF,MAAM,IAAI,GAAG,KAAK,EAAE,KAAK,KAAK,CAAC,KAAK;;;;EAIpC,KAAK,CAAC,SAAS;;;;EAIf,KAAK,CAAC,SAAS,IAAI,EAAE;;;;;;;;aAQV,CAAC,KAAK,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;CAC5C,CAAC;IACA,MAAM,OAAO,GAAG,iBAAiB,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC;IAErD,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;QAClB,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE,OAAO,EAAE,CAAC;IAC7C,CAAC;IAED,MAAM,WAAW,CAAC,MAAM,eAAe,CAAC,IAAI,EAAE,YAAY,CAAC,EAAE,OAAO,CAAC,CAAC;IACtE,MAAM,aAAa,CAAC;QAClB,IAAI;QACJ,IAAI,EAAE,yBAAyB;QAC/B,MAAM,EAAE,EAAE;QACV,SAAS,EAAE,QAAQ;QACnB,MAAM,EAAE,IAAI;QACZ,YAAY,EAAE,qBAAqB;KACpC,CAAC,CAAC;IAEH,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE,CAAC;AACpC,CAAC;AAED,SAAS,iBAAiB,CAAC,IAAgD;IACzE,IAAI,IAAI,KAAK,gBAAgB,EAAE,CAAC;QAC9B,OAAO,KAAK,CAAC;IACf,CAAC;IACD,IAAI,IAAI,KAAK,UAAU,EAAE,CAAC;QACxB,OAAO,KAAK,CAAC;IACf,CAAC;IACD,IAAI,IAAI,KAAK,YAAY,EAAE,CAAC;QAC1B,OAAO,IAAI,CAAC;IACd,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,7 @@
1
+ export interface RuntimeOptions {
2
+ root?: string;
3
+ readOnly: boolean;
4
+ }
5
+ export declare function parseRuntimeOptions(argv: readonly string[]): RuntimeOptions;
6
+ export declare function configureRuntimeOptions(options: RuntimeOptions): void;
7
+ export declare function getRuntimeOptions(): RuntimeOptions;
@@ -0,0 +1,34 @@
1
+ import path from "node:path";
2
+ let runtimeOptions = {
3
+ readOnly: process.env.ENGIMCP_READ_ONLY === "1" || process.env.ENGIMCP_READ_ONLY === "true"
4
+ };
5
+ export function parseRuntimeOptions(argv) {
6
+ const options = { readOnly: false };
7
+ for (let index = 0; index < argv.length; index += 1) {
8
+ const arg = argv[index];
9
+ if (arg === "--read-only") {
10
+ options.readOnly = true;
11
+ continue;
12
+ }
13
+ if (arg === "--root") {
14
+ const root = argv[index + 1];
15
+ if (!root) {
16
+ throw new Error("--root requires a path.");
17
+ }
18
+ options.root = path.resolve(root);
19
+ index += 1;
20
+ continue;
21
+ }
22
+ if (arg.startsWith("--root=")) {
23
+ options.root = path.resolve(arg.slice("--root=".length));
24
+ }
25
+ }
26
+ return options;
27
+ }
28
+ export function configureRuntimeOptions(options) {
29
+ runtimeOptions = { ...options };
30
+ }
31
+ export function getRuntimeOptions() {
32
+ return runtimeOptions;
33
+ }
34
+ //# sourceMappingURL=options.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"options.js","sourceRoot":"","sources":["../../src/runtime/options.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAO7B,IAAI,cAAc,GAAmB;IACnC,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,iBAAiB,KAAK,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC,iBAAiB,KAAK,MAAM;CAC5F,CAAC;AAEF,MAAM,UAAU,mBAAmB,CAAC,IAAuB;IACzD,MAAM,OAAO,GAAmB,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;IAEpD,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,IAAI,CAAC,MAAM,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;QACpD,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC;QACxB,IAAI,GAAG,KAAK,aAAa,EAAE,CAAC;YAC1B,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC;YACxB,SAAS;QACX,CAAC;QACD,IAAI,GAAG,KAAK,QAAQ,EAAE,CAAC;YACrB,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;YAC7B,IAAI,CAAC,IAAI,EAAE,CAAC;gBACV,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;YAC7C,CAAC;YACD,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;YAClC,KAAK,IAAI,CAAC,CAAC;YACX,SAAS;QACX,CAAC;QACD,IAAI,GAAG,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;YAC9B,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC;QAC3D,CAAC;IACH,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,MAAM,UAAU,uBAAuB,CAAC,OAAuB;IAC7D,cAAc,GAAG,EAAE,GAAG,OAAO,EAAE,CAAC;AAClC,CAAC;AAED,MAAM,UAAU,iBAAiB;IAC/B,OAAO,cAAc,CAAC;AACxB,CAAC"}
@@ -0,0 +1,29 @@
1
+ export interface FullTextIndexDocument {
2
+ id?: string;
3
+ path: string;
4
+ kind?: string;
5
+ status?: string;
6
+ tags: string[];
7
+ frontmatter: Record<string, unknown>;
8
+ content: string;
9
+ lowerContent: string;
10
+ }
11
+ export interface FullTextSearchOptions {
12
+ query: string;
13
+ kind?: string[];
14
+ status?: string[];
15
+ tags?: string[];
16
+ frontmatter?: Record<string, unknown>;
17
+ limit?: number;
18
+ }
19
+ export interface FullTextSearchResult {
20
+ id?: string;
21
+ path: string;
22
+ score: number;
23
+ snippet: string;
24
+ }
25
+ export interface FullTextIndex {
26
+ documents: FullTextIndexDocument[];
27
+ search(options: FullTextSearchOptions): FullTextSearchResult[];
28
+ }
29
+ export declare function rebuildFullTextIndex(rootInput: string): Promise<FullTextIndex>;
@@ -0,0 +1,96 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import { buildDocumentRegistry } from "../documents/documentService.js";
3
+ import { assertAbsoluteRoot } from "../project/pathSafety.js";
4
+ export async function rebuildFullTextIndex(rootInput) {
5
+ const root = assertAbsoluteRoot(rootInput);
6
+ const registry = await buildDocumentRegistry(root);
7
+ const documents = await Promise.all(registry.documents.map(async (document) => {
8
+ const content = await readFile(document.absolutePath, "utf8");
9
+ return {
10
+ id: document.id,
11
+ path: document.path,
12
+ kind: document.kind,
13
+ status: document.status,
14
+ tags: extractStringList(document.frontmatter.tags),
15
+ frontmatter: document.frontmatter,
16
+ content,
17
+ lowerContent: content.toLowerCase()
18
+ };
19
+ }));
20
+ return {
21
+ documents,
22
+ search(options) {
23
+ return searchIndex(documents, options);
24
+ }
25
+ };
26
+ }
27
+ function searchIndex(documents, options) {
28
+ const terms = normalizedTerms(options.query);
29
+ const kindFilter = options.kind ? new Set(options.kind) : undefined;
30
+ const statusFilter = options.status ? new Set(options.status) : undefined;
31
+ const tagFilter = options.tags ? new Set(options.tags) : undefined;
32
+ const results = [];
33
+ for (const document of documents) {
34
+ if (kindFilter && (!document.kind || !kindFilter.has(document.kind))) {
35
+ continue;
36
+ }
37
+ if (statusFilter && (!document.status || !statusFilter.has(document.status))) {
38
+ continue;
39
+ }
40
+ if (tagFilter && !document.tags.some((tag) => tagFilter.has(tag))) {
41
+ continue;
42
+ }
43
+ if (options.frontmatter && !frontmatterMatches(document.frontmatter, options.frontmatter)) {
44
+ continue;
45
+ }
46
+ const textScore = terms.reduce((sum, term) => sum + countOccurrences(document.lowerContent, term), 0);
47
+ const idScore = terms.some((term) => document.id?.toLowerCase().includes(term)) ? 5 : 0;
48
+ const totalScore = textScore + idScore;
49
+ if (totalScore === 0) {
50
+ continue;
51
+ }
52
+ results.push({
53
+ id: document.id,
54
+ path: document.path,
55
+ score: totalScore,
56
+ snippet: makeSnippet(document.content, terms)
57
+ });
58
+ }
59
+ return results
60
+ .sort((left, right) => right.score - left.score || left.path.localeCompare(right.path))
61
+ .slice(0, options.limit ?? 20);
62
+ }
63
+ function frontmatterMatches(frontmatter, filters) {
64
+ return Object.entries(filters).every(([key, expected]) => {
65
+ const actual = frontmatter[key];
66
+ if (Array.isArray(actual)) {
67
+ return actual.some((item) => item === expected);
68
+ }
69
+ return actual === expected;
70
+ });
71
+ }
72
+ function extractStringList(value) {
73
+ if (Array.isArray(value)) {
74
+ return value.filter((item) => typeof item === "string");
75
+ }
76
+ return typeof value === "string" ? [value] : [];
77
+ }
78
+ function normalizedTerms(query) {
79
+ return query
80
+ .toLowerCase()
81
+ .split(/[^a-z0-9]+/)
82
+ .filter(Boolean);
83
+ }
84
+ function countOccurrences(content, term) {
85
+ return content.split(term).length - 1;
86
+ }
87
+ function makeSnippet(content, terms) {
88
+ const lowerContent = content.toLowerCase();
89
+ const index = terms.map((term) => lowerContent.indexOf(term)).find((position) => position >= 0) ?? 0;
90
+ const start = Math.max(0, index - 60);
91
+ return content
92
+ .slice(start, start + 160)
93
+ .replace(/\s+/g, " ")
94
+ .trim();
95
+ }
96
+ //# sourceMappingURL=ftsIndex.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ftsIndex.js","sourceRoot":"","sources":["../../src/search/ftsIndex.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ export interface SearchProjectInput {
2
+ root: string;
3
+ query: string;
4
+ filters?: {
5
+ kind?: string[];
6
+ status?: string[];
7
+ tags?: string[];
8
+ frontmatter?: Record<string, unknown>;
9
+ };
10
+ limit?: number;
11
+ }
12
+ export interface SearchResult {
13
+ id?: string;
14
+ path: string;
15
+ score: number;
16
+ snippet: string;
17
+ }
18
+ export declare function searchProject(input: SearchProjectInput): Promise<{
19
+ results: SearchResult[];
20
+ }>;
@@ -0,0 +1,17 @@
1
+ import { assertAbsoluteRoot } from "../project/pathSafety.js";
2
+ import { rebuildFullTextIndex } from "./ftsIndex.js";
3
+ export async function searchProject(input) {
4
+ const root = assertAbsoluteRoot(input.root);
5
+ const index = await rebuildFullTextIndex(root);
6
+ return {
7
+ results: index.search({
8
+ query: input.query,
9
+ kind: input.filters?.kind,
10
+ status: input.filters?.status,
11
+ tags: input.filters?.tags,
12
+ frontmatter: input.filters?.frontmatter,
13
+ limit: input.limit
14
+ })
15
+ };
16
+ }
17
+ //# sourceMappingURL=searchService.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"searchService.js","sourceRoot":"","sources":["../../src/search/searchService.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAC9D,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AAqBrD,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,KAAyB;IAEzB,MAAM,IAAI,GAAG,kBAAkB,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC5C,MAAM,KAAK,GAAG,MAAM,oBAAoB,CAAC,IAAI,CAAC,CAAC;IAE/C,OAAO;QACL,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC;YACpB,KAAK,EAAE,KAAK,CAAC,KAAK;YAClB,IAAI,EAAE,KAAK,CAAC,OAAO,EAAE,IAAI;YACzB,MAAM,EAAE,KAAK,CAAC,OAAO,EAAE,MAAM;YAC7B,IAAI,EAAE,KAAK,CAAC,OAAO,EAAE,IAAI;YACzB,WAAW,EAAE,KAAK,CAAC,OAAO,EAAE,WAAW;YACvC,KAAK,EAAE,KAAK,CAAC,KAAK;SACnB,CAAC;KACH,CAAC;AACJ,CAAC"}
@@ -0,0 +1,2 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function createServer(): McpServer;
package/dist/server.js ADDED
@@ -0,0 +1,16 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { registerPrompts } from "./mcp/prompts.js";
3
+ import { registerResources } from "./mcp/resources.js";
4
+ import { registerTools } from "./mcp/tools.js";
5
+ import { ENGI_MCP_VERSION } from "./version.js";
6
+ export function createServer() {
7
+ const server = new McpServer({
8
+ name: "engimcp",
9
+ version: ENGI_MCP_VERSION
10
+ });
11
+ registerTools(server);
12
+ registerResources(server);
13
+ registerPrompts(server);
14
+ return server;
15
+ }
16
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAEhD,MAAM,UAAU,YAAY;IAC1B,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;QAC3B,IAAI,EAAE,SAAS;QACf,OAAO,EAAE,gBAAgB;KAC1B,CAAC,CAAC;IAEH,aAAa,CAAC,MAAM,CAAC,CAAC;IACtB,iBAAiB,CAAC,MAAM,CAAC,CAAC;IAC1B,eAAe,CAAC,MAAM,CAAC,CAAC;IAExB,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,15 @@
1
+ export interface RebuildIndexResult {
2
+ ok: boolean;
3
+ path: string;
4
+ documents: number;
5
+ relations: number;
6
+ validation_issues: number;
7
+ }
8
+ export interface EnsureIndexResult {
9
+ ok: boolean;
10
+ path: string;
11
+ rebuilt: boolean;
12
+ index?: RebuildIndexResult;
13
+ }
14
+ export declare function ensureIndex(root: string): Promise<EnsureIndexResult>;
15
+ export declare function rebuildIndex(root: string): Promise<RebuildIndexResult>;