@takara-ai/miru-code 0.8.0 → 1.0.3

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 CHANGED
@@ -114,7 +114,46 @@ Pass the **project root** as `repo` for local projects. Prefer these over Grep,
114
114
 
115
115
  Hybrid search: Takara embeddings + BM25 + fusion + reranking. Indexes **code**, **docs**, **config**, or **all** via `--content`.
116
116
 
117
- Disk cache: `~/Library/Caches/miru` (macOS), `~/.cache/miru` (Linux). MCP watches local files and updates incrementally; run `miru clear .` after big refactors when using CLI only.
117
+ Disk cache: `~/Library/Caches/miru` (macOS), `~/.cache/miru` (Linux). MCP watches local files and updates incrementally; run `miru clear .` after big refactors when using CLI only. Upgrading Miru invalidates stale indexes automatically when the package version epoch changes.
118
+
119
+ ### Chunking & languages
120
+
121
+ Miru chunks source in tiers: **AST** (tree-sitter, default) → **structural** heuristics → **line** splits.
122
+
123
+ **AST chunking** — 22 languages (syntax-aware boundaries via vendored `web-tree-sitter` grammars):
124
+
125
+ | Language | Typical extensions |
126
+ |----------|-------------------|
127
+ | bash | `.sh`, `.bash`, `.zsh` |
128
+ | c | `.c` |
129
+ | cpp | `.cpp`, `.h`, `.hpp`, etc. |
130
+ | csharp | `.cs` |
131
+ | css | `.css` |
132
+ | dart | `.dart` |
133
+ | elixir | `.ex`, `.exs` |
134
+ | embeddedtemplate | ERB-style templates |
135
+ | go | `.go` |
136
+ | haskell | `.hs` |
137
+ | html | `.html` |
138
+ | java | `.java` |
139
+ | javascript | `.js`, `.jsx`, `.mjs`, `.cjs` |
140
+ | json | `.json` |
141
+ | ocaml | `.ml`, etc. |
142
+ | php | `.php` |
143
+ | python | `.py`, `.pyi` |
144
+ | ruby | `.rb` |
145
+ | rust | `.rs` |
146
+ | scala | `.scala` |
147
+ | solidity | `.sol` |
148
+ | typescript | `.ts`, `.mts`, `.cts` |
149
+
150
+ **Also shipped:** `.tsx` uses a dedicated TSX grammar; extra OCaml and PHP-only grammars are vendored alongside the main set.
151
+
152
+ **Structural fallback** (brace/indent heuristics when AST is unavailable): python, go, typescript, javascript, cpp, c.
153
+
154
+ **Line fallback:** everything else that gets indexed (kotlin, swift, vue, sql, etc.) — still searchable, coarser chunks.
155
+
156
+ Set `MIRU_AST_CHUNKING=0` to disable AST and use structural → lines only.
118
157
 
119
158
  ## CLI reference
120
159
 
@@ -149,10 +188,12 @@ const results = await index.search({ query: "BM25 tokenize", topK: 10 });
149
188
  |----------|-------|
150
189
  | `TAKARA_API_KEY` | Required |
151
190
  | `MIRU_OPENAI_BASE_URL` | Default `https://infer.takara.ai/v1` |
191
+ | `MIRU_OPENAI_EMBEDDING_MODEL` | Default `ds1-miru-int8` |
152
192
  | `MIRU_WORKSPACE_ROOT` | Restrict MCP local `repo` paths to this directory |
153
193
  | `MIRU_MAX_INDEX_FILES` | Cap files indexed per operation |
154
194
  | `MIRU_ALLOW_HTTP_GIT` | Set `1` to allow plain `http://` git clones |
155
195
  | `MIRU_MCP_WATCH` | Set `0` to disable MCP file watch |
196
+ | `MIRU_AST_CHUNKING` | Set `0` to disable tree-sitter AST chunking |
156
197
  | `NO_COLOR` | Disable CLI colors |
157
198
 
158
199
  See `.env.example` for more.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@takara-ai/miru-code",
3
- "version": "0.8.0",
3
+ "version": "1.0.3",
4
4
  "description": "Miru (見る) — hybrid code search for agents. Bun, TypeScript, Takara embeddings.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -1,15 +1,16 @@
1
1
  import { mapPool, resolveWorkerConcurrency } from "../concurrency.ts";
2
2
  import { envFirstString, envOptionalInt, resolveEmbeddingApiKey } from "../env.ts";
3
3
 
4
- const DEFAULT_MODEL = "ds1-potion-code-16m";
4
+ const DEFAULT_MODEL = "ds1-miru-int8";
5
5
  const DEFAULT_BASE_URL = "https://infer.takara.ai/v1";
6
6
  const DEFAULT_BATCH_SIZE = 32;
7
7
  const DEFAULT_MAX_EMBED_CHARS = 1300;
8
8
  const WINDOW_OVERLAP_CHARS = 120;
9
9
 
