@de-otio/repo-aegis-mcp 0.2.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 (46) hide show
  1. package/README.md +96 -0
  2. package/dist/index.d.ts +3 -0
  3. package/dist/index.d.ts.map +1 -0
  4. package/dist/index.js +15 -0
  5. package/dist/index.js.map +1 -0
  6. package/dist/server.d.ts +16 -0
  7. package/dist/server.d.ts.map +1 -0
  8. package/dist/server.js +42 -0
  9. package/dist/server.js.map +1 -0
  10. package/dist/server.test.d.ts +2 -0
  11. package/dist/server.test.d.ts.map +1 -0
  12. package/dist/server.test.js +171 -0
  13. package/dist/server.test.js.map +1 -0
  14. package/dist/tools/_util.d.ts +26 -0
  15. package/dist/tools/_util.d.ts.map +1 -0
  16. package/dist/tools/_util.js +33 -0
  17. package/dist/tools/_util.js.map +1 -0
  18. package/dist/tools/audit.d.ts +20 -0
  19. package/dist/tools/audit.d.ts.map +1 -0
  20. package/dist/tools/audit.js +317 -0
  21. package/dist/tools/audit.js.map +1 -0
  22. package/dist/tools/check.d.ts +3 -0
  23. package/dist/tools/check.d.ts.map +1 -0
  24. package/dist/tools/check.js +133 -0
  25. package/dist/tools/check.js.map +1 -0
  26. package/dist/tools/engagements.d.ts +3 -0
  27. package/dist/tools/engagements.d.ts.map +1 -0
  28. package/dist/tools/engagements.js +89 -0
  29. package/dist/tools/engagements.js.map +1 -0
  30. package/dist/tools/first-touch.d.ts +26 -0
  31. package/dist/tools/first-touch.d.ts.map +1 -0
  32. package/dist/tools/first-touch.js +49 -0
  33. package/dist/tools/first-touch.js.map +1 -0
  34. package/dist/tools/first-touch.test.d.ts +2 -0
  35. package/dist/tools/first-touch.test.d.ts.map +1 -0
  36. package/dist/tools/first-touch.test.js +224 -0
  37. package/dist/tools/first-touch.test.js.map +1 -0
  38. package/dist/tools/markers.d.ts +3 -0
  39. package/dist/tools/markers.d.ts.map +1 -0
  40. package/dist/tools/markers.js +121 -0
  41. package/dist/tools/markers.js.map +1 -0
  42. package/dist/tools/status.d.ts +11 -0
  43. package/dist/tools/status.d.ts.map +1 -0
  44. package/dist/tools/status.js +68 -0
  45. package/dist/tools/status.js.map +1 -0
  46. package/package.json +35 -0
