@de-otio/repo-aegis-mcp 0.5.0 → 0.7.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@de-otio/repo-aegis-mcp",
3
- "version": "0.5.0",
3
+ "version": "0.7.0",
4
4
  "description": "Model Context Protocol server wrapping repo-aegis as agent-readable tools",
5
5
  "license": "GPL-3.0-or-later",
6
6
  "author": "Richard Myers",
@@ -22,13 +22,14 @@
22
22
  }
23
23
  },
24
24
  "files": [
25
- "dist"
25
+ "dist",
26
+ "!**/*.test.*"
26
27
  ],
27
28
  "scripts": {
28
29
  "build": "tsc && chmod +x dist/index.js"
29
30
  },
30
31
  "dependencies": {
31
- "@de-otio/repo-aegis-core": "^0.5.0",
32
+ "@de-otio/repo-aegis-core": "^0.7.0",
32
33
  "@modelcontextprotocol/sdk": "^1.29.0",
33
34
  "zod": "^4.4.3"
34
35
  }
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=server.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"server.test.d.ts","sourceRoot":"","sources":["../src/server.test.ts"],"names":[],"mappings":""}
@@ -1,171 +0,0 @@
1
- // SPDX-License-Identifier: GPL-3.0-or-later
2
- // Copyright (C) 2026 Richard Myers and contributors.
3
- // Smoke test for the MCP server: boot it with an in-memory transport pair,
4
- // list tools, and call one tool end-to-end. Verifies that:
5
- // - every tool the server should register is actually registered;
6
- // - a non-trivial tool (status) returns valid JSON of the expected shape;
7
- // - the redaction policy holds (no literal markers in any output).
8
- //
9
- // Skips gracefully if the MCP SDK isn't installed in node_modules — useful
10
- // in environments where the workspace install hasn't run yet.
11
- import { describe, it, before, after } from "node:test";
12
- import assert from "node:assert/strict";
13
- import { execFileSync } from "node:child_process";
14
- import { mkdirSync, mkdtempSync, rmSync, writeFileSync, } from "node:fs";
15
- import { tmpdir } from "node:os";
16
- import { join } from "node:path";
17
- const EXPECTED_TOOLS = [
18
- "repo_aegis_status",
19
- "repo_aegis_check_path",
20
- "repo_aegis_check_staged",
21
- "repo_aegis_engagements_list",
22
- "repo_aegis_engagements_show",
23
- "repo_aegis_markers_test",
24
- "repo_aegis_markers_list",
25
- "repo_aegis_audit",
26
- "aegis_classify_first_touch",
27
- ];
28
- async function loadHarness() {
29
- try {
30
- const [{ buildServer }, { Client }, { InMemoryTransport }] = await Promise.all([
31
- import("./server.js"),
32
- import("@modelcontextprotocol/sdk/client/index.js"),
33
- import("@modelcontextprotocol/sdk/inMemory.js"),
34
- ]);
35
- return { buildServer, Client, InMemoryTransport };
36
- }
37
- catch {
38
- return null;
39
- }
40
- }
41
- const harness = await loadHarness();
42
- if (!harness) {
43
- describe("repo-aegis MCP server (skipped: SDK not installed)", () => {
44
- it("skips when @modelcontextprotocol/sdk isn't resolvable", { skip: true }, () => {
45
- /* skipped */
46
- });
47
- });
48
- }
49
- else {
50
- const { buildServer, Client, InMemoryTransport } = harness;
51
- let tmp;
52
- let home;
53
- let repo;
54
- before(async () => {
55
- tmp = mkdtempSync(join(tmpdir(), "repo-aegis-mcp-test-"));
56
- home = join(tmp, "home");
57
- const markersDir = join(home, "markers");
58
- const stateDir = join(home, "state");
59
- mkdirSync(markersDir, { recursive: true });
60
- mkdirSync(stateDir, { recursive: true });
61
- // No engagements / no marker files: status should report an empty
62
- // deny set and zero patterns. We do NOT scaffold a registry.yaml here
63
- // because we're testing the "fresh install" path; loadRegistry's
64
- // RegistryNotFoundError is silently absorbed by the status tool.
65
- process.env["REPO_AEGIS_HOME"] = home;
66
- repo = join(tmp, "repo");
67
- mkdirSync(repo, { recursive: true });
68
- execFileSync("git", ["init", "-q"], { cwd: repo });
69
- execFileSync("git", ["config", "user.name", "test"], { cwd: repo });
70
- execFileSync("git", ["config", "user.email", "test@example.com"], { cwd: repo });
71
- // Class: private-strict (default). No engagements.
72
- });
73
- after(() => {
74
- delete process.env["REPO_AEGIS_HOME"];
75
- rmSync(tmp, { recursive: true, force: true });
76
- });
77
- describe("repo-aegis MCP server", () => {
78
- it("registers every expected tool", async () => {
79
- const server = buildServer();
80
- const client = new Client({ name: "test-client", version: "0.0.0" });
81
- const [serverTransport, clientTransport] = InMemoryTransport.createLinkedPair();
82
- await Promise.all([server.connect(serverTransport), client.connect(clientTransport)]);
83
- try {
84
- const list = await client.listTools();
85
- const names = list.tools.map(t => t.name).sort();
86
- for (const expected of EXPECTED_TOOLS) {
87
- assert.ok(names.includes(expected), `expected tool ${expected} to be registered; got ${names.join(", ")}`);
88
- }
89
- }
90
- finally {
91
- await client.close();
92
- await server.close();
93
- }
94
- });
95
- it("repo_aegis_status returns the canonical shape against a tmp git repo", async () => {
96
- const server = buildServer();
97
- const client = new Client({ name: "test-client", version: "0.0.0" });
98
- const [serverTransport, clientTransport] = InMemoryTransport.createLinkedPair();
99
- await Promise.all([server.connect(serverTransport), client.connect(clientTransport)]);
100
- try {
101
- const result = await client.callTool({
102
- name: "repo_aegis_status",
103
- arguments: { cwd: repo },
104
- });
105
- assert.equal(result.isError, undefined);
106
- const content = result.content;
107
- assert.ok(content && content.length > 0, "expected content array");
108
- const text = content[0].text;
109
- assert.ok(typeof text === "string", "expected text content");
110
- const parsed = JSON.parse(text);
111
- assert.equal(parsed.repo.isGitRepo, true);
112
- assert.equal(parsed.repo.class, "private-strict");
113
- assert.deepEqual(parsed.repo.engagements, []);
114
- assert.equal(parsed.denySet.patternCount, 0);
115
- assert.deepEqual(parsed.allowedEngagements, []);
116
- }
117
- finally {
118
- await client.close();
119
- await server.close();
120
- }
121
- });
122
- it("repo_aegis_markers_test redacts the input and returns no hits when deny set is empty", async () => {
123
- const server = buildServer();
124
- const client = new Client({ name: "test-client", version: "0.0.0" });
125
- const [serverTransport, clientTransport] = InMemoryTransport.createLinkedPair();
126
- await Promise.all([server.connect(serverTransport), client.connect(clientTransport)]);
127
- try {
128
- const result = await client.callTool({
129
- name: "repo_aegis_markers_test",
130
- arguments: { input: "some-private-string", cwd: repo },
131
- });
132
- assert.equal(result.isError, undefined);
133
- const content = result.content;
134
- const parsed = JSON.parse(content[0].text);
135
- // Input must be redacted in the response — never returned verbatim.
136
- assert.notEqual(parsed.input, "some-private-string");
137
- assert.ok(parsed.input.length > 0);
138
- assert.deepEqual(parsed.hits, []);
139
- // Avoid asserting "input does not contain literal" too eagerly — the
140
- // redactMatch preview keeps a short prefix. The important invariant
141
- // is "not equal to literal", which we check above.
142
- void writeFileSync; // keep import used
143
- }
144
- finally {
145
- await client.close();
146
- await server.close();
147
- }
148
- });
149
- it("repo_aegis_engagements_list returns REGISTRY_NOT_FOUND when no registry exists", async () => {
150
- const server = buildServer();
151
- const client = new Client({ name: "test-client", version: "0.0.0" });
152
- const [serverTransport, clientTransport] = InMemoryTransport.createLinkedPair();
153
- await Promise.all([server.connect(serverTransport), client.connect(clientTransport)]);
154
- try {
155
- const result = await client.callTool({
156
- name: "repo_aegis_engagements_list",
157
- arguments: {},
158
- });
159
- assert.equal(result.isError, true);
160
- const content = result.content;
161
- const parsed = JSON.parse(content[0].text);
162
- assert.equal(parsed.code, "REGISTRY_NOT_FOUND");
163
- }
164
- finally {
165
- await client.close();
166
- await server.close();
167
- }
168
- });
169
- });
170
- }
171
- //# sourceMappingURL=server.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"server.test.js","sourceRoot":"","sources":["../src/server.test.ts"],"names":[],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=first-touch.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"first-touch.test.d.ts","sourceRoot":"","sources":["../../src/tools/first-touch.test.ts"],"names":[],"mappings":""}
@@ -1,224 +0,0 @@
1
- // SPDX-License-Identifier: GPL-3.0-or-later
2
- // Copyright (C) 2026 Richard Myers and contributors.
3
- //
4
- // Unit tests for the `aegis_classify_first_touch` MCP tool. The tests
5
- // drive `firstTouchClassify` directly (the impl function exported from
6
- // the tool module) so we can spin up real git fixtures and a real
7
- // registry per case without paying the MCP transport overhead. The
8
- // server-side smoke test in server.test.ts covers tool registration
9
- // and one end-to-end call.
10
- import { describe, it, before, after, beforeEach } from "node:test";
11
- import assert from "node:assert/strict";
12
- import { execFileSync } from "node:child_process";
13
- import { mkdtempSync, mkdirSync, rmSync, writeFileSync, } from "node:fs";
14
- import { tmpdir } from "node:os";
15
- import { join } from "node:path";
16
- import { firstTouchClassify, redactOrg } from "./first-touch.js";
17
- let tmp;
18
- let gitDir;
19
- let nonGitDir;
20
- let registryPath;
21
- function git(cwd, args) {
22
- execFileSync("git", args, {
23
- cwd,
24
- stdio: ["ignore", "pipe", "ignore"],
25
- });
26
- }
27
- function setRemote(cwd, url) {
28
- try {
29
- git(cwd, ["remote", "remove", "origin"]);
30
- }
31
- catch {
32
- /* not set */
33
- }
34
- git(cwd, ["remote", "add", "origin", url]);
35
- }
36
- function removeRemote(cwd) {
37
- try {
38
- git(cwd, ["remote", "remove", "origin"]);
39
- }
40
- catch {
41
- /* not set */
42
- }
43
- }
44
- function unsetClass(cwd) {
45
- try {
46
- execFileSync("git", ["config", "--unset", "repo-aegis.class"], {
47
- cwd,
48
- stdio: ["ignore", "ignore", "ignore"],
49
- });
50
- }
51
- catch {
52
- /* not set */
53
- }
54
- try {
55
- execFileSync("git", ["config", "--unset-all", "repo-aegis.engagement"], {
56
- cwd,
57
- stdio: ["ignore", "ignore", "ignore"],
58
- });
59
- }
60
- catch {
61
- /* not set */
62
- }
63
- }
64
- function writeRegistry(body) {
65
- writeFileSync(registryPath, body, { mode: 0o600 });
66
- }
67
- before(() => {
68
- tmp = mkdtempSync(join(tmpdir(), "repo-aegis-first-touch-"));
69
- gitDir = join(tmp, "git");
70
- nonGitDir = join(tmp, "non-git");
71
- registryPath = join(tmp, "engagements.yaml");
72
- mkdirSync(gitDir, { recursive: true });
73
- mkdirSync(nonGitDir, { recursive: true });
74
- git(gitDir, ["init", "-q", "-b", "main"]);
75
- git(gitDir, ["config", "user.email", "test@example.com"]);
76
- git(gitDir, ["config", "user.name", "test"]);
77
- process.env["REPO_AEGIS_REGISTRY"] = registryPath;
78
- });
79
- after(() => {
80
- delete process.env["REPO_AEGIS_REGISTRY"];
81
- rmSync(tmp, { recursive: true, force: true });
82
- });
83
- beforeEach(() => {
84
- unsetClass(gitDir);
85
- removeRemote(gitDir);
86
- });
87
- describe("firstTouchClassify — skipped paths", () => {
88
- it("non-git cwd → status: skipped, reason: non-git", () => {
89
- const result = firstTouchClassify({ cwd: nonGitDir });
90
- assert.equal(result.status, "skipped");
91
- if (result.status === "skipped") {
92
- assert.equal(result.reason, "non-git");
93
- }
94
- });
95
- it("git repo with no remote → status: skipped, reason: no-remote", () => {
96
- writeRegistry(`schemaVersion: 2\nengagements: []\n`);
97
- const result = firstTouchClassify({ cwd: gitDir });
98
- assert.equal(result.status, "skipped");
99
- if (result.status === "skipped") {
100
- assert.equal(result.reason, "no-remote");
101
- }
102
- });
103
- it("non-github remote → status: skipped, reason: non-github-host", () => {
104
- writeRegistry(`schemaVersion: 2\nengagements: []\n`);
105
- setRemote(gitDir, "git@gitlab.com:foo/bar.git");
106
- const result = firstTouchClassify({ cwd: gitDir });
107
- assert.equal(result.status, "skipped");
108
- if (result.status === "skipped") {
109
- assert.equal(result.reason, "non-github-host");
110
- }
111
- });
112
- it("registry not found → status: skipped, reason: registry-not-found", () => {
113
- rmSync(registryPath, { force: true });
114
- setRemote(gitDir, "git@github.com:foo/bar.git");
115
- const result = firstTouchClassify({ cwd: gitDir });
116
- assert.equal(result.status, "skipped");
117
- if (result.status === "skipped") {
118
- assert.equal(result.reason, "registry-not-found");
119
- }
120
- });
121
- });
122
- describe("firstTouchClassify — already-classified", () => {
123
- it("returns status: already-classified when class is already set", () => {
124
- writeRegistry(`schemaVersion: 2\nengagements: []\n`);
125
- setRemote(gitDir, "git@github.com:foo/bar.git");
126
- execFileSync("git", ["config", "repo-aegis.class", "private-strict"], {
127
- cwd: gitDir,
128
- });
129
- const result = firstTouchClassify({ cwd: gitDir });
130
- assert.equal(result.status, "already-classified");
131
- if (result.status === "already-classified") {
132
- assert.equal(result.class, "private-strict");
133
- }
134
- });
135
- });
136
- describe("firstTouchClassify — applied", () => {
137
- it("personalOrgs match → applied, class: public-eligible", () => {
138
- writeRegistry(`schemaVersion: 2
139
- personalOrgs: [my-handle]
140
- engagements: []
141
- `);
142
- setRemote(gitDir, "git@github.com:my-handle/dotfiles.git");
143
- const result = firstTouchClassify({ cwd: gitDir });
144
- assert.equal(result.status, "applied");
145
- if (result.status === "applied") {
146
- assert.equal(result.class, "public-eligible");
147
- assert.equal(result.engagement, null);
148
- assert.equal(result.markerWarning, null);
149
- }
150
- });
151
- it("engagement match with markers → applied, class: customer-coupled, markerWarning: null", () => {
152
- writeRegistry(`schemaVersion: 2
153
- engagements:
154
- - id: foo-corp
155
- name: Foo Corp
156
- githubOrgs: [foo-corp]
157
- markers: [foo-marker]
158
- `);
159
- setRemote(gitDir, "git@github.com:foo-corp/proj.git");
160
- const result = firstTouchClassify({ cwd: gitDir });
161
- assert.equal(result.status, "applied");
162
- if (result.status === "applied") {
163
- assert.equal(result.class, "customer-coupled");
164
- assert.equal(result.engagement, "foo-corp");
165
- assert.equal(result.markerWarning, null);
166
- }
167
- });
168
- it("[SEC H-5] engagement match with zero markers → applied with markerWarning", () => {
169
- writeRegistry(`schemaVersion: 2
170
- engagements:
171
- - id: bare-co
172
- name: Bare Co
173
- githubOrgs: [bare-co]
174
- markers: []
175
- `);
176
- setRemote(gitDir, "git@github.com:bare-co/proj.git");
177
- const result = firstTouchClassify({ cwd: gitDir });
178
- assert.equal(result.status, "applied");
179
- if (result.status === "applied") {
180
- assert.deepEqual(result.markerWarning, {
181
- engagementId: "bare-co",
182
- count: 0,
183
- });
184
- }
185
- });
186
- });
187
- describe("firstTouchClassify — needs-confirmation", () => {
188
- it("unknown org → status: needs-confirmation with redactedOrg", () => {
189
- writeRegistry(`schemaVersion: 2\nengagements: []\n`);
190
- setRemote(gitDir, "git@github.com:unknown-org/proj.git");
191
- const result = firstTouchClassify({ cwd: gitDir });
192
- assert.equal(result.status, "needs-confirmation");
193
- if (result.status === "needs-confirmation") {
194
- assert.equal(result.org, "unknown-org");
195
- assert.notEqual(result.redactedOrg, result.org);
196
- assert.match(result.redactedOrg, /^un\*\*\*g$/);
197
- assert.ok("newEngagement" in result.suggestion);
198
- }
199
- });
200
- it("does not mutate per-repo config on needs-confirmation", () => {
201
- writeRegistry(`schemaVersion: 2\nengagements: []\n`);
202
- setRemote(gitDir, "git@github.com:another-unknown/proj.git");
203
- firstTouchClassify({ cwd: gitDir });
204
- // git config --get exits 0 with value, or 1 if unset; we expect 1.
205
- let threw = false;
206
- try {
207
- execFileSync("git", ["config", "--get", "repo-aegis.class"], {
208
- cwd: gitDir,
209
- stdio: ["ignore", "pipe", "ignore"],
210
- });
211
- }
212
- catch {
213
- threw = true;
214
- }
215
- assert.equal(threw, true, "class should not be set");
216
- });
217
- it("[SEC H-5] redactedOrg is the same as org when org < 4 chars", () => {
218
- assert.equal(redactOrg("ab"), "ab");
219
- assert.equal(redactOrg("abc"), "abc");
220
- assert.equal(redactOrg("abcd"), "ab***d");
221
- assert.equal(redactOrg("acme-corp"), "ac***p");
222
- });
223
- });
224
- //# sourceMappingURL=first-touch.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"first-touch.test.js","sourceRoot":"","sources":["../../src/tools/first-touch.test.ts"],"names":[],"mappings":"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"}