create-graphene 0.0.18 → 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 -20
  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.18",
14
+ version: "0.0.19",
15
15
  private: true,
16
16
  license: "Elastic-2.0",
17
17
  author: "Graphene Systems Inc",
@@ -57,33 +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",
61
- svelte: "5.55.3",
60
+ "playwright-core": "1.58.2",
61
+ "sanitize-html": "^2.17.4",
62
+ svelte: "5.55.7",
62
63
  unified: "^11.0.5",
63
64
  "unist-util-visit": "4.1.2",
64
65
  vite: "7.3.2",
65
- ws: "^8.18.0"
66
+ ws: "^8.20.1"
66
67
  },
67
68
  devDependencies: {
69
+ "@aws-sdk/client-athena": "^3.1049.0",
68
70
  "@clickhouse/client": "^1.18.2",
69
71
  "@duckdb/node-api": "1.3.2-alpha.26",
70
- "@google-cloud/bigquery": "^8.2.0",
72
+ "@google-cloud/bigquery": "^8.3.1",
71
73
  "@types/fs-extra": "^11.0.4",
72
74
  "@types/node": "^20.0.0",
75
+ "@types/pg": "8.11.11",
73
76
  "@types/sanitize-html": "^2.16.0",
74
77
  "@types/ws": "^8.18.1",
75
78
  esbuild: "^0.27.2",
79
+ pg: "8.13.3",
76
80
  "snowflake-sdk": "2.4.0",
77
81
  vitest: "4.0.18",
78
82
  "vscode-languageserver-types": "^3.17.0"
79
83
  },
80
84
  peerDependencies: {
85
+ "@aws-sdk/client-athena": "^3.1049.0",
81
86
  "@clickhouse/client": "^1.18.2",
82
87
  "@duckdb/node-api": "1.3.2-alpha.26",
83
88
  "@google-cloud/bigquery": "^8.2.0",
89
+ pg: "8.13.3",
84
90
  "snowflake-sdk": "2.4.0"
85
91
  },
