gencow 0.1.122 → 0.1.123
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 +94 -237
- package/package.json +3 -3
- package/server/index.js +10 -1
- package/server/index.js.map +2 -2
- package/templates/ai-chat/ai.ts +41 -0
- package/templates/ai.ts +41 -0
- package/templates/fullstack/ai.ts +41 -0
- package/templates/guardrails.ts +13 -13
- package/templates/memory.ts +29 -25
- package/templates/parsers.ts +55 -8
- package/templates/prompts.ts +13 -13
- package/templates/rag.ts +88 -56
- package/templates/reranker.ts +9 -9
- package/templates/schema-rag.ts +17 -10
package/bin/gencow.mjs
CHANGED
|
@@ -1049,88 +1049,9 @@ ${hasPrompt ? `
|
|
|
1049
1049
|
},
|
|
1050
1050
|
|
|
1051
1051
|
// ── db:reset ─────────────────────────────────────────
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
async "db:reset"(...args) {
|
|
1056
|
-
const config = loadConfig();
|
|
1057
|
-
const cwd = process.cwd();
|
|
1058
|
-
const isLocal = args.includes("--local");
|
|
1059
|
-
|
|
1060
|
-
if (!isLocal) {
|
|
1061
|
-
// Cloud reset은 미지원 — 안내 메시지
|
|
1062
|
-
error("db:reset requires --local flag.");
|
|
1063
|
-
info(`${DIM}Cloud DB reset is only available via Dashboard (data protection).${RESET}`);
|
|
1064
|
-
info(`${DIM}To reset local DB: gencow db:reset --local${RESET}`);
|
|
1065
|
-
log("");
|
|
1066
|
-
return;
|
|
1067
|
-
}
|
|
1068
|
-
|
|
1069
|
-
const port = process.env.PORT || config.port || 5456;
|
|
1070
|
-
|
|
1071
|
-
log(`\n${BOLD}${CYAN}Gencow DB Reset${RESET}\n`);
|
|
1072
|
-
|
|
1073
|
-
// 서버가 실행 중인지 확인
|
|
1074
|
-
let serverAlive = false;
|
|
1075
|
-
try {
|
|
1076
|
-
const res = await fetch(`http://localhost:${port}/_admin/status`, { signal: AbortSignal.timeout(2000) });
|
|
1077
|
-
serverAlive = res.ok;
|
|
1078
|
-
} catch { /* 서버 꺼져있음 */ }
|
|
1079
|
-
|
|
1080
|
-
if (serverAlive) {
|
|
1081
|
-
// ── 서버 실행 중: API 기반 TRUNCATE + seed ──
|
|
1082
|
-
info(`Server detected on :${port} — using API reset (TRUNCATE + seed)`);
|
|
1083
|
-
log("");
|
|
1084
|
-
|
|
1085
|
-
try {
|
|
1086
|
-
const res = await fetch(`http://localhost:${port}/_admin/reset`, {
|
|
1087
|
-
method: "POST",
|
|
1088
|
-
headers: { "Content-Type": "application/json" },
|
|
1089
|
-
body: JSON.stringify({ confirm: "delete all data" }),
|
|
1090
|
-
});
|
|
1091
|
-
const data = await res.json();
|
|
1092
|
-
|
|
1093
|
-
if (!res.ok) {
|
|
1094
|
-
error(`Reset failed: ${data.error || "Unknown error"}`);
|
|
1095
|
-
log("");
|
|
1096
|
-
return;
|
|
1097
|
-
}
|
|
1098
|
-
|
|
1099
|
-
success(`TRUNCATE done: ${data.truncated?.length || 0} tables`);
|
|
1100
|
-
if (data.truncated?.length > 0) {
|
|
1101
|
-
info(` ${DIM}${data.truncated.join(", ")}${RESET}`);
|
|
1102
|
-
}
|
|
1103
|
-
if (data.seeded) {
|
|
1104
|
-
success(`Seed completed ✓`);
|
|
1105
|
-
} else {
|
|
1106
|
-
info(`${DIM}No seed.ts found — skipping${RESET}`);
|
|
1107
|
-
}
|
|
1108
|
-
} catch (e) {
|
|
1109
|
-
error(`Server connection failed: ${e.message}`);
|
|
1110
|
-
}
|
|
1111
|
-
} else {
|
|
1112
|
-
// ── 서버 꺼짐: 기존 PGlite 파일 삭제 ──
|
|
1113
|
-
const dbPath = resolve(cwd, config.db.url);
|
|
1114
|
-
if (existsSync(dbPath)) {
|
|
1115
|
-
// 1. Backup first
|
|
1116
|
-
const backupDir = resolve(cwd, ".gencow", "backups");
|
|
1117
|
-
const ts = new Date().toISOString().replace(/[:.]/g, "-");
|
|
1118
|
-
const backupPath = resolve(backupDir, ts);
|
|
1119
|
-
mkdirSync(backupPath, { recursive: true });
|
|
1120
|
-
cpSync(dbPath, backupPath, { recursive: true });
|
|
1121
|
-
success(`Backup created: .gencow/backups/${ts}`);
|
|
1122
|
-
|
|
1123
|
-
// 2. Cleanup old backups (keep last 3)
|
|
1124
|
-
cleanupOldBackups(backupDir, 3);
|
|
1125
|
-
|
|
1126
|
-
// 3. Delete DB
|
|
1127
|
-
rmSync(dbPath, { recursive: true, force: true });
|
|
1128
|
-
success("DB deleted — restart with gencow dev to create a new one");
|
|
1129
|
-
} else {
|
|
1130
|
-
info("DB does not exist yet. Run gencow dev to get started.");
|
|
1131
|
-
}
|
|
1132
|
-
}
|
|
1133
|
-
log("");
|
|
1052
|
+
async "db:reset"() {
|
|
1053
|
+
info(`db:reset is ${BOLD}coming soon${RESET}.`);
|
|
1054
|
+
info(`${DIM}Use Gencow Dashboard for cloud DB management.${RESET}\n`);
|
|
1134
1055
|
},
|
|
1135
1056
|
|
|
1136
1057
|
// ── db:seed ──────────────────────────────────────────
|
|
@@ -1141,47 +1062,8 @@ ${hasPrompt ? `
|
|
|
1141
1062
|
const isLocal = args.includes("--local");
|
|
1142
1063
|
|
|
1143
1064
|
if (isLocal) {
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
log(`\n${BOLD}${CYAN}Gencow DB Seed${RESET} ${DIM}(local)${RESET}\n`);
|
|
1148
|
-
|
|
1149
|
-
// 서버가 실행 중인지 확인
|
|
1150
|
-
try {
|
|
1151
|
-
const statusRes = await fetch(`http://localhost:${port}/_admin/status`, { signal: AbortSignal.timeout(2000) });
|
|
1152
|
-
if (!statusRes.ok) throw new Error("Server not ready");
|
|
1153
|
-
} catch {
|
|
1154
|
-
error(`Server not running on :${port}`);
|
|
1155
|
-
info(`${DIM}Start server first: gencow dev --local${RESET}`);
|
|
1156
|
-
log("");
|
|
1157
|
-
return;
|
|
1158
|
-
}
|
|
1159
|
-
|
|
1160
|
-
try {
|
|
1161
|
-
const res = await fetch(`http://localhost:${port}/_admin/seed`, {
|
|
1162
|
-
method: "POST",
|
|
1163
|
-
headers: { "Content-Type": "application/json" },
|
|
1164
|
-
});
|
|
1165
|
-
const data = await res.json();
|
|
1166
|
-
|
|
1167
|
-
if (res.status === 404) {
|
|
1168
|
-
warn("gencow/seed.ts not found");
|
|
1169
|
-
info(`\n ${DIM}Create gencow/seed.ts:${RESET}\n`);
|
|
1170
|
-
log(` ${DIM}import { tasks } from "./schema";${RESET}`);
|
|
1171
|
-
log(` ${DIM}export default async function seed(ctx) {${RESET}`);
|
|
1172
|
-
log(` ${DIM} await ctx.db.insert(tasks).values([${RESET}`);
|
|
1173
|
-
log(` ${DIM} { title: "Hello World" },${RESET}`);
|
|
1174
|
-
log(` ${DIM} ]);${RESET}`);
|
|
1175
|
-
log(` ${DIM}};${RESET}`);
|
|
1176
|
-
} else if (!res.ok) {
|
|
1177
|
-
error(`Seed failed: ${data.error || "Unknown error"}`);
|
|
1178
|
-
} else {
|
|
1179
|
-
success("Seed completed ✓");
|
|
1180
|
-
}
|
|
1181
|
-
} catch (e) {
|
|
1182
|
-
error(`Server connection failed: ${e.message}`);
|
|
1183
|
-
}
|
|
1184
|
-
log("");
|
|
1065
|
+
info(`Local db:seed is ${BOLD}coming soon${RESET}.`);
|
|
1066
|
+
info(`${DIM}Use cloud mode (default): gencow db:seed${RESET}\n`);
|
|
1185
1067
|
return;
|
|
1186
1068
|
}
|
|
1187
1069
|
|
|
@@ -1210,7 +1092,6 @@ ${hasPrompt ? `
|
|
|
1210
1092
|
if (!appId) {
|
|
1211
1093
|
error("Cloud app not found. Make sure gencow.json exists with an appId.");
|
|
1212
1094
|
info(`${DIM}Run 'gencow dev' first to create your app.${RESET}`);
|
|
1213
|
-
info(`${DIM}To seed local DB: gencow db:seed --local${RESET}`);
|
|
1214
1095
|
log("");
|
|
1215
1096
|
return;
|
|
1216
1097
|
}
|
|
@@ -1317,9 +1198,12 @@ ${hasPrompt ? `
|
|
|
1317
1198
|
if (devArgs.includes("--verbose")) {
|
|
1318
1199
|
process.env.GENCOW_VERBOSE = "true";
|
|
1319
1200
|
}
|
|
1320
|
-
// --local 플래그:
|
|
1201
|
+
// --local 플래그: coming soon
|
|
1321
1202
|
if (devArgs.includes("--local")) {
|
|
1322
|
-
|
|
1203
|
+
log(`\n${BOLD}${CYAN}Gencow Dev${RESET} ${DIM}(local)${RESET}\n`);
|
|
1204
|
+
info(`Local development mode is ${BOLD}coming soon${RESET}.`);
|
|
1205
|
+
info(`${DIM}Use cloud mode (default): gencow dev${RESET}\n`);
|
|
1206
|
+
return;
|
|
1323
1207
|
}
|
|
1324
1208
|
// --cloud 하위 호환 (이미 기본이므로 그대로 진행)
|
|
1325
1209
|
// 기본 = 클라우드 모드
|
|
@@ -1541,18 +1425,8 @@ ${hasPrompt ? `
|
|
|
1541
1425
|
const isLocal = args.includes("--local");
|
|
1542
1426
|
|
|
1543
1427
|
if (isLocal) {
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
if (!hasDb) {
|
|
1547
|
-
const envPath = resolve(process.cwd(), ".env");
|
|
1548
|
-
if (existsSync(envPath)) hasDb = readFileSync(envPath, "utf8").includes("DATABASE_URL=");
|
|
1549
|
-
}
|
|
1550
|
-
const targetDb = hasDb ? "local PG" : "local fallback: PGlite";
|
|
1551
|
-
log(`\n${BOLD}${CYAN}Gencow DB Push${RESET} ${DIM}(${targetDb})${RESET}\n`);
|
|
1552
|
-
info("Pushing schema.ts → database (no migration files)...");
|
|
1553
|
-
runInServer("pnpm db:push --force", buildEnv(config));
|
|
1554
|
-
success("Schema pushed!");
|
|
1555
|
-
log(` ${DIM}Tables are in sync with schema.ts${RESET}\n`);
|
|
1428
|
+
info(`Local db:push is ${BOLD}coming soon${RESET}.`);
|
|
1429
|
+
info(`${DIM}Use cloud mode (default): gencow db:push${RESET}\n`);
|
|
1556
1430
|
return;
|
|
1557
1431
|
}
|
|
1558
1432
|
|
|
@@ -1634,7 +1508,7 @@ ${hasPrompt ? `
|
|
|
1634
1508
|
} catch (e) {
|
|
1635
1509
|
const msg = e.stderr?.toString() || e.message || "";
|
|
1636
1510
|
if (msg.includes("No schema changes") || msg.includes("nothing to migrate") || msg.includes("No changes detected")) {
|
|
1637
|
-
log(`${DIM}
|
|
1511
|
+
log(`${DIM} ✓ Migrations up-to-date — no new schema changes detected${RESET}`);
|
|
1638
1512
|
} else {
|
|
1639
1513
|
warn(`Migration generation failed: ${msg.split("\n")[0]}`);
|
|
1640
1514
|
info("Will attempt schema push via server.");
|
|
@@ -1715,21 +1589,14 @@ ${hasPrompt ? `
|
|
|
1715
1589
|
|
|
1716
1590
|
// ── db:studio ────────────────────────────────────────
|
|
1717
1591
|
async "db:studio"() {
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
info("Opening Drizzle Studio...");
|
|
1721
|
-
runInServer("pnpm db:studio", buildEnv(config));
|
|
1592
|
+
info(`Drizzle Studio is ${BOLD}coming soon${RESET}.`);
|
|
1593
|
+
info(`${DIM}Use Gencow Dashboard at https://gencow.app instead.${RESET}\n`);
|
|
1722
1594
|
},
|
|
1723
1595
|
|
|
1724
1596
|
// ── dashboard ────────────────────────────────────────
|
|
1725
1597
|
async dashboard() {
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
const url = `http://localhost:${port}/_admin`;
|
|
1729
|
-
log(`\n${BOLD}${CYAN}Gencow Dashboard${RESET}\n`);
|
|
1730
|
-
info(`Opening ${url}`);
|
|
1731
|
-
const { default: open } = await import("open");
|
|
1732
|
-
await open(url);
|
|
1598
|
+
info(`Local dashboard is ${BOLD}coming soon${RESET}.`);
|
|
1599
|
+
info(`${DIM}Use Gencow Dashboard at https://gencow.app${RESET}\n`);
|
|
1733
1600
|
},
|
|
1734
1601
|
|
|
1735
1602
|
|
|
@@ -1745,36 +1612,25 @@ ${BOLD}Quick Start:${RESET}
|
|
|
1745
1612
|
${GREEN}init <name>${RESET} Create a new Gencow project
|
|
1746
1613
|
${DIM}--template, -t Select template (default, task-app, fullstack, ai-chat)${RESET}
|
|
1747
1614
|
${DIM}--force, -f Initialize in non-empty directory (preserves existing files)${RESET}
|
|
1748
|
-
|
|
1749
|
-
${
|
|
1750
|
-
${GREEN}dev${RESET} Watch + auto-deploy to cloud + live logs ${DIM}(default)${RESET}
|
|
1751
|
-
${DIM}--local Use local PGlite instead of cloud${RESET}
|
|
1752
|
-
${DIM}--verbose Show all HTTP logs (including admin/ws)${RESET}
|
|
1753
|
-
${GREEN}dashboard${RESET} Open the Gencow admin dashboard in browser
|
|
1754
|
-
${GREEN}db:push${RESET} Sync schema.ts → cloud DB ${DIM}(default: cloud)${RESET}
|
|
1755
|
-
${DIM}--local Push to local DB instead of cloud${RESET}
|
|
1756
|
-
${DIM}--prod Push to production DB (confirmation required)${RESET}
|
|
1757
|
-
${GREEN}db:generate${RESET} Generate SQL migration files from schema.ts
|
|
1758
|
-
${GREEN}db:seed${RESET} Run gencow/seed.ts on cloud app ${DIM}(default: cloud)${RESET}
|
|
1759
|
-
${DIM}--local Seed local DB instead of cloud${RESET}
|
|
1760
|
-
${DIM}--prod Seed production app${RESET}
|
|
1761
|
-
${GREEN}db:reset${RESET} TRUNCATE all data + run seed.ts ${DIM}(local only)${RESET}
|
|
1762
|
-
${DIM}--local Required — local DB reset only (cloud: use Dashboard)${RESET}
|
|
1763
|
-
${GREEN}db:studio${RESET} Open Drizzle Studio ${DIM}(visual DB browser)${RESET}
|
|
1764
|
-
${GREEN}add <comp...>${RESET} Add components ${DIM}(AI RAG Tools Memory Analytics)${RESET}
|
|
1765
|
-
${GREEN}mcp${RESET} Start MCP server for AI agent integration ${DIM}(stdio)${RESET}
|
|
1766
|
-
${GREEN}codegen${RESET} Generate frontend-independent api.ts
|
|
1615
|
+
${GREEN}add <comp...>${RESET} Add components ${DIM}(AI RAG Tools Memory)${RESET}
|
|
1616
|
+
${GREEN}codegen${RESET} Generate frontend api.ts from schema
|
|
1767
1617
|
${DIM}--outdir, -o Output directory (default: src/gencow/)${RESET}
|
|
1768
1618
|
|
|
1769
|
-
${BOLD}
|
|
1619
|
+
${BOLD}Commands (login required):${RESET}
|
|
1770
1620
|
${GREEN}login${RESET} Login to Gencow Platform ${DIM}(browser → token)${RESET}
|
|
1771
1621
|
${GREEN}logout${RESET} Clear credentials
|
|
1772
1622
|
${GREEN}whoami${RESET} Show current user info
|
|
1773
|
-
${GREEN}
|
|
1774
|
-
${DIM}--
|
|
1623
|
+
${GREEN}dev${RESET} Watch + auto-deploy to cloud + live logs
|
|
1624
|
+
${DIM}--verbose Show all HTTP logs (including admin/ws)${RESET}
|
|
1625
|
+
${GREEN}db:push${RESET} Sync schema.ts → cloud DB
|
|
1626
|
+
${DIM}--prod Push to production DB (confirmation required)${RESET}
|
|
1627
|
+
${GREEN}db:generate${RESET} Generate SQL migration files from schema.ts
|
|
1628
|
+
${GREEN}db:seed${RESET} Run gencow/seed.ts on cloud app
|
|
1629
|
+
${DIM}--prod Seed production app${RESET}
|
|
1630
|
+
${GREEN}static [dir]${RESET} Deploy static files ${DIM}(dist/, out/, build/)${RESET}
|
|
1631
|
+
${DIM}--prod Deploy to production app${RESET}
|
|
1775
1632
|
${DIM}--force, -f Skip dependency audit${RESET}
|
|
1776
|
-
${GREEN}deploy${RESET} Deploy to production ${DIM}(Pro+ only)${RESET}
|
|
1777
|
-
${DIM}--static [dir] Deploy static files to production${RESET}
|
|
1633
|
+
${GREEN}deploy${RESET} Deploy backend to production ${DIM}(Pro+ only)${RESET}
|
|
1778
1634
|
${DIM}--rollback Rollback to previous deployment${RESET}
|
|
1779
1635
|
${DIM}--force, -f Skip dependency audit${RESET}
|
|
1780
1636
|
${GREEN}env list${RESET} List cloud env vars ${DIM}(--prod for production)${RESET}
|
|
@@ -1785,9 +1641,10 @@ ${BOLD}BaaS commands (login required):${RESET}
|
|
|
1785
1641
|
${GREEN}files list${RESET} List uploaded files
|
|
1786
1642
|
${GREEN}files delete${RESET} Delete uploaded file ${DIM}(--yes to skip confirm)${RESET}
|
|
1787
1643
|
${GREEN}files url${RESET} Get serving URL for a file
|
|
1788
|
-
${GREEN}config set${RESET} Set
|
|
1789
|
-
|
|
1790
|
-
${GREEN}config
|
|
1644
|
+
${GREEN}config set${RESET} Set image config ${DIM}(config set image.maxWidth 1920)${RESET}
|
|
1645
|
+
${DIM}Keys: image.maxWidth (0-10000), image.quality (0-100)${RESET}
|
|
1646
|
+
${GREEN}config get${RESET} Show current image config
|
|
1647
|
+
${GREEN}config reset${RESET} Reset image config to tier defaults
|
|
1791
1648
|
${GREEN}domain set${RESET} Connect custom domain ${DIM}(myapp.com)${RESET}
|
|
1792
1649
|
${GREEN}domain status${RESET} Check domain DNS/TLS status
|
|
1793
1650
|
${GREEN}domain remove${RESET} Disconnect custom domain
|
|
@@ -1955,19 +1812,19 @@ ${BOLD}Examples:${RESET}
|
|
|
1955
1812
|
}
|
|
1956
1813
|
},
|
|
1957
1814
|
|
|
1958
|
-
// ── static —
|
|
1815
|
+
// ── static — 정적 파일 배포 (dev 기본, --prod 로 프로덕션) ──
|
|
1959
1816
|
async static(...staticArgs) {
|
|
1960
1817
|
const creds = requireCreds();
|
|
1961
1818
|
|
|
1962
1819
|
let staticDir = null;
|
|
1963
1820
|
let forceDeploy = false;
|
|
1964
|
-
let noBackend = false;
|
|
1965
1821
|
let appId = null;
|
|
1822
|
+
let isProd = false;
|
|
1966
1823
|
|
|
1967
1824
|
for (let i = 0; i < staticArgs.length; i++) {
|
|
1968
1825
|
const a = staticArgs[i];
|
|
1969
1826
|
if (a === "--force" || a === "-f") forceDeploy = true;
|
|
1970
|
-
else if (a === "--
|
|
1827
|
+
else if (a === "--prod") isProd = true;
|
|
1971
1828
|
else if (a === "--app" || a === "-a") appId = staticArgs[++i];
|
|
1972
1829
|
else if (!a.startsWith("-")) {
|
|
1973
1830
|
staticDir = a;
|
|
@@ -1976,9 +1833,21 @@ ${BOLD}Examples:${RESET}
|
|
|
1976
1833
|
|
|
1977
1834
|
// gencow.json에서 appId 로드
|
|
1978
1835
|
const gencowJsonPath = resolve(process.cwd(), "gencow.json");
|
|
1979
|
-
|
|
1836
|
+
let prodAppId = null;
|
|
1837
|
+
if (existsSync(gencowJsonPath)) {
|
|
1980
1838
|
const gencowJson = JSON.parse(readFileSync(gencowJsonPath, "utf8"));
|
|
1981
|
-
appId = gencowJson.appId || gencowJson.appName;
|
|
1839
|
+
if (!appId) appId = gencowJson.appId || gencowJson.appName;
|
|
1840
|
+
prodAppId = gencowJson.prodApp || null;
|
|
1841
|
+
}
|
|
1842
|
+
|
|
1843
|
+
// --prod: prod app 대상
|
|
1844
|
+
const deployTarget = isProd ? (prodAppId || appId) : appId;
|
|
1845
|
+
const envTarget = isProd ? "prod" : "dev";
|
|
1846
|
+
|
|
1847
|
+
if (isProd && !prodAppId) {
|
|
1848
|
+
error("No production app found. Run 'gencow deploy' first to create one.");
|
|
1849
|
+
info(`${DIM}For dev static deploy, omit --prod: gencow static [dir]${RESET}\n`);
|
|
1850
|
+
return;
|
|
1982
1851
|
}
|
|
1983
1852
|
|
|
1984
1853
|
// displayName
|
|
@@ -1991,8 +1860,8 @@ ${BOLD}Examples:${RESET}
|
|
|
1991
1860
|
}
|
|
1992
1861
|
if (!displayName) displayName = basename(process.cwd());
|
|
1993
1862
|
|
|
1994
|
-
return await this._deployStatic(creds,
|
|
1995
|
-
forceDeploy, noBackend, envTarget
|
|
1863
|
+
return await this._deployStatic(creds, deployTarget, displayName, staticDir, gencowJsonPath, {
|
|
1864
|
+
forceDeploy, noBackend: true, envTarget,
|
|
1996
1865
|
});
|
|
1997
1866
|
},
|
|
1998
1867
|
|
|
@@ -2004,10 +1873,7 @@ ${BOLD}Examples:${RESET}
|
|
|
2004
1873
|
let appId = null;
|
|
2005
1874
|
let displayName = null;
|
|
2006
1875
|
let envTarget = "prod"; // v0.1.120: deploy = prod 기본값
|
|
2007
|
-
let staticDir = null; // --static 옵션
|
|
2008
|
-
let isStatic = false;
|
|
2009
1876
|
let forceDeploy = false; // --force: skip dependency audit
|
|
2010
|
-
let noBackend = false; // --no-backend: skip backend auto-deploy in --static mode
|
|
2011
1877
|
let isRollback = false; // --rollback: rollback to previous deploy
|
|
2012
1878
|
|
|
2013
1879
|
// ── subcommand 분기 (logs / status) ───────────────────
|
|
@@ -2079,33 +1945,30 @@ ${BOLD}Examples:${RESET}
|
|
|
2079
1945
|
envTarget = "prod";
|
|
2080
1946
|
}
|
|
2081
1947
|
else if (a === "--force" || a === "-f") forceDeploy = true;
|
|
2082
|
-
else if (a === "--no-backend") noBackend = true;
|
|
2083
1948
|
else if (a === "--rollback") isRollback = true;
|
|
2084
1949
|
else if (a === "--app" || a === "-a") appId = deployArgs[++i];
|
|
2085
1950
|
else if (a === "--static") {
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
}
|
|
1951
|
+
// Deprecated: redirect to gencow static --prod
|
|
1952
|
+
warn(`${YELLOW}--static is deprecated. Use: gencow static --prod${RESET}`);
|
|
1953
|
+
return;
|
|
1954
|
+
}
|
|
1955
|
+
else if (a === "--no-backend") {
|
|
1956
|
+
// Deprecated: silently ignore
|
|
2093
1957
|
}
|
|
2094
1958
|
else if (!a.startsWith("-")) {
|
|
2095
1959
|
// 미인식 subcommand — 에러 출력
|
|
2096
1960
|
error(`Unknown deploy argument: "${a}"`);
|
|
2097
1961
|
log("");
|
|
2098
1962
|
info(`Usage: gencow deploy [options]`);
|
|
2099
|
-
info(` gencow deploy Production deploy (Pro+)`);
|
|
2100
|
-
info(` gencow deploy --static Production static deploy (Pro+)`);
|
|
1963
|
+
info(` gencow deploy Production backend deploy (Pro+)`);
|
|
2101
1964
|
info(` gencow deploy --rollback Rollback to previous version`);
|
|
2102
1965
|
info(` gencow deploy logs View server logs`);
|
|
2103
1966
|
info(` gencow deploy status Check app status`);
|
|
2104
1967
|
info(` gencow deploy --force Skip dependency audit`);
|
|
2105
1968
|
log("");
|
|
2106
|
-
info(`💡
|
|
2107
|
-
info(` gencow
|
|
2108
|
-
info(` gencow static
|
|
1969
|
+
info(`💡 Static files:`);
|
|
1970
|
+
info(` gencow static [dir] Deploy static files (dev)`);
|
|
1971
|
+
info(` gencow static --prod Deploy static files (production)`);
|
|
2109
1972
|
process.exit(1);
|
|
2110
1973
|
}
|
|
2111
1974
|
}
|
|
@@ -2180,12 +2043,6 @@ ${BOLD}Examples:${RESET}
|
|
|
2180
2043
|
return;
|
|
2181
2044
|
}
|
|
2182
2045
|
|
|
2183
|
-
// ── Static Deploy 분기 ────────────────────────────────
|
|
2184
|
-
if (isStatic) {
|
|
2185
|
-
// prod 모드면 prodApp 대상으로 정적 배포
|
|
2186
|
-
const staticTarget = (envTarget === "prod" && prodAppId) ? prodAppId : appId;
|
|
2187
|
-
return await this._deployStatic(creds, staticTarget, displayName, staticDir, gencowJsonPath, { forceDeploy, noBackend, envTarget });
|
|
2188
|
-
}
|
|
2189
2046
|
|
|
2190
2047
|
// ── Prod 앱 자동 생성 + 배포 대상 전환 (Pro+) ──────────
|
|
2191
2048
|
if (envTarget === "prod" && appId) {
|
|
@@ -2299,7 +2156,7 @@ ${BOLD}Examples:${RESET}
|
|
|
2299
2156
|
msg.includes("nothing to migrate") ||
|
|
2300
2157
|
msg.includes("No changes detected")
|
|
2301
2158
|
) {
|
|
2302
|
-
log(`${DIM}
|
|
2159
|
+
log(`${DIM} ✓ Migrations up-to-date — no new schema changes detected${RESET}`);
|
|
2303
2160
|
} else {
|
|
2304
2161
|
warn(`Migration generation warning: ${msg.split("\n")[0] || "unknown"}`);
|
|
2305
2162
|
warn("gencow/migrations/ missing or outdated — platform may skip schema apply.");
|
|
@@ -2822,7 +2679,7 @@ ${BOLD}Examples:${RESET}
|
|
|
2822
2679
|
} catch (e) {
|
|
2823
2680
|
const msg = e.stderr?.toString() || e.message || "";
|
|
2824
2681
|
if (msg.includes("No schema changes") || msg.includes("nothing to migrate") || msg.includes("No changes detected")) {
|
|
2825
|
-
log(`${DIM}
|
|
2682
|
+
log(`${DIM} ✓ Migrations up-to-date — no new schema changes detected${RESET}`);
|
|
2826
2683
|
} else {
|
|
2827
2684
|
warn(`Migration generation failed: ${msg.split("\\n")[0]}`);
|
|
2828
2685
|
info("Will attempt schema push via server.");
|
|
@@ -3978,28 +3835,9 @@ ${BOLD}Examples:${RESET}
|
|
|
3978
3835
|
}
|
|
3979
3836
|
},
|
|
3980
3837
|
|
|
3981
|
-
async mcp(
|
|
3982
|
-
|
|
3983
|
-
|
|
3984
|
-
if (mcpArgs[i] === "--port" || mcpArgs[i] === "-p") port = mcpArgs[++i];
|
|
3985
|
-
}
|
|
3986
|
-
|
|
3987
|
-
const mcpScript = resolve(fileURLToPath(import.meta.url), "..", "gencow-mcp.mjs");
|
|
3988
|
-
if (!existsSync(mcpScript)) {
|
|
3989
|
-
error("gencow-mcp.mjs not found. Ensure the CLI package is properly installed.");
|
|
3990
|
-
process.exit(1);
|
|
3991
|
-
}
|
|
3992
|
-
|
|
3993
|
-
// MCP stdio 서버를 직접 실행 (stdin/stdout 상속)
|
|
3994
|
-
const { execFileSync } = await import("child_process");
|
|
3995
|
-
try {
|
|
3996
|
-
execFileSync("node", [mcpScript], {
|
|
3997
|
-
stdio: "inherit",
|
|
3998
|
-
env: { ...process.env, GENCOW_PORT: port },
|
|
3999
|
-
});
|
|
4000
|
-
} catch {
|
|
4001
|
-
// MCP 서버가 종료될 때 정상적으로 종료
|
|
4002
|
-
}
|
|
3838
|
+
async mcp() {
|
|
3839
|
+
info(`MCP server is ${BOLD}coming soon${RESET}.`);
|
|
3840
|
+
info(`${DIM}MCP integration requires local dev server (coming soon).${RESET}\n`);
|
|
4003
3841
|
},
|
|
4004
3842
|
|
|
4005
3843
|
|
|
@@ -4034,8 +3872,16 @@ ${BOLD}Examples:${RESET}
|
|
|
4034
3872
|
let runtimeRoot;
|
|
4035
3873
|
try { runtimeRoot = findServerRoot(); } catch { runtimeRoot = process.cwd(); }
|
|
4036
3874
|
const extractTsPath = resolve(runtimeRoot, ".gencow-extract.ts");
|
|
3875
|
+
|
|
3876
|
+
// @gencow/core — 번들된 core 절대 경로 우선, 없으면 bare specifier
|
|
3877
|
+
// generateApiTs()와 동일 해석 전략: 글로벌 CLI에서도 resolve 보장
|
|
3878
|
+
const bundledCorePath = resolve(runtimeRoot, "../core/index.js");
|
|
3879
|
+
const coreImport = existsSync(bundledCorePath)
|
|
3880
|
+
? bundledCorePath.replace(/\\/g, "/")
|
|
3881
|
+
: "@gencow/core";
|
|
3882
|
+
|
|
4037
3883
|
const script = `
|
|
4038
|
-
import { getRegisteredQueries, getRegisteredMutations } from "
|
|
3884
|
+
import { getRegisteredQueries, getRegisteredMutations } from "${coreImport}";
|
|
4039
3885
|
import "${absoluteFunctions}/index.ts";
|
|
4040
3886
|
console.log("GENCOW_API_JSON=" + JSON.stringify({
|
|
4041
3887
|
queries: getRegisteredQueries(),
|
|
@@ -4044,13 +3890,22 @@ console.log("GENCOW_API_JSON=" + JSON.stringify({
|
|
|
4044
3890
|
process.exit(0);
|
|
4045
3891
|
`;
|
|
4046
3892
|
info("Extracting function list...");
|
|
3893
|
+
// NODE_PATH: 사용자 프로젝트 node_modules + CLI node_modules 포함
|
|
3894
|
+
// generateApiTs()와 동일 — 글로벌 설치 시 사용자 의존성 해석 보장
|
|
3895
|
+
const cwdNodeModules = resolve(process.cwd(), "node_modules");
|
|
3896
|
+
const cliNodeModules = resolve(__dirname, "..", "node_modules");
|
|
3897
|
+
const extractEnv = {
|
|
3898
|
+
...process.env,
|
|
3899
|
+
NODE_PATH: [cwdNodeModules, cliNodeModules, process.env.NODE_PATH || ""].filter(Boolean).join(":"),
|
|
3900
|
+
};
|
|
4047
3901
|
try {
|
|
4048
3902
|
writeFileSync(extractTsPath, script);
|
|
4049
3903
|
let outStr;
|
|
4050
3904
|
try {
|
|
4051
3905
|
outStr = execSync(`bun ${extractTsPath}`, {
|
|
4052
3906
|
cwd: runtimeRoot,
|
|
4053
|
-
stdio: ["pipe", "pipe", "pipe"]
|
|
3907
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
3908
|
+
env: extractEnv,
|
|
4054
3909
|
}).toString();
|
|
4055
3910
|
} catch (execErr) {
|
|
4056
3911
|
const stderr = execErr.stderr?.toString() || "";
|
|
@@ -4941,7 +4796,8 @@ ${BOLD}${CYAN}🚀 Gencow Cloud Dev${RESET}
|
|
|
4941
4796
|
log(` ${GREEN}Prompts${RESET} Reusable prompt templates`);
|
|
4942
4797
|
log(` ${GREEN}Parsers${RESET} PDF/HTML/CSV file parsing`);
|
|
4943
4798
|
log(` ${GREEN}Memory${RESET} Agent memory ${DIM}(episodic/semantic/procedural)${RESET}`);
|
|
4944
|
-
log(
|
|
4799
|
+
log(`\n${BOLD}Coming soon:${RESET}`);
|
|
4800
|
+
log(` ${DIM}Analytics${RESET} LLM call tracking`);
|
|
4945
4801
|
log(`\n${BOLD}Examples:${RESET}`);
|
|
4946
4802
|
log(` ${DIM}gencow add AI${RESET}`);
|
|
4947
4803
|
log(` ${DIM}gencow add AI RAG Reranker${RESET}`);
|
|
@@ -4988,10 +4844,11 @@ ${BOLD}${CYAN}🚀 Gencow Cloud Dev${RESET}
|
|
|
4988
4844
|
env: {},
|
|
4989
4845
|
requires: ["ai"],
|
|
4990
4846
|
guide: [
|
|
4991
|
-
`gencow/rag.ts
|
|
4992
|
-
`
|
|
4993
|
-
`
|
|
4994
|
-
`
|
|
4847
|
+
`gencow/rag.ts — rag.ingest(), rag.search(), rag.ask()`,
|
|
4848
|
+
`Shared KB: await rag.ingest(ctx, "manual.pdf", text)`,
|
|
4849
|
+
`Personal: await rag.ingest(ctx, "notes.pdf", text, { userId: user.id })`,
|
|
4850
|
+
`Search: const results = await rag.search(ctx, "query", { userId: user.id })`,
|
|
4851
|
+
`Import schema-rag.ts in your schema.ts to create DB tables`,
|
|
4995
4852
|
],
|
|
4996
4853
|
},
|
|
4997
4854
|
memory: {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gencow",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.123",
|
|
4
4
|
"description": "Gencow — AI Backend Engine",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -21,13 +21,13 @@
|
|
|
21
21
|
},
|
|
22
22
|
"dependencies": {
|
|
23
23
|
"@modelcontextprotocol/sdk": "^1.27.1",
|
|
24
|
+
"esbuild": "^0.27.3",
|
|
24
25
|
"open": "^10.1.0",
|
|
25
26
|
"tar": "^7",
|
|
26
27
|
"ws": "^8.19.0",
|
|
27
28
|
"zod": "^4.3.6"
|
|
28
29
|
},
|
|
29
30
|
"devDependencies": {
|
|
30
|
-
"@types/node": "^25"
|
|
31
|
-
"esbuild": "^0.27.3"
|
|
31
|
+
"@types/node": "^25"
|
|
32
32
|
}
|
|
33
33
|
}
|
package/server/index.js
CHANGED
|
@@ -62096,7 +62096,16 @@ function createAdminRoutes(db, rawSql, driver, getCtx, storage, functionsPath) {
|
|
|
62096
62096
|
async function runSeedFile(functionsPath, getCtx) {
|
|
62097
62097
|
const seedTs = resolve3(functionsPath, "seed.ts");
|
|
62098
62098
|
const seedJs = resolve3(functionsPath, "seed.js");
|
|
62099
|
-
|
|
62099
|
+
let seedFile = existsSync2(seedTs) ? seedTs : existsSync2(seedJs) ? seedJs : null;
|
|
62100
|
+
if (!seedFile && functionsPath.endsWith("gencow-bc")) {
|
|
62101
|
+
const originalDir = resolve3(functionsPath, "..", "gencow");
|
|
62102
|
+
const origTs = resolve3(originalDir, "seed.ts");
|
|
62103
|
+
const origJs = resolve3(originalDir, "seed.js");
|
|
62104
|
+
seedFile = existsSync2(origTs) ? origTs : existsSync2(origJs) ? origJs : null;
|
|
62105
|
+
if (seedFile) {
|
|
62106
|
+
console.log(`[seed] seed.ts not in bytecode dir \u2014 using original: ${seedFile}`);
|
|
62107
|
+
}
|
|
62108
|
+
}
|
|
62100
62109
|
if (!seedFile) {
|
|
62101
62110
|
console.log("[seed] gencow/seed.ts not found \u2014 skipping");
|
|
62102
62111
|
return false;
|