create-graphene 0.0.16 → 0.0.18
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/cli.js +230 -70
- package/package.json +5 -2
package/dist/cli.js
CHANGED
|
@@ -6,14 +6,19 @@ import * as clack from "@clack/prompts";
|
|
|
6
6
|
import { spawn } from "node:child_process";
|
|
7
7
|
import { access, mkdir, readFile, readlink, readdir, symlink, writeFile } from "node:fs/promises";
|
|
8
8
|
import path2 from "node:path";
|
|
9
|
+
import { styleText } from "node:util";
|
|
9
10
|
|
|
10
11
|
// ../cli/package.json
|
|
11
12
|
var package_default = {
|
|
12
13
|
name: "@graphenedata/cli",
|
|
13
|
-
version: "0.0.
|
|
14
|
+
version: "0.0.18",
|
|
14
15
|
private: true,
|
|
15
16
|
license: "Elastic-2.0",
|
|
16
17
|
author: "Graphene Systems Inc",
|
|
18
|
+
repository: {
|
|
19
|
+
type: "git",
|
|
20
|
+
url: "git+https://github.com/graphene-data/graphene.git"
|
|
21
|
+
},
|
|
17
22
|
bin: {
|
|
18
23
|
graphene: "./bin.js"
|
|
19
24
|
},
|
|
@@ -53,6 +58,7 @@ var package_default = {
|
|
|
53
58
|
json5: "^2.2.3",
|
|
54
59
|
mdsvex: "^0.12.6",
|
|
55
60
|
"sanitize-html": "^2.17.0",
|
|
61
|
+
svelte: "5.55.3",
|
|
56
62
|
unified: "^11.0.5",
|
|
57
63
|
"unist-util-visit": "4.1.2",
|
|
58
64
|
vite: "7.3.2",
|
|
@@ -113,7 +119,7 @@ var CreateCancelled = class extends Error {
|
|
|
113
119
|
}
|
|
114
120
|
};
|
|
115
121
|
function parseArgs(argv) {
|
|
116
|
-
let options = { yes: false, install: true, name: void 0, targetDir: void 0, help: false };
|
|
122
|
+
let options = { yes: false, install: true, skipCredentialValidation: false, name: void 0, targetDir: void 0, help: false };
|
|
117
123
|
for (let i = 0; i < argv.length; i++) {
|
|
118
124
|
let arg = argv[i];
|
|
119
125
|
if (arg === "--yes" || arg === "-y") {
|
|
@@ -124,6 +130,10 @@ function parseArgs(argv) {
|
|
|
124
130
|
options.install = false;
|
|
125
131
|
continue;
|
|
126
132
|
}
|
|
133
|
+
if (arg === "--skip-credential-validation") {
|
|
134
|
+
options.skipCredentialValidation = true;
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
127
137
|
if (arg === "--help" || arg === "-h") {
|
|
128
138
|
options.help = true;
|
|
129
139
|
continue;
|
|
@@ -167,8 +177,10 @@ function renderTemplate({ answers, cliVersion }) {
|
|
|
167
177
|
if (answers.duckdbPath) graphene.duckdb = { path: answers.duckdbPath };
|
|
168
178
|
} else if (answers.database === "snowflake") {
|
|
169
179
|
graphene.snowflake = { account: answers.snowflakeAccount || "", username: answers.snowflakeUsername || "" };
|
|
170
|
-
} else {
|
|
180
|
+
} else if (answers.database === "bigquery") {
|
|
171
181
|
graphene.bigquery = { projectId: answers.bigqueryProjectId || "" };
|
|
182
|
+
} else {
|
|
183
|
+
graphene.clickhouse = { url: answers.clickhouseUrl || "", username: answers.clickhouseUsername || "" };
|
|
172
184
|
}
|
|
173
185
|
let pkg = {
|
|
174
186
|
name: answers.projectName,
|
|
@@ -191,7 +203,7 @@ function renderTemplate({ answers, cliVersion }) {
|
|
|
191
203
|
let files = {
|
|
192
204
|
"package.json": JSON.stringify(pkg, null, 2) + "\n",
|
|
193
205
|
".gitignore": ["node_modules", ".env", "*.duckdb"].join("\n") + "\n",
|
|
194
|
-
|
|
206
|
+
[agentsFileName(answers.skillLinkTarget)]: renderAgents(answers),
|
|
195
207
|
"index.md": renderIndex(answers)
|
|
196
208
|
};
|
|
197
209
|
if (answers.packageManager?.name === "yarn") files[".yarnrc.yml"] = "nodeLinker: node-modules\n";
|
|
@@ -205,6 +217,10 @@ function grapheneCommand(packageManager, args) {
|
|
|
205
217
|
if (packageManager?.name === "bun") return `bun run graphene ${args}`;
|
|
206
218
|
return `npx graphene ${args}`;
|
|
207
219
|
}
|
|
220
|
+
function agentsFileName(skillLinkTarget) {
|
|
221
|
+
if (skillLinkTarget === ".claude") return "CLAUDE.md";
|
|
222
|
+
return "AGENTS.md";
|
|
223
|
+
}
|
|
208
224
|
function renderAgents(answers) {
|
|
209
225
|
return [
|
|
210
226
|
"## Graphene Reference",
|
|
@@ -221,6 +237,7 @@ function renderAgents(answers) {
|
|
|
221
237
|
function databaseLabel(database) {
|
|
222
238
|
if (database === "snowflake") return "Snowflake";
|
|
223
239
|
if (database === "bigquery") return "BigQuery";
|
|
240
|
+
if (database === "clickhouse") return "ClickHouse";
|
|
224
241
|
return "DuckDB";
|
|
225
242
|
}
|
|
226
243
|
function renderIndex(answers) {
|
|
@@ -233,6 +250,8 @@ function renderEnvFile(answers) {
|
|
|
233
250
|
if (answers.snowflakePassphrase) lines.push(`SNOWFLAKE_PRI_PASSPHRASE=${answers.snowflakePassphrase}`);
|
|
234
251
|
} else if (answers.database === "bigquery") {
|
|
235
252
|
lines.push(`GOOGLE_APPLICATION_CREDENTIALS=${answers.bigqueryKeyPath || ""}`);
|
|
253
|
+
} else if (answers.database === "clickhouse") {
|
|
254
|
+
lines.push(`CLICKHOUSE_PASSWORD=${answers.clickhousePassword || ""}`);
|
|
236
255
|
}
|
|
237
256
|
return lines.length ? lines.join("\n") + "\n" : null;
|
|
238
257
|
}
|
|
@@ -258,9 +277,10 @@ function printHelp(stdout) {
|
|
|
258
277
|
"Usage: npm create graphene [target-dir] [-- --yes] [--name <project-name>] [--no-install]",
|
|
259
278
|
"",
|
|
260
279
|
"Options:",
|
|
261
|
-
" -y, --yes
|
|
262
|
-
" --name <name>
|
|
263
|
-
" --no-install
|
|
280
|
+
" -y, --yes Skip prompts and accept defaults",
|
|
281
|
+
" --name <name> Set the generated package name",
|
|
282
|
+
" --no-install Skip dependency installation",
|
|
283
|
+
" --skip-credential-validation Skip warehouse credential validation"
|
|
264
284
|
].join("\n") + "\n"
|
|
265
285
|
);
|
|
266
286
|
}
|
|
@@ -280,11 +300,18 @@ function validateFileExtension(filePath, expectedExtension) {
|
|
|
280
300
|
if (typeof filePath !== "string" || !filePath.trim()) return `Path to ${expectedExtension} file is required`;
|
|
281
301
|
if (!filePath.endsWith(expectedExtension)) return `File must end with ${expectedExtension}`;
|
|
282
302
|
}
|
|
283
|
-
async function promptExistingFilePath({
|
|
303
|
+
async function promptExistingFilePath({
|
|
304
|
+
message,
|
|
305
|
+
expectedExtension,
|
|
306
|
+
initialValue,
|
|
307
|
+
input,
|
|
308
|
+
output
|
|
309
|
+
}) {
|
|
284
310
|
while (true) {
|
|
285
311
|
let filePath = unwrapPrompt(
|
|
286
312
|
await clack.path({
|
|
287
313
|
message,
|
|
314
|
+
initialValue,
|
|
288
315
|
validate: (value) => validateFileExtension(value, expectedExtension),
|
|
289
316
|
...promptOptions(input, output)
|
|
290
317
|
})
|
|
@@ -297,14 +324,10 @@ async function promptExistingFilePath({ message, expectedExtension, input, outpu
|
|
|
297
324
|
}
|
|
298
325
|
}
|
|
299
326
|
}
|
|
300
|
-
function namespacePlaceholder(database) {
|
|
301
|
-
if (database === "snowflake") return "MY_DB.ANALYTICS";
|
|
302
|
-
if (database === "bigquery") return "my-project.analytics";
|
|
303
|
-
return "analytics";
|
|
304
|
-
}
|
|
305
327
|
function getWarehouseClient(database) {
|
|
306
328
|
if (database === "snowflake") return "snowflake-sdk";
|
|
307
329
|
if (database === "bigquery") return "@google-cloud/bigquery";
|
|
330
|
+
if (database === "clickhouse") return "@clickhouse/client";
|
|
308
331
|
return "@duckdb/node-api";
|
|
309
332
|
}
|
|
310
333
|
function getWarehouseClientVersion(packageName) {
|
|
@@ -312,6 +335,175 @@ function getWarehouseClientVersion(packageName) {
|
|
|
312
335
|
if (!version) throw new Error(`Missing ${packageName} peerDependency in cli/package.json`);
|
|
313
336
|
return version;
|
|
314
337
|
}
|
|
338
|
+
async function promptWarehouseCredentials(answers, input, output) {
|
|
339
|
+
if (answers.database === "snowflake") {
|
|
340
|
+
answers.snowflakeAccount = unwrapPrompt(
|
|
341
|
+
await clack.text({
|
|
342
|
+
message: "Snowflake account ID",
|
|
343
|
+
placeholder: "myorg-myaccount",
|
|
344
|
+
initialValue: answers.snowflakeAccount,
|
|
345
|
+
validate: validateRequired("Snowflake account ID is required"),
|
|
346
|
+
...promptOptions(input, output)
|
|
347
|
+
})
|
|
348
|
+
);
|
|
349
|
+
answers.snowflakeUsername = unwrapPrompt(
|
|
350
|
+
await clack.text({
|
|
351
|
+
message: "Snowflake username",
|
|
352
|
+
placeholder: "graphene_user",
|
|
353
|
+
initialValue: answers.snowflakeUsername,
|
|
354
|
+
validate: validateRequired("Snowflake username is required"),
|
|
355
|
+
...promptOptions(input, output)
|
|
356
|
+
})
|
|
357
|
+
);
|
|
358
|
+
answers.snowflakeKeyPath = await promptExistingFilePath({ message: "Path to .p8 key file", expectedExtension: ".p8", initialValue: answers.snowflakeKeyPath, input, output });
|
|
359
|
+
answers.snowflakePassphrase = unwrapPrompt(await clack.password({ message: "Key passphrase", ...promptOptions(input, output) }));
|
|
360
|
+
return;
|
|
361
|
+
}
|
|
362
|
+
if (answers.database === "bigquery") {
|
|
363
|
+
answers.bigqueryProjectId = unwrapPrompt(
|
|
364
|
+
await clack.text({
|
|
365
|
+
message: "GCP project ID",
|
|
366
|
+
placeholder: "my-project-123",
|
|
367
|
+
initialValue: answers.bigqueryProjectId,
|
|
368
|
+
validate: validateRequired("GCP project ID is required"),
|
|
369
|
+
...promptOptions(input, output)
|
|
370
|
+
})
|
|
371
|
+
);
|
|
372
|
+
answers.bigqueryKeyPath = await promptExistingFilePath({
|
|
373
|
+
message: "Path to service account .json key file",
|
|
374
|
+
expectedExtension: ".json",
|
|
375
|
+
initialValue: answers.bigqueryKeyPath,
|
|
376
|
+
input,
|
|
377
|
+
output
|
|
378
|
+
});
|
|
379
|
+
return;
|
|
380
|
+
}
|
|
381
|
+
if (answers.database === "clickhouse") {
|
|
382
|
+
answers.clickhouseUrl = unwrapPrompt(
|
|
383
|
+
await clack.text({
|
|
384
|
+
message: "ClickHouse URL",
|
|
385
|
+
placeholder: "https://example.clickhouse.cloud:8443",
|
|
386
|
+
initialValue: answers.clickhouseUrl,
|
|
387
|
+
validate: validateRequired("ClickHouse URL is required"),
|
|
388
|
+
...promptOptions(input, output)
|
|
389
|
+
})
|
|
390
|
+
);
|
|
391
|
+
answers.clickhouseUsername = unwrapPrompt(
|
|
392
|
+
await clack.text({
|
|
393
|
+
message: "ClickHouse username",
|
|
394
|
+
placeholder: "default",
|
|
395
|
+
initialValue: answers.clickhouseUsername,
|
|
396
|
+
validate: validateRequired("ClickHouse username is required"),
|
|
397
|
+
...promptOptions(input, output)
|
|
398
|
+
})
|
|
399
|
+
);
|
|
400
|
+
answers.clickhousePassword = unwrapPrompt(
|
|
401
|
+
await clack.password({
|
|
402
|
+
message: "ClickHouse password",
|
|
403
|
+
validate: validateRequired("ClickHouse password is required"),
|
|
404
|
+
...promptOptions(input, output)
|
|
405
|
+
})
|
|
406
|
+
);
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
async function collectWarehouseCredentials(answers, options, input, output) {
|
|
410
|
+
while (true) {
|
|
411
|
+
await promptWarehouseCredentials(answers, input, output);
|
|
412
|
+
if (options.skipCredentialValidation) return;
|
|
413
|
+
let result = await testWarehouseCredentials(answers, output);
|
|
414
|
+
if (result.ok) return;
|
|
415
|
+
clack.log.error(`${databaseLabel(answers.database)} credential validation failed: ${result.error}`, { output });
|
|
416
|
+
let action = unwrapPrompt(
|
|
417
|
+
await clack.select({
|
|
418
|
+
message: "How would you like to continue?",
|
|
419
|
+
options: [
|
|
420
|
+
{ value: "edit", label: "Edit credentials" },
|
|
421
|
+
{ value: "continue", label: "Continue anyway" }
|
|
422
|
+
],
|
|
423
|
+
...promptOptions(input, output)
|
|
424
|
+
})
|
|
425
|
+
);
|
|
426
|
+
if (action === "continue") return;
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
async function testWarehouseCredentials(answers, output) {
|
|
430
|
+
let task = clack.taskLog({ title: `Testing ${databaseLabel(answers.database)} credentials...`, retainLog: true, output });
|
|
431
|
+
try {
|
|
432
|
+
await withTimeout(runWarehouseCredentialTest(answers), 15e3, `${databaseLabel(answers.database)} credential validation timed out`);
|
|
433
|
+
task.success("Credentials validated");
|
|
434
|
+
return { ok: true };
|
|
435
|
+
} catch (err) {
|
|
436
|
+
task.error("Credential validation failed", { showLog: true });
|
|
437
|
+
return { ok: false, error: formatCredentialError(err) };
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
async function withTimeout(promise, ms, message) {
|
|
441
|
+
let timeout;
|
|
442
|
+
try {
|
|
443
|
+
return await Promise.race([
|
|
444
|
+
promise,
|
|
445
|
+
new Promise((_resolve, reject) => {
|
|
446
|
+
timeout = setTimeout(() => reject(new Error(message)), ms);
|
|
447
|
+
})
|
|
448
|
+
]);
|
|
449
|
+
} finally {
|
|
450
|
+
if (timeout) clearTimeout(timeout);
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
function runWarehouseCredentialTest(answers) {
|
|
454
|
+
if (answers.database === "snowflake") return testSnowflakeCredentials(answers);
|
|
455
|
+
if (answers.database === "bigquery") return testBigQueryCredentials(answers);
|
|
456
|
+
if (answers.database === "clickhouse") return testClickHouseCredentials(answers);
|
|
457
|
+
return Promise.resolve();
|
|
458
|
+
}
|
|
459
|
+
async function testSnowflakeCredentials(answers) {
|
|
460
|
+
let snowflake = (await import("snowflake-sdk")).default;
|
|
461
|
+
snowflake.configure({ logLevel: "WARN", logFilePath: "/dev/null" });
|
|
462
|
+
let connection = snowflake.createConnection({
|
|
463
|
+
account: answers.snowflakeAccount,
|
|
464
|
+
username: answers.snowflakeUsername,
|
|
465
|
+
privateKeyPath: answers.snowflakeKeyPath,
|
|
466
|
+
privateKeyPass: answers.snowflakePassphrase,
|
|
467
|
+
authenticator: "SNOWFLAKE_JWT",
|
|
468
|
+
application: "Graphene"
|
|
469
|
+
});
|
|
470
|
+
try {
|
|
471
|
+
await new Promise((resolve, reject) => {
|
|
472
|
+
connection.connect((err) => err ? reject(err) : resolve());
|
|
473
|
+
});
|
|
474
|
+
} finally {
|
|
475
|
+
await new Promise((resolve) => {
|
|
476
|
+
connection.destroy(() => resolve());
|
|
477
|
+
}).catch(() => {
|
|
478
|
+
});
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
async function testBigQueryCredentials(answers) {
|
|
482
|
+
let { BigQuery } = await import("@google-cloud/bigquery");
|
|
483
|
+
let credentials = JSON.parse(await readFile(answers.bigqueryKeyPath || "", "utf8"));
|
|
484
|
+
let client = new BigQuery({ projectId: answers.bigqueryProjectId, credentials, userAgent: "Graphene" });
|
|
485
|
+
await client.createQueryJob({ query: "select 1", useLegacySql: false, dryRun: true });
|
|
486
|
+
}
|
|
487
|
+
async function testClickHouseCredentials(answers) {
|
|
488
|
+
let { createClient } = await import("@clickhouse/client");
|
|
489
|
+
let client = createClient({
|
|
490
|
+
url: answers.clickhouseUrl,
|
|
491
|
+
username: answers.clickhouseUsername,
|
|
492
|
+
password: answers.clickhousePassword,
|
|
493
|
+
database: answers.defaultNamespace || "default",
|
|
494
|
+
application: "Graphene"
|
|
495
|
+
});
|
|
496
|
+
try {
|
|
497
|
+
let result = await client.query({ query: "SELECT 1", format: "JSONEachRow" });
|
|
498
|
+
await result.json();
|
|
499
|
+
} finally {
|
|
500
|
+
await client.close();
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
function formatCredentialError(err) {
|
|
504
|
+
if (err instanceof Error && err.message) return err.message;
|
|
505
|
+
return String(err || "Unknown error");
|
|
506
|
+
}
|
|
315
507
|
async function collectAnswers({ options, packageManager, input, output }) {
|
|
316
508
|
if (options.yes) {
|
|
317
509
|
let targetDir2 = options.targetDir || "graphene-app";
|
|
@@ -340,74 +532,23 @@ async function collectAnswers({ options, packageManager, input, output }) {
|
|
|
340
532
|
await clack.select({
|
|
341
533
|
message: "Database",
|
|
342
534
|
options: [
|
|
343
|
-
{ value: "duckdb", label: "DuckDB (local file)" },
|
|
344
535
|
{ value: "snowflake", label: "Snowflake" },
|
|
345
|
-
{ value: "bigquery", label: "BigQuery" }
|
|
536
|
+
{ value: "bigquery", label: "BigQuery" },
|
|
537
|
+
{ value: "clickhouse", label: "ClickHouse" },
|
|
538
|
+
{ value: "duckdb", label: "DuckDB (local file)" }
|
|
346
539
|
],
|
|
347
540
|
...promptOptions(input, output)
|
|
348
541
|
})
|
|
349
542
|
);
|
|
350
|
-
let defaultNamespace = unwrapPrompt(
|
|
351
|
-
await clack.text({
|
|
352
|
-
message: "Default namespace (optional)",
|
|
353
|
-
placeholder: namespacePlaceholder(database),
|
|
354
|
-
...promptOptions(input, output)
|
|
355
|
-
})
|
|
356
|
-
).trim();
|
|
357
543
|
let answers = {
|
|
358
544
|
targetDir,
|
|
359
545
|
projectName,
|
|
360
546
|
packageManager,
|
|
361
547
|
database,
|
|
362
|
-
defaultNamespace: defaultNamespace || void 0,
|
|
363
548
|
skillLinkTarget: "none"
|
|
364
549
|
};
|
|
365
|
-
if (database
|
|
366
|
-
answers
|
|
367
|
-
await clack.text({
|
|
368
|
-
message: "Path to .duckdb file",
|
|
369
|
-
placeholder: "./data.duckdb",
|
|
370
|
-
validate(value) {
|
|
371
|
-
if (typeof value !== "string" || !value.trim()) return;
|
|
372
|
-
if (!value.endsWith(".duckdb")) return "DuckDB path must end with .duckdb";
|
|
373
|
-
},
|
|
374
|
-
...promptOptions(input, output)
|
|
375
|
-
})
|
|
376
|
-
).trim() || void 0;
|
|
377
|
-
} else if (database === "snowflake") {
|
|
378
|
-
answers.snowflakeAccount = unwrapPrompt(
|
|
379
|
-
await clack.text({
|
|
380
|
-
message: "Snowflake account ID",
|
|
381
|
-
placeholder: "myorg-myaccount",
|
|
382
|
-
validate: validateRequired("Snowflake account ID is required"),
|
|
383
|
-
...promptOptions(input, output)
|
|
384
|
-
})
|
|
385
|
-
);
|
|
386
|
-
answers.snowflakeUsername = unwrapPrompt(
|
|
387
|
-
await clack.text({
|
|
388
|
-
message: "Snowflake username",
|
|
389
|
-
placeholder: "graphene_user",
|
|
390
|
-
validate: validateRequired("Snowflake username is required"),
|
|
391
|
-
...promptOptions(input, output)
|
|
392
|
-
})
|
|
393
|
-
);
|
|
394
|
-
answers.snowflakeKeyPath = await promptExistingFilePath({ message: "Path to .p8 key file", expectedExtension: ".p8", input, output });
|
|
395
|
-
answers.snowflakePassphrase = unwrapPrompt(
|
|
396
|
-
await clack.password({
|
|
397
|
-
message: "Key passphrase",
|
|
398
|
-
...promptOptions(input, output)
|
|
399
|
-
})
|
|
400
|
-
);
|
|
401
|
-
} else {
|
|
402
|
-
answers.bigqueryProjectId = unwrapPrompt(
|
|
403
|
-
await clack.text({
|
|
404
|
-
message: "GCP project ID",
|
|
405
|
-
placeholder: "my-project-123",
|
|
406
|
-
validate: validateRequired("GCP project ID is required"),
|
|
407
|
-
...promptOptions(input, output)
|
|
408
|
-
})
|
|
409
|
-
);
|
|
410
|
-
answers.bigqueryKeyPath = await promptExistingFilePath({ message: "Path to service account .json key file", expectedExtension: ".json", input, output });
|
|
550
|
+
if (database !== "duckdb") {
|
|
551
|
+
await collectWarehouseCredentials(answers, options, input, output);
|
|
411
552
|
}
|
|
412
553
|
if (options.install) {
|
|
413
554
|
answers.skillLinkTarget = unwrapPrompt(
|
|
@@ -505,7 +646,7 @@ async function runCreate({ argv, cwd, env = {}, stdin, stdout }) {
|
|
|
505
646
|
if (install.code !== 0) throw new Error(install.stderr.trim() || `${packageManager.name} install failed with code ${install.code}`);
|
|
506
647
|
await symlinkGrapheneSkill(targetDir, answers.skillLinkTarget);
|
|
507
648
|
}
|
|
508
|
-
clack.outro(
|
|
649
|
+
clack.outro(completionMessage(answers), { output: stdout });
|
|
509
650
|
} catch (err) {
|
|
510
651
|
if (err instanceof CreateCancelled) {
|
|
511
652
|
clack.cancel("Operation cancelled.", { output: stdout });
|
|
@@ -514,6 +655,25 @@ async function runCreate({ argv, cwd, env = {}, stdin, stdout }) {
|
|
|
514
655
|
throw err;
|
|
515
656
|
}
|
|
516
657
|
}
|
|
658
|
+
function completionMessage(answers) {
|
|
659
|
+
if (answers.database !== "duckdb") return "Done!";
|
|
660
|
+
return [
|
|
661
|
+
"Done!",
|
|
662
|
+
"",
|
|
663
|
+
`For DuckDB, copy your ${color("cyan", ".duckdb")} file into the ${color("magenta", answers.projectName)} folder so Graphene can discover it.`,
|
|
664
|
+
"",
|
|
665
|
+
`If the duckdb file lives elsewhere, set the path in ${color("magenta", "package.json")}:`,
|
|
666
|
+
"",
|
|
667
|
+
color("gray", '"graphene": {'),
|
|
668
|
+
color("gray", ' "duckdb": {'),
|
|
669
|
+
color("gray", ' "path": "/path/to/example.duckdb"'),
|
|
670
|
+
color("gray", " }"),
|
|
671
|
+
color("gray", "}")
|
|
672
|
+
].join("\n");
|
|
673
|
+
}
|
|
674
|
+
function color(style, text2) {
|
|
675
|
+
return styleText(style, text2, { validateStream: false });
|
|
676
|
+
}
|
|
517
677
|
|
|
518
678
|
// cli.ts
|
|
519
679
|
await runCreate({
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-graphene",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.18",
|
|
4
4
|
"license": "Elastic-2.0",
|
|
5
5
|
"author": "Graphene Systems Inc",
|
|
6
6
|
"repository": {
|
|
@@ -25,7 +25,10 @@
|
|
|
25
25
|
"prepack": "pnpm run build"
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@clack/prompts": "^1.2.0"
|
|
28
|
+
"@clack/prompts": "^1.2.0",
|
|
29
|
+
"@clickhouse/client": "^1.18.2",
|
|
30
|
+
"@google-cloud/bigquery": "^8.2.0",
|
|
31
|
+
"snowflake-sdk": "2.4.0"
|
|
29
32
|
},
|
|
30
33
|
"devDependencies": {
|
|
31
34
|
"esbuild": "^0.27.2"
|