10
- /** Native output size for Takara ds1-potion-code-16m (override with MIRU_EMBEDDING_DIMENSIONS). */
10
+ /** Native output size per model (override with MIRU_EMBEDDING_DIMENSIONS). */
11
11
  const MODEL_DEFAULT_DIMENSIONS: Record<string, number> = {
12
12
  "ds1-potion-code-16m": 256,
13
+ "ds1-miru-int8": 256,
13
14
  };
14
15
 
15
16
  export interface EmbeddingTransportStats {
@@ -123,9 +124,47 @@ export function resolveEmbeddingBaseUrl(): string {
123
124
  );
124
125
  }
125
126
 
127
+ interface Int8Embedding {
128
+ dtype: "i8";
129
+ values: number[];
130
+ scale: number;
131
+ zero_point: number;
132
+ }
133
+
134
+ type EmbeddingPayload = number[] | Int8Embedding;
135
+
126
136
  interface EmbeddingResponseItem {
127
137
  index: number;
128
- embedding: number[];
138
+ embedding: EmbeddingPayload;
139
+ }
140
+
141
+ function isInt8Embedding(embedding: EmbeddingPayload): embedding is Int8Embedding {
142
+ return (
143
+ typeof embedding === "object" &&
144
+ embedding !== null &&
145
+ !Array.isArray(embedding) &&
146
+ embedding.dtype === "i8" &&
147
+ Array.isArray(embedding.values)
148
+ );
149
+ }
150
+
151
+ export function embeddingDimensions(embedding: EmbeddingPayload): number {
152
+ return isInt8Embedding(embedding) ? embedding.values.length : embedding.length;
153
+ }
154
+
155
+ export function dequantizeEmbedding(embedding: EmbeddingPayload): Float32Array {
156
+ if (Array.isArray(embedding)) {
157
+ return new Float32Array(embedding);
158
+ }
159
+ if (isInt8Embedding(embedding)) {
160
+ const { values, scale, zero_point } = embedding;
161
+ const out = new Float32Array(values.length);
162
+ for (let i = 0; i < values.length; i++) {
163
+ out[i] = ((values[i] ?? 0) - zero_point) * scale;
164
+ }
165
+ return out;
166
+ }
167
+ throw new Error("Embedding API returned unsupported embedding format");
129
168
  }
130
169
 
131
170
  interface EmbeddingResponse {
@@ -402,7 +441,7 @@ function vectorsFromResponse(data: EmbeddingResponseItem[], expected: number): F
402
441
  const byIndex = new Map<number, Float32Array>();
403
442
  for (const item of data) {
404
443
  if (item.index >= 0 && item.index < expected) {
405
- byIndex.set(item.index, new Float32Array(item.embedding));
444
+ byIndex.set(item.index, dequantizeEmbedding(item.embedding));
406
445
  }
407
446
  }
408
447
  if (byIndex.size !== expected) {
@@ -1,4 +1,5 @@
1
1
  import {
2
+ embeddingDimensions,
2
3
  resolveEmbeddingBaseUrl,
3
4
  resolveEmbeddingDimensions,
4
5
  resolveEmbeddingModel,
@@ -65,21 +66,29 @@ export async function validateEmbeddingApiKey(options: {
65
66
 
66
67
  try {
67
68
  const payload = (await response.json()) as {
68
- data?: Array<{ embedding?: number[] }>;
69
+ data?: Array<{ embedding?: Parameters<typeof embeddingDimensions>[0] }>;
69
70
  };
70
71
  const embedding = payload.data?.[0]?.embedding;
71
- if (!embedding || embedding.length === 0) {
72
+ if (!embedding) {
72
73
  return {
73
74
  valid: false,
74
75
  status: response.status,
75
76
  message: "Embedding API returned an empty response.",
76
77
  };
77
78
  }
78
- if (dimensions != null && embedding.length !== dimensions) {
79
+ const dim = embeddingDimensions(embedding);
80
+ if (dim === 0) {
79
81
  return {
80
82
  valid: false,
81
83
  status: response.status,
82
- message: `Expected ${dimensions} embedding dimensions, got ${embedding.length}.`,
84
+ message: "Embedding API returned an empty response.",
85
+ };
86
+ }
87
+ if (dimensions != null && dim !== dimensions) {
88
+ return {
89
+ valid: false,
90
+ status: response.status,
91
+ message: `Expected ${dimensions} embedding dimensions, got ${dim}.`,
83
92
  };
84
93
  }
85
94
  } catch {
package/src/help.ts CHANGED
@@ -55,6 +55,8 @@ export function printEnvHelp(): void {
55
55
  writeStdout(" Takara bearer token for embeddings");
56
56
  writeStdout(" MIRU_OPENAI_BASE_URL");
57
57
  writeStdout(" Default: https://infer.takara.ai/v1");
58
+ writeStdout(" MIRU_OPENAI_EMBEDDING_MODEL");
59
+ writeStdout(" Default: ds1-miru-int8");
58
60
  writeStdout(" MIRU_CONCURRENCY");
59
61
  writeStdout(" Parallel workers (default: CPUs − 2)");
60
62
  writeStdout("");