agent-dir 1.0.0 → 1.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.
@@ -5,6 +5,7 @@ import { createRequire } from "node:module";
5
5
  import { resolve } from "node:path";
6
6
  import { createInterface } from "node:readline/promises";
7
7
  import { parseArgs } from "node:util";
8
+ import { CodeGraphIntegration } from "../src/codegraph.js";
8
9
  import { configPath, loadConfig, mergeProfile, saveConfig } from "../src/config.js";
9
10
  import { printBanner, printHelp, printRequestHeader } from "../src/logging.js";
10
11
  import { startServer } from "../src/server.js";
@@ -445,6 +446,10 @@ if (allowedCommands)
445
446
  if (commandConfig.blacklistedCommands?.length) {
446
447
  bannerOptions.blacklistedCommands = commandConfig.blacklistedCommands;
447
448
  }
449
+ const codeGraph = new CodeGraphIntegration(directory);
450
+ const codeGraphCapability = await codeGraph.prepare();
451
+ if (codeGraphCapability.tool)
452
+ bannerOptions.codeGraph = true;
448
453
  printBanner(bannerOptions);
449
454
  const telemetrySessionId = randomUUID();
450
455
  const server = await startServer({
@@ -452,12 +457,16 @@ const server = await startServer({
452
457
  port,
453
458
  token,
454
459
  commandConfig,
460
+ codeGraph,
455
461
  telemetry: {
456
462
  ...(config.telemetry ?? { level: "none" }),
457
463
  ...(telemetryConfigId ? { configId: telemetryConfigId } : {}),
458
464
  sessionId: telemetrySessionId,
459
465
  persist: true,
460
466
  },
467
+ }).catch(async (error) => {
468
+ await codeGraph.close();
469
+ throw error;
461
470
  });
462
471
  let tunnelResult;
463
472
  console.log(" ✓ SERVER ONLINE");
@@ -18,6 +18,7 @@ export declare class CodeGraphIntegration {
18
18
  private readonly pending;
19
19
  constructor(root: string);
20
20
  capability(): Promise<CodeGraphCapability>;
21
+ prepare(): Promise<CodeGraphCapability>;
21
22
  explore(query: string, maxFiles?: number): Promise<Record<string, unknown>>;
22
23
  close(): Promise<void>;
23
24
  private detect;
@@ -27,6 +27,18 @@ export class CodeGraphIntegration {
27
27
  this.capabilityPromise = this.detect();
28
28
  return this.capabilityPromise;
29
29
  }
30
+ async prepare() {
31
+ const capability = await this.capability();
32
+ if (capability.status === "available") {
33
+ try {
34
+ await this.ensureStarted();
35
+ }
36
+ catch {
37
+ // Keep Agent Dir startup available even if CodeGraph fails to start.
38
+ }
39
+ }
40
+ return this.capability();
41
+ }
30
42
  async explore(query, maxFiles) {
31
43
  const capability = await this.capability();
32
44
  if (capability.status === "not_installed")
@@ -11,6 +11,7 @@ export declare function printBanner(options: {
11
11
  npmScripts?: string[];
12
12
  commands?: string[];
13
13
  blacklistedCommands?: string[];
14
+ codeGraph?: boolean;
14
15
  }): void;
15
16
  export declare function printRequestLog(entry: RequestLog): void;
16
17
  export declare function logRequest(entry: RequestLog): void;
@@ -149,6 +149,9 @@ export function printBanner(options) {
149
149
  writeLine(` ${color(toolLabel("run_npm_batch"), BRIGHT_BLUE)}`);
150
150
  writeLine(` ${color(toolLabel("run_command_batch"), BRIGHT_CYAN)}`);
151
151
  writeLine(` ${color(toolLabel("file_info"), YELLOW)}`);
152
+ if (options.codeGraph) {
153
+ writeLine(` ${color(toolLabel("codegraph_explore"), BRIGHT_MAGENTA)}`);
154
+ }
152
155
  writeLine("");
153
156
  if (options.npmScripts?.length) {
154
157
  writeLine(" NPM COMMANDS");
package/dist/src/mcp.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { CodeGraphIntegration } from "./codegraph.js";
1
2
  import { TelemetryRecorder } from "./telemetry/recorder.js";
2
3
  import type { TelemetryConfig } from "./telemetry/types.js";
3
4
  import type { CommandConfig } from "./types.js";
@@ -6,6 +7,6 @@ interface McpHandler {
6
7
  closeSubscriptions: () => void;
7
8
  telemetrySnapshot: () => ReturnType<TelemetryRecorder["snapshot"]>;
8
9
  }
9
- export declare function createMcpHandler(root: string, commandConfig?: CommandConfig, telemetry?: TelemetryConfig): McpHandler;
10
+ export declare function createMcpHandler(root: string, commandConfig?: CommandConfig, telemetry?: TelemetryConfig, codeGraphIntegration?: CodeGraphIntegration): McpHandler;
10
11
  export declare function validateMcpParamHeaders(inputSchema: Record<string, unknown>, args: Record<string, unknown>, headers: Headers): string | undefined;
11
12
  export {};
package/dist/src/mcp.js CHANGED
@@ -162,8 +162,8 @@ function tool(name, description, properties, outputSchema, required = []) {
162
162
  outputSchema,
163
163
  };
164
164
  }
165
- export function createMcpHandler(root, commandConfig = {}, telemetry = { level: "none" }) {
166
- const codeGraph = new CodeGraphIntegration(root);
165
+ export function createMcpHandler(root, commandConfig = {}, telemetry = { level: "none" }, codeGraphIntegration) {
166
+ const codeGraph = codeGraphIntegration ?? new CodeGraphIntegration(root);
167
167
  const telemetryRecorder = new TelemetryRecorder({
168
168
  level: telemetry.level,
169
169
  persist: telemetry.persist ?? false,
@@ -2,7 +2,7 @@ import type { ServerOptions } from "./types.js";
2
2
  export interface ServerHandle {
3
3
  close: () => Promise<void>;
4
4
  }
5
- export declare function startServer({ root, port, token, commandConfig, telemetry, }: ServerOptions): Promise<ServerHandle>;
5
+ export declare function startServer({ root, port, token, commandConfig, telemetry, codeGraph, }: ServerOptions): Promise<ServerHandle>;
6
6
  export declare function validateMcpHeaders(request: Request, message: Record<string, unknown> | null): Response | undefined;
7
7
  export declare function getMcpLog(body: Buffer, responseBody?: unknown): {
8
8
  name: string;
@@ -9,8 +9,8 @@ const REQUEST_TIMEOUT_MS = 120_000;
9
9
  const HEADERS_TIMEOUT_MS = 30_000;
10
10
  const KEEP_ALIVE_TIMEOUT_MS = 5_000;
11
11
  const HEALTH_PATH = "/__health";
12
- export function startServer({ root, port, token, commandConfig = {}, telemetry = { level: "none" }, }) {
13
- const mcp = createMcpHandler(root, commandConfig, telemetry);
12
+ export function startServer({ root, port, token, commandConfig = {}, telemetry = { level: "none" }, codeGraph, }) {
13
+ const mcp = createMcpHandler(root, commandConfig, telemetry, codeGraph);
14
14
  const httpTelemetry = new TelemetryRecorder({
15
15
  level: telemetry.level,
16
16
  persist: telemetry.persist ?? false,
@@ -138,10 +138,15 @@ export function startServer({ root, port, token, commandConfig = {}, telemetry =
138
138
  return new Promise((resolve, reject) => {
139
139
  server.once("error", reject);
140
140
  server.listen(port, "127.0.0.1", () => resolve({
141
- close: () => new Promise((done) => {
141
+ close: async () => {
142
142
  mcp.closeSubscriptions();
143
- server.close(() => done());
144
- }),
143
+ try {
144
+ await new Promise((done) => server.close(() => done()));
145
+ }
146
+ finally {
147
+ await codeGraph?.close();
148
+ }
149
+ },
145
150
  }));
146
151
  });
147
152
  }
@@ -41,6 +41,7 @@ export interface ServerOptions {
41
41
  token: string;
42
42
  commandConfig?: CommandConfig;
43
43
  telemetry?: TelemetryConfig;
44
+ codeGraph?: import("./codegraph.js").CodeGraphIntegration;
44
45
  }
45
46
  export interface RequestLog {
46
47
  method: string;
package/docs/RELEASING.md CHANGED
@@ -6,10 +6,7 @@ This document is the authoritative maintainer/agent procedure for publishing `ag
6
6
 
7
7
  feature/*
8
8
  │
9
- ├── PR → staging
10
- │ └── CI
11
- │
12
- └── promotion PR → main
9
+ └── PR → main
13
10
  └── CI
14
11
  │
15
12
  ▼
@@ -28,7 +25,7 @@ This document is the authoritative maintainer/agent procedure for publishing `ag
28
25
  ├── create GitHub Release
29
26
  └── publish npm package
30
27
 
31
- `main` and `staging` are protected. Normal human and agent changes reach them through pull requests.
28
+ `main` is the single protected release branch. Normal human and agent changes reach it through pull requests. There is no permanent `staging` branch.
32
29
 
33
30
  ## Release source of truth
34
31
 
@@ -61,21 +58,15 @@ Do not manually edit the package version.
61
58
 
62
59
  `npm pack --dry-run` is important: inspect the file list and make sure the package does not contain credentials, local configuration, development-only files, or other unintended content.
63
60
 
64
- ### 3. Merge through staging
61
+ ### 3. Open and merge a pull request
65
62
 
66
- Push the feature branch and open a PR targeting `staging`.
63
+ Push the branch and open a PR targeting `main`.
67
64
 
68
65
  The required CI check is `Check`. It runs `npm ci`, `npm run check`, `npm test`, and `npm pack --dry-run`.
69
66
 
70
- Do not bypass a failing check. After checks pass, merge the PR into `staging`.
71
-
72
- ### 4. Promote staging to main
73
-
74
- Create a promotion PR: `staging → main`.
75
-
76
- CI runs again because `main` is also a pull-request target. Merge only after the required `Check` status is green.
67
+ Do not bypass a failing check. Merge only after the required `Check` status is green and the required review is approved.
77
68
 
78
- ### 5. Let GitHub Actions publish
69
+ ### 4. Let GitHub Actions publish
79
70
 
80
71
  The merge to `main` creates a push to `main`, which starts `.github/workflows/publish.yml`.
81
72
 
@@ -179,7 +170,7 @@ If a release was partially created, reconcile the actual Git/npm/GitHub state be
179
170
 
180
171
  ## CI workflow constraints
181
172
 
182
- `.github/workflows/ci.yml` runs for pull requests targeting `staging` and `main`.
173
+ `.github/workflows/ci.yml` runs on pushes to `main` and pull requests targeting `main`.
183
174
 
184
175
  Its concurrency key must remain safe for both PR events and any diagnostic/manual event that may temporarily be introduced:
185
176
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-dir",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "Expose a local project to an AI agent through authenticated MCP, filesystem tools, and allowlisted development commands",
5
5
  "repository": {
6
6
  "type": "git",