@@ -0,0 +1,317 @@
1
+ // SPDX-License-Identifier: GPL-3.0-or-later
2
+ // Copyright (C) 2026 Richard Myers and contributors.
3
+ import { execFileSync } from "node:child_process";
4
+ import { existsSync, readdirSync, readFileSync, statSync } from "node:fs";
5
+ import { join, relative } from "node:path";
6
+ import { z } from "zod";
7
+ import { computeDenySet, readRepoConfig, scanFile, } from "@de-otio/repo-aegis-core";
8
+ import { jsonResult } from "./_util.js";
9
+ /**
10
+ * Hard-coded redaction policy: see check.ts. Audit findings include the
11
+ * `matchPreview` field from scanFile, which is already redacted when
12
+ * `revealMatches` is false. Setting it explicitly here keeps the policy
13
+ * auditable from this file alone.
14
+ */
15
+ const SCAN_OPTS = { revealMatches: false };
16
+ function gitCmd(cwd, args) {
17
+ try {
18
+ const stdout = execFileSync("git", args, {
19
+ cwd,
20
+ encoding: "utf8",
21
+ stdio: ["ignore", "pipe", "ignore"],
22
+ });
23
+ return { ok: true, stdout: stdout.trim() };
24
+ }
25
+ catch {
26
+ return { ok: false, stdout: "" };
27
+ }
28
+ }
29
+ function listTrackedFiles(cwd) {
30
+ const r = gitCmd(cwd, ["ls-files"]);
31
+ if (!r.ok)
32
+ return [];
33
+ return r.stdout.split("\n").filter(Boolean);
34
+ }
35
+ function checkMarkerScan(cwd, repo, denySet) {
36
+ if (!repo.isGitRepo) {
37
+ return {
38
+ name: "marker-scan",
39
+ ok: true,
40
+ findings: [],
41
+ skipped: true,
42
+ skipReason: "not a git repo",
43
+ };
44
+ }
45
+ if (denySet.combinedRegex === "") {
46
+ return {
47
+ name: "marker-scan",
48
+ ok: true,
49
+ findings: [],
50
+ skipped: true,
51
+ skipReason: "empty deny set",
52
+ };
53
+ }
54
+ const findings = [];
55
+ for (const f of listTrackedFiles(cwd)) {
56
+ const abs = join(cwd, f);
57
+ if (!existsSync(abs))
58
+ continue;
59
+ const r = scanFile(abs, denySet, SCAN_OPTS, cwd);
60
+ for (const h of r.hits) {
61
+ findings.push({
62
+ message: `${f}:${h.line}:${h.column}`,
63
+ detail: { path: f, line: h.line, column: h.column, matchPreview: h.matchPreview },
64
+ });
65
+ }
66
+ }
67
+ return { name: "marker-scan", ok: findings.length === 0, findings };
68
+ }
69
+ function checkLockfile(cwd) {
70
+ const lockPath = join(cwd, "package-lock.json");
71
+ if (!existsSync(lockPath)) {
72
+ return {
73
+ name: "lockfile",
74
+ ok: true,
75
+ findings: [],
76
+ skipped: true,
77
+ skipReason: "no package-lock.json",
78
+ };
79
+ }
80
+ let parsed;
81
+ try {
82
+ parsed = JSON.parse(readFileSync(lockPath, "utf8"));
83
+ }
84
+ catch {
85
+ return {
86
+ name: "lockfile",
87
+ ok: false,
88
+ findings: [{ message: "package-lock.json is not valid JSON" }],
89
+ };
90
+ }
91
+ const findings = [];
92
+ const root = parsed;
93
+ if (root.packages) {
94
+ for (const [pkgPath, info] of Object.entries(root.packages)) {
95
+ const resolved = info?.resolved;
96
+ if (!resolved)
97
+ continue;
98
+ try {
99
+ const u = new URL(resolved);
100
+ if (u.host !== "registry.npmjs.org" &&
101
+ u.host !== "registry.yarnpkg.com" &&
102
+ !u.host.endsWith(".github.com") &&
103
+ u.host !== "codeload.github.com") {
104
+ findings.push({
105
+ message: `${pkgPath || "(root)"} resolved from non-public registry: ${u.host}`,
106
+ detail: { pkg: pkgPath, host: u.host, resolved },
107
+ });
108
+ }
109
+ }
110
+ catch {
111
+ /* skip non-URL entries */
112
+ }
113
+ }
114
+ }
115
+ return { name: "lockfile", ok: findings.length === 0, findings };
116
+ }
117
+ const FIXTURE_DIR_NAMES = new Set([
118
+ "__fixtures__",
119
+ "fixtures",
120
+ "fixture",
121
+ "test-fixtures",
122
+ "testdata",
123
+ ]);
124
+ function findFixtureDirs(cwd) {
125
+ const out = [];
126
+ function recurse(dir, depth) {
127
+ if (depth > 4)
128
+ return;
129
+ let entries;
130
+ try {
131
+ entries = readdirSync(dir);
132
+ }
133
+ catch {
134
+ return;
135
+ }
136
+ for (const name of entries) {
137
+ if (name === ".git" || name === "node_modules")
138
+ continue;
139
+ const full = join(dir, name);
140
+ let st;
141
+ try {
142
+ st = statSync(full);
143
+ }
144
+ catch {
145
+ continue;
146
+ }
147
+ if (!st.isDirectory())
148
+ continue;
149
+ if (FIXTURE_DIR_NAMES.has(name)) {
150
+ out.push(full);
151
+ }
152
+ else {
153
+ recurse(full, depth + 1);
154
+ }
155
+ }
156
+ }
157
+ recurse(cwd, 0);
158
+ return out;
159
+ }
160
+ function checkFixtures(cwd, repo, denySet) {
161
+ if (denySet.combinedRegex === "") {
162
+ return {
163
+ name: "fixtures",
164
+ ok: true,
165
+ findings: [],
166
+ skipped: true,
167
+ skipReason: "empty deny set",
168
+ };
169
+ }
170
+ const dirs = findFixtureDirs(cwd);
171
+ if (dirs.length === 0) {
172
+ return {
173
+ name: "fixtures",
174
+ ok: true,
175
+ findings: [],
176
+ skipped: true,
177
+ skipReason: "no fixture directories found",
178
+ };
179
+ }
180
+ const findings = [];
181
+ function recurse(dir) {
182
+ let entries;
183
+ try {
184
+ entries = readdirSync(dir);
185
+ }
186
+ catch {
187
+ return;
188
+ }
189
+ for (const name of entries) {
190
+ const full = join(dir, name);
191
+ let st;
192
+ try {
193
+ st = statSync(full);
194
+ }
195
+ catch {
196
+ continue;
197
+ }
198
+ if (st.isDirectory()) {
199
+ recurse(full);
200
+ continue;
201
+ }
202
+ if (!st.isFile())
203
+ continue;
204
+ const r = scanFile(full, denySet, SCAN_OPTS, repo.isGitRepo ? cwd : undefined);
205
+ for (const h of r.hits) {
206
+ const rel = relative(cwd, full);
207
+ findings.push({
208
+ message: `${rel}:${h.line}:${h.column}`,
209
+ detail: { path: rel, line: h.line, column: h.column, matchPreview: h.matchPreview },
210
+ });
211
+ }
212
+ }
213
+ }
214
+ for (const d of dirs)
215
+ recurse(d);
216
+ return { name: "fixtures", ok: findings.length === 0, findings };
217
+ }
218
+ function checkRemote(cwd, repo) {
219
+ if (!repo.isGitRepo) {
220
+ return {
221
+ name: "remote",
222
+ ok: true,
223
+ findings: [],
224
+ skipped: true,
225
+ skipReason: "not a git repo",
226
+ };
227
+ }
228
+ const r = gitCmd(cwd, ["remote", "get-url", "origin"]);
229
+ const remote = r.ok ? r.stdout : "";
230
+ const findings = [];
231
+ if (repo.class === "scratch") {
232
+ if (remote !== "") {
233
+ findings.push({
234
+ message: `class=scratch but origin remote is set: ${remote}`,
235
+ detail: { remote },
236
+ });
237
+ }
238
+ return { name: "remote", ok: findings.length === 0, findings };
239
+ }
240
+ if (repo.class === "customer-coupled") {
241
+ if (remote === "") {
242
+ findings.push({ message: "class=customer-coupled but no origin remote is set" });
243
+ return { name: "remote", ok: false, findings };
244
+ }
245
+ const lower = remote.toLowerCase();
246
+ const anyEngagementInRemote = repo.engagements.some(e => lower.includes(e.toLowerCase()));
247
+ if (!anyEngagementInRemote) {
248
+ findings.push({
249
+ message: "class=customer-coupled but no engagement id appears in the remote URL",
250
+ detail: { remote, engagements: repo.engagements },
251
+ });
252
+ }
253
+ return { name: "remote", ok: findings.length === 0, findings };
254
+ }
255
+ return { name: "remote", ok: true, findings: [] };
256
+ }
257
+ const auditInput = {
258
+ cwd: z
259
+ .string()
260
+ .optional()
261
+ .describe("Working directory to audit (defaults to server cwd)."),
262
+ };
263
+ /**
264
+ * `repo_aegis_audit` — composite repo health check.
265
+ *
266
+ * Runs the same default checks as `repo-aegis audit --json` minus the
267
+ * network-dependent / archive-extracting flags (`--org`, `--published`,
268
+ * `--history`). Those are intentionally omitted from the MCP surface:
269
+ *
270
+ * - `--org` is a cross-border data transfer and requires explicit
271
+ * human consent (`--accept-cross-border` or the matching env var).
272
+ * The agent must never opt the user in to that.
273
+ * - `--published` extracts archives to a temp dir; that's a CLI
274
+ * workflow, not an interactive-agent one.
275
+ * - `--history` is slow (full git-log sweep per pattern). If the user
276
+ * wants it, they run the CLI directly.
277
+ *
278
+ * Hits are returned with `matchPreview` already redacted by core.
279
+ */
280
+ export function registerAuditTool(server) {
281
+ server.registerTool("repo_aegis_audit", {
282
+ description: "Composite repo health check: marker scan over tracked files, " +
283
+ "package-lock.json non-public-registry check, fixture-directory scan, " +
284
+ "remote-vs-class consistency. Equivalent to `repo-aegis audit --json` " +
285
+ "with default flags. Network sweeps (--org), archive scans " +
286
+ "(--published), and full-history sweeps (--history) are deliberately " +
287
+ "NOT exposed here — those require explicit human consent or run " +
288
+ "long; use the CLI for them.",
289
+ inputSchema: auditInput,
290
+ }, async ({ cwd }) => {
291
+ const wd = cwd ?? process.cwd();
292
+ const repo = readRepoConfig(wd);
293
+ const denySet = computeDenySet(repo);
294
+ const results = [
295
+ checkMarkerScan(wd, repo, denySet),
296
+ checkLockfile(wd),
297
+ checkFixtures(wd, repo, denySet),
298
+ checkRemote(wd, repo),
299
+ ];
300
+ const failed = results.filter(c => !c.ok);
301
+ const totalFindings = results.reduce((sum, c) => sum + c.findings.length, 0);
302
+ return jsonResult({
303
+ action: "audit",
304
+ cwd: wd,
305
+ class: repo.class,
306
+ engagements: repo.engagements,
307
+ checks: results,
308
+ summary: {
309
+ run: results.length,
310
+ failed: failed.length,
311
+ totalFindings,
312
+ },
313
+ warnings: denySet.warnings,
314
+ });
315
+ });
316
+ }
317
+ //# sourceMappingURL=audit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit.js","sourceRoot":"","sources":["../../src/tools/audit.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function registerCheckTools(server: McpServer): void;
3
+ //# sourceMappingURL=check.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../../src/tools/check.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAmDzE,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAyG1D"}
@@ -0,0 +1,133 @@
1
+ // SPDX-License-Identifier: GPL-3.0-or-later
2
+ // Copyright (C) 2026 Richard Myers and contributors.
3
+ import { z } from "zod";
4
+ import { computeDenySet, CustomerCoupledNoEngagementError, readRepoConfig, scanFile, scanStagedDiff, } from "@de-otio/repo-aegis-core";
5
+ import { errorResult, jsonResult } from "./_util.js";
6
+ /**
7
+ * Hard-coded redaction policy: literal markers MUST NOT cross the MCP
8
+ * boundary. The `--verbose` / `revealMatches` path is for a human at a
9
+ * terminal only. Setting this explicitly (rather than relying on the
10
+ * core default) keeps the policy auditable from this file alone.
11
+ */
12
+ const SCAN_OPTS = { revealMatches: false };
13
+ function repoJson(repo) {
14
+ return {
15
+ cwd: repo.cwd,
16
+ isGitRepo: repo.isGitRepo,
17
+ class: repo.class,
18
+ classExplicit: repo.classExplicit,
19
+ engagements: repo.engagements,
20
+ };
21
+ }
22
+ const checkPathInput = {
23
+ path: z
24
+ .string()
25
+ .describe("Path to scan. Resolved (symlinks followed) and rejected if it escapes the repo working tree."),
26
+ cwd: z
27
+ .string()
28
+ .optional()
29
+ .describe("Working directory for repo class/engagement lookup (defaults to server cwd)."),
30
+ };
31
+ const checkStagedInput = {
32
+ cwd: z
33
+ .string()
34
+ .optional()
35
+ .describe("Working directory inside the git repo whose staged diff to scan."),
36
+ };
37
+ export function registerCheckTools(server) {
38
+ server.registerTool("repo_aegis_check_path", {
39
+ description: "Scan a single file against this repo's scoped deny set. " +
40
+ "Equivalent to `repo-aegis check --path <file> --json`. Returns hits " +
41
+ "with line/column and engagement attribution; literal matches are " +
42
+ "redacted (matchPreview), and the agent must NEVER paste them back to " +
43
+ "the user verbatim — refer to the leak abstractly.",
44
+ inputSchema: checkPathInput,
45
+ }, async ({ path, cwd }) => {
46
+ const repo = readRepoConfig(cwd ?? process.cwd());
47
+ if (repo.isGitRepo && repo.class === "customer-coupled" && repo.engagements.length === 0) {
48
+ const err = new CustomerCoupledNoEngagementError();
49
+ return errorResult({ code: err.code, error: err.message });
50
+ }
51
+ const denySet = computeDenySet(repo);
52
+ if (denySet.combinedRegex === "") {
53
+ return jsonResult({
54
+ mode: "path",
55
+ hits: [],
56
+ historyHits: [],
57
+ skipped: [],
58
+ repo: repoJson(repo),
59
+ denySet: { files: denySet.files.map(f => f.stem), patternCount: 0 },
60
+ advisory: repo.class === "scratch",
61
+ warnings: denySet.warnings,
62
+ status: "no-deny-set",
63
+ });
64
+ }
65
+ let hits = [];
66
+ let skipped = [];
67
+ try {
68
+ const r = scanFile(path, denySet, SCAN_OPTS, repo.isGitRepo ? repo.cwd : undefined);
69
+ hits = r.hits;
70
+ skipped = r.skipped;
71
+ }
72
+ catch (err) {
73
+ return errorResult({ error: err.message });
74
+ }
75
+ const result = {
76
+ mode: "path",
77
+ hits,
78
+ historyHits: [],
79
+ skipped,
80
+ repo: repoJson(repo),
81
+ denySet: { files: denySet.files.map(f => f.stem), patternCount: denySet.patterns.length },
82
+ advisory: repo.class === "scratch",
83
+ warnings: denySet.warnings,
84
+ };
85
+ return jsonResult(result);
86
+ });
87
+ server.registerTool("repo_aegis_check_staged", {
88
+ description: "Scan the staged diff (added lines only) against this repo's scoped " +
89
+ "deny set. Equivalent to `repo-aegis check --staged --json`. Use this " +
90
+ "as a pre-commit gate. Returns the same shape as check_path; redaction " +
91
+ "applies.",
92
+ inputSchema: checkStagedInput,
93
+ }, async ({ cwd }) => {
94
+ const repo = readRepoConfig(cwd ?? process.cwd());
95
+ if (!repo.isGitRepo) {
96
+ return errorResult({
97
+ code: "NOT_GIT_REPO",
98
+ error: "not a git repo; --staged requires a git repo",
99
+ });
100
+ }
101
+ if (repo.class === "customer-coupled" && repo.engagements.length === 0) {
102
+ const err = new CustomerCoupledNoEngagementError();
103
+ return errorResult({ code: err.code, error: err.message });
104
+ }
105
+ const denySet = computeDenySet(repo);
106
+ if (denySet.combinedRegex === "") {
107
+ return jsonResult({
108
+ mode: "staged",
109
+ hits: [],
110
+ historyHits: [],
111
+ skipped: [],
112
+ repo: repoJson(repo),
113
+ denySet: { files: denySet.files.map(f => f.stem), patternCount: 0 },
114
+ advisory: repo.class === "scratch",
115
+ warnings: denySet.warnings,
116
+ status: "no-deny-set",
117
+ });
118
+ }
119
+ const r = scanStagedDiff(repo, denySet, SCAN_OPTS);
120
+ const result = {
121
+ mode: "staged",
122
+ hits: r.hits,
123
+ historyHits: [],
124
+ skipped: r.skipped,
125
+ repo: repoJson(repo),
126
+ denySet: { files: denySet.files.map(f => f.stem), patternCount: denySet.patterns.length },
127
+ advisory: repo.class === "scratch",
128
+ warnings: denySet.warnings,
129
+ };
130
+ return jsonResult(result);
131
+ });
132
+ }
133
+ //# sourceMappingURL=check.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check.js","sourceRoot":"","sources":["../../src/tools/check.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function registerEngagementsTools(server: McpServer): void;
3
+ //# sourceMappingURL=engagements.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"engagements.d.ts","sourceRoot":"","sources":["../../src/tools/engagements.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAgBzE,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAkFhE"}
@@ -0,0 +1,89 @@
1
+ // SPDX-License-Identifier: GPL-3.0-or-later
2
+ // Copyright (C) 2026 Richard Myers and contributors.
3
+ import { z } from "zod";
4
+ import { isActive, loadRegistry, RegistryNotFoundError, } from "@de-otio/repo-aegis-core";
5
+ import { errorResult, jsonResult } from "./_util.js";
6
+ const listInput = {
7
+ includeEnded: z
8
+ .boolean()
9
+ .optional()
10
+ .describe("If true, include engagements past the 12-month retention window (equivalent to `--all`). Default: false."),
11
+ };
12
+ const showInput = {
13
+ id: z.string().min(1).describe("Engagement id (exact, not fuzzy)."),
14
+ };
15
+ export function registerEngagementsTools(server) {
16
+ server.registerTool("repo_aegis_engagements_list", {
17
+ description: "List engagements in the registry. Equivalent to " +
18
+ "`repo-aegis engagements list --json`. Returns id, name, started, " +
19
+ "ended, active, markerCount per engagement (markers themselves are " +
20
+ "NOT exposed). Use `includeEnded` to see retained ended engagements.",
21
+ inputSchema: listInput,
22
+ }, async ({ includeEnded }) => {
23
+ let reg;
24
+ try {
25
+ reg = loadRegistry();
26
+ }
27
+ catch (err) {
28
+ if (err instanceof RegistryNotFoundError) {
29
+ return errorResult({
30
+ code: "REGISTRY_NOT_FOUND",
31
+ error: "engagement registry not found; run `repo-aegis init` first",
32
+ details: err.path,
33
+ });
34
+ }
35
+ return errorResult({ error: err.message });
36
+ }
37
+ const filtered = includeEnded ? reg.engagements : reg.engagements.filter(isActive);
38
+ return jsonResult({
39
+ engagements: filtered.map(e => ({
40
+ id: e.id,
41
+ name: e.name,
42
+ started: e.started ?? null,
43
+ ended: e.ended ?? null,
44
+ active: isActive(e),
45
+ markerCount: e.markers.length,
46
+ })),
47
+ alwaysBlock: { patternCount: reg.alwaysBlock.length },
48
+ });
49
+ });
50
+ server.registerTool("repo_aegis_engagements_show", {
51
+ description: "Show one engagement's metadata (no markers). Equivalent to " +
52
+ "`repo-aegis engagements show <id> --json`. Returns id, name, started, " +
53
+ "ended, active, markerCount, notes.",
54
+ inputSchema: showInput,
55
+ }, async ({ id }) => {
56
+ let reg;
57
+ try {
58
+ reg = loadRegistry();
59
+ }
60
+ catch (err) {
61
+ if (err instanceof RegistryNotFoundError) {
62
+ return errorResult({
63
+ code: "REGISTRY_NOT_FOUND",
64
+ error: "engagement registry not found; run `repo-aegis init` first",
65
+ details: err.path,
66
+ });
67
+ }
68
+ return errorResult({ error: err.message });
69
+ }
70
+ const e = reg.engagements.find(x => x.id === id);
71
+ if (!e) {
72
+ return errorResult({
73
+ code: "ENGAGEMENT_NOT_FOUND",
74
+ error: `engagement "${id}" not found`,
75
+ });
76
+ }
77
+ return jsonResult({
78
+ action: "engagements-show",
79
+ id: e.id,
80
+ name: e.name,
81
+ started: e.started ?? null,
82
+ ended: e.ended ?? null,
83
+ active: isActive(e),
84
+ markerCount: e.markers.length,
85
+ notes: e.notes ?? null,
86
+ });
87
+ });
88
+ }
89
+ //# sourceMappingURL=engagements.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"engagements.js","sourceRoot":"","sources":["../../src/tools/engagements.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export { firstTouchClassify, redactOrg, } from "@de-otio/repo-aegis-core";
3
+ export type { FirstTouchResult, FirstTouchOptions, FirstTouchSkipReason, } from "@de-otio/repo-aegis-core";
4
+ /**
5
+ * `aegis_classify_first_touch` — agent-facing entry point for Phase 1
6
+ * of the zero-config onboarding flow. Called once per session at
7
+ * SessionStart. Returns one of four statuses; the agent reacts:
8
+ *
9
+ * - `already-classified`: nothing to do; proceed.
10
+ * - `applied`: per-repo config was just set; proceed. If
11
+ * `markerWarning` is non-null, prompt the user to populate
12
+ * markers via `suggest-markers`.
13
+ * - `needs-confirmation`: surface `redactedOrg` to the user with a
14
+ * confirmation prompt. On user-confirm, call
15
+ * `repo_aegis_engagements_add` (with the full `org` from the
16
+ * response) to register the engagement, then call this tool
17
+ * again to apply the classification.
18
+ * - `skipped`: nothing applicable; proceed.
19
+ *
20
+ * Important: this tool **does not mutate the registry**. The
21
+ * `applied` path mutates per-repo `git config` only. Registry edits
22
+ * always require explicit user confirmation via a follow-up
23
+ * `repo_aegis_engagements_add` call.
24
+ */
25
+ export declare function registerFirstTouchTool(server: McpServer): void;
26
+ //# sourceMappingURL=first-touch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"first-touch.d.ts","sourceRoot":"","sources":["../../src/tools/first-touch.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAIzE,OAAO,EACL,kBAAkB,EAClB,SAAS,GACV,MAAM,0BAA0B,CAAC;AAClC,YAAY,EACV,gBAAgB,EAChB,iBAAiB,EACjB,oBAAoB,GACrB,MAAM,0BAA0B,CAAC;AAWlC;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAkB9D"}
@@ -0,0 +1,49 @@
1
+ // SPDX-License-Identifier: GPL-3.0-or-later
2
+ // Copyright (C) 2026 Richard Myers and contributors.
3
+ import { z } from "zod";
4
+ import { firstTouchClassify } from "@de-otio/repo-aegis-core";
5
+ import { jsonResult } from "./_util.js";
6
+ // Re-export for tests that import from this module path.
7
+ export { firstTouchClassify, redactOrg, } from "@de-otio/repo-aegis-core";
8
+ const inputSchema = {
9
+ cwd: z
10
+ .string()
11
+ .optional()
12
+ .describe("Working directory to inspect (defaults to the server process's cwd). Should be the agent's session cwd."),
13
+ };
14
+ /**
15
+ * `aegis_classify_first_touch` — agent-facing entry point for Phase 1
16
+ * of the zero-config onboarding flow. Called once per session at
17
+ * SessionStart. Returns one of four statuses; the agent reacts:
18
+ *
19
+ * - `already-classified`: nothing to do; proceed.
20
+ * - `applied`: per-repo config was just set; proceed. If
21
+ * `markerWarning` is non-null, prompt the user to populate
22
+ * markers via `suggest-markers`.
23
+ * - `needs-confirmation`: surface `redactedOrg` to the user with a
24
+ * confirmation prompt. On user-confirm, call
25
+ * `repo_aegis_engagements_add` (with the full `org` from the
26
+ * response) to register the engagement, then call this tool
27
+ * again to apply the classification.
28
+ * - `skipped`: nothing applicable; proceed.
29
+ *
30
+ * Important: this tool **does not mutate the registry**. The
31
+ * `applied` path mutates per-repo `git config` only. Registry edits
32
+ * always require explicit user confirmation via a follow-up
33
+ * `repo_aegis_engagements_add` call.
34
+ */
35
+ export function registerFirstTouchTool(server) {
36
+ server.registerTool("aegis_classify_first_touch", {
37
+ description: "Classify the current repo on first touch (Phase 1 onboarding). " +
38
+ "Returns one of: already-classified, applied, needs-confirmation, " +
39
+ "skipped. Never mutates the registry — only per-repo git config. " +
40
+ "On `needs-confirmation`, the agent must use `redactedOrg` in any " +
41
+ "context-bearing summary; the full `org` is for the user's " +
42
+ "confirmation prompt only.",
43
+ inputSchema,
44
+ }, async ({ cwd }) => {
45
+ const result = firstTouchClassify({ ...(cwd !== undefined && { cwd }) });
46
+ return jsonResult(result);
47
+ });
48
+ }
49
+ //# sourceMappingURL=first-touch.js.map