@nebutra/sandbox-runtime 0.1.0 → 0.1.1
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/.nebutra/debug/sandbox-runtime.jsonl +1 -1
- package/.turbo/turbo-build.log +4 -4
- package/.turbo/turbo-test.log +4 -4
- package/.turbo/turbo-typecheck.log +1 -1
- package/CHANGELOG.md +11 -0
- package/dist/{chunk-UGJKHUL3.js → chunk-5TXS6ZSQ.js} +9 -16
- package/dist/chunk-5TXS6ZSQ.js.map +1 -0
- package/dist/cli.js +1 -1
- package/dist/index.js +1 -1
- package/package.json +4 -2
- package/src/index.ts +8 -19
- package/dist/chunk-UGJKHUL3.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"at":"2026-05-
|
|
1
|
+
{"at":"2026-05-19T08:15:00.536Z","type":"exec","provider":"local_mac","command":"echo sandbox ok","result":{"exitCode":0,"aggregatedOutput":"sandbox ok\n","executedOn":"local_mac"}}
|
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
> @nebutra/sandbox-runtime@0.1.
|
|
2
|
+
> @nebutra/sandbox-runtime@0.1.1 build /home/runner/work/Nebutra-Sailor/Nebutra-Sailor/packages/ai/sandbox-runtime
|
|
3
3
|
> tsup
|
|
4
4
|
|
|
5
5
|
[34mCLI[39m Building entry: src/cli.ts, src/index.ts
|
|
@@ -11,12 +11,12 @@
|
|
|
11
11
|
[34mESM[39m Build start
|
|
12
12
|
[32mESM[39m [1mdist/cli.js [22m[32m882.00 B[39m
|
|
13
13
|
[32mESM[39m [1mdist/index.js [22m[32m302.00 B[39m
|
|
14
|
-
[32mESM[39m [1mdist/chunk-
|
|
14
|
+
[32mESM[39m [1mdist/chunk-5TXS6ZSQ.js [22m[32m4.66 KB[39m
|
|
15
15
|
[32mESM[39m [1mdist/cli.js.map [22m[32m1.56 KB[39m
|
|
16
16
|
[32mESM[39m [1mdist/index.js.map [22m[32m71.00 B[39m
|
|
17
|
-
[32mESM[39m [1mdist/chunk-
|
|
17
|
+
[32mESM[39m [1mdist/chunk-5TXS6ZSQ.js.map [22m[32m9.32 KB[39m
|
|
18
18
|
[32mESM[39m ⚡️ Build success in 81ms
|
|
19
19
|
[34mDTS[39m Build start
|
|
20
|
-
[32mDTS[39m ⚡️ Build success in
|
|
20
|
+
[32mDTS[39m ⚡️ Build success in 10574ms
|
|
21
21
|
[32mDTS[39m [1mdist/cli.d.ts [22m[32m13.00 B[39m
|
|
22
22
|
[32mDTS[39m [1mdist/index.d.ts [22m[32m1.83 KB[39m
|
package/.turbo/turbo-test.log
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
|
|
2
|
-
> @nebutra/sandbox-runtime@0.1.
|
|
2
|
+
> @nebutra/sandbox-runtime@0.1.1 test /home/runner/work/Nebutra-Sailor/Nebutra-Sailor/packages/ai/sandbox-runtime
|
|
3
3
|
> vitest run
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
[1m[30m[46m RUN [49m[39m[22m [36mv4.1.4 [39m[90m/home/runner/work/Nebutra-Sailor/Nebutra-Sailor/packages/ai/sandbox-runtime[39m
|
|
7
7
|
|
|
8
|
-
[32m✓[39m src/index.test.ts [2m([22m[2m2 tests[22m[2m)[22m[32m
|
|
8
|
+
[32m✓[39m src/index.test.ts [2m([22m[2m2 tests[22m[2m)[22m[32m 263[2mms[22m[39m
|
|
9
9
|
|
|
10
10
|
[2m Test Files [22m [1m[32m1 passed[39m[22m[90m (1)[39m
|
|
11
11
|
[2m Tests [22m [1m[32m2 passed[39m[22m[90m (2)[39m
|
|
12
|
-
[2m Start at [22m
|
|
13
|
-
[2m Duration [22m 1.
|
|
12
|
+
[2m Start at [22m 08:14:59
|
|
13
|
+
[2m Duration [22m 1.35s[2m (transform 376ms, setup 0ms, import 442ms, tests 263ms, environment 0ms)[22m
|
|
14
14
|
|
package/CHANGELOG.md
ADDED
|
@@ -1,17 +1,15 @@
|
|
|
1
1
|
// src/index.ts
|
|
2
|
-
import {
|
|
3
|
-
|
|
2
|
+
import {
|
|
3
|
+
appendCapabilityDebug,
|
|
4
|
+
capabilityDebugPath,
|
|
5
|
+
readCapabilityDebug
|
|
6
|
+
} from "@nebutra/capability-kit/debug";
|
|
4
7
|
import { CapabilityError } from "@nebutra/errors";
|
|
5
8
|
function sandboxDebugPath() {
|
|
6
|
-
return
|
|
9
|
+
return capabilityDebugPath("sandbox-runtime");
|
|
7
10
|
}
|
|
8
11
|
async function appendSandboxDebug(entry) {
|
|
9
|
-
|
|
10
|
-
await mkdir(dirname(path), { recursive: true });
|
|
11
|
-
await writeFile(path, `${JSON.stringify({ at: (/* @__PURE__ */ new Date()).toISOString(), ...entry })}
|
|
12
|
-
`, {
|
|
13
|
-
flag: "a"
|
|
14
|
-
});
|
|
12
|
+
await appendCapabilityDebug("sandbox-runtime", entry);
|
|
15
13
|
}
|
|
16
14
|
function createLocalMacSandbox(options = {}) {
|
|
17
15
|
const endpoint = options.endpoint ?? process.env.SANDBOX_RUNTIME_LOCAL_URL ?? "http://127.0.0.1:8020/api/v1/sandbox/exec";
|
|
@@ -133,12 +131,7 @@ var SandboxRuntime = class _SandboxRuntime {
|
|
|
133
131
|
}
|
|
134
132
|
};
|
|
135
133
|
async function readSandboxDebug(limit = 10) {
|
|
136
|
-
|
|
137
|
-
const raw = await readFile(sandboxDebugPath(), "utf8");
|
|
138
|
-
return raw.trim().split("\n").filter(Boolean).slice(-limit).map((line) => JSON.parse(line));
|
|
139
|
-
} catch {
|
|
140
|
-
return [];
|
|
141
|
-
}
|
|
134
|
+
return readCapabilityDebug("sandbox-runtime", { limit });
|
|
142
135
|
}
|
|
143
136
|
|
|
144
137
|
export {
|
|
@@ -148,4 +141,4 @@ export {
|
|
|
148
141
|
SandboxRuntime,
|
|
149
142
|
readSandboxDebug
|
|
150
143
|
};
|
|
151
|
-
//# sourceMappingURL=chunk-
|
|
144
|
+
//# sourceMappingURL=chunk-5TXS6ZSQ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import {\n appendCapabilityDebug,\n capabilityDebugPath,\n readCapabilityDebug,\n} from \"@nebutra/capability-kit/debug\";\nimport { CapabilityError } from \"@nebutra/errors\";\n\nexport interface ExecHints {\n readonly durationS?: number;\n readonly needsGpu?: boolean;\n readonly networkAccess?: boolean;\n}\n\nexport interface ExecRequest {\n readonly cmd: string;\n readonly filesIn?: Record<string, string>;\n readonly hints?: ExecHints;\n readonly tenantId?: string;\n readonly threadId?: string;\n}\n\nexport interface ExecResponse {\n readonly exitCode: number;\n readonly aggregatedOutput: string;\n readonly executedOn: string;\n}\n\nexport interface SandboxHealth {\n readonly provider: string;\n readonly ok: boolean;\n readonly suggestion?: string;\n}\n\nexport interface Sandbox {\n readonly id: string;\n exec(request: ExecRequest): Promise<ExecResponse>;\n doctor(): Promise<SandboxHealth>;\n}\n\nexport interface RouteRule {\n readonly when: Partial<ExecHints>;\n readonly provider: string;\n}\n\nexport interface SandboxRuntimeConfig {\n readonly providers?: readonly Sandbox[];\n readonly routes?: readonly RouteRule[];\n}\n\nexport function sandboxDebugPath(): string {\n return capabilityDebugPath(\"sandbox-runtime\");\n}\n\nasync function appendSandboxDebug(entry: Record<string, unknown>): Promise<void> {\n await appendCapabilityDebug(\"sandbox-runtime\", entry);\n}\n\nexport function createLocalMacSandbox(\n options: { endpoint?: string; fetch?: typeof fetch } = {},\n): Sandbox {\n const endpoint =\n options.endpoint ??\n process.env.SANDBOX_RUNTIME_LOCAL_URL ??\n \"http://127.0.0.1:8020/api/v1/sandbox/exec\";\n const fetchImpl = options.fetch ?? fetch;\n return {\n id: \"local_mac\",\n async exec(request) {\n const response = await fetchImpl(endpoint, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify({\n tenantId: request.tenantId ?? \"local\",\n threadId: request.threadId ?? \"local\",\n command: request.cmd,\n capabilityPolicy: {\n kind: \"external_sandbox\",\n network_access: request.hints?.networkAccess ?? false,\n },\n }),\n });\n if (!response.ok) {\n const detail = await response.text().catch(() => \"\");\n throw new CapabilityError(\n \"sandbox-runtime\",\n `Local sandbox refused execution (${response.status})`,\n {\n suggestion:\n \"Start the Rust sandbox service or route this task to a configured remote provider.\",\n metadata: { detail },\n statusCode: response.status,\n },\n );\n }\n const result = (await response.json()) as ExecResponse;\n await appendSandboxDebug({\n type: \"exec\",\n provider: \"local_mac\",\n command: request.cmd,\n result,\n });\n return result;\n },\n async doctor() {\n try {\n const result = await this.exec({ cmd: \"echo sandbox ok\" });\n return { provider: \"local_mac\", ok: result.exitCode === 0 };\n } catch (error) {\n return {\n provider: \"local_mac\",\n ok: false,\n suggestion:\n error instanceof Error ? error.message : \"Check local sandbox service reachability.\",\n };\n }\n },\n };\n}\n\nexport function createRemotePlaceholder(\n id: \"remote_code\" | \"remote_gpu\" | \"remote_workspace\",\n envKey: string,\n): Sandbox {\n return {\n id,\n async exec() {\n throw new CapabilityError(\"sandbox-runtime\", `${id} adapter is not configured`, {\n suggestion: `Set ${envKey} and wire the provider SDK before routing tasks to ${id}.`,\n statusCode: 503,\n });\n },\n async doctor() {\n return process.env[envKey]\n ? { provider: id, ok: true }\n : { provider: id, ok: false, suggestion: `Set ${envKey} to enable ${id}.` };\n },\n };\n}\n\nexport class SandboxRuntime {\n readonly #providers = new Map<string, Sandbox>();\n readonly #routes: readonly RouteRule[];\n\n constructor(config: SandboxRuntimeConfig = {}) {\n for (const provider of config.providers ?? [\n createLocalMacSandbox(),\n createRemotePlaceholder(\"remote_code\", \"SANDBOX_REMOTE_CODE_TOKEN\"),\n createRemotePlaceholder(\"remote_gpu\", \"SANDBOX_REMOTE_GPU_TOKEN\"),\n createRemotePlaceholder(\"remote_workspace\", \"SANDBOX_REMOTE_WORKSPACE_TOKEN\"),\n ]) {\n this.#providers.set(provider.id, provider);\n }\n this.#routes = config.routes ?? [\n { when: { needsGpu: true }, provider: \"remote_gpu\" },\n { when: { durationS: 30 }, provider: \"remote_code\" },\n { when: { needsGpu: false }, provider: \"local_mac\" },\n ];\n }\n\n static fromConfig(config: SandboxRuntimeConfig = {}): SandboxRuntime {\n return new SandboxRuntime(config);\n }\n\n plan(request: ExecRequest): { provider: string; reason: string } {\n const hints = request.hints ?? {};\n for (const rule of this.#routes) {\n const matches = Object.entries(rule.when).every(\n ([key, value]) => hints[key as keyof ExecHints] === value,\n );\n if (matches && this.#providers.has(rule.provider)) {\n return { provider: rule.provider, reason: \"matched static routing rule\" };\n }\n }\n return {\n provider: this.#providers.has(\"local_mac\")\n ? \"local_mac\"\n : (Array.from(this.#providers.keys())[0] ?? \"\"),\n reason: \"default route\",\n };\n }\n\n async exec(request: ExecRequest): Promise<ExecResponse> {\n const plan = this.plan(request);\n const provider = this.#providers.get(plan.provider);\n if (!provider) {\n throw new CapabilityError(\"sandbox-runtime\", \"No sandbox provider available\", {\n suggestion: \"Configure at least one sandbox provider before executing commands.\",\n metadata: plan,\n });\n }\n return provider.exec(request);\n }\n\n async doctor(): Promise<SandboxHealth[]> {\n return Promise.all(Array.from(this.#providers.values()).map((provider) => provider.doctor()));\n }\n}\n\nexport async function readSandboxDebug(limit = 10): Promise<unknown[]> {\n return readCapabilityDebug(\"sandbox-runtime\", { limit });\n}\n"],"mappings":"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","names":[]}
|
package/dist/cli.js
CHANGED
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nebutra/sandbox-runtime",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "Unified sandbox runtime router for local and remote execution providers",
|
|
5
5
|
"private": false,
|
|
6
6
|
"license": "MIT",
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
"nebutra": {
|
|
9
9
|
"featureId": "sandbox-runtime",
|
|
10
10
|
"category": "ai",
|
|
11
|
+
"surface": "execution-router",
|
|
11
12
|
"summary": "Sandbox trait, provider router, doctor, and debug tools"
|
|
12
13
|
},
|
|
13
14
|
"main": "./src/index.ts",
|
|
@@ -16,7 +17,8 @@
|
|
|
16
17
|
".": "./src/index.ts"
|
|
17
18
|
},
|
|
18
19
|
"dependencies": {
|
|
19
|
-
"@nebutra/
|
|
20
|
+
"@nebutra/capability-kit": "0.2.1",
|
|
21
|
+
"@nebutra/errors": "0.1.1"
|
|
20
22
|
},
|
|
21
23
|
"devDependencies": {
|
|
22
24
|
"@types/node": "^22.19.15",
|
package/src/index.ts
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import {
|
|
2
|
+
appendCapabilityDebug,
|
|
3
|
+
capabilityDebugPath,
|
|
4
|
+
readCapabilityDebug,
|
|
5
|
+
} from "@nebutra/capability-kit/debug";
|
|
3
6
|
import { CapabilityError } from "@nebutra/errors";
|
|
4
7
|
|
|
5
8
|
export interface ExecHints {
|
|
@@ -45,15 +48,11 @@ export interface SandboxRuntimeConfig {
|
|
|
45
48
|
}
|
|
46
49
|
|
|
47
50
|
export function sandboxDebugPath(): string {
|
|
48
|
-
return
|
|
51
|
+
return capabilityDebugPath("sandbox-runtime");
|
|
49
52
|
}
|
|
50
53
|
|
|
51
54
|
async function appendSandboxDebug(entry: Record<string, unknown>): Promise<void> {
|
|
52
|
-
|
|
53
|
-
await mkdir(dirname(path), { recursive: true });
|
|
54
|
-
await writeFile(path, `${JSON.stringify({ at: new Date().toISOString(), ...entry })}\n`, {
|
|
55
|
-
flag: "a",
|
|
56
|
-
});
|
|
55
|
+
await appendCapabilityDebug("sandbox-runtime", entry);
|
|
57
56
|
}
|
|
58
57
|
|
|
59
58
|
export function createLocalMacSandbox(
|
|
@@ -198,15 +197,5 @@ export class SandboxRuntime {
|
|
|
198
197
|
}
|
|
199
198
|
|
|
200
199
|
export async function readSandboxDebug(limit = 10): Promise<unknown[]> {
|
|
201
|
-
|
|
202
|
-
const raw = await readFile(sandboxDebugPath(), "utf8");
|
|
203
|
-
return raw
|
|
204
|
-
.trim()
|
|
205
|
-
.split("\n")
|
|
206
|
-
.filter(Boolean)
|
|
207
|
-
.slice(-limit)
|
|
208
|
-
.map((line) => JSON.parse(line) as unknown);
|
|
209
|
-
} catch {
|
|
210
|
-
return [];
|
|
211
|
-
}
|
|
200
|
+
return readCapabilityDebug("sandbox-runtime", { limit });
|
|
212
201
|
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport { dirname, join } from \"node:path\";\nimport { CapabilityError } from \"@nebutra/errors\";\n\nexport interface ExecHints {\n readonly durationS?: number;\n readonly needsGpu?: boolean;\n readonly networkAccess?: boolean;\n}\n\nexport interface ExecRequest {\n readonly cmd: string;\n readonly filesIn?: Record<string, string>;\n readonly hints?: ExecHints;\n readonly tenantId?: string;\n readonly threadId?: string;\n}\n\nexport interface ExecResponse {\n readonly exitCode: number;\n readonly aggregatedOutput: string;\n readonly executedOn: string;\n}\n\nexport interface SandboxHealth {\n readonly provider: string;\n readonly ok: boolean;\n readonly suggestion?: string;\n}\n\nexport interface Sandbox {\n readonly id: string;\n exec(request: ExecRequest): Promise<ExecResponse>;\n doctor(): Promise<SandboxHealth>;\n}\n\nexport interface RouteRule {\n readonly when: Partial<ExecHints>;\n readonly provider: string;\n}\n\nexport interface SandboxRuntimeConfig {\n readonly providers?: readonly Sandbox[];\n readonly routes?: readonly RouteRule[];\n}\n\nexport function sandboxDebugPath(): string {\n return join(process.cwd(), \".nebutra\", \"debug\", \"sandbox-runtime.jsonl\");\n}\n\nasync function appendSandboxDebug(entry: Record<string, unknown>): Promise<void> {\n const path = sandboxDebugPath();\n await mkdir(dirname(path), { recursive: true });\n await writeFile(path, `${JSON.stringify({ at: new Date().toISOString(), ...entry })}\\n`, {\n flag: \"a\",\n });\n}\n\nexport function createLocalMacSandbox(\n options: { endpoint?: string; fetch?: typeof fetch } = {},\n): Sandbox {\n const endpoint =\n options.endpoint ??\n process.env.SANDBOX_RUNTIME_LOCAL_URL ??\n \"http://127.0.0.1:8020/api/v1/sandbox/exec\";\n const fetchImpl = options.fetch ?? fetch;\n return {\n id: \"local_mac\",\n async exec(request) {\n const response = await fetchImpl(endpoint, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify({\n tenantId: request.tenantId ?? \"local\",\n threadId: request.threadId ?? \"local\",\n command: request.cmd,\n capabilityPolicy: {\n kind: \"external_sandbox\",\n network_access: request.hints?.networkAccess ?? false,\n },\n }),\n });\n if (!response.ok) {\n const detail = await response.text().catch(() => \"\");\n throw new CapabilityError(\n \"sandbox-runtime\",\n `Local sandbox refused execution (${response.status})`,\n {\n suggestion:\n \"Start the Rust sandbox service or route this task to a configured remote provider.\",\n metadata: { detail },\n statusCode: response.status,\n },\n );\n }\n const result = (await response.json()) as ExecResponse;\n await appendSandboxDebug({\n type: \"exec\",\n provider: \"local_mac\",\n command: request.cmd,\n result,\n });\n return result;\n },\n async doctor() {\n try {\n const result = await this.exec({ cmd: \"echo sandbox ok\" });\n return { provider: \"local_mac\", ok: result.exitCode === 0 };\n } catch (error) {\n return {\n provider: \"local_mac\",\n ok: false,\n suggestion:\n error instanceof Error ? error.message : \"Check local sandbox service reachability.\",\n };\n }\n },\n };\n}\n\nexport function createRemotePlaceholder(\n id: \"remote_code\" | \"remote_gpu\" | \"remote_workspace\",\n envKey: string,\n): Sandbox {\n return {\n id,\n async exec() {\n throw new CapabilityError(\"sandbox-runtime\", `${id} adapter is not configured`, {\n suggestion: `Set ${envKey} and wire the provider SDK before routing tasks to ${id}.`,\n statusCode: 503,\n });\n },\n async doctor() {\n return process.env[envKey]\n ? { provider: id, ok: true }\n : { provider: id, ok: false, suggestion: `Set ${envKey} to enable ${id}.` };\n },\n };\n}\n\nexport class SandboxRuntime {\n readonly #providers = new Map<string, Sandbox>();\n readonly #routes: readonly RouteRule[];\n\n constructor(config: SandboxRuntimeConfig = {}) {\n for (const provider of config.providers ?? [\n createLocalMacSandbox(),\n createRemotePlaceholder(\"remote_code\", \"SANDBOX_REMOTE_CODE_TOKEN\"),\n createRemotePlaceholder(\"remote_gpu\", \"SANDBOX_REMOTE_GPU_TOKEN\"),\n createRemotePlaceholder(\"remote_workspace\", \"SANDBOX_REMOTE_WORKSPACE_TOKEN\"),\n ]) {\n this.#providers.set(provider.id, provider);\n }\n this.#routes = config.routes ?? [\n { when: { needsGpu: true }, provider: \"remote_gpu\" },\n { when: { durationS: 30 }, provider: \"remote_code\" },\n { when: { needsGpu: false }, provider: \"local_mac\" },\n ];\n }\n\n static fromConfig(config: SandboxRuntimeConfig = {}): SandboxRuntime {\n return new SandboxRuntime(config);\n }\n\n plan(request: ExecRequest): { provider: string; reason: string } {\n const hints = request.hints ?? {};\n for (const rule of this.#routes) {\n const matches = Object.entries(rule.when).every(\n ([key, value]) => hints[key as keyof ExecHints] === value,\n );\n if (matches && this.#providers.has(rule.provider)) {\n return { provider: rule.provider, reason: \"matched static routing rule\" };\n }\n }\n return {\n provider: this.#providers.has(\"local_mac\")\n ? \"local_mac\"\n : (Array.from(this.#providers.keys())[0] ?? \"\"),\n reason: \"default route\",\n };\n }\n\n async exec(request: ExecRequest): Promise<ExecResponse> {\n const plan = this.plan(request);\n const provider = this.#providers.get(plan.provider);\n if (!provider) {\n throw new CapabilityError(\"sandbox-runtime\", \"No sandbox provider available\", {\n suggestion: \"Configure at least one sandbox provider before executing commands.\",\n metadata: plan,\n });\n }\n return provider.exec(request);\n }\n\n async doctor(): Promise<SandboxHealth[]> {\n return Promise.all(Array.from(this.#providers.values()).map((provider) => provider.doctor()));\n }\n}\n\nexport async function readSandboxDebug(limit = 10): Promise<unknown[]> {\n try {\n const raw = await readFile(sandboxDebugPath(), \"utf8\");\n return raw\n .trim()\n .split(\"\\n\")\n .filter(Boolean)\n .slice(-limit)\n .map((line) => JSON.parse(line) as unknown);\n } catch {\n return [];\n }\n}\n"],"mappings":"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","names":[]}
|