@vibesdotdev/runtime-environment-bun 0.0.0
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/dist/bun-environment.impl.d.ts +71 -0
- package/dist/bun-environment.impl.d.ts.map +1 -0
- package/dist/bun-environment.impl.js +130 -0
- package/dist/bun-environment.impl.js.map +1 -0
- package/dist/bun-loader.impl.d.ts +12 -0
- package/dist/bun-loader.impl.d.ts.map +1 -0
- package/dist/bun-loader.impl.js +96 -0
- package/dist/bun-loader.impl.js.map +1 -0
- package/dist/discovery/discovery.assets.consumer.d.ts +13 -0
- package/dist/discovery/discovery.assets.consumer.d.ts.map +1 -0
- package/dist/discovery/discovery.assets.consumer.js +116 -0
- package/dist/discovery/discovery.assets.consumer.js.map +1 -0
- package/dist/host/host.consumer.d.ts +12 -0
- package/dist/host/host.consumer.d.ts.map +1 -0
- package/dist/host/host.consumer.js +13 -0
- package/dist/host/host.consumer.js.map +1 -0
- package/dist/index.d.ts +49 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +77 -0
- package/dist/index.js.map +1 -0
- package/dist/loaders/fallback-loader.impl.consumer.d.ts +7 -0
- package/dist/loaders/fallback-loader.impl.consumer.d.ts.map +1 -0
- package/dist/loaders/fallback-loader.impl.consumer.js +63 -0
- package/dist/loaders/fallback-loader.impl.consumer.js.map +1 -0
- package/dist/package-plugins/candidates.consumer.d.ts +8 -0
- package/dist/package-plugins/candidates.consumer.d.ts.map +1 -0
- package/dist/package-plugins/candidates.consumer.js +133 -0
- package/dist/package-plugins/candidates.consumer.js.map +1 -0
- package/dist/package-plugins/import-module.consumer.d.ts +14 -0
- package/dist/package-plugins/import-module.consumer.d.ts.map +1 -0
- package/dist/package-plugins/import-module.consumer.js +28 -0
- package/dist/package-plugins/import-module.consumer.js.map +1 -0
- package/dist/package-plugins/index.d.ts +8 -0
- package/dist/package-plugins/index.d.ts.map +1 -0
- package/dist/package-plugins/index.js +8 -0
- package/dist/package-plugins/index.js.map +1 -0
- package/dist/package-plugins/installer.consumer.d.ts +14 -0
- package/dist/package-plugins/installer.consumer.d.ts.map +1 -0
- package/dist/package-plugins/installer.consumer.js +29 -0
- package/dist/package-plugins/installer.consumer.js.map +1 -0
- package/dist/package-plugins/loader.consumer.d.ts +12 -0
- package/dist/package-plugins/loader.consumer.d.ts.map +1 -0
- package/dist/package-plugins/loader.consumer.js +59 -0
- package/dist/package-plugins/loader.consumer.js.map +1 -0
- package/dist/package-plugins/reporting.d.ts +5 -0
- package/dist/package-plugins/reporting.d.ts.map +1 -0
- package/dist/package-plugins/reporting.js +10 -0
- package/dist/package-plugins/reporting.js.map +1 -0
- package/dist/package-plugins/resolve.consumer.d.ts +22 -0
- package/dist/package-plugins/resolve.consumer.d.ts.map +1 -0
- package/dist/package-plugins/resolve.consumer.js +265 -0
- package/dist/package-plugins/resolve.consumer.js.map +1 -0
- package/dist/process-spawn.impl.d.ts +15 -0
- package/dist/process-spawn.impl.d.ts.map +1 -0
- package/dist/process-spawn.impl.js +41 -0
- package/dist/process-spawn.impl.js.map +1 -0
- package/dist/services/runtime-path.impl.d.ts +20 -0
- package/dist/services/runtime-path.impl.d.ts.map +1 -0
- package/dist/services/runtime-path.impl.js +20 -0
- package/dist/services/runtime-path.impl.js.map +1 -0
- package/dist/services/self-spawn.consumer.d.ts +55 -0
- package/dist/services/self-spawn.consumer.d.ts.map +1 -0
- package/dist/services/self-spawn.consumer.js +85 -0
- package/dist/services/self-spawn.consumer.js.map +1 -0
- package/dist/services/workspace-resolve.d.ts +84 -0
- package/dist/services/workspace-resolve.d.ts.map +1 -0
- package/dist/services/workspace-resolve.js +107 -0
- package/dist/services/workspace-resolve.js.map +1 -0
- package/package.json +66 -0
- package/src/bun-environment.impl.ts +179 -0
- package/src/bun-loader.impl.ts +102 -0
- package/src/discovery/discovery.assets.consumer.ts +135 -0
- package/src/host/host.consumer.ts +23 -0
- package/src/index.ts +92 -0
- package/src/loaders/fallback-loader.impl.consumer.ts +57 -0
- package/src/package-plugins/candidates.consumer.ts +133 -0
- package/src/package-plugins/import-module.consumer.ts +27 -0
- package/src/package-plugins/index.ts +8 -0
- package/src/package-plugins/installer.consumer.ts +38 -0
- package/src/package-plugins/loader.consumer.ts +80 -0
- package/src/package-plugins/reporting.ts +13 -0
- package/src/package-plugins/resolve.consumer.ts +292 -0
- package/src/process-spawn.impl.ts +52 -0
- package/src/services/runtime-path.impl.ts +20 -0
- package/src/services/self-spawn.consumer.ts +91 -0
- package/src/services/workspace-resolve.ts +146 -0
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unified Workspace Root Resolution
|
|
3
|
+
*
|
|
4
|
+
* Single source of truth for resolving the workspace root path.
|
|
5
|
+
* This consolidates the various fallback patterns used across the codebase.
|
|
6
|
+
*
|
|
7
|
+
* Priority order (highest to lowest):
|
|
8
|
+
* 1. Explicit override (e.g., MCP request header)
|
|
9
|
+
* 2. Runtime context workspacePath
|
|
10
|
+
* 3. Environment config workspacePath
|
|
11
|
+
* 4. CLI invocation cwd
|
|
12
|
+
* 5. process.cwd() fallback
|
|
13
|
+
*
|
|
14
|
+
* NOTE: This module lives in @vibesdotdev/runtime (not workspace) to avoid
|
|
15
|
+
* a circular dependency between runtime and workspace. The workspace package
|
|
16
|
+
* re-exports from here for backward compatibility.
|
|
17
|
+
*/
|
|
18
|
+
function normalizeCandidate(path) {
|
|
19
|
+
if (typeof path !== 'string')
|
|
20
|
+
return undefined;
|
|
21
|
+
const trimmed = path.trim();
|
|
22
|
+
return trimmed.length > 0 ? trimmed : undefined;
|
|
23
|
+
}
|
|
24
|
+
function readStringField(value, key) {
|
|
25
|
+
if (!value)
|
|
26
|
+
return undefined;
|
|
27
|
+
const candidate = value[key];
|
|
28
|
+
return typeof candidate === 'string' ? candidate : undefined;
|
|
29
|
+
}
|
|
30
|
+
const RESOLUTION_ORDER = [
|
|
31
|
+
'override',
|
|
32
|
+
'runtimeContext',
|
|
33
|
+
'environment',
|
|
34
|
+
'cliCwd',
|
|
35
|
+
'cwd'
|
|
36
|
+
];
|
|
37
|
+
/**
|
|
38
|
+
* Resolve workspace root path from multiple sources with priority fallback.
|
|
39
|
+
*
|
|
40
|
+
* @param sources - Object containing potential workspace path sources
|
|
41
|
+
* @returns The resolved workspace path (never undefined)
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```ts
|
|
45
|
+
* const workspace = resolveWorkspaceRoot({
|
|
46
|
+
* override: request.workspacePath,
|
|
47
|
+
* runtimeContext: context.workspacePath,
|
|
48
|
+
* environment: context.environment?.workspacePath,
|
|
49
|
+
* cliCwd: context.cli?.cwd
|
|
50
|
+
* });
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
export function resolveWorkspaceRoot(sources = {}) {
|
|
54
|
+
const { path } = resolveWorkspaceRootWithSource(sources);
|
|
55
|
+
return path;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Resolve workspace root path with source information for debugging.
|
|
59
|
+
*
|
|
60
|
+
* @param sources - Object containing potential workspace path sources
|
|
61
|
+
* @returns Object with resolved path and source that provided it
|
|
62
|
+
*/
|
|
63
|
+
export function resolveWorkspaceRootWithSource(sources = {}) {
|
|
64
|
+
for (const source of RESOLUTION_ORDER) {
|
|
65
|
+
const path = normalizeCandidate(sources[source]);
|
|
66
|
+
if (path) {
|
|
67
|
+
return { path, source };
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
const fallback = sources.cwd || process.cwd();
|
|
71
|
+
return { path: fallback, source: 'processCwd' };
|
|
72
|
+
}
|
|
73
|
+
// Context Extraction Helpers
|
|
74
|
+
/**
|
|
75
|
+
* Extract workspace sources from a RuntimeContext-like object.
|
|
76
|
+
* Handles the various shapes of context objects in the codebase.
|
|
77
|
+
*
|
|
78
|
+
* @param context - Runtime context object with optional workspace-related fields
|
|
79
|
+
* @param override - Optional explicit override (e.g., from MCP request)
|
|
80
|
+
* @returns WorkspaceSources for use with resolveWorkspaceRoot
|
|
81
|
+
*/
|
|
82
|
+
export function extractWorkspaceSources(context, override) {
|
|
83
|
+
return {
|
|
84
|
+
override: normalizeCandidate(override),
|
|
85
|
+
runtimeContext: normalizeCandidate(context.workspacePath),
|
|
86
|
+
environment: normalizeCandidate(readStringField(context.environment, 'workspacePath')),
|
|
87
|
+
cliCwd: normalizeCandidate(readStringField(context.cli, 'cwd'))
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Convenience function: Extract sources and resolve in one step.
|
|
92
|
+
*
|
|
93
|
+
* @param context - Runtime context object
|
|
94
|
+
* @param override - Optional explicit override
|
|
95
|
+
* @returns Resolved workspace path
|
|
96
|
+
*/
|
|
97
|
+
export function resolveWorkspaceFromContext(context, override) {
|
|
98
|
+
return resolveWorkspaceRoot(extractWorkspaceSources(context, override));
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Resolve the current workspace as an object with rootPath.
|
|
102
|
+
* Convenience wrapper for callers that expect `{ rootPath: string }`.
|
|
103
|
+
*/
|
|
104
|
+
export function resolveCurrentWorkspace() {
|
|
105
|
+
return { rootPath: resolveWorkspaceRoot() };
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=workspace-resolve.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workspace-resolve.js","sourceRoot":"","sources":["../../src/services/workspace-resolve.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAIH,SAAS,kBAAkB,CAAC,IAAwB;IACnD,IAAI,OAAO,IAAI,KAAK,QAAQ;QAAE,OAAO,SAAS,CAAC;IAC/C,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;IAC5B,OAAO,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC;AACjD,CAAC;AAED,SAAS,eAAe,CACvB,KAAgC,EAChC,GAA4B;IAE5B,IAAI,CAAC,KAAK;QAAE,OAAO,SAAS,CAAC;IAC7B,MAAM,SAAS,GAAI,KAA6D,CAAC,GAAG,CAAC,CAAC;IACtF,OAAO,OAAO,SAAS,KAAK,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC;AAC9D,CAAC;AAqBD,MAAM,gBAAgB,GAAkC;IACvD,UAAU;IACV,gBAAgB;IAChB,aAAa;IACb,QAAQ;IACR,KAAK;CACL,CAAC;AAEF;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,oBAAoB,CAAC,UAA4B,EAAE;IAClE,MAAM,EAAE,IAAI,EAAE,GAAG,8BAA8B,CAAC,OAAO,CAAC,CAAC;IACzD,OAAO,IAAI,CAAC;AACb,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,8BAA8B,CAC7C,UAA4B,EAAE;IAE9B,KAAK,MAAM,MAAM,IAAI,gBAAgB,EAAE,CAAC;QACvC,MAAM,IAAI,GAAG,kBAAkB,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;QACjD,IAAI,IAAI,EAAE,CAAC;YACV,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;QACzB,CAAC;IACF,CAAC;IAED,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;IAC9C,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,YAAY,EAAE,CAAC;AACjD,CAAC;AAED,6BAA6B;AAE7B;;;;;;;GAOG;AACH,MAAM,UAAU,uBAAuB,CACtC,OAAmC,EACnC,QAAiB;IAEjB,OAAO;QACN,QAAQ,EAAE,kBAAkB,CAAC,QAAQ,CAAC;QACtC,cAAc,EAAE,kBAAkB,CAAC,OAAO,CAAC,aAAa,CAAC;QACzD,WAAW,EAAE,kBAAkB,CAAC,eAAe,CAAC,OAAO,CAAC,WAAW,EAAE,eAAe,CAAC,CAAC;QACtF,MAAM,EAAE,kBAAkB,CAAC,eAAe,CAAC,OAAO,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;KAC/D,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,2BAA2B,CAC1C,OAAmC,EACnC,QAAiB;IAEjB,OAAO,oBAAoB,CAAC,uBAAuB,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC;AACzE,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,uBAAuB;IACtC,OAAO,EAAE,QAAQ,EAAE,oBAAoB,EAAE,EAAE,CAAC;AAC7C,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@vibesdotdev/runtime-environment-bun",
|
|
3
|
+
"version": "0.0.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"types": "./dist/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"bun": "./src/index.ts",
|
|
11
|
+
"import": "./dist/index.js",
|
|
12
|
+
"default": "./dist/index.js"
|
|
13
|
+
},
|
|
14
|
+
"./loader": {
|
|
15
|
+
"types": "./dist/bun-loader.impl.d.ts",
|
|
16
|
+
"bun": "./src/bun-loader.impl.ts",
|
|
17
|
+
"import": "./dist/bun-loader.impl.js",
|
|
18
|
+
"default": "./dist/bun-loader.impl.js"
|
|
19
|
+
},
|
|
20
|
+
"./loaders/fallback-loader.impl.consumer": {
|
|
21
|
+
"types": "./dist/loaders/fallback-loader.impl.consumer.d.ts",
|
|
22
|
+
"bun": "./src/loaders/fallback-loader.impl.consumer.ts",
|
|
23
|
+
"import": "./dist/loaders/fallback-loader.impl.consumer.js",
|
|
24
|
+
"default": "./dist/loaders/fallback-loader.impl.consumer.js"
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
"dependencies": {
|
|
28
|
+
"@vibesdotdev/runtime": "0.0.1"
|
|
29
|
+
},
|
|
30
|
+
"scripts": {
|
|
31
|
+
"build": "tsc -p tsconfig.json",
|
|
32
|
+
"check": "bun --bun tsc -p tsconfig.json --noEmit"
|
|
33
|
+
},
|
|
34
|
+
"license": "MIT",
|
|
35
|
+
"files": [
|
|
36
|
+
"dist",
|
|
37
|
+
"src",
|
|
38
|
+
"bin",
|
|
39
|
+
"README.md",
|
|
40
|
+
"SPEC.md",
|
|
41
|
+
"LICENSE",
|
|
42
|
+
"!src/**/__tests__/**",
|
|
43
|
+
"!src/**/__stubs__/**",
|
|
44
|
+
"!src/**/*.test.ts",
|
|
45
|
+
"!src/**/*.test.tsx",
|
|
46
|
+
"!src/**/*.spec.ts",
|
|
47
|
+
"!src/**/*.spec.tsx",
|
|
48
|
+
"!dist/**/__tests__/**",
|
|
49
|
+
"!dist/**/__stubs__/**",
|
|
50
|
+
"!dist/**/*.test.js",
|
|
51
|
+
"!dist/**/*.test.js.map",
|
|
52
|
+
"!dist/**/*.test.d.ts",
|
|
53
|
+
"!dist/**/*.test.d.ts.map",
|
|
54
|
+
"!dist/**/*.spec.js",
|
|
55
|
+
"!dist/**/*.spec.js.map",
|
|
56
|
+
"!dist/**/*.spec.d.ts",
|
|
57
|
+
"!dist/**/*.spec.d.ts.map"
|
|
58
|
+
],
|
|
59
|
+
"publishConfig": {
|
|
60
|
+
"registry": "https://registry.npmjs.org",
|
|
61
|
+
"access": "public"
|
|
62
|
+
},
|
|
63
|
+
"vibes": {
|
|
64
|
+
"visibility": "public-framework"
|
|
65
|
+
}
|
|
66
|
+
}
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bun Runtime Environment Implementation
|
|
3
|
+
*
|
|
4
|
+
* Captures environment at construction and provides Bun-specific
|
|
5
|
+
* implementations for scope, env access, secrets, and module loading.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type {
|
|
9
|
+
RuntimeDiscoveryConfig,
|
|
10
|
+
RuntimeDiscoveryProvider,
|
|
11
|
+
RuntimeEnvironmentImplementation,
|
|
12
|
+
RuntimeLoaderImplementation
|
|
13
|
+
} from '@vibesdotdev/runtime';
|
|
14
|
+
import type { RuntimeScope, TenancyConfig } from '@vibesdotdev/runtime';
|
|
15
|
+
import { BunLoader } from './bun-loader.impl';
|
|
16
|
+
import { bunRuntimePath } from './services/runtime-path.impl';
|
|
17
|
+
|
|
18
|
+
export interface BunEnvironmentOptions {
|
|
19
|
+
/** Surface override (default: detected from env) */
|
|
20
|
+
surface?: string;
|
|
21
|
+
/** Hardware override (default: detected from env) */
|
|
22
|
+
hardware?: string;
|
|
23
|
+
/** Purpose override (default: detected from env) */
|
|
24
|
+
purpose?: string;
|
|
25
|
+
/** Tenancy configuration */
|
|
26
|
+
tenancy?: TenancyConfig;
|
|
27
|
+
/** Dev mode flag */
|
|
28
|
+
dev?: boolean;
|
|
29
|
+
/** Whether daemon endpoints/process features should be enabled for this runtime */
|
|
30
|
+
daemon?: boolean;
|
|
31
|
+
/** Optional discovery defaults for this environment capability */
|
|
32
|
+
discoveryDefaults?: RuntimeDiscoveryConfig;
|
|
33
|
+
/** Optional discovery provider override for this environment capability */
|
|
34
|
+
discoveryProvider?: RuntimeDiscoveryProvider;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export class BunEnvironment implements RuntimeEnvironmentImplementation {
|
|
38
|
+
readonly id: string;
|
|
39
|
+
readonly description: string;
|
|
40
|
+
readonly capabilities: Record<string, boolean>;
|
|
41
|
+
readonly scope: RuntimeScope;
|
|
42
|
+
readonly loader: RuntimeLoaderImplementation;
|
|
43
|
+
readonly discovery: {
|
|
44
|
+
readonly defaults: RuntimeDiscoveryConfig;
|
|
45
|
+
readonly provider?: RuntimeDiscoveryProvider;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
private _envSnapshot: Record<string, string> | undefined;
|
|
49
|
+
|
|
50
|
+
constructor(options: BunEnvironmentOptions = {}) {
|
|
51
|
+
this.id = 'bun';
|
|
52
|
+
this.description = 'Bun runtime environment';
|
|
53
|
+
|
|
54
|
+
// Capture env snapshot FIRST - required for any _detect* methods below
|
|
55
|
+
this._envSnapshot = this._captureEnv();
|
|
56
|
+
|
|
57
|
+
const daemon = this._detectDaemonCapability(options);
|
|
58
|
+
this.capabilities = {
|
|
59
|
+
esm: true,
|
|
60
|
+
typescript: true,
|
|
61
|
+
nativeLoader: true,
|
|
62
|
+
secrets: false,
|
|
63
|
+
daemon
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
// Build scope from captured env + options
|
|
67
|
+
this.scope = this._buildScope(options);
|
|
68
|
+
|
|
69
|
+
// Create Bun-specific loader
|
|
70
|
+
this.loader = new BunLoader();
|
|
71
|
+
this.discovery = {
|
|
72
|
+
defaults: options.discoveryDefaults ?? {
|
|
73
|
+
basePaths: [process.cwd()],
|
|
74
|
+
skipPlugins: false,
|
|
75
|
+
respectGitignore: true
|
|
76
|
+
},
|
|
77
|
+
...(options.discoveryProvider ? { provider: options.discoveryProvider } : {})
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Capture environment variables at construction time.
|
|
83
|
+
* This is the ONLY place process.env is accessed.
|
|
84
|
+
*/
|
|
85
|
+
private _captureEnv(): Record<string, string> {
|
|
86
|
+
const captured: Record<string, string> = {};
|
|
87
|
+
if (typeof process !== 'undefined' && process.env) {
|
|
88
|
+
for (const [key, value] of Object.entries(process.env)) {
|
|
89
|
+
if (typeof value === 'string') {
|
|
90
|
+
captured[key] = value;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return captured;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Return the env snapshot, healing it if a cross-module or partially
|
|
99
|
+
* initialized BunEnvironment instance was attached to the runtime.
|
|
100
|
+
* This makes `dev mcp serve` (and other heavy CLI commands) robust when
|
|
101
|
+
* reusing the runtime created by createVibesCliApp.
|
|
102
|
+
*/
|
|
103
|
+
private _getSnapshot(): Record<string, string> {
|
|
104
|
+
if (!this._envSnapshot) {
|
|
105
|
+
this._envSnapshot = this._captureEnv();
|
|
106
|
+
}
|
|
107
|
+
return this._envSnapshot;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Build runtime scope from captured environment.
|
|
112
|
+
*/
|
|
113
|
+
private _buildScope(options: BunEnvironmentOptions): RuntimeScope {
|
|
114
|
+
const surface = options.surface ?? this._detectSurface();
|
|
115
|
+
const hardware = options.hardware ?? this._detectHardware();
|
|
116
|
+
const purpose = options.purpose ?? this._detectPurpose();
|
|
117
|
+
const snap = this._getSnapshot();
|
|
118
|
+
const dev = options.dev ?? (snap.NODE_ENV !== 'production');
|
|
119
|
+
const daemon = this._detectDaemonCapability(options, surface, hardware);
|
|
120
|
+
|
|
121
|
+
return {
|
|
122
|
+
surface,
|
|
123
|
+
hardware,
|
|
124
|
+
purpose,
|
|
125
|
+
capabilities: {
|
|
126
|
+
daemon
|
|
127
|
+
},
|
|
128
|
+
qualifiers: {
|
|
129
|
+
dev,
|
|
130
|
+
...(options.tenancy?.teamId && { teamId: options.tenancy.teamId })
|
|
131
|
+
},
|
|
132
|
+
tenancy: options.tenancy
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
private _detectDaemonCapability(
|
|
137
|
+
options: BunEnvironmentOptions,
|
|
138
|
+
surface?: string,
|
|
139
|
+
hardware?: string
|
|
140
|
+
): boolean {
|
|
141
|
+
if (typeof options.daemon === 'boolean') return options.daemon;
|
|
142
|
+
const snap = this._getSnapshot();
|
|
143
|
+
if (snap.VIBES_RUNTIME_DAEMON === '1' || snap.VIBES_DAEMON === '1') {
|
|
144
|
+
return true;
|
|
145
|
+
}
|
|
146
|
+
const resolvedSurface = surface ?? options.surface ?? this._detectSurface();
|
|
147
|
+
const resolvedHardware = hardware ?? options.hardware ?? this._detectHardware();
|
|
148
|
+
return resolvedSurface === 'daemon' || resolvedHardware === 'consumer';
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
private _detectSurface(): string {
|
|
152
|
+
return this._getSnapshot().VIBES_SURFACE ?? 'ssr';
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
private _detectHardware(): string {
|
|
156
|
+
return this._getSnapshot().VIBES_HARDWARE ?? 'consumer';
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
private _detectPurpose(): string {
|
|
160
|
+
return this._getSnapshot().VIBES_PURPOSE ?? 'direct';
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Get environment variable from captured snapshot.
|
|
165
|
+
* No direct process.env access.
|
|
166
|
+
*/
|
|
167
|
+
getEnv(key: string): string | undefined {
|
|
168
|
+
return this._getSnapshot()[key];
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Get secret value.
|
|
173
|
+
* Bun doesn't have a secrets API, so this falls back to env.
|
|
174
|
+
* Cloudflare environment will use CF Secrets Store.
|
|
175
|
+
*/
|
|
176
|
+
async getSecret(key: string): Promise<string | undefined> {
|
|
177
|
+
return this._getSnapshot()[key];
|
|
178
|
+
}
|
|
179
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bun Loader Implementation
|
|
3
|
+
*
|
|
4
|
+
* Uses Bun.import() for module loading with native ESM support.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type {
|
|
8
|
+
RuntimeLoaderImplementation,
|
|
9
|
+
RuntimeLoaderModuleMaps,
|
|
10
|
+
RuntimeLoaderOptions,
|
|
11
|
+
RuntimeLoaderKindDiscoveryOptions
|
|
12
|
+
} from '@vibesdotdev/runtime';
|
|
13
|
+
import type { RuntimeDescriptor } from '@vibesdotdev/runtime';
|
|
14
|
+
import { Glob } from 'bun';
|
|
15
|
+
import { join, basename } from 'path';
|
|
16
|
+
|
|
17
|
+
export class BunLoader implements RuntimeLoaderImplementation {
|
|
18
|
+
async loadModules(options: RuntimeLoaderOptions): Promise<RuntimeLoaderModuleMaps> {
|
|
19
|
+
const { scope, discovery } = options;
|
|
20
|
+
const basePaths = discovery?.basePaths ?? [process.cwd()];
|
|
21
|
+
const patterns = discovery?.patterns ?? {
|
|
22
|
+
plugin: '**/*.plugin.ts',
|
|
23
|
+
descriptor: '**/*.descriptor*.ts',
|
|
24
|
+
implementation: '**/*.impl*.ts*'
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const result: RuntimeLoaderModuleMaps = {
|
|
28
|
+
plugins: {},
|
|
29
|
+
descriptors: {},
|
|
30
|
+
implementations: {}
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
for (const basePath of basePaths) {
|
|
34
|
+
// Load plugins
|
|
35
|
+
const pluginGlob = new Glob(patterns.plugin ?? '**/*.plugin.ts');
|
|
36
|
+
const pluginFiles: string[] = [];
|
|
37
|
+
for await (const file of pluginGlob.scan({ cwd: basePath, absolute: true } as never)) {
|
|
38
|
+
if (file) pluginFiles.push(file);
|
|
39
|
+
}
|
|
40
|
+
for (const file of pluginFiles) {
|
|
41
|
+
const fullPath = join(basePath, file);
|
|
42
|
+
result.plugins[fullPath] = () => import(fullPath);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Load descriptors
|
|
46
|
+
const descriptorGlob = new Glob(patterns.descriptor ?? '**/*.descriptor*.ts');
|
|
47
|
+
const descriptorFiles: string[] = [];
|
|
48
|
+
for await (const file of descriptorGlob.scan({ cwd: basePath, absolute: true } as never)) {
|
|
49
|
+
if (file) descriptorFiles.push(file);
|
|
50
|
+
}
|
|
51
|
+
for (const file of descriptorFiles) {
|
|
52
|
+
const fullPath = join(basePath, file);
|
|
53
|
+
result.descriptors[fullPath] = () => import(fullPath);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Load implementations
|
|
57
|
+
const implGlob = new Glob(patterns.implementation ?? '**/*.impl*.ts*');
|
|
58
|
+
const implFiles: string[] = [];
|
|
59
|
+
for await (const file of implGlob.scan({ cwd: basePath, absolute: true } as never)) {
|
|
60
|
+
if (file) implFiles.push(file);
|
|
61
|
+
}
|
|
62
|
+
for (const file of implFiles) {
|
|
63
|
+
const fullPath = join(basePath, file);
|
|
64
|
+
result.implementations[fullPath] = () => import(fullPath);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return result;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
async discoverKindDescriptors(
|
|
72
|
+
options: RuntimeLoaderKindDiscoveryOptions
|
|
73
|
+
): Promise<RuntimeDescriptor[]> {
|
|
74
|
+
const { scope, discovery, kindPatterns } = options;
|
|
75
|
+
const basePaths = discovery?.basePaths ?? [process.cwd()];
|
|
76
|
+
const descriptors: RuntimeDescriptor[] = [];
|
|
77
|
+
|
|
78
|
+
for (const kindPattern of kindPatterns) {
|
|
79
|
+
const glob = new Glob(kindPattern.pattern);
|
|
80
|
+
for (const basePath of basePaths) {
|
|
81
|
+
for await (const file of glob.scan({ cwd: basePath, absolute: true } as never)) {
|
|
82
|
+
const fullPath = join(basePath, file!);
|
|
83
|
+
try {
|
|
84
|
+
const module = await import(fullPath);
|
|
85
|
+
if (module.default) {
|
|
86
|
+
const descriptor = module.default as RuntimeDescriptor;
|
|
87
|
+
if (descriptor.kind === kindPattern.kindId) {
|
|
88
|
+
descriptors.push(descriptor);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
} catch (error) {
|
|
92
|
+
if (discovery?.debug) {
|
|
93
|
+
console.warn(`Failed to load descriptor ${fullPath}:`, error);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return descriptors;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plugin Asset Discovery
|
|
3
|
+
*
|
|
4
|
+
* Scans the filesystem for descriptor and implementation files,
|
|
5
|
+
* registers descriptors eagerly, and implementations as lazy loaders.
|
|
6
|
+
* Consumer/Bun-only helper for plugin-local asset discovery.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { fileURLToPath } from 'node:url';
|
|
10
|
+
import { dirname, resolve } from 'node:path';
|
|
11
|
+
import type { RuntimeRef } from '@vibesdotdev/runtime/factory/plugin';
|
|
12
|
+
import { extractDescriptorStem, parseImplFilename } from '@vibesdotdev/runtime/discovery/scope-parser';
|
|
13
|
+
|
|
14
|
+
type FsGlobModule = {
|
|
15
|
+
globSync?: (pattern: string, options: { cwd: string }) => string[];
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
type ProcessWithBuiltinModule = typeof process & {
|
|
19
|
+
getBuiltinModule?: (id: 'node:fs') => FsGlobModule | undefined;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export async function discoverAssets(
|
|
23
|
+
runtime: RuntimeRef,
|
|
24
|
+
baseUrl: string | undefined,
|
|
25
|
+
kindPatterns: Record<string, string | string[]>
|
|
26
|
+
): Promise<{ descriptors: number; loaders: number }> {
|
|
27
|
+
// Filesystem asset discovery requires a real `file://` base URL. In workerd
|
|
28
|
+
// and other non-filesystem runtimes `import.meta.url` is undefined, so
|
|
29
|
+
// the caller can't give us a baseUrl. Short-circuit instead of throwing.
|
|
30
|
+
if (typeof baseUrl !== 'string' || baseUrl.length === 0) {
|
|
31
|
+
return { descriptors: 0, loaders: 0 };
|
|
32
|
+
}
|
|
33
|
+
if (baseUrl.includes('/$bunfs/') || baseUrl.includes('/$bun/')) {
|
|
34
|
+
return { descriptors: 0, loaders: 0 };
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const baseDir = dirname(fileURLToPath(baseUrl));
|
|
38
|
+
let descriptors = 0;
|
|
39
|
+
let loaders = 0;
|
|
40
|
+
|
|
41
|
+
for (const [kind, rawPatterns] of Object.entries(kindPatterns)) {
|
|
42
|
+
const patterns = Array.isArray(rawPatterns) ? rawPatterns : [rawPatterns];
|
|
43
|
+
const files = scanPatterns(patterns, baseDir);
|
|
44
|
+
|
|
45
|
+
const descriptorFiles = files.filter((f) => f.includes('.descriptor.'));
|
|
46
|
+
const implFiles = files.filter((f) => f.includes('.impl.'));
|
|
47
|
+
|
|
48
|
+
for (const file of descriptorFiles) {
|
|
49
|
+
try {
|
|
50
|
+
const absPath = resolve(baseDir, file);
|
|
51
|
+
const mod = await import(absPath);
|
|
52
|
+
const desc = mod.default;
|
|
53
|
+
if (!desc || !desc.id) continue;
|
|
54
|
+
|
|
55
|
+
const descKind = desc.kind ?? kind;
|
|
56
|
+
runtime.registerDescriptor(descKind, desc);
|
|
57
|
+
descriptors++;
|
|
58
|
+
|
|
59
|
+
const stem = extractDescriptorStem(file)?.stem;
|
|
60
|
+
if (!stem) continue;
|
|
61
|
+
const matchingImpl = implFiles.find((candidate) => {
|
|
62
|
+
try {
|
|
63
|
+
return parseImplFilename(candidate).stem === stem;
|
|
64
|
+
} catch {
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
if (!matchingImpl) continue;
|
|
69
|
+
|
|
70
|
+
const implPath = resolve(baseDir, matchingImpl);
|
|
71
|
+
runtime.registerLoader(descKind, desc.id, async () => {
|
|
72
|
+
const exported = (await import(implPath)).default;
|
|
73
|
+
if (
|
|
74
|
+
exported &&
|
|
75
|
+
typeof exported === 'object' &&
|
|
76
|
+
'impl' in exported &&
|
|
77
|
+
'meta' in exported
|
|
78
|
+
) {
|
|
79
|
+
return exported;
|
|
80
|
+
}
|
|
81
|
+
return {
|
|
82
|
+
meta: {
|
|
83
|
+
id: desc.id,
|
|
84
|
+
kind: descKind,
|
|
85
|
+
priority: 0
|
|
86
|
+
},
|
|
87
|
+
impl: exported
|
|
88
|
+
};
|
|
89
|
+
});
|
|
90
|
+
loaders++;
|
|
91
|
+
} catch {
|
|
92
|
+
// Descriptor may have unresolvable imports in this environment — skip
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return { descriptors, loaders };
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function scanPatterns(patterns: string[], cwd: string): string[] {
|
|
101
|
+
const results: string[] = [];
|
|
102
|
+
for (const pattern of patterns) {
|
|
103
|
+
for (const expanded of expandScopedPattern(pattern)) {
|
|
104
|
+
results.push(...scanGlob(expanded, cwd));
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return results;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function expandScopedPattern(pattern: string): string[] {
|
|
111
|
+
if (!pattern.includes('{descriptor,impl}')) return [pattern];
|
|
112
|
+
return [
|
|
113
|
+
pattern.replace('{descriptor,impl}', 'descriptor*'),
|
|
114
|
+
pattern.replace('{descriptor,impl}', 'impl*')
|
|
115
|
+
];
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function scanGlob(pattern: string, cwd: string): string[] {
|
|
119
|
+
if (typeof globalThis !== 'undefined' && 'Bun' in globalThis) {
|
|
120
|
+
const BunGlob = (globalThis as Record<string, unknown>).Bun as {
|
|
121
|
+
Glob: new (p: string) => {
|
|
122
|
+
scanSync: (o: { cwd: string; onlyFiles: boolean }) => Iterable<string>;
|
|
123
|
+
};
|
|
124
|
+
};
|
|
125
|
+
return [...new BunGlob.Glob(pattern).scanSync({ cwd, onlyFiles: true })];
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const builtinProcess = process as ProcessWithBuiltinModule;
|
|
129
|
+
const fsModule = builtinProcess.getBuiltinModule?.('node:fs');
|
|
130
|
+
if (typeof fsModule?.globSync === 'function') {
|
|
131
|
+
return fsModule.globSync(pattern, { cwd });
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return [];
|
|
135
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal RuntimeHost interface (duplicated here to avoid export map changes in runtime core).
|
|
3
|
+
* Matches the contract in packages/runtime/src/env/host.contracts.ts.
|
|
4
|
+
*/
|
|
5
|
+
interface RuntimeHost {
|
|
6
|
+
kind: 'browser' | 'node' | 'cloud';
|
|
7
|
+
cwd(): string | null;
|
|
8
|
+
readTextFile(path: string): Promise<string>;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
import { readFile } from 'node:fs/promises';
|
|
12
|
+
import { resolve } from 'node:path';
|
|
13
|
+
|
|
14
|
+
export const host: RuntimeHost = {
|
|
15
|
+
kind: 'node',
|
|
16
|
+
cwd(): string {
|
|
17
|
+
return process.cwd();
|
|
18
|
+
},
|
|
19
|
+
async readTextFile(path: string): Promise<string> {
|
|
20
|
+
const absolute = resolve(process.cwd(), path);
|
|
21
|
+
return await readFile(absolute, 'utf8');
|
|
22
|
+
}
|
|
23
|
+
};
|