Skip to content

Commit 4d142c0

Browse files
committed
chore: poc manifest 4
1 parent c7f5fa6 commit 4d142c0

13 files changed

Lines changed: 762 additions & 218 deletions

File tree

packages/appkit/src/plugins/analytics/manifest.json

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
"name": "analytics",
44
"displayName": "Analytics Plugin",
55
"description": "SQL query execution against Databricks SQL Warehouses",
6+
"agentHint": "Run 'databricks warehouses list' to find your SQL Warehouse ID.",
67
"resources": {
78
"required": [
89
{
@@ -14,7 +15,14 @@
1415
"fields": {
1516
"id": {
1617
"env": "DATABRICKS_WAREHOUSE_ID",
17-
"description": "SQL Warehouse ID"
18+
"description": "SQL Warehouse ID",
19+
"resolution": "user-provided",
20+
"discovery": {
21+
"cliCommand": "databricks warehouses list --profile <PROFILE> -o json",
22+
"selectField": ".id",
23+
"displayField": ".name",
24+
"shortcut": "databricks experimental aitools tools get-default-warehouse --profile <PROFILE>"
25+
}
1826
}
1927
}
2028
}
@@ -32,5 +40,18 @@
3240
}
3341
}
3442
}
35-
}
43+
},
44+
"postScaffold": [
45+
{ "step": 1, "instruction": "Create SQL query files in config/queries/" },
46+
{ "step": 2, "instruction": "Run: npm run typegen", "blocking": true },
47+
{
48+
"step": 3,
49+
"instruction": "Read client/src/appKitTypes.d.ts for generated types"
50+
},
51+
{ "step": 4, "instruction": "Write UI code using the generated types" },
52+
{
53+
"step": 5,
54+
"instruction": "Update tests/smoke.spec.ts selectors for your app"
55+
}
56+
]
3657
}

packages/appkit/src/plugins/files/manifest.json

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
"name": "files",
44
"displayName": "Files Plugin",
55
"description": "File operations against Databricks Volumes and Unity Catalog",
6+
"agentHint": "Provide the full volume path, e.g. /Volumes/catalog/schema/volume_name.",
67
"resources": {
78
"required": [
89
{
@@ -14,7 +15,13 @@
1415
"fields": {
1516
"path": {
1617
"env": "DATABRICKS_VOLUME_FILES",
17-
"description": "Volume path for file storage (e.g. /Volumes/catalog/schema/volume_name)"
18+
"description": "Volume path for file storage (e.g. /Volumes/catalog/schema/volume_name)",
19+
"resolution": "user-provided",
20+
"discovery": {
21+
"cliCommand": "databricks volumes list <catalog>.<schema> --profile <PROFILE> -o json",
22+
"selectField": ".full_name",
23+
"displayField": ".name"
24+
}
1825
}
1926
}
2027
}
@@ -37,5 +44,12 @@
3744
}
3845
}
3946
}
40-
}
47+
},
48+
"postScaffold": [
49+
{
50+
"step": 1,
51+
"instruction": "Use the files plugin API to read/write volume files in your tRPC procedures"
52+
},
53+
{ "step": 2, "instruction": "Build UI for file upload/download using tRPC" }
54+
]
4155
}

