gencow 0.1.126 → 0.1.128

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/bin/gencow.mjs CHANGED
@@ -425,6 +425,40 @@ function spawnInServer(cmd, args, env = process.env) {
425
425
  return spawn(cmd, args, { cwd: serverRoot, stdio: "inherit", shell: true, env });
426
426
  }
427
427
 
428
+ // ─── Core Import Resolution ───────────────────────────────
429
+
430
+ /**
431
+ * @gencow/core import 경로 해석 — 3단계 fallback
432
+ *
433
+ * 1. CLI 패키지 내 번들된 core (../core/index.js relative to server/)
434
+ * 2. 사용자 프로젝트 node_modules/@gencow/core/dist/index.js (절대 경로)
435
+ * 3. bare specifier "@gencow/core" (모노레포 등 이미 resolve 가능한 경우)
436
+ *
437
+ * Bun ESM은 NODE_PATH를 무시하므로, bare specifier fallback은
438
+ * .gencow-extract.ts 파일 위치(CLI server 디렉토리) 기준으로만 해석됨.
439
+ * 따라서 2단계에서 프로젝트 node_modules의 절대 경로를 명시적으로 시도하여
440
+ * 글로벌/npx 설치 환경에서도 안정적으로 resolve.
441
+ *
442
+ * @param {string} serverRoot - findServerRoot()가 반환한 서버 루트 경로
443
+ * @returns {string} import 경로 (절대 경로 또는 bare specifier)
444
+ */
445
+ function resolveCoreImport(serverRoot) {
446
+ // 1차: CLI 패키지 내 번들된 core
447
+ const bundledCorePath = resolve(serverRoot, "../core/index.js");
448
+ if (existsSync(bundledCorePath)) return bundledCorePath.replace(/\\/g, "/");
449
+
450
+ // 2차: 사용자 프로젝트 node_modules (절대 경로 — Bun ESM에서 확실히 resolve)
451
+ const cwdCoreDist = resolve(process.cwd(), "node_modules/@gencow/core/dist/index.js");
452
+ if (existsSync(cwdCoreDist)) return cwdCoreDist.replace(/\\/g, "/");
453
+
454
+ // 2차-b: src/ 직접 참조 (모노레포 workspace 등에서 dist 미빌드 시)
455
+ const cwdCoreSrc = resolve(process.cwd(), "node_modules/@gencow/core/src/index.ts");
456
+ if (existsSync(cwdCoreSrc)) return cwdCoreSrc.replace(/\\/g, "/");
457
+
458
+ // 3차: bare specifier — 모노레포 또는 이미 resolve 가능한 환경
459
+ return "@gencow/core";
460
+ }
461
+
428
462
  // ─── API Codegen ──────────────────────────────────────────
429
463
 
