@takara-ai/miru-code 0.4.5 → 0.4.6
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/README.md +6 -4
- package/package.json +1 -1
- package/src/cache.ts +1 -1
- package/src/cli.ts +1 -1
- package/src/env.ts +2 -1
- package/src/installer/agents.ts +67 -22
- package/src/installer/config.ts +0 -1
package/README.md
CHANGED
|
@@ -25,7 +25,7 @@ miru setup --key YOUR_TOKEN # non-interactive
|
|
|
25
25
|
miru setup --clear # remove stored key
|
|
26
26
|
```
|
|
27
27
|
|
|
28
|
-
MCP loads your key from `credentials.json` automatically
|
|
28
|
+
MCP loads your key from `credentials.json` automatically — no env block needed in MCP config.
|
|
29
29
|
|
|
30
30
|
## Add to your IDE
|
|
31
31
|
|
|
@@ -39,7 +39,7 @@ Interactive — pick your agent and what to enable (MCP, instructions, sub-agent
|
|
|
39
39
|
miru uninstall # remove miru config
|
|
40
40
|
```
|
|
41
41
|
|
|
42
|
-
**Supported:** Cursor · Claude Code · Gemini CLI · Kiro · OpenCode · GitHub Copilot · Codex · VS Code
|
|
42
|
+
**Supported:** Cursor · Claude Code · Gemini CLI · Kiro · OpenCode · GitHub Copilot · Codex · VS Code · Visual Studio (Windows)
|
|
43
43
|
|
|
44
44
|
| IDE | Config written by `miru install` |
|
|
45
45
|
|-----|----------------------------------|
|
|
@@ -50,6 +50,7 @@ miru uninstall # remove miru config
|
|
|
50
50
|
| OpenCode | `~/.config/opencode/opencode.json(c)` + agents dir |
|
|
51
51
|
| GitHub Copilot | `~/.copilot/mcp-config.json` + `~/.copilot/agents/miru-code.agent.md` |
|
|
52
52
|
| Codex / VS Code | MCP config only |
|
|
53
|
+
| Visual Studio | `%USERPROFILE%\.mcp.json` (Windows, Copilot Agent Mode) |
|
|
53
54
|
|
|
54
55
|
**Team sub-agent in a repo** (optional):
|
|
55
56
|
|
|
@@ -132,12 +133,13 @@ See `.env.example` for more.
|
|
|
132
133
|
{
|
|
133
134
|
"miru": {
|
|
134
135
|
"command": "miru",
|
|
135
|
-
"args": []
|
|
136
|
-
"env": { "TAKARA_API_KEY": "your-token" }
|
|
136
|
+
"args": []
|
|
137
137
|
}
|
|
138
138
|
}
|
|
139
139
|
```
|
|
140
140
|
|
|
141
|
+
Run `miru setup` once so the server can load your key from `credentials.json`.
|
|
142
|
+
|
|
141
143
|
Use `bunx` + `@takara-ai/miru-code` if `miru` is not global. Wrapper key varies by IDE (`mcpServers`, `servers`, or `mcp`).
|
|
142
144
|
|
|
143
145
|
## Developing
|
package/package.json
CHANGED
package/src/cache.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
2
|
import { rm } from "node:fs/promises";
|
|
3
3
|
import { join } from "node:path";
|
|
4
|
-
import { computeSourceCacheKey } from "./utils.ts";
|
|
5
4
|
import { resolveEmbeddingDimensions, resolveEmbeddingModel } from "./embeddings/openai.ts";
|
|
6
5
|
import {
|
|
7
6
|
loadBm25,
|
|
@@ -13,6 +12,7 @@ import {
|
|
|
13
12
|
import { resolveSemanticStorage, semanticStorageFromMetadata } from "./index/vector-storage.ts";
|
|
14
13
|
import type { Chunk, ContentType } from "./types.ts";
|
|
15
14
|
import { chunkFromDict } from "./types.ts";
|
|
15
|
+
import { computeSourceCacheKey } from "./utils.ts";
|
|
16
16
|
|
|
17
17
|
export function resolveCacheFolder(): string {
|
|
18
18
|
const name = "miru";
|
package/src/cli.ts
CHANGED
|
@@ -11,8 +11,8 @@ import {
|
|
|
11
11
|
success,
|
|
12
12
|
} from "./cli-ui.ts";
|
|
13
13
|
import { loadStoredCredentials } from "./credentials.ts";
|
|
14
|
-
import { loadEnvFiles } from "./env-files.ts";
|
|
15
14
|
import { normalizeTakaraApiKeyEnv } from "./env.ts";
|
|
15
|
+
import { loadEnvFiles } from "./env-files.ts";
|
|
16
16
|
import {
|
|
17
17
|
AGENT_IDS,
|
|
18
18
|
formatUnknownAgent,
|
package/src/env.ts
CHANGED
|
@@ -33,7 +33,8 @@ export function envOptionalInt(names: string[], min = 1): number | undefined {
|
|
|
33
33
|
|
|
34
34
|
export const TAKARA_API_KEY_ENV = "TAKARA_API_KEY";
|
|
35
35
|
|
|
36
|
-
const
|
|
36
|
+
const MCP_KEY_PLACEHOLDER = "$" + "{TAKARA_API_KEY}";
|
|
37
|
+
const TAKARA_API_KEY_PLACEHOLDERS = new Set([MCP_KEY_PLACEHOLDER, "$TAKARA_API_KEY"]);
|
|
37
38
|
|
|
38
39
|
/** True when the value is a real key, not empty or an unexpanded MCP env placeholder. */
|
|
39
40
|
export function isUsableTakaraApiKey(value: string | undefined): boolean {
|
package/src/installer/agents.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { existsSync } from "node:fs";
|
|
2
|
+
import { readdir } from "node:fs/promises";
|
|
2
3
|
import { homedir } from "node:os";
|
|
3
4
|
import { join } from "node:path";
|
|
4
5
|
import type { AgentId } from "../agents.ts";
|
|
@@ -19,30 +20,21 @@ export const MIRU_END = "<!-- miru:end -->";
|
|
|
19
20
|
|
|
20
21
|
const HOME = homedir();
|
|
21
22
|
|
|
22
|
-
const TAKARA_KEY_PLACEHOLDER = "$" + "{TAKARA_API_KEY}";
|
|
23
|
-
|
|
24
|
-
const MCP_ENV: Record<string, string> = {
|
|
25
|
-
TAKARA_API_KEY: TAKARA_KEY_PLACEHOLDER,
|
|
26
|
-
};
|
|
27
|
-
|
|
28
23
|
const STDIO_SERVER_CONFIG: Record<string, unknown> = {
|
|
29
24
|
command: "bunx",
|
|
30
25
|
args: ["@takara-ai/miru-code"],
|
|
31
26
|
type: "stdio",
|
|
32
|
-
env: MCP_ENV,
|
|
33
27
|
};
|
|
34
28
|
|
|
35
29
|
const BARE_STDIO_SERVER_CONFIG: Record<string, unknown> = {
|
|
36
30
|
command: "bunx",
|
|
37
31
|
args: ["@takara-ai/miru-code"],
|
|
38
|
-
env: MCP_ENV,
|
|
39
32
|
};
|
|
40
33
|
|
|
41
34
|
const OPENCODE_SERVER_CONFIG: Record<string, unknown> = {
|
|
42
35
|
command: ["bunx", "@takara-ai/miru-code"],
|
|
43
36
|
type: "local",
|
|
44
37
|
enabled: true,
|
|
45
|
-
environment: MCP_ENV,
|
|
46
38
|
};
|
|
47
39
|
|
|
48
40
|
export const INSTRUCTIONS = `${MIRU_START}
|
|
@@ -54,7 +46,7 @@ A \`miru\` MCP server is available with two tools:
|
|
|
54
46
|
|
|
55
47
|
Always call \`search\` before using Grep, Glob, or Read to explore the codebase. Use Grep/Glob/Read only for exact path lookup, exhaustive literal matches, or when the returned chunk lacks enough context.
|
|
56
48
|
|
|
57
|
-
Run \`miru setup\` once to store your API key — the MCP server loads it from \`credentials.json
|
|
49
|
+
Run \`miru setup\` once to store your API key — the MCP server loads it from \`credentials.json\` automatically.
|
|
58
50
|
|
|
59
51
|
Pass \`--content docs\` to search documentation, \`--content config\` for config files, or \`--content all\` for everything.
|
|
60
52
|
|
|
@@ -92,7 +84,7 @@ export interface McpConfig {
|
|
|
92
84
|
}
|
|
93
85
|
|
|
94
86
|
export interface AgentTarget {
|
|
95
|
-
id: AgentId | "codex" | "vscode";
|
|
87
|
+
id: AgentId | "codex" | "vscode" | "visualstudio";
|
|
96
88
|
displayName: string;
|
|
97
89
|
binary: string | null;
|
|
98
90
|
configDir: string | null;
|
|
@@ -128,6 +120,45 @@ export function vscodeMcpPath(): string {
|
|
|
128
120
|
return join(xdg, "Code", "User", "mcp.json");
|
|
129
121
|
}
|
|
130
122
|
|
|
123
|
+
/** Global MCP config for Visual Studio (GitHub Copilot Agent Mode). */
|
|
124
|
+
export function visualStudioMcpPath(): string {
|
|
125
|
+
const profile = process.env.USERPROFILE ?? HOME;
|
|
126
|
+
return join(profile, ".mcp.json");
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export function visualStudioInstallDir(): string | null {
|
|
130
|
+
if (process.platform !== "win32") {
|
|
131
|
+
return null;
|
|
132
|
+
}
|
|
133
|
+
const programFiles = process.env.ProgramFiles ?? join("C:", "Program Files");
|
|
134
|
+
return join(programFiles, "Microsoft Visual Studio");
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
async function detectVisualStudio(): Promise<boolean> {
|
|
138
|
+
if (process.platform !== "win32") {
|
|
139
|
+
return false;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const installDir = visualStudioInstallDir();
|
|
143
|
+
if (installDir && existsSync(installDir)) {
|
|
144
|
+
try {
|
|
145
|
+
const entries = await readdir(installDir);
|
|
146
|
+
if (entries.length > 0) {
|
|
147
|
+
return true;
|
|
148
|
+
}
|
|
149
|
+
} catch {
|
|
150
|
+
// ignore unreadable install directory
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
try {
|
|
155
|
+
const proc = Bun.spawn(["where", "devenv"], { stdout: "pipe", stderr: "ignore" });
|
|
156
|
+
return (await proc.exited) === 0;
|
|
157
|
+
} catch {
|
|
158
|
+
return false;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
131
162
|
function jsonMcp(path: string, key: string, entry: Record<string, unknown>): McpConfig {
|
|
132
163
|
return { path, key, memberKey: "miru", entry, format: "json" };
|
|
133
164
|
}
|
|
@@ -171,7 +202,6 @@ export const AGENT_TARGETS: AgentTarget[] = [
|
|
|
171
202
|
mcp: jsonMcp(join(HOME, ".kiro", "settings", "mcp.json"), "mcpServers", {
|
|
172
203
|
...STDIO_SERVER_CONFIG,
|
|
173
204
|
env: {
|
|
174
|
-
...MCP_ENV,
|
|
175
205
|
PATH: "/usr/local/bin:/usr/bin:/bin",
|
|
176
206
|
},
|
|
177
207
|
}),
|
|
@@ -225,19 +255,34 @@ export const AGENT_TARGETS: AgentTarget[] = [
|
|
|
225
255
|
subagentPath: null,
|
|
226
256
|
subagentId: null,
|
|
227
257
|
},
|
|
258
|
+
{
|
|
259
|
+
id: "visualstudio",
|
|
260
|
+
displayName: process.platform === "win32" ? "Visual Studio" : "Visual Studio (Windows)",
|
|
261
|
+
binary: null,
|
|
262
|
+
configDir: visualStudioInstallDir(),
|
|
263
|
+
mcp: jsonMcp(visualStudioMcpPath(), "servers", STDIO_SERVER_CONFIG),
|
|
264
|
+
instructionsPath: null,
|
|
265
|
+
subagentPath: null,
|
|
266
|
+
subagentId: null,
|
|
267
|
+
},
|
|
228
268
|
];
|
|
229
269
|
|
|
270
|
+
async function commandOnPath(command: string): Promise<boolean> {
|
|
271
|
+
const lookup = process.platform === "win32" ? ["where", command] : ["which", command];
|
|
272
|
+
try {
|
|
273
|
+
const proc = Bun.spawn(lookup, { stdout: "pipe", stderr: "ignore" });
|
|
274
|
+
return (await proc.exited) === 0;
|
|
275
|
+
} catch {
|
|
276
|
+
return false;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
230
280
|
export async function isAgentDetected(agent: AgentTarget): Promise<boolean> {
|
|
231
|
-
if (agent.
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
return true;
|
|
237
|
-
}
|
|
238
|
-
} catch {
|
|
239
|
-
// which unavailable
|
|
240
|
-
}
|
|
281
|
+
if (agent.id === "visualstudio") {
|
|
282
|
+
return detectVisualStudio();
|
|
283
|
+
}
|
|
284
|
+
if (agent.binary && (await commandOnPath(agent.binary))) {
|
|
285
|
+
return true;
|
|
241
286
|
}
|
|
242
287
|
if (agent.configDir) {
|
|
243
288
|
return Bun.file(agent.configDir).exists();
|
package/src/installer/config.ts
CHANGED
|
@@ -6,7 +6,6 @@ const CODEX_MCP_HEADER = "[mcp_servers.miru]";
|
|
|
6
6
|
const CODEX_MCP_BLOCK = `[mcp_servers.miru]
|
|
7
7
|
command = "bunx"
|
|
8
8
|
args = ["@takara-ai/miru-code"]
|
|
9
|
-
env = { TAKARA_API_KEY = "\${TAKARA_API_KEY}" }
|
|
10
9
|
`;
|
|
11
10
|
|
|
12
11
|
/** Strip line and block comments so JSONC configs can be parsed. */
|