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 +194 -0
- package/package.json +27 -6
- package/src/index.ts +225 -0
- package/tsconfig.json +9 -0
- package/README.md +0 -3
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.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
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
package/README.md
DELETED