create-graphene 0.0.17 → 0.0.19

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.
Files changed (2) hide show
  1. package/dist/cli.js +159 -19
  2. package/package.json +3 -2
package/dist/cli.js CHANGED
@@ -11,7 +11,7 @@ import { styleText } from "node:util";
11
11
  // ../cli/package.json
12
12
  var package_default = {
13
13
  name: "@graphenedata/cli",
14
- version: "0.0.17",
14
+ version: "0.0.19",
15
15
  private: true,
16
16
  license: "Elastic-2.0",
17
17
  author: "Graphene Systems Inc",
@@ -57,32 +57,42 @@ var package_default = {
57
57
  "js-yaml": "^3.14.2",
58
58
  json5: "^2.2.3",
59
59
  mdsvex: "^0.12.6",
60
- "sanitize-html": "^2.17.0",
60
+ "playwright-core": "1.58.2",
61
+ "sanitize-html": "^2.17.4",
62
+ svelte: "5.55.7",
61
63
  unified: "^11.0.5",
62
64
  "unist-util-visit": "4.1.2",
63
65
  vite: "7.3.2",
64
- ws: "^8.18.0"
66
+ ws: "^8.20.1"
65
67
  },
66
68
  devDependencies: {
69
+ "@aws-sdk/client-athena": "^3.1049.0",
67
70
  "@clickhouse/client": "^1.18.2",
68
71
  "@duckdb/node-api": "1.3.2-alpha.26",
69
- "@google-cloud/bigquery": "^8.2.0",
72
+ "@google-cloud/bigquery": "^8.3.1",
70
73
  "@types/fs-extra": "^11.0.4",
71
74
  "@types/node": "^20.0.0",
75
+ "@types/pg": "8.11.11",
72
76
  "@types/sanitize-html": "^2.16.0",
73
77
  "@types/ws": "^8.18.1",
74
78
  esbuild: "^0.27.2",
79
+ pg: "8.13.3",
75
80
  "snowflake-sdk": "2.4.0",
76
81
  vitest: "4.0.18",
77
82
  "vscode-languageserver-types": "^3.17.0"
78
83
  },
79
84
  peerDependencies: {
85
+ "@aws-sdk/client-athena": "^3.1049.0",
80
86
  "@clickhouse/client": "^1.18.2",
81
87
  "@duckdb/node-api": "1.3.2-alpha.26",
82
88
  "@google-cloud/bigquery": "^8.2.0",
89
+ pg: "8.13.3",
83
90
  "snowflake-sdk": "2.4.0"
84
91
  },
85
92
  peerDependenciesMeta: {
93
+ "@aws-sdk/client-athena": {
94
+ optional: true
95
+ },
86
96
  "@clickhouse/client": {
87
97
  optional: true
88
98
  },
@@ -92,6 +102,9 @@ var package_default = {
92
102
  "@google-cloud/bigquery": {
93
103
  optional: true
94
104
  },
105
+ pg: {
106
+ optional: true
107
+ },
95
108
  "snowflake-sdk": {
96
109
  optional: true
97
110
  }
@@ -178,8 +191,16 @@ function renderTemplate({ answers, cliVersion }) {
178
191
  graphene.snowflake = { account: answers.snowflakeAccount || "", username: answers.snowflakeUsername || "" };
179
192
  } else if (answers.database === "bigquery") {
180
193
  graphene.bigquery = { projectId: answers.bigqueryProjectId || "" };
181
- } else {
194
+ } else if (answers.database === "clickhouse") {
182
195
  graphene.clickhouse = { url: answers.clickhouseUrl || "", username: answers.clickhouseUsername || "" };
196
+ } else {
197
+ graphene.postgres = {
198
+ host: answers.postgresHost || "",
199
+ port: Number(answers.postgresPort || 5432),
200
+ database: answers.postgresDatabase || "",
201
+ user: answers.postgresUsername || ""
202
+ };
203
+ if (answers.postgresSsl) graphene.postgres.ssl = true;
183
204
  }
184
205
  let pkg = {
185
206
  name: answers.projectName,
@@ -202,9 +223,10 @@ function renderTemplate({ answers, cliVersion }) {
202
223
  let files = {
203
224
  "package.json": JSON.stringify(pkg, null, 2) + "\n",
204
225
  ".gitignore": ["node_modules", ".env", "*.duckdb"].join("\n") + "\n",
205
- [agentsFileName(answers.skillLinkTarget)]: renderAgents(answers),
226
+ [agentsFileName(answers.agentSetup)]: renderAgents(answers),
206
227
  "index.md": renderIndex(answers)
207
228
  };
229
+ if (answers.agentSetup === "codex") files[".codex/config.toml"] = renderCodexConfig();
208
230
  if (answers.packageManager?.name === "yarn") files[".yarnrc.yml"] = "nodeLinker: node-modules\n";
209
231
  let envFile = renderEnvFile(answers);
210
232
  if (envFile) files[".env"] = envFile;
@@ -216,8 +238,8 @@ function grapheneCommand(packageManager, args) {
216
238
  if (packageManager?.name === "bun") return `bun run graphene ${args}`;
217
239
  return `npx graphene ${args}`;
218
240
  }
219
- function agentsFileName(skillLinkTarget) {
220
- if (skillLinkTarget === ".claude") return "CLAUDE.md";
241
+ function agentsFileName(agentSetup) {
242
+ if (agentSetup === "claude") return "CLAUDE.md";
221
243
  return "AGENTS.md";
222
244
  }
223
245
  function renderAgents(answers) {
@@ -233,10 +255,32 @@ function renderAgents(answers) {
233
255
  `- ${grapheneCommand(answers.packageManager, "serve --bg")} - start or restart the local dev server`
234
256
  ].join("\n") + "\n";
235
257
  }
258
+ function renderCodexConfig() {
259
+ return [
260
+ "# Enable Graphene page screenshots in Codex by allowing the local dev server.",
261
+ 'default_permissions = "graphene"',
262
+ "",
263
+ "[permissions.graphene.filesystem]",
264
+ '":root" = "read"',
265
+ '":project_roots" = { "." = "write" }',
266
+ '":tmpdir" = "write"',
267
+ "",
268
+ "[permissions.graphene.network]",
269
+ "enabled = true",
270
+ 'mode = "full"',
271
+ "allow_local_binding = true",
272
+ "",
273
+ "[permissions.graphene.network.domains]",
274
+ '"localhost" = "allow"',
275
+ '"127.0.0.1" = "allow"',
276
+ '"::1" = "allow"'
277
+ ].join("\n") + "\n";
278
+ }
236
279
  function databaseLabel(database) {
237
280
  if (database === "snowflake") return "Snowflake";
238
281
  if (database === "bigquery") return "BigQuery";
239
282
  if (database === "clickhouse") return "ClickHouse";
283
+ if (database === "postgres") return "Postgres";
240
284
  return "DuckDB";
241
285
  }
242
286
  function renderIndex(answers) {
@@ -251,6 +295,8 @@ function renderEnvFile(answers) {
251
295
  lines.push(`GOOGLE_APPLICATION_CREDENTIALS=${answers.bigqueryKeyPath || ""}`);
252
296
  } else if (answers.database === "clickhouse") {
253
297
  lines.push(`CLICKHOUSE_PASSWORD=${answers.clickhousePassword || ""}`);
298
+ } else if (answers.database === "postgres") {
299
+ lines.push(`POSTGRES_PASSWORD=${answers.postgresPassword || ""}`);
254
300
  }
255
301
  return lines.length ? lines.join("\n") + "\n" : null;
256
302
  }
@@ -327,6 +373,7 @@ function getWarehouseClient(database) {
327
373
  if (database === "snowflake") return "snowflake-sdk";
328
374
  if (database === "bigquery") return "@google-cloud/bigquery";
329
375
  if (database === "clickhouse") return "@clickhouse/client";
376
+ if (database === "postgres") return "pg";
330
377
  return "@duckdb/node-api";
331
378
  }
332
379
  function getWarehouseClientVersion(packageName) {
@@ -403,6 +450,71 @@ async function promptWarehouseCredentials(answers, input, output) {
403
450
  ...promptOptions(input, output)
404
451
  })
405
452
  );
453
+ return;
454
+ }
455
+ if (answers.database === "postgres") {
456
+ answers.postgresHost = unwrapPrompt(
457
+ await clack.text({
458
+ message: "Postgres host",
459
+ placeholder: "localhost",
460
+ initialValue: answers.postgresHost || "localhost",
461
+ validate: validateRequired("Postgres host is required"),
462
+ ...promptOptions(input, output)
463
+ })
464
+ );
465
+ answers.postgresPort = unwrapPrompt(
466
+ await clack.text({
467
+ message: "Postgres port",
468
+ placeholder: "5432",
469
+ initialValue: answers.postgresPort || "5432",
470
+ validate: (value) => {
471
+ if (!value) return "Postgres port is required";
472
+ if (!/^\d+$/.test(value)) return "Postgres port must be a number";
473
+ },
474
+ ...promptOptions(input, output)
475
+ })
476
+ );
477
+ answers.postgresDatabase = unwrapPrompt(
478
+ await clack.text({
479
+ message: "Postgres database",
480
+ placeholder: "analytics",
481
+ initialValue: answers.postgresDatabase,
482
+ validate: validateRequired("Postgres database is required"),
483
+ ...promptOptions(input, output)
484
+ })
485
+ );
486
+ answers.postgresUsername = unwrapPrompt(
487
+ await clack.text({
488
+ message: "Postgres username",
489
+ placeholder: "graphene_user",
490
+ initialValue: answers.postgresUsername,
491
+ validate: validateRequired("Postgres username is required"),
492
+ ...promptOptions(input, output)
493
+ })
494
+ );
495
+ answers.postgresPassword = unwrapPrompt(
496
+ await clack.password({
497
+ message: "Postgres password",
498
+ validate: validateRequired("Postgres password is required"),
499
+ ...promptOptions(input, output)
500
+ })
501
+ );
502
+ answers.defaultNamespace = unwrapPrompt(
503
+ await clack.text({
504
+ message: "Postgres schema",
505
+ placeholder: "public",
506
+ initialValue: answers.defaultNamespace || "public",
507
+ validate: validateRequired("Postgres schema is required"),
508
+ ...promptOptions(input, output)
509
+ })
510
+ );
511
+ answers.postgresSsl = unwrapPrompt(
512
+ await clack.confirm({
513
+ message: "Use SSL for Postgres?",
514
+ initialValue: answers.postgresSsl || false,
515
+ ...promptOptions(input, output)
516
+ })
517
+ );
406
518
  }
407
519
  }
408
520
  async function collectWarehouseCredentials(answers, options, input, output) {
@@ -453,6 +565,7 @@ function runWarehouseCredentialTest(answers) {
453
565
  if (answers.database === "snowflake") return testSnowflakeCredentials(answers);
454
566
  if (answers.database === "bigquery") return testBigQueryCredentials(answers);
455
567
  if (answers.database === "clickhouse") return testClickHouseCredentials(answers);
568
+ if (answers.database === "postgres") return testPostgresCredentials(answers);
456
569
  return Promise.resolve();
457
570
  }
458
571
  async function testSnowflakeCredentials(answers) {
@@ -499,6 +612,25 @@ async function testClickHouseCredentials(answers) {
499
612
  await client.close();
500
613
  }
501
614
  }
615
+ async function testPostgresCredentials(answers) {
616
+ let pg = (await import("pg")).default;
617
+ let client = new pg.Client({
618
+ host: answers.postgresHost,
619
+ port: Number(answers.postgresPort || 5432),
620
+ database: answers.postgresDatabase,
621
+ user: answers.postgresUsername,
622
+ password: answers.postgresPassword,
623
+ ssl: answers.postgresSsl,
624
+ application_name: "Graphene"
625
+ });
626
+ try {
627
+ await client.connect();
628
+ await client.query("SELECT 1");
629
+ } finally {
630
+ await client.end().catch(() => {
631
+ });
632
+ }
633
+ }
502
634
  function formatCredentialError(err) {
503
635
  if (err instanceof Error && err.message) return err.message;
504
636
  return String(err || "Unknown error");
@@ -511,7 +643,7 @@ async function collectAnswers({ options, packageManager, input, output }) {
511
643
  projectName: options.name || defaultProjectName(targetDir2),
512
644
  packageManager,
513
645
  database: "duckdb",
514
- skillLinkTarget: "none"
646
+ agentSetup: "none"
515
647
  };
516
648
  }
517
649
  let targetDir = options.targetDir;
@@ -534,6 +666,7 @@ async function collectAnswers({ options, packageManager, input, output }) {
534
666
  { value: "snowflake", label: "Snowflake" },
535
667
  { value: "bigquery", label: "BigQuery" },
536
668
  { value: "clickhouse", label: "ClickHouse" },
669
+ { value: "postgres", label: "Postgres" },
537
670
  { value: "duckdb", label: "DuckDB (local file)" }
538
671
  ],
539
672
  ...promptOptions(input, output)
@@ -544,19 +677,20 @@ async function collectAnswers({ options, packageManager, input, output }) {
544
677
  projectName,
545
678
  packageManager,
546
679
  database,
547
- skillLinkTarget: "none"
680
+ agentSetup: "none"
548
681
  };
549
682
  if (database !== "duckdb") {
550
683
  await collectWarehouseCredentials(answers, options, input, output);
551
684
  }
552
685
  if (options.install) {
553
- answers.skillLinkTarget = unwrapPrompt(
686
+ answers.agentSetup = unwrapPrompt(
554
687
  await clack.select({
555
- message: "Add the Graphene skill for agents?",
688
+ message: "Configure which agent?",
556
689
  options: [
557
- { value: ".agents", label: ".agents/skills/graphene" },
558
- { value: ".claude", label: ".claude/skills/graphene" },
559
- { value: "none", label: "Skip" }
690
+ { value: "codex", label: "Codex" },
691
+ { value: "claude", label: "Claude" },
692
+ { value: "other", label: "Other agent" },
693
+ { value: "none", label: "Skip extra setup" }
560
694
  ],
561
695
  ...promptOptions(input, output)
562
696
  })
@@ -611,10 +745,16 @@ async function installDeps(targetDir, packageManager, env) {
611
745
  else task.error(`${command} install failed`, { showLog: true });
612
746
  return { code, stderr };
613
747
  }
614
- async function symlinkGrapheneSkill(targetDir, skillLinkTarget) {
615
- if (skillLinkTarget === "none") return;
748
+ function skillLinkDirectory(agentSetup) {
749
+ if (agentSetup === "codex" || agentSetup === "other") return ".agents";
750
+ if (agentSetup === "claude") return ".claude";
751
+ return null;
752
+ }
753
+ async function symlinkGrapheneSkill(targetDir, agentSetup) {
754
+ let linkDirectory = skillLinkDirectory(agentSetup);
755
+ if (!linkDirectory) return;
616
756
  let sourcePath = path2.join(targetDir, "node_modules/@graphenedata/cli/dist/skills/graphene");
617
- let linkPath = path2.join(targetDir, skillLinkTarget, "skills/graphene");
757
+ let linkPath = path2.join(targetDir, linkDirectory, "skills/graphene");
618
758
  let relativeSourcePath = path2.relative(path2.dirname(linkPath), sourcePath);
619
759
  await mkdir(path2.dirname(linkPath), { recursive: true });
620
760
  try {
@@ -643,7 +783,7 @@ async function runCreate({ argv, cwd, env = {}, stdin, stdout }) {
643
783
  if (options.install) {
644
784
  let install = await installDeps(targetDir, packageManager, env);
645
785
  if (install.code !== 0) throw new Error(install.stderr.trim() || `${packageManager.name} install failed with code ${install.code}`);
646
- await symlinkGrapheneSkill(targetDir, answers.skillLinkTarget);
786
+ await symlinkGrapheneSkill(targetDir, answers.agentSetup);
647
787
  }
648
788
  clack.outro(completionMessage(answers), { output: stdout });
649
789
  } catch (err) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-graphene",
3
- "version": "0.0.17",
3
+ "version": "0.0.19",
4
4
  "license": "Elastic-2.0",
5
5
  "author": "Graphene Systems Inc",
6
6
  "repository": {
@@ -27,7 +27,8 @@
27
27
  "dependencies": {
28
28
  "@clack/prompts": "^1.2.0",
29
29
  "@clickhouse/client": "^1.18.2",
30
- "@google-cloud/bigquery": "^8.2.0",
30
+ "@google-cloud/bigquery": "^8.3.1",
31
+ "pg": "8.13.3",
31
32
  "snowflake-sdk": "2.4.0"
32
33
  },
33
34
  "devDependencies": {