engmemory 0.0.0-stage → 0.1.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.
package/dist/index.js ADDED
@@ -0,0 +1,194 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/index.ts
4
+ import process from "process";
5
+ import { Command } from "commander";
6
+ import fs from "fs";
7
+ import path from "path";
8
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
9
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
10
+ import { z } from "zod";
11
+ import {
12
+ cleanIndexes,
13
+ diffKnowledge,
14
+ doctor,
15
+ initializeRepository,
16
+ publishKnowledge,
17
+ scanRepository,
18
+ syncRepository,
19
+ verifyKnowledge
20
+ } from "@engmemory/core";
21
+ import { searchKnowledge } from "@engmemory/knowledge-retrieval";
22
+ var program = new Command();
23
+ program.name("engmemory").description("Persistent engineering knowledge for Git repositories").version("0.1.0");
24
+ program.command("init").description("Initialize Engineering Memory in the current Git repository").option("--json", "Print machine-readable output").action(async (options) => {
25
+ try {
26
+ const result = await initializeRepository(process.cwd());
27
+ if (options.json) {
28
+ process.stdout.write(`${JSON.stringify(result, null, 2)}
29
+ `);
30
+ return;
31
+ }
32
+ process.stdout.write(`Initialized Engineering Memory at ${result.repositoryRoot}
33
+ `);
34
+ if (result.created.length > 0) {
35
+ process.stdout.write(`Created ${result.created.length} knowledge files.
36
+ `);
37
+ }
38
+ if (result.preserved.length > 0) {
39
+ process.stdout.write(`Preserved ${result.preserved.length} existing knowledge files.
40
+ `);
41
+ }
42
+ } catch (error) {
43
+ const message = error instanceof Error ? error.message : String(error);
44
+ program.error(message, { exitCode: 1 });
45
+ }
46
+ });
47
+ program.command("diff").description("Show pending knowledge changes").option("--json").action(async (options) => {
48
+ const result = await diffKnowledge(process.cwd());
49
+ if (options.json) process.stdout.write(`${JSON.stringify(result, null, 2)}
50
+ `);
51
+ else process.stdout.write(result.output || `Pending knowledge files:
52
+ ${result.files.map((file) => ` ${file}`).join("\n") || "none"}
53
+ `);
54
+ });
55
+ program.command("publish").description("Create a knowledge branch and pull request").option("--dry-run", "Validate publishing without creating a branch or commit").option("--branch <name>", "Knowledge branch name").action(async (options) => {
56
+ const result = await publishKnowledge(process.cwd(), options);
57
+ process.stdout.write(`${JSON.stringify(result, null, 2)}
58
+ `);
59
+ });
60
+ program.command("doctor").description("Diagnose local Git and GitHub tooling").option("--json").action(async (options) => {
61
+ const result = await doctor(process.cwd());
62
+ process.stdout.write(`${JSON.stringify(result, null, 2)}
63
+ `);
64
+ });
65
+ program.command("clean").description("Remove derived knowledge indexes for a rebuild").action(async () => {
66
+ const removed = await cleanIndexes(process.cwd());
67
+ process.stdout.write(`Removed derived index entries: ${removed.length}
68
+ `);
69
+ });
70
+ program.command("status").description("Show repository knowledge status").option("--json", "Print machine-readable output").action(async (options) => {
71
+ try {
72
+ const fs2 = await import("fs");
73
+ const path2 = await import("path");
74
+ const indexPath = path2.join(process.cwd(), ".engineering-memory", "indexes", "extracted-knowledge.json");
75
+ if (!fs2.existsSync(indexPath)) {
76
+ program.error("Knowledge index not found. Run engmemory scan first.", { exitCode: 1 });
77
+ }
78
+ const knowledge = JSON.parse(fs2.readFileSync(indexPath, "utf8"));
79
+ const result = {
80
+ apis: knowledge.apis?.length ?? 0,
81
+ databases: knowledge.databases?.length ?? 0,
82
+ businessRules: knowledge.businessRules?.length ?? 0,
83
+ technicalRules: knowledge.technicalRules?.length ?? 0
84
+ };
85
+ if (options.json) process.stdout.write(`${JSON.stringify(result, null, 2)}
86
+ `);
87
+ else process.stdout.write(`APIs: ${result.apis}; databases: ${result.databases}; business rules: ${result.businessRules}; technical rules: ${result.technicalRules}
88
+ `);
89
+ } catch (error) {
90
+ program.error(error instanceof Error ? error.message : String(error), { exitCode: 1 });
91
+ }
92
+ });
93
+ program.command("mcp").description("Start the local read-only MCP server").action(() => {
94
+ const repositoryRoot = process.cwd();
95
+ const server = new McpServer({
96
+ name: "engineering-memory",
97
+ version: "0.1.0"
98
+ });
99
+ server.registerTool(
100
+ "search_knowledge",
101
+ {
102
+ description: "Search Engineering Memory knowledge in the repository.",
103
+ inputSchema: {
104
+ query: z.string().min(1),
105
+ category: z.string().optional(),
106
+ status: z.string().optional()
107
+ }
108
+ },
109
+ async ({ query, category, status }) => ({
110
+ content: [{
111
+ type: "text",
112
+ text: JSON.stringify(searchKnowledge(repositoryRoot, query, { category, status }), null, 2)
113
+ }]
114
+ })
115
+ );
116
+ server.registerTool(
117
+ "get_project_overview",
118
+ {
119
+ description: "Read the repository Engineering Memory overview.",
120
+ inputSchema: {}
121
+ },
122
+ async () => {
123
+ const overviewPath = path.join(repositoryRoot, ".engineering-memory", "project", "overview.md");
124
+ const overview = fs.existsSync(overviewPath) ? fs.readFileSync(overviewPath, "utf8") : "";
125
+ return { content: [{ type: "text", text: overview }] };
126
+ }
127
+ );
128
+ return server.connect(new StdioServerTransport());
129
+ });
130
+ program.command("sync").description("Synchronize knowledge changed since the last scan").option("--json", "Print machine-readable output").action(async (options) => {
131
+ try {
132
+ const result = await syncRepository(process.cwd());
133
+ if (options.json) process.stdout.write(`${JSON.stringify(result, null, 2)}
134
+ `);
135
+ else process.stdout.write(`Synchronized ${result.changedFiles.length} changed files; ${result.unchangedFiles} unchanged.
136
+ `);
137
+ } catch (error) {
138
+ program.error(error instanceof Error ? error.message : String(error), { exitCode: 1 });
139
+ }
140
+ });
141
+ program.command("search <query>").description("Search repository knowledge").option("--json", "Print machine-readable output").action(async (query, options) => {
142
+ try {
143
+ const results = searchKnowledge(process.cwd(), query);
144
+ if (options.json) process.stdout.write(`${JSON.stringify(results, null, 2)}
145
+ `);
146
+ else {
147
+ for (const result of results) process.stdout.write(`${result.id} ${result.title}
148
+ `);
149
+ if (results.length === 0) process.stdout.write("No matching knowledge found.\n");
150
+ }
151
+ } catch (error) {
152
+ program.error(error instanceof Error ? error.message : String(error), { exitCode: 1 });
153
+ }
154
+ });
155
+ program.command("verify").description("Verify extracted knowledge source references").option("--json", "Print machine-readable output").action(async (options) => {
156
+ try {
157
+ const result = await verifyKnowledge(process.cwd());
158
+ if (options.json) process.stdout.write(`${JSON.stringify(result, null, 2)}
159
+ `);
160
+ else process.stdout.write(`Verified ${result.verified} records; ${result.stale} stale records.
161
+ `);
162
+ } catch (error) {
163
+ const message = error instanceof Error ? error.message : String(error);
164
+ program.error(message, { exitCode: 1 });
165
+ }
166
+ });
167
+ program.command("scan").description("Scan repository structure and TypeScript symbols").option("--json", "Print machine-readable output").action(async (options) => {
168
+ try {
169
+ const facts = await scanRepository(process.cwd());
170
+ if (options.json) {
171
+ process.stdout.write(`${JSON.stringify(facts, null, 2)}
172
+ `);
173
+ return;
174
+ }
175
+ process.stdout.write(
176
+ `Scanned ${facts.inventory.files.length} files; found ${facts.symbols.length} symbols and ${facts.dependencies.length} dependencies.
177
+ `
178
+ );
179
+ if (facts.inventory.languages.length === 0) {
180
+ process.stdout.write("No TypeScript or JavaScript files detected.\n");
181
+ }
182
+ if (!options.json && facts.inventory.root) {
183
+ process.stdout.write("Knowledge extraction index written to .engineering-memory/indexes/extracted-knowledge.json\n");
184
+ }
185
+ if (facts.diagnostics.length > 0) {
186
+ process.stdout.write(`TypeScript diagnostics: ${facts.diagnostics.length}
187
+ `);
188
+ }
189
+ } catch (error) {
190
+ const message = error instanceof Error ? error.message : String(error);
191
+ program.error(message, { exitCode: 1 });
192
+ }
193
+ });
194
+ await program.parseAsync(process.argv);
package/package.json CHANGED
@@ -1,6 +1,27 @@
1
- {
2
- "name": "engmemory",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
1
+ {
2
+ "name": "engmemory",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "bin": {
6
+ "engmemory": "./dist/index.js"
7
+ },
8
+ "exports": "./src/index.ts",
9
+ "scripts": {
10
+ "build": "tsup src/index.ts --format esm --clean",
11
+ "typecheck": "tsc -p tsconfig.json --noEmit",
12
+ "dev": "tsx src/index.ts"
13
+ },
14
+ "dependencies": {
15
+ "@engmemory/core": "workspace:*",
16
+ "@engmemory/knowledge-retrieval": "workspace:*",
17
+ "@modelcontextprotocol/sdk": "^1.17.3",
18
+ "commander": "^14.0.1",
19
+ "zod": "^3.25.76"
20
+ },
21
+ "devDependencies": {
22
+ "@types/node": "^24.7.2",
23
+ "tsup": "^8.5.0",
24
+ "tsx": "^4.20.5",
25
+ "typescript": "^5.9.2"
26
+ }
27
+ }
package/src/index.ts ADDED
@@ -0,0 +1,225 @@
1
+ #!/usr/bin/env node
2
+
3
+ import process from "node:process";
4
+ import { Command } from "commander";
5
+ import fs from "node:fs";
6
+ import path from "node:path";
7
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
8
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
9
+ import { z } from "zod";
10
+ import {
11
+ cleanIndexes,
12
+ diffKnowledge,
13
+ doctor,
14
+ initializeRepository,
15
+ publishKnowledge,
16
+ scanRepository,
17
+ syncRepository,
18
+ verifyKnowledge,
19
+ } from "@engmemory/core";
20
+ import { searchKnowledge } from "@engmemory/knowledge-retrieval";
21
+
22
+ const program = new Command();
23
+
24
+ program
25
+ .name("engmemory")
26
+ .description("Persistent engineering knowledge for Git repositories")
27
+ .version("0.1.0");
28
+
29
+ program
30
+ .command("init")
31
+ .description("Initialize Engineering Memory in the current Git repository")
32
+ .option("--json", "Print machine-readable output")
33
+ .action(async (options: { json?: boolean }) => {
34
+ try {
35
+ const result = await initializeRepository(process.cwd());
36
+
37
+ if (options.json) {
38
+ process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
39
+ return;
40
+ }
41
+
42
+ process.stdout.write(`Initialized Engineering Memory at ${result.repositoryRoot}\n`);
43
+ if (result.created.length > 0) {
44
+ process.stdout.write(`Created ${result.created.length} knowledge files.\n`);
45
+ }
46
+ if (result.preserved.length > 0) {
47
+ process.stdout.write(`Preserved ${result.preserved.length} existing knowledge files.\n`);
48
+ }
49
+ } catch (error) {
50
+ const message = error instanceof Error ? error.message : String(error);
51
+ program.error(message, { exitCode: 1 });
52
+ }
53
+ });
54
+
55
+ program.command("diff").description("Show pending knowledge changes").option("--json").action(async (options: { json?: boolean }) => {
56
+ const result = await diffKnowledge(process.cwd());
57
+ if (options.json) process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
58
+ else process.stdout.write(result.output || `Pending knowledge files:\n${result.files.map((file) => ` ${file}`).join("\n") || "none"}\n`);
59
+ });
60
+
61
+ program.command("publish").description("Create a knowledge branch and pull request")
62
+ .option("--dry-run", "Validate publishing without creating a branch or commit")
63
+ .option("--branch <name>", "Knowledge branch name")
64
+ .action(async (options: { dryRun?: boolean; branch?: string }) => {
65
+ const result = await publishKnowledge(process.cwd(), options);
66
+ process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
67
+ });
68
+
69
+ program.command("doctor").description("Diagnose local Git and GitHub tooling").option("--json").action(async (options: { json?: boolean }) => {
70
+ const result = await doctor(process.cwd());
71
+ process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
72
+ });
73
+
74
+ program.command("clean").description("Remove derived knowledge indexes for a rebuild").action(async () => {
75
+ const removed = await cleanIndexes(process.cwd());
76
+ process.stdout.write(`Removed derived index entries: ${removed.length}\n`);
77
+ });
78
+
79
+ program
80
+ .command("status")
81
+ .description("Show repository knowledge status")
82
+ .option("--json", "Print machine-readable output")
83
+ .action(async (options: { json?: boolean }) => {
84
+ try {
85
+ const fs = await import("node:fs");
86
+ const path = await import("node:path");
87
+ const indexPath = path.join(process.cwd(), ".engineering-memory", "indexes", "extracted-knowledge.json");
88
+ if (!fs.existsSync(indexPath)) {
89
+ program.error("Knowledge index not found. Run engmemory scan first.", { exitCode: 1 });
90
+ }
91
+ const knowledge = JSON.parse(fs.readFileSync(indexPath, "utf8"));
92
+ const result = {
93
+ apis: knowledge.apis?.length ?? 0,
94
+ databases: knowledge.databases?.length ?? 0,
95
+ businessRules: knowledge.businessRules?.length ?? 0,
96
+ technicalRules: knowledge.technicalRules?.length ?? 0,
97
+ };
98
+ if (options.json) process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
99
+ else process.stdout.write(`APIs: ${result.apis}; databases: ${result.databases}; business rules: ${result.businessRules}; technical rules: ${result.technicalRules}\n`);
100
+ } catch (error) {
101
+ program.error(error instanceof Error ? error.message : String(error), { exitCode: 1 });
102
+ }
103
+ });
104
+
105
+ program
106
+ .command("mcp")
107
+ .description("Start the local read-only MCP server")
108
+ .action(() => {
109
+ const repositoryRoot = process.cwd();
110
+ const server = new McpServer({
111
+ name: "engineering-memory",
112
+ version: "0.1.0",
113
+ });
114
+
115
+ server.registerTool(
116
+ "search_knowledge",
117
+ {
118
+ description: "Search Engineering Memory knowledge in the repository.",
119
+ inputSchema: {
120
+ query: z.string().min(1),
121
+ category: z.string().optional(),
122
+ status: z.string().optional(),
123
+ },
124
+ },
125
+ async ({ query, category, status }) => ({
126
+ content: [{
127
+ type: "text",
128
+ text: JSON.stringify(searchKnowledge(repositoryRoot, query, { category, status }), null, 2),
129
+ }],
130
+ }),
131
+ );
132
+
133
+ server.registerTool(
134
+ "get_project_overview",
135
+ {
136
+ description: "Read the repository Engineering Memory overview.",
137
+ inputSchema: {},
138
+ },
139
+ async () => {
140
+ const overviewPath = path.join(repositoryRoot, ".engineering-memory", "project", "overview.md");
141
+ const overview = fs.existsSync(overviewPath) ? fs.readFileSync(overviewPath, "utf8") : "";
142
+ return { content: [{ type: "text", text: overview }] };
143
+ },
144
+ );
145
+
146
+ return server.connect(new StdioServerTransport());
147
+ });
148
+
149
+ program
150
+ .command("sync")
151
+ .description("Synchronize knowledge changed since the last scan")
152
+ .option("--json", "Print machine-readable output")
153
+ .action(async (options: { json?: boolean }) => {
154
+ try {
155
+ const result = await syncRepository(process.cwd());
156
+ if (options.json) process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
157
+ else process.stdout.write(`Synchronized ${result.changedFiles.length} changed files; ${result.unchangedFiles} unchanged.\n`);
158
+ } catch (error) {
159
+ program.error(error instanceof Error ? error.message : String(error), { exitCode: 1 });
160
+ }
161
+ });
162
+
163
+ program
164
+ .command("search <query>")
165
+ .description("Search repository knowledge")
166
+ .option("--json", "Print machine-readable output")
167
+ .action(async (query: string, options: { json?: boolean }) => {
168
+ try {
169
+ const results = searchKnowledge(process.cwd(), query);
170
+ if (options.json) process.stdout.write(`${JSON.stringify(results, null, 2)}\n`);
171
+ else {
172
+ for (const result of results) process.stdout.write(`${result.id}\t${result.title}\n`);
173
+ if (results.length === 0) process.stdout.write("No matching knowledge found.\n");
174
+ }
175
+ } catch (error) {
176
+ program.error(error instanceof Error ? error.message : String(error), { exitCode: 1 });
177
+ }
178
+ });
179
+
180
+ program
181
+ .command("verify")
182
+ .description("Verify extracted knowledge source references")
183
+ .option("--json", "Print machine-readable output")
184
+ .action(async (options: { json?: boolean }) => {
185
+ try {
186
+ const result = await verifyKnowledge(process.cwd());
187
+ if (options.json) process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
188
+ else process.stdout.write(`Verified ${result.verified} records; ${result.stale} stale records.\n`);
189
+ } catch (error) {
190
+ const message = error instanceof Error ? error.message : String(error);
191
+ program.error(message, { exitCode: 1 });
192
+ }
193
+ });
194
+
195
+ program
196
+ .command("scan")
197
+ .description("Scan repository structure and TypeScript symbols")
198
+ .option("--json", "Print machine-readable output")
199
+ .action(async (options: { json?: boolean }) => {
200
+ try {
201
+ const facts = await scanRepository(process.cwd());
202
+ if (options.json) {
203
+ process.stdout.write(`${JSON.stringify(facts, null, 2)}\n`);
204
+ return;
205
+ }
206
+ process.stdout.write(
207
+ `Scanned ${facts.inventory.files.length} files; found ${facts.symbols.length} symbols and ` +
208
+ `${facts.dependencies.length} dependencies.\n`,
209
+ );
210
+ if (facts.inventory.languages.length === 0) {
211
+ process.stdout.write("No TypeScript or JavaScript files detected.\n");
212
+ }
213
+ if (!options.json && facts.inventory.root) {
214
+ process.stdout.write("Knowledge extraction index written to .engineering-memory/indexes/extracted-knowledge.json\n");
215
+ }
216
+ if (facts.diagnostics.length > 0) {
217
+ process.stdout.write(`TypeScript diagnostics: ${facts.diagnostics.length}\n`);
218
+ }
219
+ } catch (error) {
220
+ const message = error instanceof Error ? error.message : String(error);
221
+ program.error(message, { exitCode: 1 });
222
+ }
223
+ });
224
+
225
+ await program.parseAsync(process.argv);
package/tsconfig.json ADDED
@@ -0,0 +1,9 @@
1
+ {
2
+ "extends": "../../tsconfig.base.json",
3
+ "compilerOptions": {
4
+ "outDir": "dist",
5
+ "rootDir": "src",
6
+ "types": ["node"],
7
+ },
8
+ "include": ["src/**/*.ts"]
9
+ }
package/README.md DELETED
@@ -1,3 +0,0 @@
1
- # Temporary Holding Version
2
-
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.