@jmylchreest/aide-plugin 0.0.23 → 0.0.24

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": "@jmylchreest/aide-plugin",
3
- "version": "0.0.23",
3
+ "version": "0.0.24",
4
4
  "description": "aide plugin for OpenCode — multi-agent orchestration, memory, skills, and persistence",
5
5
  "type": "module",
6
6
  "main": "./src/opencode/index.ts",
package/src/cli/config.ts CHANGED
@@ -95,7 +95,7 @@ export function addAideToConfig(
95
95
  if (!mcp[MCP_SERVER_NAME]) {
96
96
  mcp[MCP_SERVER_NAME] = {
97
97
  type: "local",
98
- command: ["npx", "-y", "-p", PLUGIN_NAME, "aide-wrapper", "mcp"],
98
+ command: ["npx", "-y", PLUGIN_NAME, "mcp"],
99
99
  environment: {
100
100
  AIDE_CODE_WATCH: "1",
101
101
  AIDE_CODE_WATCH_DELAY: "30s",
package/src/cli/index.ts CHANGED
@@ -6,11 +6,13 @@
6
6
  * bunx @jmylchreest/aide-plugin install # Install globally for OpenCode
7
7
  * bunx @jmylchreest/aide-plugin uninstall # Remove from OpenCode config
8
8
  * bunx @jmylchreest/aide-plugin status # Show current installation status
9
+ * bunx @jmylchreest/aide-plugin mcp # Start MCP server (used by OpenCode)
9
10
  */
10
11
 
11
12
  import { install } from "./install.js";
12
13
  import { uninstall } from "./uninstall.js";
13
14
  import { status } from "./status.js";
15
+ import { mcp } from "./mcp.js";
14
16
 
15
17
  const args = process.argv.slice(2);
16
18
  const command = args[0];
@@ -22,6 +24,7 @@ Usage:
22
24
  aide-plugin install Install aide plugin globally for OpenCode
23
25
  aide-plugin uninstall Remove aide plugin from OpenCode config
24
26
  aide-plugin status Show current installation status
27
+ aide-plugin mcp Start MCP server (delegates to aide-wrapper)
25
28
  aide-plugin --help Show this help message
26
29
 
27
30
  Options:
@@ -49,6 +52,9 @@ async function main(): Promise<void> {
49
52
  case "status":
50
53
  await status();
51
54
  break;
55
+ case "mcp":
56
+ await mcp(args.slice(1));
57
+ break;
52
58
  case "--help":
53
59
  case "-h":
54
60
  case "help":
@@ -1,5 +1,8 @@
1
1
  /**
2
2
  * Install command — registers aide plugin and MCP server in OpenCode config.
3
+ *
4
+ * On reinstall, detects and upgrades stale MCP command configurations
5
+ * (e.g. old `aide-wrapper` commands) to the current format.
3
6
  */
4
7
 
5
8
  import {
@@ -10,6 +13,7 @@ import {
10
13
  readConfig,
11
14
  writeConfig,
12
15
  PLUGIN_NAME,
16
+ MCP_SERVER_NAME,
13
17
  } from "./config.js";
14
18
 
15
19
  export interface InstallFlags {
@@ -17,6 +21,32 @@ export interface InstallFlags {
17
21
  noMcp?: boolean;
18
22
  }
19
23
 
24
+ /**
25
+ * Check if an existing MCP config has the current expected command format.
26
+ * Returns false if the command is missing, empty, or uses an outdated format.
27
+ */
28
+ function isMcpCommandCurrent(config: ReturnType<typeof readConfig>): boolean {
29
+ const mcpConfig = config.mcp?.[MCP_SERVER_NAME];
30
+ if (!mcpConfig?.command || mcpConfig.command.length === 0) {
31
+ return false;
32
+ }
33
+
34
+ const cmd = mcpConfig.command;
35
+
36
+ // Current format: ["npx", "-y", "@jmylchreest/aide-plugin", "mcp"]
37
+ if (
38
+ cmd.length === 4 &&
39
+ cmd[0] === "npx" &&
40
+ cmd[1] === "-y" &&
41
+ cmd[2] === PLUGIN_NAME &&
42
+ cmd[3] === "mcp"
43
+ ) {
44
+ return true;
45
+ }
46
+
47
+ return false;
48
+ }
49
+
20
50
  export async function install(flags: InstallFlags): Promise<void> {
21
51
  const configPath = flags.project
22
52
  ? getProjectConfigPath()
@@ -29,7 +59,11 @@ export async function install(flags: InstallFlags): Promise<void> {
29
59
  const existing = readConfig(configPath);
30
60
  const before = isAideConfigured(existing);
31
61
 
32
- if (before.plugin && before.mcp) {
62
+ // Check if MCP command needs updating (stale format from older versions)
63
+ const mcpNeedsUpdate =
64
+ !flags.noMcp && before.mcp && !isMcpCommandCurrent(existing);
65
+
66
+ if (before.plugin && before.mcp && !mcpNeedsUpdate) {
33
67
  console.log(`aide is already configured in ${configPath}`);
34
68
  console.log(" plugin: registered");
35
69
  console.log(" mcp: registered");
@@ -37,6 +71,11 @@ export async function install(flags: InstallFlags): Promise<void> {
37
71
  return;
38
72
  }
39
73
 
74
+ // If MCP config is stale, remove it so addAideToConfig will write the current version
75
+ if (mcpNeedsUpdate && existing.mcp) {
76
+ delete existing.mcp[MCP_SERVER_NAME];
77
+ }
78
+
40
79
  // Apply changes
41
80
  const updated = addAideToConfig(existing, { noMcp: flags.noMcp });
42
81
  writeConfig(configPath, updated);
@@ -52,7 +91,9 @@ export async function install(flags: InstallFlags): Promise<void> {
52
91
  }
53
92
 
54
93
  if (!flags.noMcp) {
55
- if (!before.mcp && after.mcp) {
94
+ if (mcpNeedsUpdate) {
95
+ console.log(` ~ Updated "aide" MCP server command (was outdated)`);
96
+ } else if (!before.mcp && after.mcp) {
56
97
  console.log(` + Added "aide" MCP server`);
57
98
  } else if (before.mcp) {
58
99
  console.log(` = MCP server already registered`);
package/src/cli/mcp.ts ADDED
@@ -0,0 +1,63 @@
1
+ /**
2
+ * MCP subcommand — delegates to aide-wrapper.sh to start the MCP server.
3
+ *
4
+ * This is the entry point used by OpenCode's MCP config:
5
+ * "command": ["npx", "-y", "@jmylchreest/aide-plugin", "mcp"]
6
+ *
7
+ * The wrapper handles binary discovery/download, then exec's `aide mcp`.
8
+ */
9
+
10
+ import { execFileSync } from "child_process";
11
+ import { existsSync } from "fs";
12
+ import { dirname, join, resolve } from "path";
13
+ import { fileURLToPath } from "url";
14
+
15
+ /**
16
+ * Find the aide-wrapper.sh script relative to this CLI module.
17
+ *
18
+ * Resolution: this file lives at <plugin-root>/src/cli/mcp.ts,
19
+ * so the wrapper is at <plugin-root>/bin/aide-wrapper.sh.
20
+ */
21
+ function findWrapper(): string {
22
+ // __dirname equivalent for ESM
23
+ const thisDir = dirname(fileURLToPath(import.meta.url));
24
+ // src/cli -> src -> plugin-root
25
+ const pluginRoot = resolve(thisDir, "..", "..");
26
+ const wrapper = join(pluginRoot, "bin", "aide-wrapper.sh");
27
+
28
+ if (!existsSync(wrapper)) {
29
+ throw new Error(
30
+ `aide-wrapper.sh not found at ${wrapper}\n` +
31
+ `Expected plugin root: ${pluginRoot}\n` +
32
+ `Ensure the package is installed correctly.`,
33
+ );
34
+ }
35
+
36
+ return wrapper;
37
+ }
38
+
39
+ /**
40
+ * Start the MCP server by exec'ing aide-wrapper.sh with "mcp" + any extra args.
41
+ * This replaces the current process so stdio is inherited directly.
42
+ */
43
+ export async function mcp(extraArgs: string[]): Promise<void> {
44
+ const wrapper = findWrapper();
45
+ const args = ["mcp", ...extraArgs];
46
+
47
+ // Use execFileSync with stdio inherit so the MCP JSON-RPC protocol
48
+ // flows directly between OpenCode and the aide binary.
49
+ // The wrapper will exec() into the aide binary, replacing itself.
50
+ try {
51
+ execFileSync(wrapper, args, {
52
+ stdio: "inherit",
53
+ env: process.env,
54
+ });
55
+ } catch (err: unknown) {
56
+ // execFileSync throws on non-zero exit. If the process was killed
57
+ // by a signal (e.g. OpenCode shutting down), exit cleanly.
58
+ if (err && typeof err === "object" && "status" in err) {
59
+ process.exit((err as { status: number }).status ?? 1);
60
+ }
61
+ throw err;
62
+ }
63
+ }
@@ -16,7 +16,7 @@
16
16
  * "mcp": {
17
17
  * "aide": {
18
18
  * "type": "local",
19
- * "command": ["npx", "-y", "-p", "@jmylchreest/aide-plugin", "aide-wrapper", "mcp"],
19
+ * "command": ["npx", "-y", "@jmylchreest/aide-plugin", "mcp"],
20
20
  * "environment": { "AIDE_CODE_WATCH": "1", "AIDE_CODE_WATCH_DELAY": "30s" },
21
21
  * "enabled": true
22
22
  * }