agent-dir 1.0.0 → 1.1.1

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,18 +457,26 @@ 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
- console.log(" ✓ SERVER ONLINE");
464
- console.log(` Local target : http://127.0.0.1:${port}`);
465
- console.log(" Auth : Bearer token");
466
- console.log(" Token : <configured>");
472
+ console.log(` ${"╭─ SERVER ONLINE ".padEnd(76, "─")}╮`
473
+ .replace("╭", "\x1b[92m╭")
474
+ .replace(/─/g, "─\x1b[92m")
475
+ .replace("╮", "╮\x1b[0m"));
476
+ console.log(` \x1b[92m│\x1b[0m ${"Local target".padEnd(14)}: http://127.0.0.1:${port}`);
477
+ console.log(` \x1b[92m│\x1b[0m ${"Auth".padEnd(14)}: Bearer token`);
478
+ console.log(` \x1b[92m│\x1b[0m ${"Token".padEnd(14)}: <configured>`);
479
+ console.log(` \x1b[92m╰${"─".repeat(74)}╯\x1b[0m`);
467
480
  if (tunnel !== "none") {
468
481
  try {
469
482
  tunnelResult = await startTunnel({
@@ -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;
@@ -4,11 +4,11 @@ const MAGENTA = "\x1b[35m";
4
4
  const YELLOW = "\x1b[33m";
5
5
  const RED = "\x1b[31m";
6
6
  const GREEN = "\x1b[32m";
7
- const BLUE = "\x1b[34m";
8
7
  const BRIGHT_BLUE = "\x1b[94m";
9
8
  const BRIGHT_CYAN = "\x1b[96m";
10
9
  const BRIGHT_MAGENTA = "\x1b[95m";
11
10
  const BRIGHT_YELLOW = "\x1b[93m";
11
+ const BRIGHT_GREEN = "\x1b[92m";
12
12
  const writeLine = (line = "") => {
13
13
  process.stdout.write(`${line}\r\n`);
14
14
  };
@@ -56,6 +56,67 @@ const TOOL_COLORS = {
56
56
  };
57
57
  const NARROW_TOOL_ICONS = new Set(["✎", "✖", "⚙", "⌘", "↪", "↗"]);
58
58
  const TOOL_ICON_SLOT_WIDTH = 3;
59
+ const DIM = "\x1b[90m";
60
+ function visibleLength(value) {
61
+ const esc = String.fromCharCode(27);
62
+ const plain = value
63
+ .replaceAll(`${esc}[90m`, "")
64
+ .replaceAll(`${esc}[0m`, "")
65
+ .replaceAll(`${esc}[92m`, "")
66
+ .replaceAll(`${esc}[96m`, "")
67
+ .replaceAll(`${esc}[95m`, "")
68
+ .replaceAll(`${esc}[94m`, "")
69
+ .replaceAll(`${esc}[93m`, "")
70
+ .replaceAll(`${esc}[32m`, "")
71
+ .replaceAll(`${esc}[36m`, "")
72
+ .replaceAll(`${esc}[35m`, "")
73
+ .replaceAll(`${esc}[34m`, "")
74
+ .replaceAll(`${esc}[33m`, "");
75
+ let width = 0;
76
+ for (const character of plain) {
77
+ const code = character.codePointAt(0) ?? 0;
78
+ width +=
79
+ code >= 0x1100 &&
80
+ (code <= 0x115f ||
81
+ code === 0x2329 ||
82
+ code === 0x232a ||
83
+ (code >= 0x2e80 && code <= 0xa4cf) ||
84
+ (code >= 0xac00 && code <= 0xd7a3) ||
85
+ (code >= 0xf900 && code <= 0xfaff) ||
86
+ (code >= 0xfe10 && code <= 0xfe19) ||
87
+ (code >= 0xfe30 && code <= 0xfe6f) ||
88
+ (code >= 0xff00 && code <= 0xff60) ||
89
+ (code >= 0xffe0 && code <= 0xffe6) ||
90
+ (code >= 0x1f300 && code <= 0x1faff))
91
+ ? 2
92
+ : 1;
93
+ }
94
+ return width;
95
+ }
96
+ const BOX_WIDTH = 76;
97
+ function boxTop(label, borderColor, width = BOX_WIDTH) {
98
+ const heading = `─ ${label} `;
99
+ return ` ${color(`╭${heading}${"─".repeat(Math.max(1, width - visibleLength(heading) - 2))}╮`, borderColor)}`;
100
+ }
101
+ function boxContent(content, borderColor, width = BOX_WIDTH) {
102
+ const padding = Math.max(0, width - visibleLength(content) - 3);
103
+ return ` ${color("│", borderColor)} ${content}${" ".repeat(padding)}${color("│", borderColor)}`;
104
+ }
105
+ function boxBottom(borderColor, width = BOX_WIDTH) {
106
+ return ` ${color(`╰${"─".repeat(width - 2)}╯`, borderColor)}`;
107
+ }
108
+ function printGrid(items, columns = 2) {
109
+ const width = Math.max(40, Math.min(100, (process.stdout.columns || 100) - 4));
110
+ const columnWidth = Math.floor(width / columns);
111
+ for (let index = 0; index < items.length; index += columns) {
112
+ const row = items.slice(index, index + columns);
113
+ writeLine(` ${row
114
+ .map((item) => item +
115
+ " ".repeat(Math.max(1, columnWidth -
116
+ item.replace(new RegExp(`${String.fromCharCode(27)}\\[[0-9;]*m`, "g"), "").length)))
117
+ .join("")}`);
118
+ }
119
+ }
59
120
  function toolIcon(name) {
60
121
  return TOOL_ICONS[name] ?? MCP_METHOD_ICONS[name] ?? "•";
61
122
  }
@@ -112,54 +173,51 @@ export function printHelp() {
112
173
  }
113
174
  export function printBanner(options) {
114
175
  writeLine("");
115
- const banner = [
116
- "╭──────────────────────────────────────────────────────────────╮",
117
- "│ AGENT-DIR │",
118
- "╰──────────────────────────────────────────────────────────────╯",
119
- ];
120
- const gradient = [BRIGHT_CYAN, BRIGHT_BLUE, BRIGHT_MAGENTA];
121
- for (let i = 0; i < banner.length; i++) {
122
- writeLine(color(banner[i] ?? "", gradient[i] ?? BRIGHT_CYAN));
123
- }
124
- writeLine("");
125
- writeLine(` Directory ${options.root}`);
126
- writeLine(` Port ${options.port}`);
127
- writeLine(` Config ${options.profileName ?? "CLI options"}`);
128
- writeLine(` Tunnel ${options.tunnel}`);
129
- if (options.blacklistedCommands?.length) {
130
- writeLine(` Blocked ${options.blacklistedCommands.join(", ")}`);
131
- }
176
+ writeLine(color(" ╭──────────────────────────────────────────────────────────────────────────────╮", BRIGHT_CYAN));
177
+ writeLine(`${color(" │", BRIGHT_CYAN)} ${color("AGENT", BRIGHT_CYAN)}${color("·", BRIGHT_MAGENTA)}${color("DIR", BRIGHT_BLUE)} ${color("LOCAL PROJECT BRIDGE", BRIGHT_MAGENTA)}`);
178
+ writeLine(color(" ╰──────────────────────────────────────────────────────────────────────────────╯", BRIGHT_CYAN));
179
+ writeLine(` ${color("● SESSION", BRIGHT_GREEN)} ${color(options.profileName ?? "CLI options", BRIGHT_CYAN)} ${color("│", DIM)} ${color(options.tunnel.toUpperCase(), BRIGHT_MAGENTA)} ${color("│", DIM)} ${color(`PORT ${options.port}`, BRIGHT_BLUE)}`);
180
+ writeLine(boxTop("PROJECT", BRIGHT_CYAN));
181
+ writeLine(boxContent(`${color("DIR", DIM)} ${options.root}`, BRIGHT_CYAN));
132
182
  if (options.subdomain)
133
- writeLine(` Domain https://${options.subdomain}.wormhole.bar`);
183
+ writeLine(boxContent(`${color("DOMAIN", DIM)} ${color(`https://${options.subdomain}.wormhole.bar`, BRIGHT_GREEN)}`, BRIGHT_CYAN));
134
184
  if (options.hostname)
135
- writeLine(` Domain https://${options.hostname}`);
185
+ writeLine(boxContent(`${color("DOMAIN", DIM)} ${color(`https://${options.hostname}`, BRIGHT_GREEN)}`, BRIGHT_CYAN));
186
+ if (options.blacklistedCommands?.length)
187
+ writeLine(boxContent(`${color("BLOCKED", BRIGHT_YELLOW)} ${options.blacklistedCommands.join(", ")}`, BRIGHT_CYAN));
188
+ writeLine(boxBottom(BRIGHT_CYAN));
136
189
  writeLine("");
137
- writeLine(" MCP");
138
- writeLine(` ${color("⚡ /mcp", CYAN)}`);
190
+ writeLine(boxTop("MCP ENDPOINT", BRIGHT_MAGENTA));
191
+ writeLine(boxContent(`${color("⚡ POST", BRIGHT_YELLOW)} ${color("/mcp", BRIGHT_CYAN)} ${color("JSON-RPC · tools · resources", DIM)}`, BRIGHT_MAGENTA));
192
+ writeLine(boxBottom(BRIGHT_MAGENTA));
139
193
  writeLine("");
140
- writeLine(" TOOLS");
141
- writeLine(` ${color(toolLabel("project_context"), BRIGHT_CYAN)}`);
142
- writeLine(` ${color(toolLabel("find_files"), CYAN)}`);
143
- writeLine(` ${color(toolLabel("search_code"), BRIGHT_CYAN)}`);
144
- writeLine(` ${color(toolLabel("find_symbol"), GREEN)}`);
145
- writeLine(` ${color(toolLabel("find_references"), GREEN)}`);
146
- writeLine(` ${color(toolLabel("read_range"), GREEN)}`);
147
- writeLine(` ${color(toolLabel("apply_changes"), BRIGHT_MAGENTA)}`);
148
- writeLine(` ${color(toolLabel("validate"), BRIGHT_YELLOW)}`);
149
- writeLine(` ${color(toolLabel("run_npm_batch"), BRIGHT_BLUE)}`);
150
- writeLine(` ${color(toolLabel("run_command_batch"), BRIGHT_CYAN)}`);
151
- writeLine(` ${color(toolLabel("file_info"), YELLOW)}`);
194
+ writeLine(boxTop("AVAILABLE TOOLS", BRIGHT_BLUE));
195
+ const toolRows = [
196
+ color(toolLabel("project_context"), BRIGHT_CYAN),
197
+ color(toolLabel("find_files"), CYAN),
198
+ color(toolLabel("search_code"), BRIGHT_CYAN),
199
+ color(toolLabel("find_symbol"), GREEN),
200
+ color(toolLabel("find_references"), GREEN),
201
+ color(toolLabel("read_range"), GREEN),
202
+ color(toolLabel("apply_changes"), BRIGHT_MAGENTA),
203
+ color(toolLabel("validate"), BRIGHT_YELLOW),
204
+ color(toolLabel("run_npm_batch"), BRIGHT_BLUE),
205
+ color(toolLabel("run_command_batch"), BRIGHT_CYAN),
206
+ color(toolLabel("file_info"), YELLOW),
207
+ ];
208
+ if (options.codeGraph)
209
+ toolRows.push(color(toolLabel("codegraph_explore"), BRIGHT_MAGENTA));
210
+ printGrid(toolRows, 2);
211
+ writeLine(boxBottom(BRIGHT_BLUE));
152
212
  writeLine("");
153
213
  if (options.npmScripts?.length) {
154
- writeLine(" NPM COMMANDS");
155
- for (const script of options.npmScripts)
156
- writeLine(` ${color("•", BLUE)} npm run ${script}`);
214
+ writeLine(` ${color("◆ NPM SCRIPTS", BRIGHT_YELLOW)} ${color("· scripts are allowlisted", "\x1b[90m")}`);
215
+ printGrid(options.npmScripts.map((script) => `${color("›", BRIGHT_YELLOW)} ${color("npm run", BRIGHT_YELLOW)} ${color(script, BRIGHT_CYAN)}`), 2);
157
216
  writeLine("");
158
217
  }
159
218
  if (options.commands?.length) {
160
- writeLine(" ALLOWED COMMANDS");
161
- for (const command of options.commands)
162
- writeLine(` ${color("•", CYAN)} ${command}`);
219
+ writeLine(` ${color("◆ COMMAND ALLOWLIST", BRIGHT_GREEN)} ${color("· shell access is restricted", "\x1b[90m")}`);
220
+ printGrid(options.commands.map((command) => `${color("›", BRIGHT_GREEN)} ${color(command, CYAN)}`), 3);
163
221
  writeLine("");
164
222
  }
165
223
  }
@@ -206,7 +264,7 @@ export function logRequest(entry) {
206
264
  }
207
265
  export function printRequestHeader() {
208
266
  writeLine("");
209
- writeLine(" ──────────────────────────────────────────────────────────────");
210
- writeLine(" [Request logs]");
211
- writeLine(" ──────────────────────────────────────────────────────────────");
267
+ writeLine(boxTop("REQUEST STREAM", BRIGHT_MAGENTA));
268
+ writeLine(boxContent(color("Live MCP traffic · method · status · tool activity", DIM), BRIGHT_MAGENTA));
269
+ writeLine(boxBottom(BRIGHT_MAGENTA));
212
270
  }
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,
@@ -774,12 +774,12 @@ async function callTool(name, args, root, npmAllowed, allowedCommands, blacklist
774
774
  const serialized = JSON.stringify(result);
775
775
  if (Buffer.byteLength(serialized, "utf8") <= maxBytes)
776
776
  return result;
777
- return {
777
+ return completeToolResult({
778
778
  truncated: true,
779
779
  originalBytes: Buffer.byteLength(serialized, "utf8"),
780
780
  message: "CodeGraph response exceeded the output budget. Narrow the query or lower maxFiles.",
781
- preview: truncateText(serialized, Math.min(2_000, maxBytes - 256)).text,
782
- };
781
+ preview: truncateText(serialized, Math.min(2_000, Math.max(256, maxBytes - 512))).text,
782
+ });
783
783
  }
784
784
  switch (name) {
785
785
  case "read_range": {
@@ -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
  }
@@ -95,10 +95,11 @@ export function startTunnel(options) {
95
95
  record(event);
96
96
  if (event.type === "online") {
97
97
  writeLine();
98
- writeLine(" ✓ TUNNEL ONLINE");
99
- writeLine(` Public URL : ${event.url}`);
100
- writeLine(` MCP endpoint : ${event.url}/mcp`);
101
- writeLine(` Forwarding : ${event.url} → http://127.0.0.1:${options.port}`);
98
+ writeLine(` \x1b[96m╭─ TUNNEL ONLINE ${"─".repeat(58)}╮\x1b[0m`);
99
+ writeLine(` \x1b[96m│\x1b[0m Public URL : \x1b[92m${event.url}\x1b[0m`);
100
+ writeLine(` \x1b[96m│\x1b[0m MCP endpoint : \x1b[96m${event.url}/mcp\x1b[0m`);
101
+ writeLine(` \x1b[96m│\x1b[0m Forwarding : ${event.url} → http://127.0.0.1:${options.port}`);
102
+ writeLine(` \x1b[96m╰${"─".repeat(74)}╯\x1b[0m`);
102
103
  writeLine();
103
104
  }
104
105
  else if (event.type === "disconnected") {
@@ -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.1",
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",