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
package/CHANGELOG.md ADDED
@@ -0,0 +1,43 @@
1
+ # Changelog
2
+
3
+ ## Unreleased
4
+
5
+ ## 1.0.0 - 2026-07-01
6
+
7
+ ### Added
8
+
9
+ - Added a TypeScript MCP server skeleton with stdio transport and structured tool registration.
10
+ - Added project initialization, status, project map, document read/create, frontmatter patch, section patch, and relationship tools.
11
+ - Added requirements, engineering decisions, tasks, test reports, BOM item creation, validation, graph query, impact analysis, context pack, search, Git status, snapshot, Git commit, and index rebuild tools.
12
+ - Added explicit MCP output schemas for all registered tools.
13
+ - Added the safe project filesystem layer: `engi_fs_tree`, `engi_fs_list`, `engi_fs_read`, `engi_fs_write`, `engi_fs_mkdir`, `engi_fs_move`, `engi_fs_copy`, `engi_fs_delete`, `engi_fs_exists`, `engi_fs_stat`, and `engi_fs_glob`.
14
+ - Added project trash semantics for safe delete operations under `.engimcp/trash/YYYY-MM-DD/<original-path>`.
15
+ - Added project-configured deny patterns on top of default deny patterns.
16
+ - Added runtime `--read-only` and `--root` options for server startup.
17
+ - Added search filters for kind, status, tags, and exact frontmatter fields.
18
+ - Added derived SQLite index restore when opening a project with a missing index.
19
+ - Added an expanded radio-controlled car example covering requirements, motors, battery, transmission, calculations, tests, BOM, and EDR impact scenarios.
20
+
21
+ ### Changed
22
+
23
+ - Filesystem write, mkdir, move, copy, and delete operations now rebuild the derived index after successful changes.
24
+ - Managed document move/delete operations now report incoming and outgoing link impact.
25
+ - Moving files with `update_links=true` updates safe internal Markdown/wiki-style path links.
26
+ - Copying managed documents now runs validation so duplicate IDs are reported.
27
+ - `engi_project_map` now honors `max_depth`.
28
+ - `context_pack` now expands task-term matches through graph neighbors and records combined inclusion reasons.
29
+ - `impact_analyze` now treats `impacts` edges bidirectionally for change-impact discovery.
30
+ - Documentation now distinguishes `engi_doc_*` managed engineering document semantics from `engi_fs_*` ordinary file/folder semantics.
31
+
32
+ ### Security
33
+
34
+ - Filesystem operations are root-jailed to `project_root`, reject traversal and symlink escape, enforce deny patterns, and block write-like actions in read-only mode.
35
+ - Overwrite-like operations refuse to modify files containing Git conflict markers.
36
+ - Delete defaults to trash mode; permanent delete is not part of the MVP.
37
+ - Write-like filesystem operations write audit log entries.
38
+
39
+ ### Tests
40
+
41
+ - Added milestone and completion tests for project init/read/index/validate, document writes, graph/impact, requirements/EDR/tasks, context pack, Git integration, v1 stabilization, security, and filesystem layer behavior.
42
+ - Added acceptance coverage for motor-change context packs and battery-change impact analysis.
43
+ - Added smoke run through `npm run smoke`.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 EngiMCP contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,345 @@
1
+ ---
2
+ id: README
3
+ kind: overview
4
+ status: draft
5
+ version: 1.0.0
6
+ ---
7
+
8
+ # EngiMCP
9
+
10
+ EngiMCP is a local MCP server for managing engineering projects stored as Markdown, YAML frontmatter, and Git history. It gives an LLM agent structured, safe access to requirements, engineering decisions, calculations, tests, tasks, BOM items, document relationships, impact analysis, context packs, and ordinary project files.
11
+
12
+ The source of truth stays in the project folder. The SQLite index under `.engimcp/index.sqlite` is derived data and can be rebuilt.
13
+
14
+ ## Why It Exists
15
+
16
+ Long-running engineering work cannot live only in chat. Requirements drift, decisions get forgotten, tests stop matching design assumptions, and documents become inconsistent.
17
+
18
+ Codex is strong at inspecting and changing code repositories, but engineering documentation needs a domain layer on top of files. EngiMCP exposes IDs, document kinds, frontmatter, links, graph relationships, validation, impact analysis, and focused writes so the agent can answer questions such as:
19
+
20
+ ```text
21
+ What breaks if we change the battery?
22
+ Prepare context for changing the project motors.
23
+ Create an EDR for this design choice.
24
+ Find requirements that are not verified by tests.
25
+ ```
26
+
27
+ ## Requirements
28
+
29
+ - Node.js 20 or newer.
30
+ - npm.
31
+ - Git, for Git status/snapshot/commit workflows.
32
+ - An MCP-compatible client such as Codex, Claude Code, or another local MCP client.
33
+
34
+ ## User Guide
35
+
36
+ EngiMCP is meant to be used through an MCP client. In normal use, you do not call TypeScript code directly. You start the server, connect it to your agent, and then ask the agent engineering-project questions in plain language.
37
+
38
+ ### 1. Prepare an Engineering Project Folder
39
+
40
+ Choose or create a local folder for the project:
41
+
42
+ ```bash
43
+ mkdir -p ~/Work/Projects/RC-Car
44
+ cd ~/Work/Projects/RC-Car
45
+ git init
46
+ ```
47
+
48
+ EngiMCP will keep the source of truth in this folder as Markdown files plus `project.yaml`.
49
+
50
+ ### 2. Install and Build EngiMCP
51
+
52
+ From the EngiMCP repository:
53
+
54
+ ```bash
55
+ npm install
56
+ npm run build
57
+ ```
58
+
59
+ ### 3. Connect It to an MCP Client
60
+
61
+ Use the built server command in your MCP client configuration:
62
+
63
+ ```text
64
+ node /absolute/path/to/EngiMCP/dist/index.js --root /absolute/path/to/your/project
65
+ ```
66
+
67
+ For a read-only review session:
68
+
69
+ ```text
70
+ node /absolute/path/to/EngiMCP/dist/index.js --root /absolute/path/to/your/project --read-only
71
+ ```
72
+
73
+ After package installation, the binary form is:
74
+
75
+ ```text
76
+ engimcp --root /absolute/path/to/project
77
+ engimcp --root /absolute/path/to/project --read-only
78
+ ```
79
+
80
+ When `--root` is set, tool calls must use that same project root. When `--read-only` is set, write-like tools are rejected.
81
+
82
+ ### 4. Initialize the Project
83
+
84
+ Ask your agent:
85
+
86
+ ```text
87
+ Initialize this folder as an EngiMCP project.
88
+ ```
89
+
90
+ The agent should call:
91
+
92
+ ```text
93
+ engi_project_init(root="/absolute/path/to/project")
94
+ ```
95
+
96
+ This creates the basic project files:
97
+
98
+ ```text
99
+ project.yaml
100
+ docs/
101
+ templates/
102
+ .engimcp/
103
+ ```
104
+
105
+ ### 5. Start Working
106
+
107
+ Useful first prompts:
108
+
109
+ ```text
110
+ Show project status.
111
+ Create a requirement: the car must run for 30 minutes.
112
+ Create an engineering decision for using four geared motors.
113
+ What breaks if we change the battery?
114
+ Prepare context for changing the project motors.
115
+ Find requirements that are not verified by tests.
116
+ Validate the project and show what needs fixing.
117
+ Show the Git diff summary.
118
+ ```
119
+
120
+ The agent will use EngiMCP tools to read the right documents, build context, analyze links, and apply focused edits.
121
+
122
+ ## Common User Workflows
123
+
124
+ ### Create Requirements
125
+
126
+ Ask:
127
+
128
+ ```text
129
+ Add a requirement that the radio-controlled car must stop safely when radio control is lost.
130
+ ```
131
+
132
+ EngiMCP creates a managed Markdown requirement with an ID such as `FR-001`, `NFR-001`, `SEC-001`, or `AC-001`.
133
+
134
+ ### Record Engineering Decisions
135
+
136
+ Ask:
137
+
138
+ ```text
139
+ Create an EDR explaining why we selected a 2S LiPo battery.
140
+ ```
141
+
142
+ EngiMCP creates an Engineering Decision Record such as `EDR-0001` with context, options, decision, consequences, and links.
143
+
144
+ ### Analyze Change Impact
145
+
146
+ Ask:
147
+
148
+ ```text
149
+ What documents, tests, BOM items, and decisions are affected if we change the battery?
150
+ ```
151
+
152
+ EngiMCP follows frontmatter links and inline links to return direct and transitive impact.
153
+
154
+ ### Prepare Focused Context
155
+
156
+ Ask:
157
+
158
+ ```text
159
+ Prepare context for changing the drive motors.
160
+ ```
161
+
162
+ EngiMCP builds a compact context pack instead of forcing the agent to read the whole project.
163
+
164
+ ### Edit Documents Safely
165
+
166
+ Ask:
167
+
168
+ ```text
169
+ Update the Battery Estimate section with the new runtime calculation.
170
+ ```
171
+
172
+ The agent should use section-level document tools, so the edit stays focused and reviewable in Git.
173
+
174
+ ### Work with Ordinary Files
175
+
176
+ Ask:
177
+
178
+ ```text
179
+ List files under docs.
180
+ Read docs/battery-notes.md.
181
+ Create a folder for test reports.
182
+ Move this draft file into docs/archive.
183
+ Delete this temporary note.
184
+ ```
185
+
186
+ EngiMCP uses the safe `engi_fs_*` layer. Deletes go to `.engimcp/trash/...` by default.
187
+
188
+ ## Project Format
189
+
190
+ A valid project has:
191
+
192
+ ```text
193
+ project.yaml
194
+ docs/
195
+ templates/
196
+ .engimcp/
197
+ ```
198
+
199
+ Managed Markdown documents use YAML frontmatter with at least:
200
+
201
+ ```yaml
202
+ ---
203
+ id: DOC-EXAMPLE
204
+ kind: design_doc
205
+ status: draft
206
+ version: 0.1.0
207
+ ---
208
+ ```
209
+
210
+ You can edit Markdown files manually in VS Code, Obsidian, or another editor. Run validation after manual edits:
211
+
212
+ ```text
213
+ Validate the project.
214
+ ```
215
+
216
+ ## Quick Start
217
+
218
+ 1. Start the MCP server from this repository or install it as a binary.
219
+ 2. Connect an MCP client over stdio.
220
+ 3. Initialize or open a project root.
221
+ 4. Call `engi_project_status` to verify the project.
222
+ 5. Use `engi_context_pack` before asking the agent to change a subsystem.
223
+ 6. Use `engi_impact_analyze` before changing requirements, decisions, battery, motors, BOM, tests, or calculations.
224
+ 7. Use `engi_validate_project` after changes.
225
+ 8. Review the Git diff with `engi_git_status`.
226
+
227
+ Example workflow:
228
+
229
+ ```text
230
+ engi_project_status(root)
231
+ engi_context_pack(root, task="we are changing the project motors")
232
+ engi_impact_analyze(root, changed_ids=["DOC-RC-CAR-BATTERY"])
233
+ engi_doc_patch_section(root, id="DOC-RC-CAR-BATTERY", heading_path=["Initial Estimate"], ...)
234
+ engi_validate_project(root)
235
+ engi_git_status(root)
236
+ ```
237
+
238
+ ## Core Tools
239
+
240
+ Project:
241
+
242
+ - `engi_project_init`
243
+ - `engi_project_status`
244
+ - `engi_project_map`
245
+ - `engi_rebuild_index`
246
+
247
+ Managed engineering documents:
248
+
249
+ - `engi_doc_read`
250
+ - `engi_doc_create`
251
+ - `engi_frontmatter_patch`
252
+ - `engi_doc_patch_section`
253
+ - `engi_doc_add_relationship`
254
+
255
+ Engineering entities:
256
+
257
+ - `engi_requirement_create`
258
+ - `engi_decision_create`
259
+ - `engi_task_create`
260
+ - `engi_test_report_create`
261
+ - `engi_bom_item_create`
262
+
263
+ Analysis and retrieval:
264
+
265
+ - `engi_search`
266
+ - `engi_graph_query`
267
+ - `engi_impact_analyze`
268
+ - `engi_context_pack`
269
+ - `engi_validate_project`
270
+
271
+ Git:
272
+
273
+ - `engi_git_status`
274
+ - `engi_project_snapshot`
275
+ - `engi_git_commit`
276
+
277
+ Safe filesystem layer:
278
+
279
+ - `engi_fs_tree`
280
+ - `engi_fs_list`
281
+ - `engi_fs_read`
282
+ - `engi_fs_write`
283
+ - `engi_fs_mkdir`
284
+ - `engi_fs_move`
285
+ - `engi_fs_copy`
286
+ - `engi_fs_delete`
287
+ - `engi_fs_exists`
288
+ - `engi_fs_stat`
289
+ - `engi_fs_glob`
290
+
291
+ Use `engi_doc_*` for managed engineering documents where IDs, frontmatter, links, graph, and validation matter. Use `engi_fs_*` for ordinary files and folders inside the project root.
292
+
293
+ ## Safety Model
294
+
295
+ EngiMCP is not raw filesystem access.
296
+
297
+ - All operations are restricted to `project_root`.
298
+ - Runtime `--root` pins the allowed project root.
299
+ - `../` traversal and absolute-path escape are rejected.
300
+ - Symlink escape outside the root is rejected.
301
+ - Deny patterns block `.git`, `.env`, SSH keys, secrets, private files, cache paths, and dependency folders.
302
+ - Project-configured deny patterns extend the defaults.
303
+ - Write-like tools respect read-only mode.
304
+ - Deletes use trash by default: `.engimcp/trash/YYYY-MM-DD/<original-path>`.
305
+ - Writes are atomic where practical.
306
+ - Write/move/copy/delete/mkdir operations write audit log entries.
307
+ - Overwrite-like operations refuse to modify files containing Git conflict markers.
308
+
309
+ ## Validation and Indexing
310
+
311
+ `engi_validate_project` checks IDs, required frontmatter, duplicate IDs, broken links, dependency cycles, and requirement verification gaps.
312
+
313
+ `engi_rebuild_index` regenerates `.engimcp/index.sqlite` from Markdown and frontmatter. Filesystem write-like operations rebuild the index after successful changes, and `engi_project_status` restores the index if it is missing.
314
+
315
+ ## Development Commands
316
+
317
+ ```bash
318
+ npm run build
319
+ npm run lint
320
+ npm run format
321
+ npm run format:check
322
+ npm test
323
+ npm run check
324
+ npm run smoke
325
+ ```
326
+
327
+ `npm run check` runs build, lint, format check, and the test suite. `npm run smoke` builds the project and runs a project-status smoke check against the radio-controlled car example.
328
+
329
+ ## Important Documentation
330
+
331
+ - `docs/02_requirements/technical_requirements.md` - functional and non-functional requirements.
332
+ - `docs/02_requirements/filesystem_overlay_requirements.md` - safe filesystem layer requirements.
333
+ - `docs/02_requirements/acceptance_criteria.md` - acceptance criteria.
334
+ - `docs/03_architecture/system_architecture.md` - system architecture.
335
+ - `docs/04_data_model/entities_and_schema.md` - entity and frontmatter model.
336
+ - `docs/05_mcp_interface/tools_spec.md` - MCP tool contracts.
337
+ - `docs/05_mcp_interface/filesystem_tools_spec.md` - filesystem tool contracts.
338
+ - `docs/07_quality/testing_strategy.md` - test strategy.
339
+ - `docs/08_security/security_model.md` - security model.
340
+ - `docs/09_delivery/roadmap.md` - milestone roadmap.
341
+ - `CHANGELOG.md` - release notes.
342
+
343
+ ## License
344
+
345
+ MIT.
@@ -0,0 +1,9 @@
1
+ export interface AuditLogInput {
2
+ root: string;
3
+ tool: string;
4
+ target: string;
5
+ operation: string;
6
+ result: "ok" | "error";
7
+ diff_summary: string;
8
+ }
9
+ export declare function writeAuditLog(input: AuditLogInput): Promise<string>;
@@ -0,0 +1,20 @@
1
+ import { mkdir, appendFile } from "node:fs/promises";
2
+ import path from "node:path";
3
+ export async function writeAuditLog(input) {
4
+ const auditId = `AUD-${new Date().toISOString().replace(/[-:.TZ]/g, "")}`;
5
+ const auditDirectory = path.join(input.root, ".engimcp");
6
+ const auditPath = path.join(auditDirectory, "audit.log");
7
+ const record = {
8
+ id: auditId,
9
+ ts: new Date().toISOString(),
10
+ tool: input.tool,
11
+ target: input.target,
12
+ operation: input.operation,
13
+ result: input.result,
14
+ diff_summary: input.diff_summary
15
+ };
16
+ await mkdir(auditDirectory, { recursive: true });
17
+ await appendFile(auditPath, `${JSON.stringify(record)}\n`, "utf8");
18
+ return auditId;
19
+ }
20
+ //# sourceMappingURL=auditLog.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auditLog.js","sourceRoot":"","sources":["../../src/audit/auditLog.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,IAAI,MAAM,WAAW,CAAC;AAW7B,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,KAAoB;IACtD,MAAM,OAAO,GAAG,OAAO,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,EAAE,CAAC;IAC1E,MAAM,cAAc,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;IACzD,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,WAAW,CAAC,CAAC;IACzD,MAAM,MAAM,GAAG;QACb,EAAE,EAAE,OAAO;QACX,EAAE,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QAC5B,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,YAAY,EAAE,KAAK,CAAC,YAAY;KACjC,CAAC;IAEF,MAAM,KAAK,CAAC,cAAc,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACjD,MAAM,UAAU,CAAC,SAAS,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAEnE,OAAO,OAAO,CAAC;AACjB,CAAC"}
@@ -0,0 +1,23 @@
1
+ export interface CreateBomItemInput {
2
+ root: string;
3
+ id: string;
4
+ part_name: string;
5
+ quantity: number;
6
+ status?: "candidate" | "approved" | "rejected";
7
+ source?: string;
8
+ unit_cost?: number;
9
+ currency?: string;
10
+ related?: string[];
11
+ dry_run?: boolean;
12
+ }
13
+ export declare function createBomItem(input: CreateBomItemInput): Promise<{
14
+ id: string;
15
+ path: string;
16
+ content: string;
17
+ audit_id?: undefined;
18
+ } | {
19
+ id: string;
20
+ path: string;
21
+ audit_id: string;
22
+ content?: undefined;
23
+ }>;
@@ -0,0 +1,44 @@
1
+ import { writeAuditLog } from "../audit/auditLog.js";
2
+ import { serializeDocument } from "../documents/frontmatter.js";
3
+ import { assertAbsoluteRoot, resolveSafePath } from "../project/pathSafety.js";
4
+ import { assertProjectWritable } from "../project/writeGuards.js";
5
+ import { atomicWrite } from "../utils/atomicWrite.js";
6
+ import { slugify } from "../utils/ids.js";
7
+ export async function createBomItem(input) {
8
+ const root = assertAbsoluteRoot(input.root);
9
+ await assertProjectWritable(root);
10
+ const relativePath = `docs/bom/${input.id}-${slugify(input.part_name)}.md`;
11
+ const content = serializeDocument({
12
+ id: input.id,
13
+ kind: "bom_item",
14
+ status: input.status ?? "candidate",
15
+ version: "0.1.0",
16
+ part_name: input.part_name,
17
+ quantity: input.quantity,
18
+ source: input.source,
19
+ unit_cost: input.unit_cost,
20
+ currency: input.currency,
21
+ relates_to: input.related ?? []
22
+ }, `# ${input.id}: ${input.part_name}
23
+
24
+ | Field | Value |
25
+ |---|---|
26
+ | Quantity | ${input.quantity} |
27
+ | Status | ${input.status ?? "candidate"} |
28
+ | Source | ${input.source ?? ""} |
29
+ `);
30
+ if (input.dry_run) {
31
+ return { id: input.id, path: relativePath, content };
32
+ }
33
+ await atomicWrite(await resolveSafePath(root, relativePath), content);
34
+ const auditId = await writeAuditLog({
35
+ root,
36
+ tool: "engi_bom_item_create",
37
+ target: input.id,
38
+ operation: "create",
39
+ result: "ok",
40
+ diff_summary: "BOM item created"
41
+ });
42
+ return { id: input.id, path: relativePath, audit_id: auditId };
43
+ }
44
+ //# sourceMappingURL=bomService.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bomService.js","sourceRoot":"","sources":["../../src/bom/bomService.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,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,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAe1C,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,KAAyB;IAC3D,MAAM,IAAI,GAAG,kBAAkB,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC5C,MAAM,qBAAqB,CAAC,IAAI,CAAC,CAAC;IAClC,MAAM,YAAY,GAAG,YAAY,KAAK,CAAC,EAAE,IAAI,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC,KAAK,CAAC;IAC3E,MAAM,OAAO,GAAG,iBAAiB,CAC/B;QACE,EAAE,EAAE,KAAK,CAAC,EAAE;QACZ,IAAI,EAAE,UAAU;QAChB,MAAM,EAAE,KAAK,CAAC,MAAM,IAAI,WAAW;QACnC,OAAO,EAAE,OAAO;QAChB,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,UAAU,EAAE,KAAK,CAAC,OAAO,IAAI,EAAE;KAChC,EACD,KAAK,KAAK,CAAC,EAAE,KAAK,KAAK,CAAC,SAAS;;;;eAItB,KAAK,CAAC,QAAQ;aAChB,KAAK,CAAC,MAAM,IAAI,WAAW;aAC3B,KAAK,CAAC,MAAM,IAAI,EAAE;CAC9B,CACE,CAAC;IAEF,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;QAClB,OAAO,EAAE,EAAE,EAAE,KAAK,CAAC,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE,OAAO,EAAE,CAAC;IACvD,CAAC;IAED,MAAM,WAAW,CAAC,MAAM,eAAe,CAAC,IAAI,EAAE,YAAY,CAAC,EAAE,OAAO,CAAC,CAAC;IACtE,MAAM,OAAO,GAAG,MAAM,aAAa,CAAC;QAClC,IAAI;QACJ,IAAI,EAAE,sBAAsB;QAC5B,MAAM,EAAE,KAAK,CAAC,EAAE;QAChB,SAAS,EAAE,QAAQ;QACnB,MAAM,EAAE,IAAI;QACZ,YAAY,EAAE,kBAAkB;KACjC,CAAC,CAAC;IAEH,OAAO,EAAE,EAAE,EAAE,KAAK,CAAC,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC;AACjE,CAAC"}
@@ -0,0 +1,16 @@
1
+ export interface EngiProjectConfig {
2
+ project: {
3
+ id: string;
4
+ name?: string;
5
+ schema_version?: string;
6
+ source_of_truth?: string;
7
+ };
8
+ mcp?: {
9
+ read_only_mode?: boolean;
10
+ };
11
+ security?: {
12
+ deny_patterns?: string[];
13
+ follow_symlinks?: boolean;
14
+ };
15
+ }
16
+ export declare function readProjectConfig(root: string): Promise<EngiProjectConfig>;
@@ -0,0 +1,16 @@
1
+ import { access, readFile } from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { parse } from "yaml";
4
+ import { EngiMcpError } from "../mcp/errors.js";
5
+ import { projectConfigSchema } from "./schema.js";
6
+ export async function readProjectConfig(root) {
7
+ const configPath = path.join(root, "project.yaml");
8
+ await access(configPath);
9
+ const parsed = parse(await readFile(configPath, "utf8"));
10
+ const config = projectConfigSchema.parse(parsed);
11
+ if (config.project.schema_version !== "1.0.0") {
12
+ throw new EngiMcpError("UNSUPPORTED_SCHEMA_VERSION", `Unsupported project schema_version ${config.project.schema_version}; expected 1.0.0. Run a project migration before opening this project.`);
13
+ }
14
+ return config;
15
+ }
16
+ //# sourceMappingURL=projectConfig.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"projectConfig.js","sourceRoot":"","sources":["../../src/config/projectConfig.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,KAAK,EAAE,MAAM,MAAM,CAAC;AAC7B,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAkBlD,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,IAAY;IAClD,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,cAAc,CAAC,CAAC;IACnD,MAAM,MAAM,CAAC,UAAU,CAAC,CAAC;IAEzB,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC,CAAY,CAAC;IACpE,MAAM,MAAM,GAAG,mBAAmB,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IACjD,IAAI,MAAM,CAAC,OAAO,CAAC,cAAc,KAAK,OAAO,EAAE,CAAC;QAC9C,MAAM,IAAI,YAAY,CACpB,4BAA4B,EAC5B,sCAAsC,MAAM,CAAC,OAAO,CAAC,cAAc,wEAAwE,CAC5I,CAAC;IACJ,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,16 @@
1
+ import { z } from "zod";
2
+ export declare const projectConfigSchema: z.ZodObject<{
3
+ project: z.ZodObject<{
4
+ id: z.ZodString;
5
+ name: z.ZodOptional<z.ZodString>;
6
+ schema_version: z.ZodDefault<z.ZodString>;
7
+ source_of_truth: z.ZodOptional<z.ZodString>;
8
+ }, z.core.$strip>;
9
+ mcp: z.ZodOptional<z.ZodObject<{
10
+ read_only_mode: z.ZodDefault<z.ZodBoolean>;
11
+ }, z.core.$strip>>;
12
+ security: z.ZodOptional<z.ZodObject<{
13
+ deny_patterns: z.ZodOptional<z.ZodArray<z.ZodString>>;
14
+ follow_symlinks: z.ZodDefault<z.ZodBoolean>;
15
+ }, z.core.$strip>>;
16
+ }, z.core.$strip>;
@@ -0,0 +1,21 @@
1
+ import { z } from "zod";
2
+ export const projectConfigSchema = z.object({
3
+ project: z.object({
4
+ id: z.string(),
5
+ name: z.string().optional(),
6
+ schema_version: z.string().default("1.0.0"),
7
+ source_of_truth: z.string().optional()
8
+ }),
9
+ mcp: z
10
+ .object({
11
+ read_only_mode: z.boolean().default(false)
12
+ })
13
+ .optional(),
14
+ security: z
15
+ .object({
16
+ deny_patterns: z.array(z.string()).optional(),
17
+ follow_symlinks: z.boolean().default(false)
18
+ })
19
+ .optional()
20
+ });
21
+ //# sourceMappingURL=schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/config/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC1C,OAAO,EAAE,CAAC,CAAC,MAAM,CAAC;QAChB,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE;QACd,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;QAC3B,cAAc,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC;QAC3C,eAAe,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;KACvC,CAAC;IACF,GAAG,EAAE,CAAC;SACH,MAAM,CAAC;QACN,cAAc,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC;KAC3C,CAAC;SACD,QAAQ,EAAE;IACb,QAAQ,EAAE,CAAC;SACR,MAAM,CAAC;QACN,aAAa,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE;QAC7C,eAAe,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC;KAC5C,CAAC;SACD,QAAQ,EAAE;CACd,CAAC,CAAC"}
@@ -0,0 +1,31 @@
1
+ export interface ContextPackInput {
2
+ root: string;
3
+ task: string;
4
+ seed_ids?: string[];
5
+ max_tokens?: number;
6
+ include_sections?: boolean;
7
+ include_decisions?: boolean;
8
+ include_open_tasks?: boolean;
9
+ include_validation?: boolean;
10
+ }
11
+ export interface ContextPackItem {
12
+ id?: string;
13
+ path: string;
14
+ kind?: string;
15
+ reason: string;
16
+ content_mode: "full" | "section";
17
+ content: string;
18
+ }
19
+ export interface ContextPackResult {
20
+ pack_id: string;
21
+ task: string;
22
+ estimated_tokens: number;
23
+ items: ContextPackItem[];
24
+ excluded: Array<{
25
+ id?: string;
26
+ path: string;
27
+ reason: string;
28
+ }>;
29
+ warnings: string[];
30
+ }
31
+ export declare function buildContextPack(input: ContextPackInput): Promise<ContextPackResult>;