@dbx-tools/cli 0.9.60 → 0.9.64
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 +175 -81
- package/bin/dbx-genie.ts +10 -0
- package/index.ts +13 -1
- package/lib/bin/dbx-genie.d.ts +2 -0
- package/lib/bin/dbx-genie.js +10 -0
- package/lib/index.d.ts +13 -1
- package/lib/index.js +10 -2
- package/lib/src/auth/cli.js +13 -2
- package/lib/src/auth/options.d.ts +4 -0
- package/lib/src/auth/options.js +5 -1
- package/lib/src/cli.js +19 -4
- package/lib/src/genie-code/cli.d.ts +19 -0
- package/lib/src/genie-code/cli.js +36 -0
- package/lib/src/genie-code/config.d.ts +38 -0
- package/lib/src/genie-code/config.js +108 -0
- package/lib/src/genie-code/install.d.ts +21 -0
- package/lib/src/genie-code/install.js +69 -0
- package/lib/src/genie-code/options.d.ts +7 -0
- package/lib/src/genie-code/options.js +7 -0
- package/lib/src/genie-code/runner.d.ts +21 -0
- package/lib/src/genie-code/runner.js +90 -0
- package/lib/src/genie-code/runtime.d.ts +49 -0
- package/lib/src/genie-code/runtime.js +169 -0
- package/lib/src/graphiti/cli.js +2 -2
- package/lib/src/lakebase-proxy/cli.js +2 -2
- package/lib/src/model-gateway/cli.js +3 -3
- package/lib/src/model-gateway/server.d.ts +3 -0
- package/lib/src/model-gateway/server.js +39 -6
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +40 -18
- package/src/auth/cli.ts +11 -1
- package/src/auth/options.ts +4 -0
- package/src/cli.ts +17 -6
- package/src/genie-code/cli.ts +58 -0
- package/src/genie-code/config.ts +157 -0
- package/src/genie-code/install.ts +103 -0
- package/src/genie-code/options.ts +14 -0
- package/src/genie-code/runner.ts +106 -0
- package/src/genie-code/runtime.ts +231 -0
- package/src/graphiti/cli.ts +1 -1
- package/src/lakebase-proxy/cli.ts +1 -1
- package/src/model-gateway/cli.ts +6 -2
- package/src/model-gateway/server.ts +40 -5
|
@@ -5,9 +5,12 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { server } from "@databricks/appkit";
|
|
7
7
|
import { type ModelGatewayOptions } from "@dbx-tools/shared-model-gateway/options";
|
|
8
|
+
import type express from "express";
|
|
8
9
|
type AppKitServerOptions = NonNullable<Parameters<typeof server>[0]>;
|
|
9
10
|
/** Resolve AppKit server settings for the loopback model gateway. */
|
|
10
11
|
export declare function modelGatewayServerOptions(options?: ModelGatewayOptions): AppKitServerOptions;
|
|
12
|
+
/** Require one bearer token without retaining or logging request credentials. */
|
|
13
|
+
export declare function gatewayBearerMiddleware(token: string): express.RequestHandler;
|
|
11
14
|
/** Start the foreground model gateway and keep its AppKit server active. */
|
|
12
15
|
export declare function startModelGateway(options?: ModelGatewayOptions): Promise<void>;
|
|
13
16
|
export {};
|
|
@@ -3,9 +3,10 @@
|
|
|
3
3
|
*
|
|
4
4
|
* @module
|
|
5
5
|
*/
|
|
6
|
+
import { createHash, timingSafeEqual } from "node:crypto";
|
|
6
7
|
import { createApp, server } from "@databricks/appkit";
|
|
7
|
-
import {
|
|
8
|
-
import { sendHealth } from "@dbx-tools/appkit-model-gateway/routes";
|
|
8
|
+
import { ModelGateway } from "@dbx-tools/appkit-model-gateway";
|
|
9
|
+
import { sendHealth, sendInference, sendModels } from "@dbx-tools/appkit-model-gateway/routes";
|
|
9
10
|
import { workspaceClient } from "@dbx-tools/databricks";
|
|
10
11
|
import { resolveModelGatewayOptions, } from "@dbx-tools/shared-model-gateway/options";
|
|
11
12
|
/** Resolve AppKit server settings for the loopback model gateway. */
|
|
@@ -19,22 +20,54 @@ function appKitServerOptions(options) {
|
|
|
19
20
|
port: options.listen.port,
|
|
20
21
|
};
|
|
21
22
|
}
|
|
23
|
+
/** Require one bearer token without retaining or logging request credentials. */
|
|
24
|
+
export function gatewayBearerMiddleware(token) {
|
|
25
|
+
const expected = createHash("sha256").update(token).digest();
|
|
26
|
+
return (request, response, next) => {
|
|
27
|
+
const authorization = request.header("authorization");
|
|
28
|
+
const match = /^Bearer\s+(.+)$/i.exec(authorization ?? "");
|
|
29
|
+
const actual = createHash("sha256")
|
|
30
|
+
.update(match?.[1] ?? "")
|
|
31
|
+
.digest();
|
|
32
|
+
if (match && timingSafeEqual(actual, expected)) {
|
|
33
|
+
next();
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
response
|
|
37
|
+
.status(401)
|
|
38
|
+
.setHeader("www-authenticate", "Bearer")
|
|
39
|
+
.json({
|
|
40
|
+
error: {
|
|
41
|
+
message: "Invalid or missing model-gateway bearer token.",
|
|
42
|
+
type: "authentication_error",
|
|
43
|
+
code: "invalid_bearer_token",
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
};
|
|
47
|
+
}
|
|
22
48
|
/** Start the foreground model gateway and keep its AppKit server active. */
|
|
23
49
|
export async function startModelGateway(options = {}) {
|
|
24
50
|
const resolved = resolveModelGatewayOptions(options);
|
|
51
|
+
const gateway = new ModelGateway({
|
|
52
|
+
...(resolved.model ? { model: resolved.model } : {}),
|
|
53
|
+
...(resolved.modelClass ? { modelClass: resolved.modelClass } : {}),
|
|
54
|
+
});
|
|
25
55
|
const client = await workspaceClient.createWorkspaceClient({
|
|
26
56
|
...(resolved.profile ? { profile: resolved.profile } : {}),
|
|
27
57
|
});
|
|
28
58
|
await createApp({
|
|
29
59
|
client,
|
|
30
|
-
plugins: [
|
|
60
|
+
plugins: [server(appKitServerOptions(resolved))],
|
|
31
61
|
onPluginsReady(appkit) {
|
|
32
62
|
appkit.server.extend((application) => {
|
|
63
|
+
if (resolved.bearerToken) {
|
|
64
|
+
application.use(gatewayBearerMiddleware(resolved.bearerToken));
|
|
65
|
+
}
|
|
33
66
|
application.get("/api/healthz", (_request, response) => {
|
|
34
67
|
sendHealth(response);
|
|
35
68
|
});
|
|
36
69
|
application.get("/v1/models", (request, response) => {
|
|
37
|
-
void
|
|
70
|
+
void sendModels(gateway, request, response);
|
|
38
71
|
});
|
|
39
72
|
for (const [path, protocol] of [
|
|
40
73
|
["/v1/chat/completions", "openai-chat"],
|
|
@@ -43,11 +76,11 @@ export async function startModelGateway(options = {}) {
|
|
|
43
76
|
["/v1/embeddings", "openai-embeddings"],
|
|
44
77
|
]) {
|
|
45
78
|
application.post(path, (request, response) => {
|
|
46
|
-
void
|
|
79
|
+
void sendInference(gateway, protocol, request, response);
|
|
47
80
|
});
|
|
48
81
|
}
|
|
49
82
|
});
|
|
50
83
|
},
|
|
51
84
|
});
|
|
52
85
|
}
|
|
53
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
86
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VydmVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL21vZGVsLWdhdGV3YXkvc2VydmVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7O0dBSUc7QUFFSCxPQUFPLEVBQUUsVUFBVSxFQUFFLGVBQWUsRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUMxRCxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBQ3ZELE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQztBQUMvRCxPQUFPLEVBQUUsVUFBVSxFQUFFLGFBQWEsRUFBRSxVQUFVLEVBQUUsTUFBTSx3Q0FBd0MsQ0FBQztBQUMvRixPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sdUJBQXVCLENBQUM7QUFDeEQsT0FBTyxFQUNMLDBCQUEwQixHQUczQixNQUFNLHlDQUF5QyxDQUFDO0FBS2pELHFFQUFxRTtBQUNyRSxNQUFNLFVBQVUseUJBQXlCLENBQUMsVUFBK0IsRUFBRTtJQUN6RSxPQUFPLG1CQUFtQixDQUFDLDBCQUEwQixDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUM7QUFDbEUsQ0FBQztBQUVELFNBQVMsbUJBQW1CLENBQUMsT0FBb0M7SUFDL0QsT0FBTztRQUNMLFNBQVMsRUFBRSxPQUFPLENBQUMsU0FBUztRQUM1QixJQUFJLEVBQUUsT0FBTyxDQUFDLE1BQU0sQ0FBQyxJQUFJO1FBQ3pCLElBQUksRUFBRSxPQUFPLENBQUMsTUFBTSxDQUFDLElBQUk7S0FDMUIsQ0FBQztBQUNKLENBQUM7QUFFRCxpRkFBaUY7QUFDakYsTUFBTSxVQUFVLHVCQUF1QixDQUFDLEtBQWE7SUFDbkQsTUFBTSxRQUFRLEdBQUcsVUFBVSxDQUFDLFFBQVEsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQztJQUM3RCxPQUFPLENBQUMsT0FBTyxFQUFFLFFBQVEsRUFBRSxJQUFJLEVBQUUsRUFBRTtRQUNqQyxNQUFNLGFBQWEsR0FBRyxPQUFPLENBQUMsTUFBTSxDQUFDLGVBQWUsQ0FBQyxDQUFDO1FBQ3RELE1BQU0sS0FBSyxHQUFHLGtCQUFrQixDQUFDLElBQUksQ0FBQyxhQUFhLElBQUksRUFBRSxDQUFDLENBQUM7UUFDM0QsTUFBTSxNQUFNLEdBQUcsVUFBVSxDQUFDLFFBQVEsQ0FBQzthQUNoQyxNQUFNLENBQUMsS0FBSyxFQUFFLENBQUMsQ0FBQyxDQUFDLElBQUksRUFBRSxDQUFDO2FBQ3hCLE1BQU0sRUFBRSxDQUFDO1FBQ1osSUFBSSxLQUFLLElBQUksZUFBZSxDQUFDLE1BQU0sRUFBRSxRQUFRLENBQUMsRUFBRSxDQUFDO1lBQy9DLElBQUksRUFBRSxDQUFDO1lBQ1AsT0FBTztRQUNULENBQUM7UUFDRCxRQUFRO2FBQ0wsTUFBTSxDQUFDLEdBQUcsQ0FBQzthQUNYLFNBQVMsQ0FBQyxrQkFBa0IsRUFBRSxRQUFRLENBQUM7YUFDdkMsSUFBSSxDQUFDO1lBQ0osS0FBSyxFQUFFO2dCQUNMLE9BQU8sRUFBRSxnREFBZ0Q7Z0JBQ3pELElBQUksRUFBRSxzQkFBc0I7Z0JBQzVCLElBQUksRUFBRSxzQkFBc0I7YUFDN0I7U0FDRixDQUFDLENBQUM7SUFDUCxDQUFDLENBQUM7QUFDSixDQUFDO0FBRUQsNEVBQTRFO0FBQzVFLE1BQU0sQ0FBQyxLQUFLLFVBQVUsaUJBQWlCLENBQUMsVUFBK0IsRUFBRTtJQUN2RSxNQUFNLFFBQVEsR0FBRywwQkFBMEIsQ0FBQyxPQUFPLENBQUMsQ0FBQztJQUNyRCxNQUFNLE9BQU8sR0FBRyxJQUFJLFlBQVksQ0FBQztRQUMvQixHQUFHLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsRUFBRSxLQUFLLEVBQUUsUUFBUSxDQUFDLEtBQUssRUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUM7UUFDcEQsR0FBRyxDQUFDLFFBQVEsQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDLEVBQUUsVUFBVSxFQUFFLFFBQVEsQ0FBQyxVQUFVLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDO0tBQ3BFLENBQUMsQ0FBQztJQUNILE1BQU0sTUFBTSxHQUFHLE1BQU0sZUFBZSxDQUFDLHFCQUFxQixDQUFDO1FBQ3pELEdBQUcsQ0FBQyxRQUFRLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxFQUFFLE9BQU8sRUFBRSxRQUFRLENBQUMsT0FBTyxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztLQUMzRCxDQUFDLENBQUM7SUFDSCxNQUFNLFNBQVMsQ0FBQztRQUNkLE1BQU07UUFDTixPQUFPLEVBQUUsQ0FBQyxNQUFNLENBQUMsbUJBQW1CLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQztRQUNoRCxjQUFjLENBQUMsTUFBTTtZQUNuQixNQUFNLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxDQUFDLFdBQVcsRUFBRSxFQUFFO2dCQUNuQyxJQUFJLFFBQVEsQ0FBQyxXQUFXLEVBQUUsQ0FBQztvQkFDekIsV0FBVyxDQUFDLEdBQUcsQ0FBQyx1QkFBdUIsQ0FBQyxRQUFRLENBQUMsV0FBVyxDQUFDLENBQUMsQ0FBQztnQkFDakUsQ0FBQztnQkFDRCxXQUFXLENBQUMsR0FBRyxDQUFDLGNBQWMsRUFBRSxDQUFDLFFBQVEsRUFBRSxRQUFRLEVBQUUsRUFBRTtvQkFDckQsVUFBVSxDQUFDLFFBQVEsQ0FBQyxDQUFDO2dCQUN2QixDQUFDLENBQUMsQ0FBQztnQkFDSCxXQUFXLENBQUMsR0FBRyxDQUFDLFlBQVksRUFBRSxDQUFDLE9BQU8sRUFBRSxRQUFRLEVBQUUsRUFBRTtvQkFDbEQsS0FBSyxVQUFVLENBQUMsT0FBTyxFQUFFLE9BQU8sRUFBRSxRQUFRLENBQUMsQ0FBQztnQkFDOUMsQ0FBQyxDQUFDLENBQUM7Z0JBQ0gsS0FBSyxNQUFNLENBQUMsSUFBSSxFQUFFLFFBQVEsQ0FBQyxJQUFJO29CQUM3QixDQUFDLHNCQUFzQixFQUFFLGFBQWEsQ0FBQztvQkFDdkMsQ0FBQyxlQUFlLEVBQUUsa0JBQWtCLENBQUM7b0JBQ3JDLENBQUMsY0FBYyxFQUFFLG9CQUFvQixDQUFDO29CQUN0QyxDQUFDLGdCQUFnQixFQUFFLG1CQUFtQixDQUFDO2lCQUMvQixFQUFFLENBQUM7b0JBQ1gsV0FBVyxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUUsQ0FBQyxPQUFPLEVBQUUsUUFBUSxFQUFFLEVBQUU7d0JBQzNDLEtBQUssYUFBYSxDQUFDLE9BQU8sRUFBRSxRQUFRLEVBQUUsT0FBTyxFQUFFLFFBQVEsQ0FBQyxDQUFDO29CQUMzRCxDQUFDLENBQUMsQ0FBQztnQkFDTCxDQUFDO1lBQ0gsQ0FBQyxDQUFDLENBQUM7UUFDTCxDQUFDO0tBQ0YsQ0FBQyxDQUFDO0FBQ0wsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogRm9yZWdyb3VuZCBtb2RlbC1nYXRld2F5IHNlcnZlciBvd25lZCBieSB0aGUgQ0xJIHBhY2thZ2UuXG4gKlxuICogQG1vZHVsZVxuICovXG5cbmltcG9ydCB7IGNyZWF0ZUhhc2gsIHRpbWluZ1NhZmVFcXVhbCB9IGZyb20gXCJub2RlOmNyeXB0b1wiO1xuaW1wb3J0IHsgY3JlYXRlQXBwLCBzZXJ2ZXIgfSBmcm9tIFwiQGRhdGFicmlja3MvYXBwa2l0XCI7XG5pbXBvcnQgeyBNb2RlbEdhdGV3YXkgfSBmcm9tIFwiQGRieC10b29scy9hcHBraXQtbW9kZWwtZ2F0ZXdheVwiO1xuaW1wb3J0IHsgc2VuZEhlYWx0aCwgc2VuZEluZmVyZW5jZSwgc2VuZE1vZGVscyB9IGZyb20gXCJAZGJ4LXRvb2xzL2FwcGtpdC1tb2RlbC1nYXRld2F5L3JvdXRlc1wiO1xuaW1wb3J0IHsgd29ya3NwYWNlQ2xpZW50IH0gZnJvbSBcIkBkYngtdG9vbHMvZGF0YWJyaWNrc1wiO1xuaW1wb3J0IHtcbiAgcmVzb2x2ZU1vZGVsR2F0ZXdheU9wdGlvbnMsXG4gIHR5cGUgTW9kZWxHYXRld2F5T3B0aW9ucyxcbiAgdHlwZSBSZXNvbHZlZE1vZGVsR2F0ZXdheU9wdGlvbnMsXG59IGZyb20gXCJAZGJ4LXRvb2xzL3NoYXJlZC1tb2RlbC1nYXRld2F5L29wdGlvbnNcIjtcbmltcG9ydCB0eXBlIGV4cHJlc3MgZnJvbSBcImV4cHJlc3NcIjtcblxudHlwZSBBcHBLaXRTZXJ2ZXJPcHRpb25zID0gTm9uTnVsbGFibGU8UGFyYW1ldGVyczx0eXBlb2Ygc2VydmVyPlswXT47XG5cbi8qKiBSZXNvbHZlIEFwcEtpdCBzZXJ2ZXIgc2V0dGluZ3MgZm9yIHRoZSBsb29wYmFjayBtb2RlbCBnYXRld2F5LiAqL1xuZXhwb3J0IGZ1bmN0aW9uIG1vZGVsR2F0ZXdheVNlcnZlck9wdGlvbnMob3B0aW9uczogTW9kZWxHYXRld2F5T3B0aW9ucyA9IHt9KTogQXBwS2l0U2VydmVyT3B0aW9ucyB7XG4gIHJldHVybiBhcHBLaXRTZXJ2ZXJPcHRpb25zKHJlc29sdmVNb2RlbEdhdGV3YXlPcHRpb25zKG9wdGlvbnMpKTtcbn1cblxuZnVuY3Rpb24gYXBwS2l0U2VydmVyT3B0aW9ucyhvcHRpb25zOiBSZXNvbHZlZE1vZGVsR2F0ZXdheU9wdGlvbnMpOiBBcHBLaXRTZXJ2ZXJPcHRpb25zIHtcbiAgcmV0dXJuIHtcbiAgICBib2R5TGltaXQ6IG9wdGlvbnMuYm9keUxpbWl0LFxuICAgIGhvc3Q6IG9wdGlvbnMubGlzdGVuLmhvc3QsXG4gICAgcG9ydDogb3B0aW9ucy5saXN0ZW4ucG9ydCxcbiAgfTtcbn1cblxuLyoqIFJlcXVpcmUgb25lIGJlYXJlciB0b2tlbiB3aXRob3V0IHJldGFpbmluZyBvciBsb2dnaW5nIHJlcXVlc3QgY3JlZGVudGlhbHMuICovXG5leHBvcnQgZnVuY3Rpb24gZ2F0ZXdheUJlYXJlck1pZGRsZXdhcmUodG9rZW46IHN0cmluZyk6IGV4cHJlc3MuUmVxdWVzdEhhbmRsZXIge1xuICBjb25zdCBleHBlY3RlZCA9IGNyZWF0ZUhhc2goXCJzaGEyNTZcIikudXBkYXRlKHRva2VuKS5kaWdlc3QoKTtcbiAgcmV0dXJuIChyZXF1ZXN0LCByZXNwb25zZSwgbmV4dCkgPT4ge1xuICAgIGNvbnN0IGF1dGhvcml6YXRpb24gPSByZXF1ZXN0LmhlYWRlcihcImF1dGhvcml6YXRpb25cIik7XG4gICAgY29uc3QgbWF0Y2ggPSAvXkJlYXJlclxccysoLispJC9pLmV4ZWMoYXV0aG9yaXphdGlvbiA/PyBcIlwiKTtcbiAgICBjb25zdCBhY3R1YWwgPSBjcmVhdGVIYXNoKFwic2hhMjU2XCIpXG4gICAgICAudXBkYXRlKG1hdGNoPy5bMV0gPz8gXCJcIilcbiAgICAgIC5kaWdlc3QoKTtcbiAgICBpZiAobWF0Y2ggJiYgdGltaW5nU2FmZUVxdWFsKGFjdHVhbCwgZXhwZWN0ZWQpKSB7XG4gICAgICBuZXh0KCk7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIHJlc3BvbnNlXG4gICAgICAuc3RhdHVzKDQwMSlcbiAgICAgIC5zZXRIZWFkZXIoXCJ3d3ctYXV0aGVudGljYXRlXCIsIFwiQmVhcmVyXCIpXG4gICAgICAuanNvbih7XG4gICAgICAgIGVycm9yOiB7XG4gICAgICAgICAgbWVzc2FnZTogXCJJbnZhbGlkIG9yIG1pc3NpbmcgbW9kZWwtZ2F0ZXdheSBiZWFyZXIgdG9rZW4uXCIsXG4gICAgICAgICAgdHlwZTogXCJhdXRoZW50aWNhdGlvbl9lcnJvclwiLFxuICAgICAgICAgIGNvZGU6IFwiaW52YWxpZF9iZWFyZXJfdG9rZW5cIixcbiAgICAgICAgfSxcbiAgICAgIH0pO1xuICB9O1xufVxuXG4vKiogU3RhcnQgdGhlIGZvcmVncm91bmQgbW9kZWwgZ2F0ZXdheSBhbmQga2VlcCBpdHMgQXBwS2l0IHNlcnZlciBhY3RpdmUuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gc3RhcnRNb2RlbEdhdGV3YXkob3B0aW9uczogTW9kZWxHYXRld2F5T3B0aW9ucyA9IHt9KTogUHJvbWlzZTx2b2lkPiB7XG4gIGNvbnN0IHJlc29sdmVkID0gcmVzb2x2ZU1vZGVsR2F0ZXdheU9wdGlvbnMob3B0aW9ucyk7XG4gIGNvbnN0IGdhdGV3YXkgPSBuZXcgTW9kZWxHYXRld2F5KHtcbiAgICAuLi4ocmVzb2x2ZWQubW9kZWwgPyB7IG1vZGVsOiByZXNvbHZlZC5tb2RlbCB9IDoge30pLFxuICAgIC4uLihyZXNvbHZlZC5tb2RlbENsYXNzID8geyBtb2RlbENsYXNzOiByZXNvbHZlZC5tb2RlbENsYXNzIH0gOiB7fSksXG4gIH0pO1xuICBjb25zdCBjbGllbnQgPSBhd2FpdCB3b3Jrc3BhY2VDbGllbnQuY3JlYXRlV29ya3NwYWNlQ2xpZW50KHtcbiAgICAuLi4ocmVzb2x2ZWQucHJvZmlsZSA/IHsgcHJvZmlsZTogcmVzb2x2ZWQucHJvZmlsZSB9IDoge30pLFxuICB9KTtcbiAgYXdhaXQgY3JlYXRlQXBwKHtcbiAgICBjbGllbnQsXG4gICAgcGx1Z2luczogW3NlcnZlcihhcHBLaXRTZXJ2ZXJPcHRpb25zKHJlc29sdmVkKSldLFxuICAgIG9uUGx1Z2luc1JlYWR5KGFwcGtpdCkge1xuICAgICAgYXBwa2l0LnNlcnZlci5leHRlbmQoKGFwcGxpY2F0aW9uKSA9PiB7XG4gICAgICAgIGlmIChyZXNvbHZlZC5iZWFyZXJUb2tlbikge1xuICAgICAgICAgIGFwcGxpY2F0aW9uLnVzZShnYXRld2F5QmVhcmVyTWlkZGxld2FyZShyZXNvbHZlZC5iZWFyZXJUb2tlbikpO1xuICAgICAgICB9XG4gICAgICAgIGFwcGxpY2F0aW9uLmdldChcIi9hcGkvaGVhbHRoelwiLCAoX3JlcXVlc3QsIHJlc3BvbnNlKSA9PiB7XG4gICAgICAgICAgc2VuZEhlYWx0aChyZXNwb25zZSk7XG4gICAgICAgIH0pO1xuICAgICAgICBhcHBsaWNhdGlvbi5nZXQoXCIvdjEvbW9kZWxzXCIsIChyZXF1ZXN0LCByZXNwb25zZSkgPT4ge1xuICAgICAgICAgIHZvaWQgc2VuZE1vZGVscyhnYXRld2F5LCByZXF1ZXN0LCByZXNwb25zZSk7XG4gICAgICAgIH0pO1xuICAgICAgICBmb3IgKGNvbnN0IFtwYXRoLCBwcm90b2NvbF0gb2YgW1xuICAgICAgICAgIFtcIi92MS9jaGF0L2NvbXBsZXRpb25zXCIsIFwib3BlbmFpLWNoYXRcIl0sXG4gICAgICAgICAgW1wiL3YxL3Jlc3BvbnNlc1wiLCBcIm9wZW5haS1yZXNwb25zZXNcIl0sXG4gICAgICAgICAgW1wiL3YxL21lc3NhZ2VzXCIsIFwiYW50aHJvcGljLW1lc3NhZ2VzXCJdLFxuICAgICAgICAgIFtcIi92MS9lbWJlZGRpbmdzXCIsIFwib3BlbmFpLWVtYmVkZGluZ3NcIl0sXG4gICAgICAgIF0gYXMgY29uc3QpIHtcbiAgICAgICAgICBhcHBsaWNhdGlvbi5wb3N0KHBhdGgsIChyZXF1ZXN0LCByZXNwb25zZSkgPT4ge1xuICAgICAgICAgICAgdm9pZCBzZW5kSW5mZXJlbmNlKGdhdGV3YXksIHByb3RvY29sLCByZXF1ZXN0LCByZXNwb25zZSk7XG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgIH0sXG4gIH0pO1xufVxuIl19
|
package/lib/tsconfig.tsbuildinfo
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"root":["../src/bootstrap.ts","../src/bun.ts","../src/cli.ts","../src/root.ts","../src/appkit/cli.ts","../src/appkit/env-export.ts","../src/auth/cli.ts","../src/auth/options.ts","../src/graphiti/cli.ts","../src/graphiti/options.ts","../src/lakebase-proxy/cancellation.ts","../src/lakebase-proxy/cli.ts","../src/lakebase-proxy/options.ts","../src/lakebase-proxy/protocol.ts","../src/lakebase-proxy/proxy.ts","../src/model-gateway/cli.ts","../src/model-gateway/server.ts","../src/tunnel/app.ts","../src/tunnel/cli.ts","../src/tunnel/options.ts","../src/tunnel/proxy.ts","../index.ts","../bin/dbx-graphiti.ts","../bin/dbx-lakebase-proxy.ts","../bin/dbx-model-gateway.ts","../bin/dbx-tools.ts"],"version":"5.9.3"}
|
|
1
|
+
{"root":["../src/bootstrap.ts","../src/bun.ts","../src/cli.ts","../src/root.ts","../src/appkit/cli.ts","../src/appkit/env-export.ts","../src/auth/cli.ts","../src/auth/options.ts","../src/genie-code/cli.ts","../src/genie-code/config.ts","../src/genie-code/install.ts","../src/genie-code/options.ts","../src/genie-code/runner.ts","../src/genie-code/runtime.ts","../src/graphiti/cli.ts","../src/graphiti/options.ts","../src/lakebase-proxy/cancellation.ts","../src/lakebase-proxy/cli.ts","../src/lakebase-proxy/options.ts","../src/lakebase-proxy/protocol.ts","../src/lakebase-proxy/proxy.ts","../src/model-gateway/cli.ts","../src/model-gateway/server.ts","../src/tunnel/app.ts","../src/tunnel/cli.ts","../src/tunnel/options.ts","../src/tunnel/proxy.ts","../index.ts","../bin/dbx-genie.ts","../bin/dbx-graphiti.ts","../bin/dbx-lakebase-proxy.ts","../bin/dbx-model-gateway.ts","../bin/dbx-tools.ts"],"version":"5.9.3"}
|
package/package.json
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
},
|
|
9
9
|
"bin": {
|
|
10
10
|
"dbx": "./lib/bin/dbx-tools.js",
|
|
11
|
+
"dbx-genie": "./lib/bin/dbx-genie.js",
|
|
11
12
|
"dbx-graphiti": "./lib/bin/dbx-graphiti.js",
|
|
12
13
|
"dbx-lakebase-proxy": "./lib/bin/dbx-lakebase-proxy.js",
|
|
13
14
|
"dbx-model-gateway": "./lib/bin/dbx-model-gateway.js",
|
|
@@ -33,26 +34,30 @@
|
|
|
33
34
|
"dependencies": {
|
|
34
35
|
"@clack/prompts": "^1.7.0",
|
|
35
36
|
"@databricks/appkit": "0.81.0",
|
|
36
|
-
"@dbx-tools/appkit": "^0.9.
|
|
37
|
-
"@dbx-tools/appkit-model-gateway": "^0.9.
|
|
38
|
-
"@dbx-tools/auth": "^0.9.
|
|
39
|
-
"@dbx-tools/auth-gate": "^0.9.
|
|
40
|
-
"@dbx-tools/cli-args": "^0.9.
|
|
41
|
-
"@dbx-tools/cli-service": "^0.9.
|
|
42
|
-
"@dbx-tools/core": "^0.9.
|
|
43
|
-
"@dbx-tools/databricks": "^0.9.
|
|
44
|
-
"@dbx-tools/email": "^0.9.
|
|
45
|
-
"@dbx-tools/graphiti": "^0.9.
|
|
46
|
-
"@dbx-tools/lakebase": "^0.9.
|
|
47
|
-
"@dbx-tools/postgres": "^0.9.
|
|
48
|
-
"@dbx-tools/shared-auth": "^0.9.
|
|
49
|
-
"@dbx-tools/shared-core": "^0.9.
|
|
50
|
-
"@dbx-tools/shared-email": "^0.9.
|
|
51
|
-
"@dbx-tools/shared-
|
|
52
|
-
"@dbx-tools/
|
|
37
|
+
"@dbx-tools/appkit": "^0.9.64",
|
|
38
|
+
"@dbx-tools/appkit-model-gateway": "^0.9.64",
|
|
39
|
+
"@dbx-tools/auth": "^0.9.64",
|
|
40
|
+
"@dbx-tools/auth-gate": "^0.9.64",
|
|
41
|
+
"@dbx-tools/cli-args": "^0.9.64",
|
|
42
|
+
"@dbx-tools/cli-service": "^0.9.64",
|
|
43
|
+
"@dbx-tools/core": "^0.9.64",
|
|
44
|
+
"@dbx-tools/databricks": "^0.9.64",
|
|
45
|
+
"@dbx-tools/email": "^0.9.64",
|
|
46
|
+
"@dbx-tools/graphiti": "^0.9.64",
|
|
47
|
+
"@dbx-tools/lakebase": "^0.9.64",
|
|
48
|
+
"@dbx-tools/postgres": "^0.9.64",
|
|
49
|
+
"@dbx-tools/shared-auth": "^0.9.64",
|
|
50
|
+
"@dbx-tools/shared-core": "^0.9.64",
|
|
51
|
+
"@dbx-tools/shared-email": "^0.9.64",
|
|
52
|
+
"@dbx-tools/shared-genie-code": "^0.9.64",
|
|
53
|
+
"@dbx-tools/shared-model-gateway": "^0.9.64",
|
|
54
|
+
"@dbx-tools/tunnel": "^0.9.64",
|
|
53
55
|
"commander": "^15.0.0",
|
|
56
|
+
"concurrently": "^10.0.3",
|
|
57
|
+
"get-port": "^7.1.0",
|
|
54
58
|
"http-proxy-3": "^1.23.1",
|
|
55
59
|
"pg": "^8.22.0",
|
|
60
|
+
"smol-toml": "1.8.0",
|
|
56
61
|
"zod": "4.3.6"
|
|
57
62
|
},
|
|
58
63
|
"main": "./lib/index.js",
|
|
@@ -63,6 +68,7 @@
|
|
|
63
68
|
"types": "./lib/index.d.ts",
|
|
64
69
|
"bin": {
|
|
65
70
|
"dbx": "./lib/bin/dbx-tools.js",
|
|
71
|
+
"dbx-genie": "./lib/bin/dbx-genie.js",
|
|
66
72
|
"dbx-graphiti": "./lib/bin/dbx-graphiti.js",
|
|
67
73
|
"dbx-lakebase-proxy": "./lib/bin/dbx-lakebase-proxy.js",
|
|
68
74
|
"dbx-model-gateway": "./lib/bin/dbx-model-gateway.js",
|
|
@@ -113,6 +119,14 @@
|
|
|
113
119
|
"types": "./lib/src/graphiti/options.d.ts",
|
|
114
120
|
"default": "./lib/src/graphiti/options.js"
|
|
115
121
|
},
|
|
122
|
+
"./genie": {
|
|
123
|
+
"types": "./lib/src/genie-code/cli.d.ts",
|
|
124
|
+
"default": "./lib/src/genie-code/cli.js"
|
|
125
|
+
},
|
|
126
|
+
"./genie/options": {
|
|
127
|
+
"types": "./lib/src/genie-code/options.d.ts",
|
|
128
|
+
"default": "./lib/src/genie-code/options.js"
|
|
129
|
+
},
|
|
116
130
|
"./lakebase-proxy": {
|
|
117
131
|
"types": "./lib/src/lakebase-proxy/cli.d.ts",
|
|
118
132
|
"default": "./lib/src/lakebase-proxy/cli.js"
|
|
@@ -140,7 +154,7 @@
|
|
|
140
154
|
"./package.json": "./package.json"
|
|
141
155
|
}
|
|
142
156
|
},
|
|
143
|
-
"version": "0.9.
|
|
157
|
+
"version": "0.9.64",
|
|
144
158
|
"types": "./lib/index.d.ts",
|
|
145
159
|
"dbxToolsConfig": {
|
|
146
160
|
"tags": [
|
|
@@ -193,6 +207,14 @@
|
|
|
193
207
|
"types": "./lib/src/graphiti/options.d.ts",
|
|
194
208
|
"default": "./lib/src/graphiti/options.js"
|
|
195
209
|
},
|
|
210
|
+
"./genie": {
|
|
211
|
+
"types": "./lib/src/genie-code/cli.d.ts",
|
|
212
|
+
"default": "./lib/src/genie-code/cli.js"
|
|
213
|
+
},
|
|
214
|
+
"./genie/options": {
|
|
215
|
+
"types": "./lib/src/genie-code/options.d.ts",
|
|
216
|
+
"default": "./lib/src/genie-code/options.js"
|
|
217
|
+
},
|
|
196
218
|
"./lakebase-proxy": {
|
|
197
219
|
"types": "./lib/src/lakebase-proxy/cli.d.ts",
|
|
198
220
|
"default": "./lib/src/lakebase-proxy/cli.js"
|
package/src/auth/cli.ts
CHANGED
|
@@ -123,10 +123,20 @@ export function buildProgram(
|
|
|
123
123
|
...(tokenOptions.login ? {} : { login: false }),
|
|
124
124
|
...(tokenOptions.forceRefresh ? { refresh: true } : {}),
|
|
125
125
|
});
|
|
126
|
-
dependencies.
|
|
126
|
+
if (tokenOptions.format === "text") dependencies.writeText(token.accessToken);
|
|
127
|
+
else dependencies.writeJson(tokenJson(token));
|
|
127
128
|
});
|
|
128
129
|
});
|
|
129
130
|
|
|
131
|
+
program
|
|
132
|
+
.command("headers")
|
|
133
|
+
.description("Return current Databricks authentication headers")
|
|
134
|
+
.action(async () => {
|
|
135
|
+
await withAuth(options(), dependencies, async ({ auth }) => {
|
|
136
|
+
dependencies.writeJson(await auth.headers());
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
|
|
130
140
|
program
|
|
131
141
|
.command("profile")
|
|
132
142
|
.description("Print the configured or automatically detected profile")
|
package/src/auth/options.ts
CHANGED
|
@@ -48,6 +48,10 @@ export const TokenCommandOptionsSchema = z
|
|
|
48
48
|
.object({
|
|
49
49
|
forceRefresh: z.boolean().default(false).describe("Refresh the token before returning it."),
|
|
50
50
|
login: z.boolean().default(true).describe("Log in when credentials are missing or invalid."),
|
|
51
|
+
format: z
|
|
52
|
+
.enum(["json", "text"])
|
|
53
|
+
.default("json")
|
|
54
|
+
.describe("Output structured token metadata or only the access token."),
|
|
51
55
|
})
|
|
52
56
|
.strict()
|
|
53
57
|
.describe("Options for returning a Databricks access token.");
|
package/src/cli.ts
CHANGED
|
@@ -59,8 +59,9 @@ export async function prepareAndRunProjen(projenArgs: string[], startDir?: strin
|
|
|
59
59
|
/**
|
|
60
60
|
* Mount `name` as a command that captures every following token verbatim and
|
|
61
61
|
* hands it to the program `load()` resolves. `helpOption(false)` is what lets
|
|
62
|
-
* `--help` through to the child instead of being answered here, and
|
|
63
|
-
*
|
|
62
|
+
* `--help` through to the child instead of being answered here, and
|
|
63
|
+
* `passThroughOptions()` keeps unknown flags in that token list so the child
|
|
64
|
+
* program owns them.
|
|
64
65
|
*/
|
|
65
66
|
function addForwardedCommand(
|
|
66
67
|
program: Command,
|
|
@@ -73,6 +74,7 @@ function addForwardedCommand(
|
|
|
73
74
|
.description(description)
|
|
74
75
|
.argument("[args...]", `arguments forwarded to ${name}`)
|
|
75
76
|
.allowUnknownOption()
|
|
77
|
+
.passThroughOptions()
|
|
76
78
|
.allowExcessArguments()
|
|
77
79
|
.helpOption(false)
|
|
78
80
|
.action(async (args: string[]) => {
|
|
@@ -88,6 +90,7 @@ export function buildProgram(name: string = PROGRAM_NAMES[0]): Command {
|
|
|
88
90
|
.description(
|
|
89
91
|
"Databricks developer tools: workspace lifecycle, AppKit env, auth, tunnels, and local proxies",
|
|
90
92
|
)
|
|
93
|
+
.enablePositionalOptions()
|
|
91
94
|
.showHelpAfterError()
|
|
92
95
|
.helpOption("-h, --help", `Show ${name} help`);
|
|
93
96
|
|
|
@@ -137,6 +140,13 @@ export function buildProgram(name: string = PROGRAM_NAMES[0]): Command {
|
|
|
137
140
|
async () => (await import("./model-gateway/cli.ts")).buildProgram,
|
|
138
141
|
);
|
|
139
142
|
|
|
143
|
+
addForwardedCommand(
|
|
144
|
+
program,
|
|
145
|
+
"genie",
|
|
146
|
+
"Run managed Genie Code through a local Databricks model gateway",
|
|
147
|
+
async () => (await import("./genie-code/cli.ts")).buildProgram,
|
|
148
|
+
);
|
|
149
|
+
|
|
140
150
|
addForwardedCommand(
|
|
141
151
|
program,
|
|
142
152
|
"graphiti",
|
|
@@ -150,16 +160,17 @@ export function buildProgram(name: string = PROGRAM_NAMES[0]): Command {
|
|
|
150
160
|
/** Build the complete command tree used for generated documentation. */
|
|
151
161
|
export async function buildDocumentationProgram(name: string = PROGRAM_NAMES[0]): Promise<Command> {
|
|
152
162
|
const program = buildProgram(name);
|
|
153
|
-
|
|
154
|
-
1,
|
|
155
|
-
program.commands.length - 1,
|
|
163
|
+
const children = [
|
|
156
164
|
(await import("./appkit/cli.ts")).buildProgram("appkit"),
|
|
157
165
|
(await import("./auth/cli.ts")).buildProgram("auth"),
|
|
158
166
|
(await import("./tunnel/cli.ts")).buildProgram("tunnel"),
|
|
159
167
|
(await import("./lakebase-proxy/cli.ts")).buildProgram("lakebase-proxy"),
|
|
160
168
|
(await import("./model-gateway/cli.ts")).buildProgram("model-gateway"),
|
|
169
|
+
(await import("./genie-code/cli.ts")).buildProgram("genie"),
|
|
161
170
|
(await import("./graphiti/cli.ts")).buildProgram("graphiti"),
|
|
162
|
-
|
|
171
|
+
];
|
|
172
|
+
(program.commands as Command[]).splice(1, program.commands.length - 1);
|
|
173
|
+
for (const child of children) program.addCommand(child);
|
|
163
174
|
return program;
|
|
164
175
|
}
|
|
165
176
|
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Managed `dbx genie` command.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { addArgs, parseArgs } from "@dbx-tools/cli-args";
|
|
8
|
+
import { Command } from "commander";
|
|
9
|
+
|
|
10
|
+
import { GenieCodeCliOptionsSchema, type GenieCodeCliOptions } from "./options.ts";
|
|
11
|
+
import { runGenieCode } from "./runtime.ts";
|
|
12
|
+
|
|
13
|
+
/** Injectable managed Genie execution boundary for parser tests and embedding. */
|
|
14
|
+
export interface GenieCodeCliDependencies {
|
|
15
|
+
run(input: {
|
|
16
|
+
cwd: string;
|
|
17
|
+
genieArgs: readonly string[];
|
|
18
|
+
options: GenieCodeCliOptions;
|
|
19
|
+
}): Promise<void>;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const DEFAULT_DEPENDENCIES: GenieCodeCliDependencies = {
|
|
23
|
+
run: runGenieCode,
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
/** Build the managed Genie Code command without executing it. */
|
|
27
|
+
export function buildProgram(
|
|
28
|
+
name = "dbx genie",
|
|
29
|
+
dependencies: GenieCodeCliDependencies = DEFAULT_DEPENDENCIES,
|
|
30
|
+
): Command {
|
|
31
|
+
const program = addArgs(
|
|
32
|
+
new Command()
|
|
33
|
+
.name(name)
|
|
34
|
+
.description("Run Genie Code through an authenticated local Databricks model gateway")
|
|
35
|
+
.argument(
|
|
36
|
+
"[genieArgs...]",
|
|
37
|
+
"arguments and unknown flags forwarded to Genie Code; wrapper options may be separated with --",
|
|
38
|
+
)
|
|
39
|
+
.allowUnknownOption()
|
|
40
|
+
.passThroughOptions()
|
|
41
|
+
.allowExcessArguments()
|
|
42
|
+
.showHelpAfterError(),
|
|
43
|
+
GenieCodeCliOptionsSchema,
|
|
44
|
+
);
|
|
45
|
+
program.action(async (genieArgs: string[]) => {
|
|
46
|
+
await dependencies.run({
|
|
47
|
+
cwd: process.cwd(),
|
|
48
|
+
genieArgs,
|
|
49
|
+
options: parseArgs(program, GenieCodeCliOptionsSchema),
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
return program;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** Parse argv and run managed Genie Code. */
|
|
56
|
+
export async function runCli(argv: string[]): Promise<void> {
|
|
57
|
+
await buildProgram().parseAsync(argv);
|
|
58
|
+
}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generate one persistent Genie Code home per exact profile-model pairing.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
8
|
+
import { chmod, mkdir, readFile, rename, rm, writeFile } from "node:fs/promises";
|
|
9
|
+
import { homedir } from "node:os";
|
|
10
|
+
import { dirname, join, resolve } from "node:path";
|
|
11
|
+
import { withFileLock } from "@dbx-tools/core/file-lock";
|
|
12
|
+
import { object } from "@dbx-tools/shared-core";
|
|
13
|
+
import {
|
|
14
|
+
GenieCodeBaseConfigSchema,
|
|
15
|
+
GenieCodeConfigSchema,
|
|
16
|
+
GenieCodeProviderOverlaySchema,
|
|
17
|
+
type GenieCodeBaseConfig,
|
|
18
|
+
type GenieCodeConfig,
|
|
19
|
+
type GenieCodeProviderOverlay,
|
|
20
|
+
} from "@dbx-tools/shared-genie-code/config";
|
|
21
|
+
import { genieCodeHomeName } from "@dbx-tools/shared-genie-code/options";
|
|
22
|
+
import { parse, stringify } from "smol-toml";
|
|
23
|
+
|
|
24
|
+
/** Provider identifier written to the base and invocation overlay configurations. */
|
|
25
|
+
export const GENIE_CODE_GATEWAY_PROVIDER = "dbx_tools_model_gateway";
|
|
26
|
+
|
|
27
|
+
/** Inputs used to update a persistent home and create one invocation overlay. */
|
|
28
|
+
export interface WriteGenieCodeConfigOptions {
|
|
29
|
+
bearerToken: string;
|
|
30
|
+
gatewayBaseUrl: string;
|
|
31
|
+
homeDirectory?: string;
|
|
32
|
+
model: string;
|
|
33
|
+
profile: string;
|
|
34
|
+
projectDirectory: string;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** Stable persistent home for one exact Databricks profile. */
|
|
38
|
+
export interface GenieCodeProfileHome {
|
|
39
|
+
configPath: string;
|
|
40
|
+
home: string;
|
|
41
|
+
name: string;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** Persistent profile home and invocation-specific model-provider overlay. */
|
|
45
|
+
export interface GenieCodeHome extends GenieCodeProfileHome {
|
|
46
|
+
overlayName: string;
|
|
47
|
+
overlayPath: string;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** Derive the stable home for one exact Databricks profile. */
|
|
51
|
+
export function genieCodeHome(
|
|
52
|
+
profile: string,
|
|
53
|
+
homeDirectory: string = homedir(),
|
|
54
|
+
): GenieCodeProfileHome {
|
|
55
|
+
const digest = createHash("sha256").update(profile).digest("hex").slice(0, 12);
|
|
56
|
+
const name = genieCodeHomeName({ profile, digest });
|
|
57
|
+
const home = join(homeDirectory, ".dbx-tools", "genie", "profiles", name);
|
|
58
|
+
return { name, home, configPath: join(home, "config.toml") };
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** Render the persistent profile-model configuration. */
|
|
62
|
+
export function genieCodeBaseConfig(
|
|
63
|
+
options: WriteGenieCodeConfigOptions,
|
|
64
|
+
existingProjects: Readonly<Record<string, unknown>> = {},
|
|
65
|
+
): GenieCodeBaseConfig {
|
|
66
|
+
const projects = Object.fromEntries(
|
|
67
|
+
Object.entries(existingProjects).filter(
|
|
68
|
+
([, value]) => object.isRecord(value) && value.trust_level === "trusted",
|
|
69
|
+
),
|
|
70
|
+
);
|
|
71
|
+
return GenieCodeBaseConfigSchema.parse({
|
|
72
|
+
databricks_profile: options.profile,
|
|
73
|
+
projects: {
|
|
74
|
+
...projects,
|
|
75
|
+
[resolve(options.projectDirectory)]: {
|
|
76
|
+
trust_level: "trusted",
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** Render the invocation-specific guarded provider configuration. */
|
|
83
|
+
export function genieCodeProviderOverlay(
|
|
84
|
+
options: WriteGenieCodeConfigOptions,
|
|
85
|
+
): GenieCodeProviderOverlay {
|
|
86
|
+
return GenieCodeProviderOverlaySchema.parse({
|
|
87
|
+
model_provider: GENIE_CODE_GATEWAY_PROVIDER,
|
|
88
|
+
model: options.model,
|
|
89
|
+
model_providers: {
|
|
90
|
+
[GENIE_CODE_GATEWAY_PROVIDER]: {
|
|
91
|
+
name: "dbx-tools model gateway",
|
|
92
|
+
base_url: options.gatewayBaseUrl,
|
|
93
|
+
wire_api: "responses",
|
|
94
|
+
requires_openai_auth: false,
|
|
95
|
+
supports_websockets: false,
|
|
96
|
+
http_headers: {
|
|
97
|
+
Authorization: `Bearer ${options.bearerToken}`,
|
|
98
|
+
Originator: "codex",
|
|
99
|
+
},
|
|
100
|
+
},
|
|
101
|
+
},
|
|
102
|
+
tui: {
|
|
103
|
+
model_availability_nux: {
|
|
104
|
+
[options.model]: 1,
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/** Render the merged configuration used by validation and tests. */
|
|
111
|
+
export function genieCodeConfig(options: WriteGenieCodeConfigOptions): GenieCodeConfig {
|
|
112
|
+
return GenieCodeConfigSchema.parse({
|
|
113
|
+
...genieCodeBaseConfig(options),
|
|
114
|
+
...genieCodeProviderOverlay(options),
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
async function existingProjects(path: string): Promise<Record<string, unknown>> {
|
|
119
|
+
try {
|
|
120
|
+
const value = parse(await readFile(path, "utf8"));
|
|
121
|
+
return object.isRecord(value.projects) ? value.projects : {};
|
|
122
|
+
} catch (error) {
|
|
123
|
+
if (error instanceof Error && "code" in error && error.code === "ENOENT") return {};
|
|
124
|
+
throw error;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
async function writePrivateToml(path: string, value: unknown): Promise<void> {
|
|
129
|
+
const staged = join(dirname(path), `.${randomUUID()}.toml`);
|
|
130
|
+
try {
|
|
131
|
+
await writeFile(staged, stringify(value), { mode: 0o600 });
|
|
132
|
+
await chmod(staged, 0o600);
|
|
133
|
+
await rename(staged, path);
|
|
134
|
+
} finally {
|
|
135
|
+
await rm(staged, { force: true });
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/** Update the persistent base config and write one private invocation overlay. */
|
|
140
|
+
export async function writeGenieCodeConfig(
|
|
141
|
+
options: WriteGenieCodeConfigOptions,
|
|
142
|
+
): Promise<GenieCodeHome> {
|
|
143
|
+
const base = genieCodeHome(options.profile, options.homeDirectory);
|
|
144
|
+
const overlayName = `dbx-${randomUUID().replaceAll("-", "")}`;
|
|
145
|
+
const destination = {
|
|
146
|
+
...base,
|
|
147
|
+
overlayName,
|
|
148
|
+
overlayPath: join(base.home, `${overlayName}.config.toml`),
|
|
149
|
+
};
|
|
150
|
+
await mkdir(destination.home, { recursive: true });
|
|
151
|
+
await withFileLock(["genie-code-config", destination.configPath], async () => {
|
|
152
|
+
const projects = await existingProjects(destination.configPath);
|
|
153
|
+
await writePrivateToml(destination.configPath, genieCodeBaseConfig(options, projects));
|
|
154
|
+
});
|
|
155
|
+
await writePrivateToml(destination.overlayPath, genieCodeProviderOverlay(options));
|
|
156
|
+
return destination;
|
|
157
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Install the pinned multi-file Genie Code runtime under dbx-tools ownership.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { homedir } from "node:os";
|
|
8
|
+
import { dirname, join } from "node:path";
|
|
9
|
+
import { bin } from "@dbx-tools/core";
|
|
10
|
+
import { GENIE_CODE_VERSION } from "@dbx-tools/shared-genie-code/options";
|
|
11
|
+
|
|
12
|
+
interface GenieCodeAsset {
|
|
13
|
+
target: string;
|
|
14
|
+
sha256: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const GENIE_CODE_ASSETS = {
|
|
18
|
+
"darwin:arm64": {
|
|
19
|
+
target: "aarch64-apple-darwin",
|
|
20
|
+
sha256: "78cc7e358c8bfc62d6da26364c762be37fc2e2a10b7e83f21a3b166f901f528e",
|
|
21
|
+
},
|
|
22
|
+
"darwin:x64": {
|
|
23
|
+
target: "x86_64-apple-darwin",
|
|
24
|
+
sha256: "2021b8b27ec3116fc015c1676b5f65c3ce11d57f1dff9c302aae135f6e4f1a5f",
|
|
25
|
+
},
|
|
26
|
+
"linux:arm64": {
|
|
27
|
+
target: "aarch64-unknown-linux-musl",
|
|
28
|
+
sha256: "dfd278c267dde43e1fe7e7d7a0da8d7a1a148cdf3d2004bd30b351645c4fe0a7",
|
|
29
|
+
},
|
|
30
|
+
"linux:x64": {
|
|
31
|
+
target: "x86_64-unknown-linux-musl",
|
|
32
|
+
sha256: "e3d9a55f6d51bdc745eda4744fb827ba1df6dacf1069518f7347a59f48c89430",
|
|
33
|
+
},
|
|
34
|
+
"win32:arm64": {
|
|
35
|
+
target: "aarch64-pc-windows-msvc",
|
|
36
|
+
sha256: "aeac95bd0148f942194270ba932245cec32e98da67292ba7b008bcab675ba7f8",
|
|
37
|
+
},
|
|
38
|
+
"win32:x64": {
|
|
39
|
+
target: "x86_64-pc-windows-msvc",
|
|
40
|
+
sha256: "c9f92c8d60273250262527bca525451501c4e8351e59927a1686c305be29a922",
|
|
41
|
+
},
|
|
42
|
+
} as const satisfies Record<string, GenieCodeAsset>;
|
|
43
|
+
|
|
44
|
+
/** Host overrides used by installation tests and embedded callers. */
|
|
45
|
+
export interface InstallGenieCodeOptions {
|
|
46
|
+
homeDirectory?: string;
|
|
47
|
+
platform?: NodeJS.Platform;
|
|
48
|
+
architecture?: NodeJS.Architecture;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** Resolve the pinned release asset for one supported host. */
|
|
52
|
+
export function genieCodeAsset(
|
|
53
|
+
platform: NodeJS.Platform = process.platform,
|
|
54
|
+
architecture: NodeJS.Architecture = process.arch,
|
|
55
|
+
): GenieCodeAsset {
|
|
56
|
+
const asset = GENIE_CODE_ASSETS[`${platform}:${architecture}` as keyof typeof GENIE_CODE_ASSETS];
|
|
57
|
+
if (!asset) {
|
|
58
|
+
throw new Error(
|
|
59
|
+
`Genie Code ${GENIE_CODE_VERSION} does not support ${platform}/${architecture}`,
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
return asset;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/** Install and return the shared Genie Code package entrypoint. */
|
|
66
|
+
export async function installGenieCode(
|
|
67
|
+
options: InstallGenieCodeOptions = {},
|
|
68
|
+
): Promise<bin.BinContext> {
|
|
69
|
+
const platform = options.platform ?? process.platform;
|
|
70
|
+
const asset = genieCodeAsset(platform, options.architecture ?? process.arch);
|
|
71
|
+
const executable = platform === "win32" ? "genie.exe" : "genie";
|
|
72
|
+
const helper = platform === "win32" ? "genie-code-mode-host.exe" : "genie-code-mode-host";
|
|
73
|
+
const entrypoint = join("bin", executable);
|
|
74
|
+
const root = join(
|
|
75
|
+
options.homeDirectory ?? homedir(),
|
|
76
|
+
".dbx-tools",
|
|
77
|
+
"genie",
|
|
78
|
+
"releases",
|
|
79
|
+
`${GENIE_CODE_VERSION}-${asset.target}`,
|
|
80
|
+
);
|
|
81
|
+
const destination: bin.BinContext = {
|
|
82
|
+
root,
|
|
83
|
+
binDir: join(root, dirname(entrypoint)),
|
|
84
|
+
path: join(root, entrypoint),
|
|
85
|
+
};
|
|
86
|
+
const url =
|
|
87
|
+
`https://github.com/databricks/genie-code-cli/releases/download/v${GENIE_CODE_VERSION}/` +
|
|
88
|
+
`genie-package-${asset.target}.tar.gz`;
|
|
89
|
+
return bin.ensure(
|
|
90
|
+
"genie",
|
|
91
|
+
{ url, sha256: asset.sha256 },
|
|
92
|
+
{
|
|
93
|
+
destination,
|
|
94
|
+
minVersion: "0.1.0",
|
|
95
|
+
versionParser: ({ stdout }) =>
|
|
96
|
+
stdout.trim() === `genie ${GENIE_CODE_VERSION}` ? "0.1.0" : undefined,
|
|
97
|
+
package: {
|
|
98
|
+
entrypoint,
|
|
99
|
+
requiredPaths: ["genie-package.json", join("bin", helper), "genie-path", "genie-resources"],
|
|
100
|
+
},
|
|
101
|
+
},
|
|
102
|
+
);
|
|
103
|
+
}
|