430
464
  function generateApiTs(config) {
@@ -433,11 +467,8 @@ function generateApiTs(config) {
433
467
  const apiTsPath = resolve(absoluteFunctions, "api.ts");
434
468
  const extractTsPath = resolve(serverRoot, ".gencow-extract.ts");
435
469
 
436
- // Resolve @gencow/core — bundled core is at ../core/ relative to server/
437
- const bundledCorePath = resolve(serverRoot, "../core/index.js");
438
- const coreImport = existsSync(bundledCorePath)
439
- ? bundledCorePath.replace(/\\/g, "/") // Windows 호환
440
- : "@gencow/core"; // 모노레포 등 이미 resolve 가능한 경우
470
+ // Resolve @gencow/core — 3단계 fallback (bundled CWD node_modules bare specifier)
471
+ const coreImport = resolveCoreImport(serverRoot);
441
472
 
442
473
  const script = `
443
474
  import { getRegisteredQueries, getRegisteredMutations } from "${coreImport}";
@@ -696,6 +727,21 @@ const commands = {
696
727
 
697
728
  // ── init ─────────────────────────────────────────────
698
729
  async init(...initArgs) {
730
+ // --help handler
731
+ if (initArgs.includes("--help") || initArgs.includes("-h")) {
732
+ log(`\n${BOLD}${CYAN}gencow init${RESET} — Create a new Gencow project\n`);
733
+ log(` ${BOLD}Usage:${RESET} gencow init [name] [options]\n`);
734
+ log(` ${BOLD}Arguments:${RESET}`);
735
+ log(` ${CYAN}name${RESET} Project name (creates directory) or "." for current dir\n`);
736
+ log(` ${BOLD}Options:${RESET}`);
737
+ log(` ${DIM}--template, -t${RESET} Select template (default, task-app, fullstack, ai-chat)`);
738
+ log(` ${DIM}--force, -f${RESET} Initialize in non-empty directory\n`);
739
+ log(` ${BOLD}Examples:${RESET}`);
740
+ log(` gencow init my-app`);
741
+ log(` gencow init . --force`);
742
+ log(` gencow init my-app --template fullstack\n`);
743
+ return;
744
+ }
699
745
  // Parse --template / -t flag, --force / -f flag, and project name from args
700
746
  let name = null;
701
747
  let templateId = null;
@@ -1135,6 +1181,16 @@ ${hasPrompt ? `
1135
1181
  // seed.ts 실행 (TRUNCATE 없이). 서버가 실행 중이어야 함.
1136
1182
  // Cloud-first: 기본=Cloud, --local=로컬
1137
1183
  async "db:seed"(...args) {
1184
+ // --help handler
1185
+ if (args.includes("--help") || args.includes("-h")) {
1186
+ log(`\n${BOLD}${CYAN}gencow db:seed${RESET} — Run seed.ts on cloud app\n`);
1187
+ log(` ${BOLD}Usage:${RESET} gencow db:seed [options]\n`);
1188
+ log(` ${BOLD}Options:${RESET}`);
1189
+ log(` ${DIM}--prod${RESET} Seed production app`);
1190
+ log(` ${DIM}--local${RESET} Seed local dev server`);
1191
+ log(` ${DIM}--app, -a${RESET} Target specific app\n`);
1192
+ return;
1193
+ }
1138
1194
  const config = loadConfig();
1139
1195
  const isLocal = isLocalDbTarget(args);
1140
1196
 
@@ -1531,6 +1587,16 @@ ${hasPrompt ? `
1531
1587
  // ── db:push ──────────────────────────────────────────
1532
1588
  // Cloud-first: 기본=Cloud, --local=로컬
1533
1589
  async "db:push"(...args) {
1590
+ // --help handler
1591
+ if (args.includes("--help") || args.includes("-h")) {
1592
+ log(`\n${BOLD}${CYAN}gencow db:push${RESET} — Sync schema.ts → database\n`);
1593
+ log(` ${BOLD}Usage:${RESET} gencow db:push [options]\n`);
1594
+ log(` ${BOLD}Options:${RESET}`);
1595
+ log(` ${DIM}--prod${RESET} Push to production DB (confirmation required)`);
1596
+ log(` ${DIM}--local${RESET} Push to local dev DB`);
1597
+ log(` ${DIM}--app, -a${RESET} Target specific app\n`);
1598
+ return;
1599
+ }
1534
1600
  const config = loadConfig();
1535
1601
  const isLocal = isLocalDbTarget(args);
1536
1602
 
@@ -1677,7 +1743,14 @@ ${hasPrompt ? `
1677
1743
  },
1678
1744
 
1679
1745
  // ── db:generate ──────────────────────────────────────
1680
- async "db:generate"() {
1746
+ async "db:generate"(...args) {
1747
+ // --help handler
1748
+ if (args?.includes?.("--help") || args?.includes?.("-h")) {
1749
+ log(`\n${BOLD}${CYAN}gencow db:generate${RESET} — Generate SQL migration files\n`);
1750
+ log(` ${BOLD}Usage:${RESET} gencow db:generate\n`);
1751
+ log(` Generates migration files from schema.ts using drizzle-kit.\n`);
1752
+ return;
1753
+ }
1681
1754
  const config = loadConfig();
1682
1755
  log(`\n${BOLD}${CYAN}Gencow DB Generate${RESET}\n`);
1683
1756
  info("Generating migration files from schema.ts...");
@@ -1936,6 +2009,23 @@ ${BOLD}Examples:${RESET}
1936
2009
 
1937
2010
  // ── static — 정적 파일 배포 (dev 기본, --prod 로 프로덕션) ──
1938
2011
  async static(...staticArgs) {
2012
+ // --help handler
2013
+ if (staticArgs.includes("--help") || staticArgs.includes("-h")) {
2014
+ log(`\n${BOLD}${CYAN}gencow static${RESET} — Deploy static files\n`);
2015
+ log(` ${BOLD}Usage:${RESET} gencow static [dir] [options]\n`);
2016
+ log(` ${BOLD}Arguments:${RESET}`);
2017
+ log(` ${CYAN}dir${RESET} Static directory (auto-detects dist/, out/, build/)\n`);
2018
+ log(` ${BOLD}Options:${RESET}`);
2019
+ log(` ${DIM}--prod${RESET} Deploy to production app`);
2020
+ log(` ${DIM}--no-backend${RESET} Skip backend deployment`);
2021
+ log(` ${DIM}--force, -f${RESET} Skip dependency audit`);
2022
+ log(` ${DIM}--app, -a${RESET} Target specific app\n`);
2023
+ log(` ${BOLD}Examples:${RESET}`);
2024
+ log(` gencow static dist/`);
2025
+ log(` gencow static --prod dist/`);
2026
+ log(` gencow static --no-backend dist/\n`);
2027
+ return;
2028
+ }
1939
2029
  const creds = requireCreds();
1940
2030
 
1941
2031
  let staticDir = null;
@@ -1989,6 +2079,21 @@ ${BOLD}Examples:${RESET}
1989
2079
 
1990
2080
  // ── deploy — 클라우드 배포 (dev 기본, --prod로 프로덕션) ──
1991
2081
  async deploy(...deployArgs) {
2082
+ // --help handler
2083
+ if (deployArgs.includes("--help") || deployArgs.includes("-h")) {
2084
+ log(`\n${BOLD}${CYAN}gencow deploy${RESET} — Deploy backend to cloud\n`);
2085
+ log(` ${BOLD}Usage:${RESET} gencow deploy [options]\n`);
2086
+ log(` ${BOLD}Options:${RESET}`);
2087
+ log(` ${DIM}--prod${RESET} Deploy to production (Pro+ only)`);
2088
+ log(` ${DIM}--rollback${RESET} Rollback to previous deployment`);
2089
+ log(` ${DIM}--force, -f${RESET} Skip dependency audit`);
2090
+ log(` ${DIM}--app, -a${RESET} Target specific app\n`);
2091
+ log(` ${BOLD}Examples:${RESET}`);
2092
+ log(` gencow deploy`);
2093
+ log(` gencow deploy --prod`);
2094
+ log(` gencow deploy --rollback\n`);
2095
+ return;
2096
+ }
1992
2097
  const creds = requireCreds();
1993
2098
 
1994
2099
  // gencow.json에서 앱 ID 확인 (자동 생성된 유니크 ID)
@@ -3049,6 +3154,20 @@ ${BOLD}Examples:${RESET}
3049
3154
 
3050
3155
  // ── env ───────────────────────────────────────────────
3051
3156
  async env(...envArgs) {
3157
+ // --help handler
3158
+ if (envArgs.includes("--help") || envArgs.includes("-h")) {
3159
+ log(`\n${BOLD}${CYAN}gencow env${RESET} — Environment variable management\n`);
3160
+ log(` ${BOLD}Usage:${RESET} gencow env <command> [options]\n`);
3161
+ log(` ${BOLD}Commands:${RESET}`);
3162
+ log(` ${CYAN}list${RESET} List cloud env vars`);
3163
+ log(` ${CYAN}set${RESET} KEY=VALUE Set cloud env var (hot-reload)`);
3164
+ log(` ${CYAN}unset${RESET} KEY Remove cloud env var`);
3165
+ log(` ${CYAN}push${RESET} Push .env to cloud\n`);
3166
+ log(` ${BOLD}Options:${RESET}`);
3167
+ log(` ${DIM}--prod${RESET} Target production app`);
3168
+ log(` ${DIM}--app, -a${RESET} Target specific app\n`);
3169
+ return;
3170
+ }
3052
3171
  const creds = requireCreds();
3053
3172
  const subCmd = envArgs[0] || "list";
3054
3173
  const restArgs = envArgs.slice(1);
@@ -3216,6 +3335,19 @@ ${BOLD}Examples:${RESET}
3216
3335
 
3217
3336
  // ── config ────────────────────────────────────────────
3218
3337
  async config(...configArgs) {
3338
+ // --help handler
3339
+ if (configArgs.includes("--help") || configArgs.includes("-h")) {
3340
+ log(`\n${BOLD}${CYAN}gencow config${RESET} — App configuration\n`);
3341
+ log(` ${BOLD}Usage:${RESET} gencow config <command> [options]\n`);
3342
+ log(` ${BOLD}Commands:${RESET}`);
3343
+ log(` ${CYAN}set${RESET} <key> <value> Set config (e.g. image.maxWidth 1920)`);
3344
+ log(` ${CYAN}get${RESET} Show current config`);
3345
+ log(` ${CYAN}reset${RESET} Reset to tier defaults\n`);
3346
+ log(` ${BOLD}Options:${RESET}`);
3347
+ log(` ${DIM}--prod${RESET} Target production app`);
3348
+ log(` ${DIM}--app, -a${RESET} Target specific app\n`);
3349
+ return;
3350
+ }
3219
3351
  const creds = requireCreds();
3220
3352
  const subCmd = configArgs[0] || "help";
3221
3353
  const restArgs = configArgs.slice(1);
@@ -3828,6 +3960,18 @@ ${BOLD}Examples:${RESET}
3828
3960
 
3829
3961
  // ── domain ─────────────────────────────────────────────
3830
3962
  async domain(...domainArgs) {
3963
+ // --help handler
3964
+ if (domainArgs.includes("--help") || domainArgs.includes("-h")) {
3965
+ log(`\n${BOLD}${CYAN}gencow domain${RESET} — Custom domain management\n`);
3966
+ log(` ${BOLD}Usage:${RESET} gencow domain <command> [options]\n`);
3967
+ log(` ${BOLD}Commands:${RESET}`);
3968
+ log(` ${CYAN}set${RESET} <domain> Connect custom domain (e.g. myapp.com)`);
3969
+ log(` ${CYAN}status${RESET} Check domain DNS/TLS status`);
3970
+ log(` ${CYAN}remove${RESET} Disconnect custom domain\n`);
3971
+ log(` ${BOLD}Options:${RESET}`);
3972
+ log(` ${DIM}--app, -a${RESET} Target specific app\n`);
3973
+ return;
3974
+ }
3831
3975
  const creds = requireCreds();
3832
3976
  const subCmd = domainArgs[0] || "status";
3833
3977
  const restArgs = domainArgs.slice(1);
@@ -3966,6 +4110,15 @@ ${BOLD}Examples:${RESET}
3966
4110
 
3967
4111
  // ── codegen — 프론트엔드 전용 api.ts 생성 ─────────
3968
4112
  async codegen(...codegenArgs) {
4113
+ // --help handler
4114
+ if (codegenArgs.includes("--help") || codegenArgs.includes("-h")) {
4115
+ log(`\n${BOLD}${CYAN}gencow codegen${RESET} — Generate frontend api.ts from schema\n`);
4116
+ log(` ${BOLD}Usage:${RESET} gencow codegen [options]\n`);
4117
+ log(` ${BOLD}Options:${RESET}`);
4118
+ log(` ${DIM}--outdir, -o${RESET} Output directory (default: src/gencow/)\n`);
4119
+ log(` Generates api.ts from gencow/ folder for frontend use.\n`);
4120
+ return;
4121
+ }
3969
4122
  const config = loadConfig();
3970
4123
  const absoluteFunctions = resolve(process.cwd(), config.functionsDir);
3971
4124
 
@@ -3994,12 +4147,8 @@ ${BOLD}Examples:${RESET}
3994
4147
  try { runtimeRoot = findServerRoot(); } catch { runtimeRoot = process.cwd(); }
3995
4148
  const extractTsPath = resolve(runtimeRoot, ".gencow-extract.ts");
3996
4149
 
3997
- // @gencow/core — 번들된 core 절대 경로 우선, 없으면 bare specifier
3998
- // generateApiTs()와 동일 해석 전략: 글로벌 CLI에서도 resolve 보장
3999
- const bundledCorePath = resolve(runtimeRoot, "../core/index.js");
4000
- const coreImport = existsSync(bundledCorePath)
4001
- ? bundledCorePath.replace(/\\/g, "/")
4002
- : "@gencow/core";
4150
+ // @gencow/core — 3단계 fallback (bundled CWD node_modules bare specifier)
4151
+ const coreImport = resolveCoreImport(runtimeRoot);
4003
4152
 
4004
4153
  const script = `
4005
4154
  import { getRegisteredQueries, getRegisteredMutations } from "${coreImport}";
@@ -4094,6 +4243,17 @@ process.exit(0);
4094
4243
 
4095
4244
  // ── app (subcommands: create, list, delete) ────────
4096
4245
  async app(subcmd, ...rest) {
4246
+ // --help handler
4247
+ if (subcmd === "--help" || subcmd === "-h" || rest.includes("--help") || rest.includes("-h")) {
4248
+ log(`\n${BOLD}${CYAN}gencow app${RESET} — App management\n`);
4249
+ log(` ${BOLD}Usage:${RESET} gencow app <command>\n`);
4250
+ log(` ${BOLD}Commands:${RESET}`);
4251
+ log(` ${CYAN}list${RESET} List your apps`);
4252
+ log(` ${CYAN}create${RESET} Create a new app`);
4253
+ log(` ${CYAN}delete${RESET} Delete an app (confirmation required)`);
4254
+ log(` ${CYAN}status${RESET} Show app status\n`);
4255
+ return;
4256
+ }
4097
4257
  const creds = requireCreds();
4098
4258
 
4099
4259
  if (!subcmd || subcmd === "list") {