packages/appkit/src/plugins/genie/manifest.json

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
{
2+
"$schema": "https://databricks.github.io/appkit/schemas/plugin-manifest.schema.json",
23
"name": "genie",
34
"displayName": "Genie Plugin",
45
"description": "AI/BI Genie space integration for natural language data queries",
6+
"agentHint": "Find your Genie Space ID in the AI/BI Genie UI.",
57
"resources": {
68
"required": [
79
{
@@ -13,7 +15,13 @@
1315
"fields": {
1416
"id": {
1517
"env": "DATABRICKS_GENIE_SPACE_ID",
16-
"description": "Default Genie Space ID"
18+
"description": "Default Genie Space ID",
19+
"resolution": "user-provided",
20+
"discovery": {
21+
"cliCommand": "databricks genie list-spaces --profile <PROFILE> -o json",
22+
"selectField": ".space_id",
23+
"displayField": ".title"
24+
}
1725
}
1826
}
1927
}

packages/appkit/src/plugins/lakebase/manifest.json

Lines changed: 48 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
"displayName": "Lakebase",
55
"description": "SQL query execution against Databricks Lakebase Autoscaling",
66
"hidden": false,
7+
"agentHint": "Run 'databricks postgres list-branches' to find your Lakebase branch.",
78
"resources": {
89
"required": [
910
{
@@ -15,25 +16,38 @@
1516
"fields": {
1617
"branch": {
1718
"description": "Full Lakebase Postgres branch resource name. Obtain by running `databricks postgres list-branches projects/{project-id}`, select the desired item from the output array and use its .name value.",
18-
"examples": ["projects/{project-id}/branches/{branch-id}"]
19+
"examples": ["projects/{project-id}/branches/{branch-id}"],
20+
"resolution": "user-provided",
21+
"discovery": {
22+
"cliCommand": "databricks postgres list-branches projects/{project-id} --profile <PROFILE> -o json",
23+
"selectField": ".name"
24+
}
1925
},
2026
"database": {
2127
"description": "Full Lakebase Postgres database resource name. Obtain by running `databricks postgres list-databases {branch-name}`, select the desired item from the output array and use its .name value. Requires the branch resource name.",
2228
"examples": [
2329
"projects/{project-id}/branches/{branch-id}/databases/{database-id}"
24-
]
30+
],
31+
"resolution": "user-provided",
32+
"discovery": {
33+
"cliCommand": "databricks postgres list-databases {branch} --profile <PROFILE> -o json",
34+
"selectField": ".name",
35+
"dependsOn": "branch"
36+
}
2537
},
2638
"host": {
2739
"env": "PGHOST",
2840
"localOnly": true,
2941
"resolve": "postgres:host",
30-
"description": "Postgres host for local development. Auto-injected by the platform at deploy time."
42+
"description": "Postgres host for local development. Auto-injected by the platform at deploy time.",
43+
"resolution": "platform-injected"
3144
},
3245
"databaseName": {
3346
"env": "PGDATABASE",
3447
"localOnly": true,
3548
"resolve": "postgres:databaseName",
36-
"description": "Postgres database name for local development. Auto-injected by the platform at deploy time."
49+
"description": "Postgres database name for local development. Auto-injected by the platform at deploy time.",
50+
"resolution": "platform-injected"
3751
},
3852
"endpointPath": {
3953
"env": "LAKEBASE_ENDPOINT",
@@ -42,23 +56,49 @@
4256
"description": "Lakebase endpoint resource name. Auto-injected at runtime via app.yaml valueFrom: postgres. For local development, obtain by running `databricks postgres list-endpoints {branch-name}`, select the desired item from the output array and use its .name value.",
4357
"examples": [
4458
"projects/{project-id}/branches/{branch-id}/endpoints/{endpoint-id}"
45-
]
59+
],
60+
"resolution": "user-provided",
61+
"discovery": {
62+
"cliCommand": "databricks postgres list-endpoints {branch} --profile <PROFILE> -o json",
63+
"selectField": ".name",
64+
"dependsOn": "branch"
65+
}
4666
},
4767
"port": {
4868
"env": "PGPORT",
4969
"localOnly": true,
5070
"value": "5432",
51-
"description": "Postgres port. Auto-injected by the platform at deploy time."
71+
"description": "Postgres port. Auto-injected by the platform at deploy time.",
72+
"resolution": "platform-injected"
5273
},
5374
"sslmode": {
5475
"env": "PGSSLMODE",
5576
"localOnly": true,
5677
"value": "require",
57-
"description": "Postgres SSL mode. Auto-injected by the platform at deploy time."
78+
"description": "Postgres SSL mode. Auto-injected by the platform at deploy time.",
79+
"resolution": "platform-injected"
5880
}
5981
}
6082
}
6183
],
6284
"optional": []
63-
}
85+
},
86+
"postScaffold": [
87+
{
88+
"step": 1,
89+
"instruction": "Define your schema in server/server.ts startup"
90+
},
91+
{
92+
"step": 2,
93+
"instruction": "Write tRPC procedures using pool.query() in server/server.ts"
94+
},
95+
{
96+
"step": 3,
97+
"instruction": "Build React frontend consuming tRPC procedures"
98+
},
99+
{
100+
"step": 4,
101+
"instruction": "Update tests/smoke.spec.ts selectors for your app"
102+
}
103+
]
64104
}