86
92
  peerDependenciesMeta: {
93
+ "@aws-sdk/client-athena": {
94
+ optional: true
95
+ },
87
96
  "@clickhouse/client": {
88
97
  optional: true
89
98
  },
@@ -93,6 +102,9 @@ var package_default = {
93
102
  "@google-cloud/bigquery": {
94
103
  optional: true
95
104
  },
105
+ pg: {
106
+ optional: true
107
+ },
96
108
  "snowflake-sdk": {
97
109
  optional: true
98
110
  }
@@ -179,8 +191,16 @@ function renderTemplate({ answers, cliVersion }) {
179
191
  graphene.snowflake = { account: answers.snowflakeAccount || "", username: answers.snowflakeUsername || "" };
180
192
  } else if (answers.database === "bigquery") {
181
193
  graphene.bigquery = { projectId: answers.bigqueryProjectId || "" };
182
- } else {
194
+ } else if (answers.database === "clickhouse") {
183
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;
184
204
  }
185
205
  let pkg = {
186
206
  name: answers.projectName,
@@ -203,9 +223,10 @@ function renderTemplate({ answers, cliVersion }) {
203
223
  let files = {
204
224
  "package.json": JSON.stringify(pkg, null, 2) + "\n",
205
225
  ".gitignore": ["node_modules", ".env", "*.duckdb"].join("\n") + "\n",
206
- [agentsFileName(answers.skillLinkTarget)]: renderAgents(answers),
226
+ [agentsFileName(answers.agentSetup)]: renderAgents(answers),
207
227
  "index.md": renderIndex(answers)
208
228
  };
229
+ if (answers.agentSetup === "codex") files[".codex/config.toml"] = renderCodexConfig();
209
230
  if (answers.packageManager?.name === "yarn") files[".yarnrc.yml"] = "nodeLinker: node-modules\n";
210
231
  let envFile = renderEnvFile(answers);
211
232
  if (envFile) files[".env"] = envFile;
@@ -217,8 +238,8 @@ function grapheneCommand(packageManager, args) {
217
238
  if (packageManager?.name === "bun") return `bun run graphene ${args}`;
218
239
  return `npx graphene ${args}`;
219
240
  }
220
- function agentsFileName(skillLinkTarget) {
221
- if (skillLinkTarget === ".claude") return "CLAUDE.md";
241
+ function agentsFileName(agentSetup) {
242
+ if (agentSetup === "claude") return "CLAUDE.md";
222
243
  return "AGENTS.md";
223
244
  }
224
245
  function renderAgents(answers) {
@@ -234,10 +255,32 @@ function renderAgents(answers) {
234
255
  `- ${grapheneCommand(answers.packageManager, "serve --bg")} - start or restart the local dev server`
235
256
  ].join("\n") + "\n";
236
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
+ }
237
279
  function databaseLabel(database) {
238
280
  if (database === "snowflake") return "Snowflake";
239
281
  if (database === "bigquery") return "BigQuery";
240
282
  if (database === "clickhouse") return "ClickHouse";
283
+ if (database === "postgres") return "Postgres";
241
284
  return "DuckDB";
242
285
  }
243
286
  function renderIndex(answers) {
@@ -252,6 +295,8 @@ function renderEnvFile(answers) {
252
295
  lines.push(`GOOGLE_APPLICATION_CREDENTIALS=${answers.bigqueryKeyPath || ""}`);
253
296
  } else if (answers.database === "clickhouse") {
254
297
  lines.push(`CLICKHOUSE_PASSWORD=${answers.clickhousePassword || ""}`);
298
+ } else if (answers.database === "postgres") {
299
+ lines.push(`POSTGRES_PASSWORD=${answers.postgresPassword || ""}`);
255
300
  }
256
301
  return lines.length ? lines.join("\n") + "\n" : null;
257
302
  }
@@ -328,6 +373,7 @@ function getWarehouseClient(database) {
328
373
  if (database === "snowflake") return "snowflake-sdk";
329
374
  if (database === "bigquery") return "@google-cloud/bigquery";
330
375
  if (database === "clickhouse") return "@clickhouse/client";
376
+ if (database === "postgres") return "pg";
331
377
  return "@duckdb/node-api";
332
378
  }
333
379
  function getWarehouseClientVersion(packageName) {
@@ -404,6 +450,71 @@ async function promptWarehouseCredentials(answers, input, output) {
404
450
  ...promptOptions(input, output)
405
451
  })
406
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
+ );
407
518
  }
408
519
  }
409
520
  async function collectWarehouseCredentials(answers, options, input, output) {
@@ -454,6 +565,7 @@ function runWarehouseCredentialTest(answers) {
454
565
  if (answers.database === "snowflake") return testSnowflakeCredentials(answers);
455
566
  if (answers.database === "bigquery") return testBigQueryCredentials(answers);
456
567
  if (answers.database === "clickhouse") return testClickHouseCredentials(answers);
568
+ if (answers.database === "postgres") return testPostgresCredentials(answers);
457
569
  return Promise.resolve();
458
570
  }
459
571
  async function testSnowflakeCredentials(answers) {
@@ -500,6 +612,25 @@ async function testClickHouseCredentials(answers) {
500
612
  await client.close();
501
613
  }
502
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
+ }
503
634
  function formatCredentialError(err) {
504
635
  if (err instanceof Error && err.message) return err.message;
505
636
  return String(err || "Unknown error");
@@ -512,7 +643,7 @@ async function collectAnswers({ options, packageManager, input, output }) {
512
643
  projectName: options.name || defaultProjectName(targetDir2),
513
644
  packageManager,
514
645
  database: "duckdb",
515
- skillLinkTarget: "none"
646
+ agentSetup: "none"
516
647
  };
517
648
  }
518
649
  let targetDir = options.targetDir;
@@ -535,6 +666,7 @@ async function collectAnswers({ options, packageManager, input, output }) {
535
666
  { value: "snowflake", label: "Snowflake" },
536
667
  { value: "bigquery", label: "BigQuery" },
537
668
  { value: "clickhouse", label: "ClickHouse" },
669
+ { value: "postgres", label: "Postgres" },
538
670
  { value: "duckdb", label: "DuckDB (local file)" }
539
671
  ],
540
672
  ...promptOptions(input, output)
@@ -545,19 +677,20 @@ async function collectAnswers({ options, packageManager, input, output }) {
545
677
  projectName,
546
678
  packageManager,
547
679
  database,
548
- skillLinkTarget: "none"
680
+ agentSetup: "none"
549
681
  };
550
682
  if (database !== "duckdb") {
551
683
  await collectWarehouseCredentials(answers, options, input, output);
552
684
  }
553
685
  if (options.install) {
554
- answers.skillLinkTarget = unwrapPrompt(
686
+ answers.agentSetup = unwrapPrompt(
555
687
  await clack.select({
556
- message: "Add the Graphene skill for agents?",
688
+ message: "Configure which agent?",
557
689
  options: [
558
- { value: ".agents", label: ".agents/skills/graphene" },
559
- { value: ".claude", label: ".claude/skills/graphene" },
560
- { 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" }
561
694
  ],
562
695
  ...promptOptions(input, output)
563
696
  })
@@ -612,10 +745,16 @@ async function installDeps(targetDir, packageManager, env) {
612
745
  else task.error(`${command} install failed`, { showLog: true });
613
746
  return { code, stderr };
614
747
  }
615
- async function symlinkGrapheneSkill(targetDir, skillLinkTarget) {
616
- 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;
617
756
  let sourcePath = path2.join(targetDir, "node_modules/@graphenedata/cli/dist/skills/graphene");
618
- let linkPath = path2.join(targetDir, skillLinkTarget, "skills/graphene");
757
+ let linkPath = path2.join(targetDir, linkDirectory, "skills/graphene");
619
758
  let relativeSourcePath = path2.relative(path2.dirname(linkPath), sourcePath);
620
759
  await mkdir(path2.dirname(linkPath), { recursive: true });
621
760
  try {
@@ -644,7 +783,7 @@ async function runCreate({ argv, cwd, env = {}, stdin, stdout }) {
644
783
  if (options.install) {
645
784
  let install = await installDeps(targetDir, packageManager, env);
646
785
  if (install.code !== 0) throw new Error(install.stderr.trim() || `${packageManager.name} install failed with code ${install.code}`);
647
- await symlinkGrapheneSkill(targetDir, answers.skillLinkTarget);
786
+ await symlinkGrapheneSkill(targetDir, answers.agentSetup);
648
787
  }
649
788
  clack.outro(completionMessage(answers), { output: stdout });
650
789
  } catch (err) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-graphene",
3
- "version": "0.0.18",
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": {