@takara-ai/miru-code 1.5.2 → 1.5.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@takara-ai/miru-code",
3
- "version": "1.5.2",
3
+ "version": "1.5.3",
4
4
  "description": "Miru (見る) — hybrid code search for agents. Bun, TypeScript, Takara embeddings.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -61,13 +61,6 @@ export async function readStoredCredentials(): Promise<StoredCredentials | null>
61
61
  }
62
62
  }
63
63
 
64
- function hydrateSageMakerEnv(sagemaker: StoredSageMakerCredentials): void {
65
- process.env.MIRU_SAGEMAKER_ENDPOINT_ARN = sagemaker.endpoint_arn;
66
- if (sagemaker.profile && !process.env.AWS_PROFILE) {
67
- process.env.AWS_PROFILE = sagemaker.profile;
68
- }
69
- }
70
-
71
64
  function clearSageMakerEnv(sagemaker?: StoredSageMakerCredentials): void {
72
65
  delete process.env.MIRU_SAGEMAKER_ENDPOINT_ARN;
73
66
  delete process.env.MIRU_SAGEMAKER_ENDPOINT_NAME;
@@ -81,6 +74,36 @@ function clearTakaraEnv(): void {
81
74
  delete process.env.TAKARA_API_KEY;
82
75
  }
83
76
 
77
+ function hydrateSageMakerEnv(sagemaker: StoredSageMakerCredentials): void {
78
+ process.env.MIRU_SAGEMAKER_ENDPOINT_ARN = sagemaker.endpoint_arn;
79
+ if (sagemaker.profile && !process.env.AWS_PROFILE) {
80
+ process.env.AWS_PROFILE = sagemaker.profile;
81
+ }
82
+ }
83
+
84
+ /** Drop the other backend from env so setup validation cannot see a stale mode. */
85
+ export async function beginModeSwitch(to: "takara" | "sagemaker"): Promise<void> {
86
+ const stored = await readStoredCredentials();
87
+ if (to === "takara") {
88
+ clearSageMakerEnv(stored?.sagemaker);
89
+ } else {
90
+ clearTakaraEnv();
91
+ }
92
+ }
93
+
94
+ async function writeExclusive(payload: StoredCredentials): Promise<string> {
95
+ const dir = resolveCredentialsDir();
96
+ const path = resolveCredentialsPath();
97
+ await mkdir(dir, { recursive: true, mode: 0o700 });
98
+ await Bun.write(path, `${JSON.stringify(payload, null, 2)}\n`, { mode: 0o600 });
99
+ try {
100
+ await chmod(path, 0o600);
101
+ } catch {
102
+ // Windows may not support Unix mode bits on all filesystems.
103
+ }
104
+ return path;
105
+ }
106
+
84
107
  /** Apply credentials.json as the sole mode — never leave Takara and SageMaker both active. */
85
108
  export async function loadStoredCredentials(): Promise<boolean> {
86
109
  normalizeTakaraApiKeyEnv();
@@ -89,8 +112,8 @@ export async function loadStoredCredentials(): Promise<boolean> {
89
112
  return false;
90
113
  }
91
114
 
92
- let changed = false;
93
115
  if (stored.takara_api_key) {
116
+ let changed = false;
94
117
  if (!hasTakaraApiKeyInEnv()) {
95
118
  process.env.TAKARA_API_KEY = stored.takara_api_key;
96
119
  changed = true;
@@ -103,6 +126,7 @@ export async function loadStoredCredentials(): Promise<boolean> {
103
126
  }
104
127
 
105
128
  if (stored.sagemaker) {
129
+ let changed = false;
106
130
  if (!process.env.MIRU_SAGEMAKER_ENDPOINT_ARN?.trim()) {
107
131
  hydrateSageMakerEnv(stored.sagemaker);
108
132
  changed = true;
@@ -111,46 +135,28 @@ export async function loadStoredCredentials(): Promise<boolean> {
111
135
  clearTakaraEnv();
112
136
  changed = true;
113
137
  }
138
+ return changed;
114
139
  }
115
- return changed;
140
+ return false;
116
141
  }
117
142
 
118
143
  export async function saveStoredCredentials(apiKey: string): Promise<string> {
119
- const dir = resolveCredentialsDir();
120
- const path = resolveCredentialsPath();
121
- await mkdir(dir, { recursive: true, mode: 0o700 });
122
- const previousSageMaker = (await readStoredCredentials())?.sagemaker;
123
- const payload: StoredCredentials = {
124
- version: CREDENTIALS_VERSION,
125
- takara_api_key: apiKey,
126
- };
127
- await Bun.write(path, `${JSON.stringify(payload, null, 2)}\n`, { mode: 0o600 });
128
- try {
129
- await chmod(path, 0o600);
130
- } catch {
131
- // Windows may not support Unix mode bits on all filesystems.
132
- }
133
- clearSageMakerEnv(previousSageMaker);
144
+ const previous = await readStoredCredentials();
145
+ const path = await writeExclusive({ version: CREDENTIALS_VERSION, takara_api_key: apiKey });
146
+ process.env.TAKARA_API_KEY = apiKey;
147
+ clearSageMakerEnv(previous?.sagemaker);
134
148
  return path;
135
149
  }
136
150
 
137
151
  export async function saveStoredSageMakerCredentials(
138
152
  sagemaker: StoredSageMakerCredentials,
139
153
  ): Promise<string> {
140
- const dir = resolveCredentialsDir();
141
- const path = resolveCredentialsPath();
142
- await mkdir(dir, { recursive: true, mode: 0o700 });
143
- const payload: StoredCredentials = {
144
- version: CREDENTIALS_VERSION,
145
- sagemaker,
146
- };
147
- await Bun.write(path, `${JSON.stringify(payload, null, 2)}\n`, { mode: 0o600 });
148
- try {
149
- await chmod(path, 0o600);
150
- } catch {
151
- // Windows may not support Unix mode bits on all filesystems.
152
- }
154
+ const path = await writeExclusive({ version: CREDENTIALS_VERSION, sagemaker });
153
155
  clearTakaraEnv();
156
+ process.env.MIRU_SAGEMAKER_ENDPOINT_ARN = sagemaker.endpoint_arn;
157
+ if (sagemaker.profile) {
158
+ process.env.AWS_PROFILE = sagemaker.profile;
159
+ }
154
160
  return path;
155
161
  }
156
162
 
@@ -3,7 +3,7 @@ import {
3
3
  embeddingDimensions,
4
4
  resolveEmbeddingBaseUrl,
5
5
  resolveEmbeddingDimensions,
6
- resolveEmbeddingModel,
6
+ resolveTakaraEmbeddingModel,
7
7
  } from "./openai.ts";
8
8
 
9
9
  export interface ValidateApiKeyResult {
@@ -19,7 +19,7 @@ export async function validateEmbeddingApiKey(options: {
19
19
  dimensions?: number;
20
20
  }): Promise<ValidateApiKeyResult> {
21
21
  const baseUrl = (options.baseUrl ?? resolveEmbeddingBaseUrl()).replace(/\/$/, "");
22
- const model = options.model ?? resolveEmbeddingModel();
22
+ const model = options.model ?? resolveTakaraEmbeddingModel();
23
23
  const dimensions = options.dimensions ?? resolveEmbeddingDimensions(model);
24
24
  const endpoint = `${baseUrl}/embeddings`;
25
25
 
package/src/setup.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { divider, fail, hint, info, printBrandBanner, success, writeStdout } from "./cli-ui.ts";
2
2
  import {
3
+ beginModeSwitch,
3
4
  clearStoredCredentials,
4
5
  loadStoredCredentials,
5
6
  readStoredCredentials,
@@ -163,6 +164,7 @@ export async function runSageMakerSetup(options: RunSetupOptions = {}): Promise<
163
164
  profile = await promptAwsProfile();
164
165
  }
165
166
 
167
+ await beginModeSwitch("sagemaker");
166
168
  process.env.MIRU_SAGEMAKER_ENDPOINT_ARN = arnInput;
167
169
  process.env.AWS_PROFILE = profile;
168
170
 
@@ -207,14 +209,12 @@ export async function runSetup(options: RunSetupOptions = {}): Promise<RunSetupR
207
209
  const path = resolveCredentialsPath();
208
210
  const stored = await readStoredCredentials();
209
211
  if (stored?.sagemaker) {
210
- const apiKey = resolveEmbeddingApiKey();
211
- await saveStoredCredentials(apiKey);
212
- process.env.TAKARA_API_KEY = apiKey;
212
+ const saved = await saveStoredCredentials(resolveEmbeddingApiKey());
213
213
  writeStdout("");
214
- success(`Saved credentials to ${path}`);
214
+ success(`Saved credentials to ${saved}`);
215
215
  hint("Removed the stored SageMaker endpoint — Miru now embeds only via Takara.");
216
216
  writeStdout("");
217
- return { path, newlySaved: true };
217
+ return { path: saved, newlySaved: true };
218
218
  }
219
219
  if (stored?.takara_api_key) {
220
220
  info(`API key already configured (env + ${path}). Use --force to replace stored key.`);
@@ -246,6 +246,7 @@ export async function runSetup(options: RunSetupOptions = {}): Promise<RunSetupR
246
246
 
247
247
  const apiKey = options.apiKey ?? (await promptApiKey());
248
248
 
249
+ await beginModeSwitch("takara");
249
250
  if (!options.skipValidation) {
250
251
  const spinner = new Spinner("Validating API key");
251
252
  spinner.start();
@@ -259,7 +260,6 @@ export async function runSetup(options: RunSetupOptions = {}): Promise<RunSetupR
259
260
 
260
261
  const hadSageMaker = Boolean((await readStoredCredentials())?.sagemaker);
261
262
  const path = await saveStoredCredentials(apiKey);
262
- process.env.TAKARA_API_KEY = apiKey;
263
263
  writeStdout("");
264
264
  success(`Saved credentials to ${path}`);
265
265
  if (hadSageMaker) {