packages/shared/src/cli/commands/plugin/list/list.test.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,12 @@ function cleanDir(dir: string): void {
2323
const TEMPLATE_MANIFEST_JSON = {
2424
$schema:
2525
"https://databricks.github.io/appkit/schemas/template-plugins.schema.json",
26-
version: "1.0",
26+
version: "2.0",
27+
scaffolding: {
28+
command: "databricks apps init",
29+
flags: { "--name": { required: true, description: "App name" } },
30+
rules: [],
31+
},
2732
plugins: {
2833
server: {
2934
name: "server",
@@ -94,7 +99,12 @@ describe("list", () => {
9499
JSON.stringify({
95100
$schema:
96101
"https://databricks.github.io/appkit/schemas/template-plugins.schema.json",
97-
version: "1.0",
102+
version: "2.0",
103+
scaffolding: {
104+
command: "databricks apps init",
105+
flags: { "--name": { required: true, description: "App name" } },
106+
rules: [],
107+
},
98108
plugins: {},
99109
}),
100110
);

packages/shared/src/cli/commands/plugin/manifest-types.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,19 @@ export type {
1313

1414
import type { PluginManifest } from "../../../schemas/plugin-manifest.generated";
1515

16+
export interface ScaffoldingFlag {
17+
required: boolean;
18+
description: string;
19+
pattern?: string;
20+
default?: string;
21+
}
22+
23+
export interface ScaffoldingDescriptor {
24+
command: string;
25+
flags: Record<string, ScaffoldingFlag>;
26+
rules: string[];
27+
}
28+
1629
export interface TemplatePlugin extends Omit<PluginManifest, "config"> {
1730
package: string;
1831
/** When true, this plugin is required by the template and cannot be deselected during CLI init. */
@@ -22,5 +35,6 @@ export interface TemplatePlugin extends Omit<PluginManifest, "config"> {
2235
export interface TemplatePluginsManifest {
2336
$schema: string;
2437
version: string;
38+
scaffolding: ScaffoldingDescriptor;
2539
plugins: Record<string, TemplatePlugin>;
2640
}

packages/shared/src/cli/commands/plugin/sync/sync.test.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
isWithinDirectory,
66
parseImports,
77
parsePluginUsages,
8+
SCAFFOLDING_DESCRIPTOR,
89
shouldAllowJsManifestForPackage,
910
} from "./sync";
1011

@@ -182,4 +183,45 @@ describe("plugin sync", () => {
182183
expect(shouldAllowJsManifestForPackage("@acme/plugin")).toBe(false);
183184
});
184185
});
186+
187+
describe("SCAFFOLDING_DESCRIPTOR", () => {
188+
it("has the required databricks apps init command", () => {
189+
expect(SCAFFOLDING_DESCRIPTOR.command).toBe("databricks apps init");
190+
});
191+
192+
it("has all required flags with correct required status", () => {
193+
expect(SCAFFOLDING_DESCRIPTOR.flags["--name"].required).toBe(true);
194+
expect(SCAFFOLDING_DESCRIPTOR.flags["--profile"].required).toBe(true);
195+
expect(SCAFFOLDING_DESCRIPTOR.flags["--features"].required).toBe(false);
196+
expect(SCAFFOLDING_DESCRIPTOR.flags["--set"].required).toBe(false);
197+
expect(SCAFFOLDING_DESCRIPTOR.flags["--run"].required).toBe(false);
198+
});
199+
200+
it("has a pattern for --name that enforces app name format", () => {
201+
const pattern = SCAFFOLDING_DESCRIPTOR.flags["--name"].pattern;
202+
expect(pattern).toBeDefined();
203+
const re = new RegExp(pattern!);
204+
expect(re.test("my-app")).toBe(true);
205+
expect(re.test("my app")).toBe(false);
206+
expect(re.test("MyApp")).toBe(false);
207+
expect(re.test("a".repeat(26))).toBe(true);
208+
expect(re.test("a".repeat(27))).toBe(false);
209+
});
210+
211+
it("has a default of none for --run", () => {
212+
expect(SCAFFOLDING_DESCRIPTOR.flags["--run"].default).toBe("none");
213+
});
214+
215+
it("has rules that mention platform-injected and user-provided", () => {
216+
const rulesText = SCAFFOLDING_DESCRIPTOR.rules.join(" ");
217+
expect(rulesText).toContain("platform-injected");
218+
expect(rulesText).toContain("user-provided");
219+
});
220+
221+
it("has rules that clarify requiredByTemplate behaviour", () => {
222+
const rulesText = SCAFFOLDING_DESCRIPTOR.rules.join(" ");
223+
expect(rulesText).toContain("requiredByTemplate=true");
224+
expect(rulesText).toContain("--features");
225+
});
226+
});
185227
});

0 commit comments

Comments
 (0)