@kalera/munin-runtime 1.2.6 → 1.2.8
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/.turbo/turbo-build.log +1 -1
- package/dist/env.d.ts +2 -22
- package/dist/env.js +2 -138
- package/dist/index.js +2 -2
- package/package.json +2 -2
- package/src/env.ts +11 -157
- package/src/index.ts +4 -4
package/.turbo/turbo-build.log
CHANGED
package/dist/env.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
export { parseCliArgs, loadCliEnv, resolveProjectId, executeWithRetry, safeError, } from "./index.js";
|
|
2
|
+
export type { ParsedCliArgs, CliEnv } from "./index.js";
|
|
1
3
|
export interface EnvVar {
|
|
2
4
|
key: string;
|
|
3
5
|
value: string;
|
|
@@ -13,25 +15,3 @@ export declare function resolveEncryptionKey(): string | undefined;
|
|
|
13
15
|
* - Keys are matched via string split (not regex) to prevent injection.
|
|
14
16
|
*/
|
|
15
17
|
export declare function writeEnvFile(filename: string, vars: EnvVar[], cwd?: string): void;
|
|
16
|
-
/**
|
|
17
|
-
* Resolve MUNIN_PROJECT from multiple sources, in priority order:
|
|
18
|
-
* 1. Explicit environment variable
|
|
19
|
-
* 2. .env.local in any ancestor directory (walk-up from CWD)
|
|
20
|
-
* 3. .env in any ancestor directory (walk-up from CWD)
|
|
21
|
-
*/
|
|
22
|
-
export declare function resolveProjectId(): string | undefined;
|
|
23
|
-
export interface CliEnv {
|
|
24
|
-
baseUrl: string;
|
|
25
|
-
apiKey: string | undefined;
|
|
26
|
-
timeoutMs: number;
|
|
27
|
-
retries: number;
|
|
28
|
-
backoffMs: number;
|
|
29
|
-
}
|
|
30
|
-
export declare function loadCliEnv(): CliEnv;
|
|
31
|
-
export declare function executeWithRetry<T>(task: () => Promise<T>, retries: number, backoffMs: number): Promise<T>;
|
|
32
|
-
export declare function safeError(error: unknown): Record<string, unknown>;
|
|
33
|
-
export declare function parseCliArgs(argv: string[], usage: string): {
|
|
34
|
-
action: string;
|
|
35
|
-
payload: Record<string, unknown>;
|
|
36
|
-
};
|
|
37
|
-
export * from "./mcp-server.js";
|
package/dist/env.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as fs from "fs";
|
|
2
2
|
import * as path from "path";
|
|
3
|
-
|
|
3
|
+
// Re-export all shared utilities from index.ts (single source of truth)
|
|
4
|
+
export { parseCliArgs, loadCliEnv, resolveProjectId, executeWithRetry, safeError, } from "./index.js";
|
|
4
5
|
/**
|
|
5
6
|
* Resolve the encryption key for E2EE projects from MUNIN_ENCRYPTION_KEY env var.
|
|
6
7
|
*/
|
|
@@ -62,140 +63,3 @@ export function writeEnvFile(filename, vars, cwd = process.cwd()) {
|
|
|
62
63
|
}
|
|
63
64
|
fs.writeFileSync(filePath, lines.join("\n"), "utf8");
|
|
64
65
|
}
|
|
65
|
-
/**
|
|
66
|
-
* Safe numeric env parser: returns defaultVal if value is missing or NaN.
|
|
67
|
-
*/
|
|
68
|
-
function safeParseInt(envVal, defaultVal) {
|
|
69
|
-
if (envVal === undefined)
|
|
70
|
-
return defaultVal;
|
|
71
|
-
const parsed = Number(envVal);
|
|
72
|
-
if (isNaN(parsed))
|
|
73
|
-
return defaultVal;
|
|
74
|
-
return parsed;
|
|
75
|
-
}
|
|
76
|
-
/**
|
|
77
|
-
* Walk up the directory tree from `startDir` (default CWD) toward root,
|
|
78
|
-
* searching each ancestor for `filename`. Returns the value of the first match.
|
|
79
|
-
* Stops at filesystem root or when a `.git` dir is found (project boundary).
|
|
80
|
-
*/
|
|
81
|
-
function resolveEnvFileUpward(filename, startDir) {
|
|
82
|
-
let current = startDir ?? process.cwd();
|
|
83
|
-
let last = "";
|
|
84
|
-
while (current !== last) {
|
|
85
|
-
last = current;
|
|
86
|
-
const filePath = path.join(current, filename);
|
|
87
|
-
try {
|
|
88
|
-
if (fs.existsSync(filePath)) {
|
|
89
|
-
const content = fs.readFileSync(filePath, "utf8");
|
|
90
|
-
for (const line of content.split("\n")) {
|
|
91
|
-
const trimmed = line.trim();
|
|
92
|
-
if (!trimmed.startsWith("MUNIN_PROJECT="))
|
|
93
|
-
continue;
|
|
94
|
-
return trimmed.slice("MUNIN_PROJECT=".length).trim();
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
catch (error) {
|
|
99
|
-
if (error.code !== "ENOENT") {
|
|
100
|
-
console.error(`[munin-runtime] Failed to read ${filePath}:`, error);
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
// Stop at git root (project boundary)
|
|
104
|
-
if (fs.existsSync(path.join(current, ".git")))
|
|
105
|
-
break;
|
|
106
|
-
current = path.dirname(current);
|
|
107
|
-
}
|
|
108
|
-
return undefined;
|
|
109
|
-
}
|
|
110
|
-
/**
|
|
111
|
-
* Resolve MUNIN_PROJECT from multiple sources, in priority order:
|
|
112
|
-
* 1. Explicit environment variable
|
|
113
|
-
* 2. .env.local in any ancestor directory (walk-up from CWD)
|
|
114
|
-
* 3. .env in any ancestor directory (walk-up from CWD)
|
|
115
|
-
*/
|
|
116
|
-
export function resolveProjectId() {
|
|
117
|
-
// 1. Explicit env var (highest priority)
|
|
118
|
-
if (process.env.MUNIN_PROJECT) {
|
|
119
|
-
return process.env.MUNIN_PROJECT;
|
|
120
|
-
}
|
|
121
|
-
// 2. Walk upward from CWD — find .env.local in any ancestor dir
|
|
122
|
-
const fromLocal = resolveEnvFileUpward(".env.local");
|
|
123
|
-
if (fromLocal)
|
|
124
|
-
return fromLocal;
|
|
125
|
-
// 3. Walk upward from CWD — find .env in any ancestor dir
|
|
126
|
-
const fromEnv = resolveEnvFileUpward(".env");
|
|
127
|
-
if (fromEnv)
|
|
128
|
-
return fromEnv;
|
|
129
|
-
return undefined;
|
|
130
|
-
}
|
|
131
|
-
export function loadCliEnv() {
|
|
132
|
-
return {
|
|
133
|
-
baseUrl: process.env.MUNIN_BASE_URL || "https://munin.kalera.dev",
|
|
134
|
-
apiKey: process.env.MUNIN_API_KEY,
|
|
135
|
-
timeoutMs: safeParseInt(process.env.MUNIN_TIMEOUT_MS, 15_000),
|
|
136
|
-
retries: safeParseInt(process.env.MUNIN_RETRIES, 3),
|
|
137
|
-
backoffMs: safeParseInt(process.env.MUNIN_BACKOFF_MS, 300),
|
|
138
|
-
};
|
|
139
|
-
}
|
|
140
|
-
export async function executeWithRetry(task, retries, backoffMs) {
|
|
141
|
-
let attempt = 0;
|
|
142
|
-
let lastError;
|
|
143
|
-
while (attempt < retries) {
|
|
144
|
-
try {
|
|
145
|
-
return await task();
|
|
146
|
-
}
|
|
147
|
-
catch (error) {
|
|
148
|
-
lastError = error;
|
|
149
|
-
attempt += 1;
|
|
150
|
-
if (attempt >= retries)
|
|
151
|
-
break;
|
|
152
|
-
const jitter = Math.floor(Math.random() * 100);
|
|
153
|
-
await sleep(backoffMs * 2 ** attempt + jitter);
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
throw lastError;
|
|
157
|
-
}
|
|
158
|
-
export function safeError(error) {
|
|
159
|
-
if (error instanceof Error) {
|
|
160
|
-
return {
|
|
161
|
-
name: error.name,
|
|
162
|
-
message: redactText(error.message),
|
|
163
|
-
};
|
|
164
|
-
}
|
|
165
|
-
return { message: redactText(String(error)) };
|
|
166
|
-
}
|
|
167
|
-
function redactText(text) {
|
|
168
|
-
return REDACT_KEYS.reduce((acc, key) => {
|
|
169
|
-
// Replace key=value patterns with key=[REDACTED] using simple string split
|
|
170
|
-
let result = acc;
|
|
171
|
-
let idx = result.indexOf(`${key}=`);
|
|
172
|
-
while (idx !== -1) {
|
|
173
|
-
const endIdx = result.indexOf(/[\s,;]/.test(result[idx + key.length + 1] ?? "")
|
|
174
|
-
? result[idx + key.length + 1]
|
|
175
|
-
: "");
|
|
176
|
-
const end = endIdx === -1 ? result.length : endIdx;
|
|
177
|
-
const before = result.slice(0, idx + key.length + 1);
|
|
178
|
-
const after = result.slice(end);
|
|
179
|
-
result = `${before}[REDACTED]${after}`;
|
|
180
|
-
idx = result.indexOf(`${key}=`, idx + key.length + 1);
|
|
181
|
-
}
|
|
182
|
-
return result;
|
|
183
|
-
}, text);
|
|
184
|
-
}
|
|
185
|
-
function sleep(ms) {
|
|
186
|
-
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
187
|
-
}
|
|
188
|
-
export function parseCliArgs(argv, usage) {
|
|
189
|
-
const [action, payloadRaw] = argv;
|
|
190
|
-
if (!action)
|
|
191
|
-
throw new Error(usage);
|
|
192
|
-
if (!payloadRaw)
|
|
193
|
-
return { action, payload: {} };
|
|
194
|
-
try {
|
|
195
|
-
return { action, payload: JSON.parse(payloadRaw) };
|
|
196
|
-
}
|
|
197
|
-
catch {
|
|
198
|
-
throw new Error("Payload must be valid JSON");
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
export * from "./mcp-server.js";
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
1
3
|
const REDACT_KEYS = ["apiKey", "authorization", "token", "secret", "password"];
|
|
2
4
|
export function parseCliArgs(argv, usage) {
|
|
3
5
|
const [action, payloadRaw] = argv;
|
|
@@ -38,8 +40,6 @@ function safeParseInt(envVal, defaultVal) {
|
|
|
38
40
|
* Stops at filesystem root or when a `.git` dir is found (project boundary).
|
|
39
41
|
*/
|
|
40
42
|
function resolveEnvFileUpward(filename, startDir) {
|
|
41
|
-
const fs = require("fs");
|
|
42
|
-
const path = require("path");
|
|
43
43
|
let current = startDir ?? process.cwd();
|
|
44
44
|
let last = "";
|
|
45
45
|
while (current !== last) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kalera/munin-runtime",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.8",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
},
|
|
13
13
|
"dependencies": {
|
|
14
14
|
"@modelcontextprotocol/sdk": "^1.27.1",
|
|
15
|
-
"@kalera/munin-sdk": "1.2.
|
|
15
|
+
"@kalera/munin-sdk": "1.2.8"
|
|
16
16
|
},
|
|
17
17
|
"scripts": {
|
|
18
18
|
"build": "tsc -p tsconfig.json",
|
package/src/env.ts
CHANGED
|
@@ -1,13 +1,22 @@
|
|
|
1
1
|
import * as fs from "fs";
|
|
2
2
|
import * as path from "path";
|
|
3
3
|
|
|
4
|
+
// Re-export all shared utilities from index.ts (single source of truth)
|
|
5
|
+
export {
|
|
6
|
+
parseCliArgs,
|
|
7
|
+
loadCliEnv,
|
|
8
|
+
resolveProjectId,
|
|
9
|
+
executeWithRetry,
|
|
10
|
+
safeError,
|
|
11
|
+
} from "./index.js";
|
|
12
|
+
|
|
13
|
+
export type { ParsedCliArgs, CliEnv } from "./index.js";
|
|
14
|
+
|
|
4
15
|
export interface EnvVar {
|
|
5
16
|
key: string;
|
|
6
17
|
value: string;
|
|
7
18
|
}
|
|
8
19
|
|
|
9
|
-
const REDACT_KEYS = ["apiKey", "authorization", "token", "secret", "password"];
|
|
10
|
-
|
|
11
20
|
/**
|
|
12
21
|
* Resolve the encryption key for E2EE projects from MUNIN_ENCRYPTION_KEY env var.
|
|
13
22
|
*/
|
|
@@ -79,158 +88,3 @@ export function writeEnvFile(
|
|
|
79
88
|
|
|
80
89
|
fs.writeFileSync(filePath, lines.join("\n"), "utf8");
|
|
81
90
|
}
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* Safe numeric env parser: returns defaultVal if value is missing or NaN.
|
|
85
|
-
*/
|
|
86
|
-
function safeParseInt(envVal: string | undefined, defaultVal: number): number {
|
|
87
|
-
if (envVal === undefined) return defaultVal;
|
|
88
|
-
const parsed = Number(envVal);
|
|
89
|
-
if (isNaN(parsed)) return defaultVal;
|
|
90
|
-
return parsed;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
/**
|
|
94
|
-
* Walk up the directory tree from `startDir` (default CWD) toward root,
|
|
95
|
-
* searching each ancestor for `filename`. Returns the value of the first match.
|
|
96
|
-
* Stops at filesystem root or when a `.git` dir is found (project boundary).
|
|
97
|
-
*/
|
|
98
|
-
function resolveEnvFileUpward(filename: string, startDir?: string): string | undefined {
|
|
99
|
-
let current = startDir ?? process.cwd();
|
|
100
|
-
let last = "";
|
|
101
|
-
|
|
102
|
-
while (current !== last) {
|
|
103
|
-
last = current;
|
|
104
|
-
const filePath = path.join(current, filename);
|
|
105
|
-
try {
|
|
106
|
-
if (fs.existsSync(filePath)) {
|
|
107
|
-
const content = fs.readFileSync(filePath, "utf8");
|
|
108
|
-
for (const line of content.split("\n")) {
|
|
109
|
-
const trimmed = line.trim();
|
|
110
|
-
if (!trimmed.startsWith("MUNIN_PROJECT=")) continue;
|
|
111
|
-
return trimmed.slice("MUNIN_PROJECT=".length).trim();
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
} catch (error) {
|
|
115
|
-
if ((error as NodeJS.ErrnoException).code !== "ENOENT") {
|
|
116
|
-
console.error(`[munin-runtime] Failed to read ${filePath}:`, error);
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
// Stop at git root (project boundary)
|
|
121
|
-
if (fs.existsSync(path.join(current, ".git"))) break;
|
|
122
|
-
|
|
123
|
-
current = path.dirname(current);
|
|
124
|
-
}
|
|
125
|
-
return undefined;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
/**
|
|
129
|
-
* Resolve MUNIN_PROJECT from multiple sources, in priority order:
|
|
130
|
-
* 1. Explicit environment variable
|
|
131
|
-
* 2. .env.local in any ancestor directory (walk-up from CWD)
|
|
132
|
-
* 3. .env in any ancestor directory (walk-up from CWD)
|
|
133
|
-
*/
|
|
134
|
-
export function resolveProjectId(): string | undefined {
|
|
135
|
-
// 1. Explicit env var (highest priority)
|
|
136
|
-
if (process.env.MUNIN_PROJECT) {
|
|
137
|
-
return process.env.MUNIN_PROJECT;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
// 2. Walk upward from CWD — find .env.local in any ancestor dir
|
|
141
|
-
const fromLocal = resolveEnvFileUpward(".env.local");
|
|
142
|
-
if (fromLocal) return fromLocal;
|
|
143
|
-
|
|
144
|
-
// 3. Walk upward from CWD — find .env in any ancestor dir
|
|
145
|
-
const fromEnv = resolveEnvFileUpward(".env");
|
|
146
|
-
if (fromEnv) return fromEnv;
|
|
147
|
-
|
|
148
|
-
return undefined;
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
export interface CliEnv {
|
|
152
|
-
baseUrl: string;
|
|
153
|
-
apiKey: string | undefined;
|
|
154
|
-
timeoutMs: number;
|
|
155
|
-
retries: number;
|
|
156
|
-
backoffMs: number;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
export function loadCliEnv(): CliEnv {
|
|
160
|
-
return {
|
|
161
|
-
baseUrl: process.env.MUNIN_BASE_URL || "https://munin.kalera.dev",
|
|
162
|
-
apiKey: process.env.MUNIN_API_KEY,
|
|
163
|
-
timeoutMs: safeParseInt(process.env.MUNIN_TIMEOUT_MS, 15_000),
|
|
164
|
-
retries: safeParseInt(process.env.MUNIN_RETRIES, 3),
|
|
165
|
-
backoffMs: safeParseInt(process.env.MUNIN_BACKOFF_MS, 300),
|
|
166
|
-
};
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
export async function executeWithRetry<T>(
|
|
170
|
-
task: () => Promise<T>,
|
|
171
|
-
retries: number,
|
|
172
|
-
backoffMs: number,
|
|
173
|
-
): Promise<T> {
|
|
174
|
-
let attempt = 0;
|
|
175
|
-
let lastError: unknown;
|
|
176
|
-
|
|
177
|
-
while (attempt < retries) {
|
|
178
|
-
try {
|
|
179
|
-
return await task();
|
|
180
|
-
} catch (error) {
|
|
181
|
-
lastError = error;
|
|
182
|
-
attempt += 1;
|
|
183
|
-
if (attempt >= retries) break;
|
|
184
|
-
const jitter = Math.floor(Math.random() * 100);
|
|
185
|
-
await sleep(backoffMs * 2 ** attempt + jitter);
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
throw lastError;
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
export function safeError(error: unknown): Record<string, unknown> {
|
|
193
|
-
if (error instanceof Error) {
|
|
194
|
-
return {
|
|
195
|
-
name: error.name,
|
|
196
|
-
message: redactText(error.message),
|
|
197
|
-
};
|
|
198
|
-
}
|
|
199
|
-
return { message: redactText(String(error)) };
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
function redactText(text: string): string {
|
|
203
|
-
return REDACT_KEYS.reduce((acc, key) => {
|
|
204
|
-
// Replace key=value patterns with key=[REDACTED] using simple string split
|
|
205
|
-
let result = acc;
|
|
206
|
-
let idx = result.indexOf(`${key}=`);
|
|
207
|
-
while (idx !== -1) {
|
|
208
|
-
const endIdx = result.indexOf(/[\s,;]/.test(result[idx + key.length + 1] ?? "")
|
|
209
|
-
? result[idx + key.length + 1]
|
|
210
|
-
: "");
|
|
211
|
-
const end = endIdx === -1 ? result.length : endIdx;
|
|
212
|
-
const before = result.slice(0, idx + key.length + 1);
|
|
213
|
-
const after = result.slice(end);
|
|
214
|
-
result = `${before}[REDACTED]${after}`;
|
|
215
|
-
idx = result.indexOf(`${key}=`, idx + key.length + 1);
|
|
216
|
-
}
|
|
217
|
-
return result;
|
|
218
|
-
}, text);
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
function sleep(ms: number): Promise<void> {
|
|
222
|
-
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
export function parseCliArgs(argv: string[], usage: string): { action: string; payload: Record<string, unknown> } {
|
|
226
|
-
const [action, payloadRaw] = argv;
|
|
227
|
-
if (!action) throw new Error(usage);
|
|
228
|
-
if (!payloadRaw) return { action, payload: {} };
|
|
229
|
-
try {
|
|
230
|
-
return { action, payload: JSON.parse(payloadRaw) as Record<string, unknown> };
|
|
231
|
-
} catch {
|
|
232
|
-
throw new Error("Payload must be valid JSON");
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
export * from "./mcp-server.js";
|
package/src/index.ts
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
|
|
1
4
|
export interface ParsedCliArgs {
|
|
2
5
|
action: string;
|
|
3
6
|
payload: Record<string, unknown>;
|
|
@@ -55,9 +58,6 @@ function safeParseInt(envVal: string | undefined, defaultVal: number): number {
|
|
|
55
58
|
* Stops at filesystem root or when a `.git` dir is found (project boundary).
|
|
56
59
|
*/
|
|
57
60
|
function resolveEnvFileUpward(filename: string, startDir?: string): string | undefined {
|
|
58
|
-
const fs = require("fs") as typeof import("fs");
|
|
59
|
-
const path = require("path") as typeof import("path");
|
|
60
|
-
|
|
61
61
|
let current = startDir ?? process.cwd();
|
|
62
62
|
let last = "";
|
|
63
63
|
|
|
@@ -110,7 +110,6 @@ export function resolveProjectId(): string | undefined {
|
|
|
110
110
|
return undefined;
|
|
111
111
|
}
|
|
112
112
|
|
|
113
|
-
|
|
114
113
|
export async function executeWithRetry<T>(
|
|
115
114
|
task: () => Promise<T>,
|
|
116
115
|
retries: number,
|
|
@@ -155,5 +154,6 @@ function redactText(text: string): string {
|
|
|
155
154
|
function sleep(ms: number): Promise<void> {
|
|
156
155
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
157
156
|
}
|
|
157
|
+
|
|
158
158
|
export * from "./mcp-server.js";
|
|
159
159
|
export * from "./env.js";
|