sonamu 0.7.53 → 0.8.0
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/api/config.d.ts +9 -1
- package/dist/api/config.d.ts.map +1 -1
- package/dist/api/config.js +1 -1
- package/dist/api/sonamu.d.ts +21 -1
- package/dist/api/sonamu.d.ts.map +1 -1
- package/dist/api/sonamu.js +159 -65
- package/dist/auth/plugins/entity-definitions/anonymous.d.ts +10 -0
- package/dist/auth/plugins/entity-definitions/anonymous.d.ts.map +1 -0
- package/dist/auth/plugins/entity-definitions/anonymous.js +23 -0
- package/dist/auth/plugins/entity-definitions/api-key.d.ts +9 -0
- package/dist/auth/plugins/entity-definitions/api-key.d.ts.map +1 -0
- package/dist/auth/plugins/entity-definitions/api-key.js +199 -0
- package/dist/auth/plugins/entity-definitions/index.d.ts +6 -0
- package/dist/auth/plugins/entity-definitions/index.d.ts.map +1 -1
- package/dist/auth/plugins/entity-definitions/index.js +20 -2
- package/dist/auth/plugins/entity-definitions/jwt.d.ts +9 -0
- package/dist/auth/plugins/entity-definitions/jwt.d.ts.map +1 -0
- package/dist/auth/plugins/entity-definitions/jwt.js +67 -0
- package/dist/auth/plugins/entity-definitions/organization.d.ts +9 -0
- package/dist/auth/plugins/entity-definitions/organization.d.ts.map +1 -0
- package/dist/auth/plugins/entity-definitions/organization.js +424 -0
- package/dist/auth/plugins/entity-definitions/passkey.d.ts +10 -0
- package/dist/auth/plugins/entity-definitions/passkey.d.ts.map +1 -0
- package/dist/auth/plugins/entity-definitions/passkey.js +129 -0
- package/dist/auth/plugins/entity-definitions/sso.d.ts +10 -0
- package/dist/auth/plugins/entity-definitions/sso.d.ts.map +1 -0
- package/dist/auth/plugins/entity-definitions/sso.js +110 -0
- package/dist/auth/plugins/entity-definitions/types.d.ts +1 -1
- package/dist/auth/plugins/entity-definitions/types.d.ts.map +1 -1
- package/dist/auth/plugins/entity-definitions/types.js +1 -1
- package/dist/auth/plugins/wrappers/admin.d.ts.map +1 -1
- package/dist/auth/plugins/wrappers/admin.js +2 -4
- package/dist/auth/plugins/wrappers/anonymous.d.ts +18 -0
- package/dist/auth/plugins/wrappers/anonymous.d.ts.map +1 -0
- package/dist/auth/plugins/wrappers/anonymous.js +26 -0
- package/dist/auth/plugins/wrappers/api-key.d.ts +18 -0
- package/dist/auth/plugins/wrappers/api-key.d.ts.map +1 -0
- package/dist/auth/plugins/wrappers/api-key.js +38 -0
- package/dist/auth/plugins/wrappers/index.d.ts +6 -0
- package/dist/auth/plugins/wrappers/index.d.ts.map +1 -1
- package/dist/auth/plugins/wrappers/index.js +7 -1
- package/dist/auth/plugins/wrappers/jwt.d.ts +18 -0
- package/dist/auth/plugins/wrappers/jwt.d.ts.map +1 -0
- package/dist/auth/plugins/wrappers/jwt.js +30 -0
- package/dist/auth/plugins/wrappers/organization.d.ts +18 -0
- package/dist/auth/plugins/wrappers/organization.d.ts.map +1 -0
- package/dist/auth/plugins/wrappers/organization.js +67 -0
- package/dist/auth/plugins/wrappers/passkey.d.ts +18 -0
- package/dist/auth/plugins/wrappers/passkey.d.ts.map +1 -0
- package/dist/auth/plugins/wrappers/passkey.js +32 -0
- package/dist/auth/plugins/wrappers/phone-number.d.ts.map +1 -1
- package/dist/auth/plugins/wrappers/phone-number.js +2 -4
- package/dist/auth/plugins/wrappers/sso.d.ts +853 -0
- package/dist/auth/plugins/wrappers/sso.d.ts.map +1 -0
- package/dist/auth/plugins/wrappers/sso.js +36 -0
- package/dist/auth/plugins/wrappers/two-factor.d.ts.map +1 -1
- package/dist/auth/plugins/wrappers/two-factor.js +2 -4
- package/dist/auth/plugins/wrappers/username.d.ts.map +1 -1
- package/dist/auth/plugins/wrappers/username.js +2 -4
- package/dist/bin/build-config.d.ts +2 -2
- package/dist/bin/build-config.js +6 -7
- package/dist/bin/cli.js +417 -32
- package/dist/bin/fixture.d.ts +27 -0
- package/dist/bin/fixture.d.ts.map +1 -0
- package/dist/bin/fixture.js +245 -0
- package/dist/cache/decorator.d.ts +4 -3
- package/dist/cache/decorator.d.ts.map +1 -1
- package/dist/cache/decorator.js +5 -4
- package/dist/cone/cone-generator.d.ts +33 -0
- package/dist/cone/cone-generator.d.ts.map +1 -0
- package/dist/cone/cone-generator.js +286 -0
- package/dist/database/_batch_update.d.ts.map +1 -1
- package/dist/database/_batch_update.js +16 -2
- package/dist/database/puri-subset.test-d.js +1 -1
- package/dist/database/puri-subset.types.d.ts +1 -1
- package/dist/database/puri-subset.types.d.ts.map +1 -1
- package/dist/database/puri-subset.types.js +1 -1
- package/dist/database/puri.d.ts +4 -0
- package/dist/database/puri.d.ts.map +1 -1
- package/dist/database/puri.js +20 -2
- package/dist/database/upsert-builder.d.ts.map +1 -1
- package/dist/database/upsert-builder.js +19 -3
- package/dist/dict/en.d.ts +15 -0
- package/dist/dict/en.d.ts.map +1 -1
- package/dist/dict/en.js +2 -1
- package/dist/dict/ko.d.ts +15 -0
- package/dist/dict/ko.d.ts.map +1 -1
- package/dist/dict/ko.js +2 -1
- package/dist/dict/rc-keys.d.ts +28 -0
- package/dist/dict/rc-keys.d.ts.map +1 -1
- package/dist/dict/rc-keys.js +31 -1
- package/dist/dict/sd.d.ts.map +1 -1
- package/dist/dict/sd.js +20 -4
- package/dist/entity/entity-manager.d.ts +298 -2
- package/dist/entity/entity-manager.d.ts.map +1 -1
- package/dist/entity/entity-manager.js +4 -1
- package/dist/entity/entity-template-cone.d.ts +14 -0
- package/dist/entity/entity-template-cone.d.ts.map +1 -0
- package/dist/entity/entity-template-cone.js +222 -0
- package/dist/entity/entity.d.ts +47 -2
- package/dist/entity/entity.d.ts.map +1 -1
- package/dist/entity/entity.js +161 -14
- package/dist/ssr/renderer.js +3 -3
- package/dist/syncer/api-parser.js +12 -1
- package/dist/syncer/checksum.d.ts +0 -14
- package/dist/syncer/checksum.d.ts.map +1 -1
- package/dist/syncer/checksum.js +1 -23
- package/dist/syncer/syncer-actions.d.ts.map +1 -1
- package/dist/syncer/syncer-actions.js +8 -2
- package/dist/syncer/syncer.d.ts +1 -1
- package/dist/syncer/syncer.d.ts.map +1 -1
- package/dist/syncer/syncer.js +17 -10
- package/dist/tasks/workflow-manager.d.ts +13 -1
- package/dist/tasks/workflow-manager.d.ts.map +1 -1
- package/dist/tasks/workflow-manager.js +18 -1
- package/dist/template/entity-converter.js +4 -4
- package/dist/template/helpers.d.ts +10 -0
- package/dist/template/helpers.d.ts.map +1 -1
- package/dist/template/helpers.js +48 -1
- package/dist/template/implementations/entry-server.template.d.ts +1 -1
- package/dist/template/implementations/entry-server.template.js +7 -2
- package/dist/template/implementations/generated.template.d.ts.map +1 -1
- package/dist/template/implementations/generated.template.js +5 -1
- package/dist/template/implementations/generated_http.template.d.ts +1 -0
- package/dist/template/implementations/generated_http.template.d.ts.map +1 -1
- package/dist/template/implementations/generated_http.template.js +6 -2
- package/dist/template/implementations/generated_sso.template.d.ts.map +1 -1
- package/dist/template/implementations/generated_sso.template.js +29 -8
- package/dist/template/implementations/queries.template.d.ts.map +1 -1
- package/dist/template/implementations/queries.template.js +9 -1
- package/dist/template/implementations/sd.template.d.ts +1 -1
- package/dist/template/implementations/sd.template.d.ts.map +1 -1
- package/dist/template/implementations/sd.template.js +28 -4
- package/dist/template/implementations/services.template.d.ts.map +1 -1
- package/dist/template/implementations/services.template.js +12 -12
- package/dist/template/implementations/view_form.template.d.ts +11 -7
- package/dist/template/implementations/view_form.template.d.ts.map +1 -1
- package/dist/template/implementations/view_form.template.js +97 -87
- package/dist/template/implementations/view_list.template.d.ts +3 -3
- package/dist/template/implementations/view_list.template.d.ts.map +1 -1
- package/dist/template/implementations/view_list.template.js +115 -109
- package/dist/template/implementations/view_search_input.template.d.ts.map +1 -1
- package/dist/template/implementations/view_search_input.template.js +18 -14
- package/dist/template/zod-converter.d.ts.map +1 -1
- package/dist/template/zod-converter.js +95 -7
- package/dist/testing/_relation-graph.js +1 -1
- package/dist/testing/data-explorer.d.ts +61 -0
- package/dist/testing/data-explorer.d.ts.map +1 -0
- package/dist/testing/data-explorer.js +274 -0
- package/dist/testing/faker-mappings.d.ts +20 -0
- package/dist/testing/faker-mappings.d.ts.map +1 -0
- package/dist/testing/faker-mappings.js +421 -0
- package/dist/testing/fixture-generator.d.ts +161 -0
- package/dist/testing/fixture-generator.d.ts.map +1 -0
- package/dist/testing/fixture-generator.js +954 -0
- package/dist/testing/fixture-manager.d.ts +6 -1
- package/dist/testing/fixture-manager.d.ts.map +1 -1
- package/dist/testing/fixture-manager.js +72 -4
- package/dist/testing/index.d.ts +3 -0
- package/dist/testing/index.d.ts.map +1 -1
- package/dist/testing/index.js +4 -1
- package/dist/types/types.d.ts +1520 -26
- package/dist/types/types.d.ts.map +1 -1
- package/dist/types/types.js +136 -22
- package/dist/ui/ai-client.d.ts.map +1 -1
- package/dist/ui/ai-client.js +9 -4
- package/dist/ui/api.d.ts.map +1 -1
- package/dist/ui/api.js +303 -24
- package/dist/ui-web/assets/index-CsUr-_pV.js +254 -0
- package/dist/ui-web/assets/index-T42zzs1K.css +1 -0
- package/dist/ui-web/index.html +2 -2
- package/dist/utils/fs-utils.d.ts +2 -1
- package/dist/utils/fs-utils.d.ts.map +1 -1
- package/dist/utils/fs-utils.js +14 -3
- package/package.json +19 -11
- package/src/api/config.ts +12 -1
- package/src/api/sonamu.ts +179 -65
- package/src/auth/plugins/entity-definitions/anonymous.ts +17 -0
- package/src/auth/plugins/entity-definitions/api-key.ts +93 -0
- package/src/auth/plugins/entity-definitions/index.ts +18 -0
- package/src/auth/plugins/entity-definitions/jwt.ts +35 -0
- package/src/auth/plugins/entity-definitions/organization.ts +215 -0
- package/src/auth/plugins/entity-definitions/passkey.ts +64 -0
- package/src/auth/plugins/entity-definitions/sso.ts +62 -0
- package/src/auth/plugins/entity-definitions/types.ts +11 -1
- package/src/auth/plugins/wrappers/admin.ts +1 -3
- package/src/auth/plugins/wrappers/anonymous.ts +30 -0
- package/src/auth/plugins/wrappers/api-key.ts +42 -0
- package/src/auth/plugins/wrappers/index.ts +6 -0
- package/src/auth/plugins/wrappers/jwt.ts +34 -0
- package/src/auth/plugins/wrappers/organization.ts +73 -0
- package/src/auth/plugins/wrappers/passkey.ts +36 -0
- package/src/auth/plugins/wrappers/phone-number.ts +1 -3
- package/src/auth/plugins/wrappers/sso.ts +40 -0
- package/src/auth/plugins/wrappers/two-factor.ts +1 -3
- package/src/auth/plugins/wrappers/username.ts +1 -3
- package/src/bin/build-config.ts +6 -6
- package/src/bin/cli.ts +452 -31
- package/src/bin/fixture.ts +302 -0
- package/src/cache/decorator.ts +4 -3
- package/src/cone/cone-generator.ts +363 -0
- package/src/database/_batch_update.ts +11 -0
- package/src/database/puri-subset.test-d.ts +13 -13
- package/src/database/puri-subset.types.ts +1 -1
- package/src/database/puri.ts +43 -1
- package/src/database/upsert-builder.ts +16 -2
- package/src/dict/en.ts +1 -0
- package/src/dict/ko.ts +1 -0
- package/src/dict/rc-keys.ts +32 -0
- package/src/dict/sd.ts +23 -3
- package/src/entity/entity-manager.ts +4 -0
- package/src/entity/entity-template-cone.ts +298 -0
- package/src/entity/entity.ts +189 -13
- package/src/shared/app.shared.ts.txt +5 -0
- package/src/shared/web.shared.ts.txt +9 -5
- package/src/skills/project/README.md +21 -0
- package/src/skills/project/architecture.md +373 -0
- package/src/skills/project/business-logic.md +270 -0
- package/src/skills/project/requirements.md +160 -0
- package/src/skills/sonamu/SKILL.md +168 -3
- package/src/skills/sonamu/api.md +102 -0
- package/src/skills/sonamu/database.md +220 -1
- package/src/skills/sonamu/entity-relations.md +89 -1
- package/src/skills/sonamu/fixture-cli.md +501 -0
- package/src/skills/sonamu/frontend.md +214 -0
- package/src/skills/sonamu/i18n.md +95 -0
- package/src/skills/sonamu/model.md +153 -0
- package/src/skills/sonamu/project-init.md +178 -8
- package/src/skills/sonamu/scaffolding.md +112 -0
- package/src/skills/sonamu/subset.md +9 -3
- package/src/skills/sonamu/testing.md +287 -2
- package/src/skills/sonamu/workflow.md +70 -5
- package/src/ssr/renderer.ts +2 -2
- package/src/syncer/api-parser.ts +12 -0
- package/src/syncer/checksum.ts +0 -38
- package/src/syncer/syncer-actions.ts +7 -1
- package/src/syncer/syncer.ts +16 -5
- package/src/tasks/workflow-manager.ts +29 -8
- package/src/template/entity-converter.ts +3 -3
- package/src/template/helpers.ts +49 -0
- package/src/template/implementations/entry-server.template.ts +1 -1
- package/src/template/implementations/generated.template.ts +4 -0
- package/src/template/implementations/generated_http.template.ts +1 -0
- package/src/template/implementations/generated_sso.template.ts +40 -11
- package/src/template/implementations/queries.template.ts +8 -0
- package/src/template/implementations/sd.template.ts +22 -3
- package/src/template/implementations/services.template.ts +11 -10
- package/src/template/implementations/view_form.template.ts +111 -101
- package/src/template/implementations/view_list.template.ts +120 -119
- package/src/template/implementations/view_search_input.template.ts +17 -13
- package/src/template/zod-converter.ts +103 -6
- package/src/testing/_relation-graph.ts +1 -1
- package/src/testing/data-explorer.ts +427 -0
- package/src/testing/faker-mappings.ts +434 -0
- package/src/testing/fixture-generator.ts +1166 -0
- package/src/testing/fixture-manager.ts +91 -6
- package/src/testing/index.ts +3 -0
- package/src/types/types.ts +222 -26
- package/src/ui/ai-client.ts +9 -1
- package/src/ui/api.ts +429 -23
- package/src/utils/fs-utils.ts +14 -1
- package/dist/template/implementations/view_enums_select.template.d.ts +0 -17
- package/dist/template/implementations/view_enums_select.template.d.ts.map +0 -1
- package/dist/template/implementations/view_enums_select.template.js +0 -62
- package/dist/template/implementations/view_id_async_select.template.d.ts +0 -17
- package/dist/template/implementations/view_id_async_select.template.d.ts.map +0 -1
- package/dist/template/implementations/view_id_async_select.template.js +0 -125
- package/dist/ui-web/assets/index-Bd_2AkLb.css +0 -1
- package/dist/ui-web/assets/index-BpSbhQWo.js +0 -225
- package/src/template/implementations/view_enums_select.template.ts +0 -65
- package/src/template/implementations/view_id_async_select.template.ts +0 -139
package/src/bin/build-config.ts
CHANGED
|
@@ -9,7 +9,7 @@ export type BuildArtifact<BuildCommandArgs = {}> = {
|
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* API 프로젝트 빌드 산출물에 대한 규칙들.
|
|
12
|
-
* cli.ts의
|
|
12
|
+
* cli.ts의 build_api 함수가 이것을 보고 그대로 실행합니다.
|
|
13
13
|
*/
|
|
14
14
|
export const API_ARTIFACTS: BuildArtifact<{ configFilePath: string }>[] = [
|
|
15
15
|
{
|
|
@@ -24,24 +24,24 @@ export const API_ARTIFACTS: BuildArtifact<{ configFilePath: string }>[] = [
|
|
|
24
24
|
|
|
25
25
|
/**
|
|
26
26
|
* 웹 프로젝트 빌드 산출물에 대한 규칙들.
|
|
27
|
-
* cli.ts의
|
|
27
|
+
* cli.ts의 build_web 함수가 이것을 보고 그대로 실행합니다.
|
|
28
28
|
*/
|
|
29
29
|
export const WEB_ARTIFACTS: BuildArtifact[] = [
|
|
30
30
|
{
|
|
31
31
|
name: "Web Client",
|
|
32
32
|
description: "Web 프로젝트 클라이언트 빌드 산출물",
|
|
33
33
|
projectPath: "web",
|
|
34
|
-
preBuildCommand: () => "rm -rf dist/client
|
|
34
|
+
preBuildCommand: () => "rm -rf dist/client",
|
|
35
35
|
buildCommand: () => "tsc --noEmit && vite build --outDir dist/client",
|
|
36
|
-
postBuildCommand: () => "mkdir -p ../api/public/web && cp -r dist/client/* ../api/public/web",
|
|
37
36
|
},
|
|
38
37
|
{
|
|
39
38
|
name: "Web Server",
|
|
40
39
|
description: "Web 프로젝트 서버 빌드 산출물",
|
|
41
40
|
projectPath: "web",
|
|
42
|
-
preBuildCommand: () => "rm -rf dist/server",
|
|
41
|
+
preBuildCommand: () => "rm -rf dist/server",
|
|
43
42
|
buildCommand: () =>
|
|
44
43
|
"tsc --noEmit && vite build --ssr src/entry-server.generated.tsx --outDir dist/server",
|
|
45
|
-
postBuildCommand: () =>
|
|
44
|
+
postBuildCommand: () =>
|
|
45
|
+
"rm -rf ../api/web-dist && mkdir -p ../api/web-dist && cp -r dist/* ../api/web-dist",
|
|
46
46
|
},
|
|
47
47
|
];
|
package/src/bin/cli.ts
CHANGED
|
@@ -33,9 +33,45 @@ import {
|
|
|
33
33
|
import { exists } from "../utils/fs-utils";
|
|
34
34
|
import { findApiRootPath, findAppRootPath } from "../utils/utils";
|
|
35
35
|
import { API_ARTIFACTS, type BuildArtifact, WEB_ARTIFACTS } from "./build-config";
|
|
36
|
+
import { fixtureExploreCommand, fixtureFetchCommand, fixtureGenCommand } from "./fixture";
|
|
36
37
|
|
|
37
38
|
let migrator: Migrator;
|
|
38
39
|
|
|
40
|
+
/**
|
|
41
|
+
* CLI 옵션을 파싱하는 헬퍼 함수
|
|
42
|
+
*/
|
|
43
|
+
function parseCliOptions(argv: string[] = process.argv): {
|
|
44
|
+
flags: Set<string>; // --regenerate, --ai, --no-cones 등
|
|
45
|
+
options: Record<string, string>; // --locale ko 등
|
|
46
|
+
} {
|
|
47
|
+
const flags = new Set<string>();
|
|
48
|
+
const options: Record<string, string> = {};
|
|
49
|
+
|
|
50
|
+
for (let i = 0; i < argv.length; i++) {
|
|
51
|
+
const arg = argv[i];
|
|
52
|
+
if (!arg.startsWith("--")) continue;
|
|
53
|
+
|
|
54
|
+
// --option=value 형식
|
|
55
|
+
if (arg.includes("=")) {
|
|
56
|
+
const [key, value] = arg.slice(2).split("=");
|
|
57
|
+
options[key] = value;
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// --option value 형식인지 확인
|
|
62
|
+
const nextArg = argv[i + 1];
|
|
63
|
+
if (nextArg && !nextArg.startsWith("--") && !nextArg.startsWith("-")) {
|
|
64
|
+
options[arg.slice(2)] = nextArg;
|
|
65
|
+
i++; // 다음 arg는 값이므로 스킵
|
|
66
|
+
} else {
|
|
67
|
+
// --flag 형식
|
|
68
|
+
flags.add(arg.slice(2));
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return { flags, options };
|
|
73
|
+
}
|
|
74
|
+
|
|
39
75
|
async function bootstrap() {
|
|
40
76
|
const notToInit = ["dev", "build", "start", "skills"].includes(process.argv[2] ?? "");
|
|
41
77
|
if (!notToInit) {
|
|
@@ -45,23 +81,43 @@ async function bootstrap() {
|
|
|
45
81
|
try {
|
|
46
82
|
// tsicli는 정확한 명령어 매칭만 지원하므로, --로 시작하는 옵션과 그 값을 필터링합니다.
|
|
47
83
|
// 옵션 파싱은 각 runner 함수에서 원본 process.argv를 사용하여 수행합니다.
|
|
84
|
+
// "--"(bare double dash)는 passthrough 구분자이므로, 그 뒤의 모든 인자도 제외합니다.
|
|
48
85
|
const filteredArgv: string[] = [];
|
|
49
86
|
let skipNext = false;
|
|
50
|
-
|
|
87
|
+
let afterDoubleDash = false;
|
|
88
|
+
for (let i = 0; i < process.argv.length; i++) {
|
|
89
|
+
const arg = process.argv[i];
|
|
90
|
+
if (arg === "--") {
|
|
91
|
+
afterDoubleDash = true;
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
if (afterDoubleDash) continue;
|
|
51
95
|
if (skipNext) {
|
|
52
96
|
skipNext = false;
|
|
53
97
|
continue;
|
|
54
98
|
}
|
|
55
99
|
if (arg.startsWith("--")) {
|
|
56
100
|
// --option=value 형식은 이 arg만 스킵
|
|
57
|
-
|
|
58
|
-
|
|
101
|
+
if (arg.includes("=")) {
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
// --option value 형식인지 확인: 다음 arg가 --로 시작하지 않으면 값이 있는 것
|
|
105
|
+
const nextArg = process.argv[i + 1];
|
|
106
|
+
if (nextArg && !nextArg.startsWith("--") && !nextArg.startsWith("-")) {
|
|
59
107
|
skipNext = true;
|
|
60
108
|
}
|
|
61
109
|
continue;
|
|
62
110
|
}
|
|
63
111
|
filteredArgv.push(arg);
|
|
64
112
|
}
|
|
113
|
+
|
|
114
|
+
// build/dev 명령어가 서브커맨드 없이 호출될 때 "all"을 기본값으로 추가합니다.
|
|
115
|
+
// 예: `sonamu build` → `sonamu build all`, `sonamu dev` → `sonamu dev all`
|
|
116
|
+
const cmd = filteredArgv[2];
|
|
117
|
+
if ((cmd === "build" || cmd === "dev") && filteredArgv.length === 3) {
|
|
118
|
+
filteredArgv.push("all");
|
|
119
|
+
}
|
|
120
|
+
|
|
65
121
|
await tsicli(filteredArgv, {
|
|
66
122
|
types: {
|
|
67
123
|
"#entityId": {
|
|
@@ -91,6 +147,9 @@ async function bootstrap() {
|
|
|
91
147
|
["fixture", "init"],
|
|
92
148
|
["fixture", "import", "#entityId", "#recordIds"],
|
|
93
149
|
["fixture", "sync"],
|
|
150
|
+
["fixture", "gen"],
|
|
151
|
+
["fixture", "fetch"],
|
|
152
|
+
["fixture", "explore"],
|
|
94
153
|
["migrate", "run"],
|
|
95
154
|
["migrate", "apply", "#targets"],
|
|
96
155
|
["migrate", "status"],
|
|
@@ -100,9 +159,14 @@ async function bootstrap() {
|
|
|
100
159
|
["scaffold", "model_test", "#entityId"],
|
|
101
160
|
["scaffold", "view_list", "#entityId"],
|
|
102
161
|
["scaffold", "view_form", "#entityId"],
|
|
162
|
+
["cone", "gen", "#entityId"],
|
|
103
163
|
["sync"],
|
|
104
|
-
["
|
|
105
|
-
["build"],
|
|
164
|
+
["build", "all"],
|
|
165
|
+
["build", "api"],
|
|
166
|
+
["build", "web"],
|
|
167
|
+
["dev", "all"],
|
|
168
|
+
["dev", "api"],
|
|
169
|
+
["dev", "web"],
|
|
106
170
|
["start"],
|
|
107
171
|
["skills", "sync"],
|
|
108
172
|
["skills", "create", "#name"],
|
|
@@ -115,15 +179,23 @@ async function bootstrap() {
|
|
|
115
179
|
fixture_init,
|
|
116
180
|
fixture_import,
|
|
117
181
|
fixture_sync,
|
|
182
|
+
fixture_gen,
|
|
183
|
+
fixture_fetch,
|
|
184
|
+
fixture_explore,
|
|
118
185
|
stub_practice,
|
|
119
186
|
stub_entity,
|
|
120
187
|
scaffold_model,
|
|
121
188
|
scaffold_model_test,
|
|
122
189
|
// scaffold_view_list,
|
|
123
190
|
// scaffold_view_form,
|
|
191
|
+
cone_gen,
|
|
124
192
|
sync,
|
|
125
|
-
|
|
126
|
-
|
|
193
|
+
build_all,
|
|
194
|
+
build_api,
|
|
195
|
+
build_web,
|
|
196
|
+
dev_all,
|
|
197
|
+
dev_api,
|
|
198
|
+
dev_web,
|
|
127
199
|
start,
|
|
128
200
|
skills_sync,
|
|
129
201
|
skills_create,
|
|
@@ -148,8 +220,8 @@ async function sync() {
|
|
|
148
220
|
}
|
|
149
221
|
|
|
150
222
|
/**
|
|
151
|
-
*
|
|
152
|
-
*
|
|
223
|
+
* API 개발 서버를 실행하는 공통 로직입니다.
|
|
224
|
+
* dev_all과 dev_api에서 공유합니다.
|
|
153
225
|
*
|
|
154
226
|
* TypeScript를 바로 실행할 수 있도록 @sonamu-kit/ts-loader를,
|
|
155
227
|
* HMR을 지원하기 위해 @sonamu-kit/hmr-hook을 import하며,
|
|
@@ -158,15 +230,11 @@ async function sync() {
|
|
|
158
230
|
* 이때 @sonamu-kit/ts-loader와 @sonamu-kit/hmr-hook는 sonamu가 자체적으로 가지고 있는 dependency입니다.
|
|
159
231
|
* 또한 실행에 사용하는 @sonamu-kit/hmr-runner도 마찬가지로 sonamu가 자체적으로 가지고 있는 dependency입니다.
|
|
160
232
|
* 따라서 사용자 프로젝트에서는 이 세 패키지를 직접 설치할 필요가 없습니다.
|
|
161
|
-
*
|
|
162
|
-
* Sonamu.init 없이 호출될 것을 상정하여 구현되었습니다.
|
|
163
233
|
*/
|
|
164
|
-
|
|
234
|
+
function spawnApiDevServer(options?: { extraEnv?: Record<string, string> }) {
|
|
165
235
|
const apiRoot = findApiRootPath();
|
|
166
236
|
const entryPoint = "src/index.ts";
|
|
167
237
|
|
|
168
|
-
console.log(chalk.yellow.bold("🚀 Starting Sonamu dev server...\n"));
|
|
169
|
-
|
|
170
238
|
// 이 sonamu 패키지가 dependencies로 가지고 있는 @sonamu-kit/hmr-runner의 bin/run.js를 사용합니다.
|
|
171
239
|
// 이 경로(/bin/run.js)는 @sonamu-kit/hmr-runner의 package.json의 bin 필드에 명시되어 있는 그것과 같습니다.
|
|
172
240
|
const hotRunnerBinPath = createRequire(import.meta.url).resolve(
|
|
@@ -196,6 +264,7 @@ async function dev() {
|
|
|
196
264
|
NODE_ENV: "development",
|
|
197
265
|
HOT: "yes", // 얘가 있어야 HMR이 활성화됩니다.
|
|
198
266
|
API_ROOT_PATH: apiRoot, // 이 경로가 hmr-hook의 루트 디렉토리가 됩니다.
|
|
267
|
+
...options?.extraEnv,
|
|
199
268
|
},
|
|
200
269
|
},
|
|
201
270
|
);
|
|
@@ -212,34 +281,88 @@ async function dev() {
|
|
|
212
281
|
|
|
213
282
|
serverProcess.on("exit", (code) => {
|
|
214
283
|
if (code !== 0) {
|
|
215
|
-
console.error(chalk.red(
|
|
284
|
+
console.error(chalk.red(`Server exited with code ${code}`));
|
|
216
285
|
process.exit(code || 1);
|
|
217
286
|
}
|
|
218
287
|
});
|
|
219
288
|
}
|
|
220
289
|
|
|
221
290
|
/**
|
|
222
|
-
* pnpm
|
|
223
|
-
*
|
|
291
|
+
* pnpm dev / pnpm dev all 하면 실행되는 함수입니다.
|
|
292
|
+
* 프로젝트에 대해 HMR 지원하는 개발 서버를 띄워줍니다.
|
|
224
293
|
*
|
|
225
|
-
*
|
|
294
|
+
* Sonamu.init 없이 호출될 것을 상정하여 구현되었습니다.
|
|
295
|
+
*/
|
|
296
|
+
function dev_all() {
|
|
297
|
+
console.log(chalk.yellow.bold("Starting Sonamu dev server...\n"));
|
|
298
|
+
spawnApiDevServer();
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* pnpm dev api 하면 실행되는 함수입니다.
|
|
303
|
+
* API 전용 개발 서버를 띄웁니다.
|
|
304
|
+
* dev_all과 거의 동일하되, 통합 웹 서버를 비활성화합니다.
|
|
226
305
|
*
|
|
227
|
-
*
|
|
228
|
-
|
|
306
|
+
* Sonamu.init 없이 호출될 것을 상정하여 구현되었습니다.
|
|
307
|
+
*/
|
|
308
|
+
function dev_api() {
|
|
309
|
+
console.log(chalk.yellow.bold("Starting Sonamu API-only dev server...\n"));
|
|
310
|
+
spawnApiDevServer({
|
|
311
|
+
extraEnv: { SONAMU_DISABLE_INTEGRATED_WEB: "yes" },
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* pnpm dev web 하면 실행되는 함수입니다.
|
|
317
|
+
* Vite 개발 서버를 단독으로 실행합니다.
|
|
318
|
+
* -- 뒤의 인자는 Vite에 그대로 전달됩니다.
|
|
229
319
|
*
|
|
230
320
|
* Sonamu.init 없이 호출될 것을 상정하여 구현되었습니다.
|
|
231
321
|
*/
|
|
232
|
-
async function
|
|
322
|
+
async function dev_web() {
|
|
233
323
|
const appRoot = findAppRootPath();
|
|
324
|
+
const webPath = path.join(appRoot, "web");
|
|
325
|
+
|
|
326
|
+
if (!(await exists(webPath))) {
|
|
327
|
+
console.error(`web 디렉토리를 찾을 수 없습니다: ${webPath}`);
|
|
328
|
+
process.exit(1);
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
// -- 뒤의 인자 추출
|
|
332
|
+
const doubleDashIndex = process.argv.indexOf("--");
|
|
333
|
+
const passthroughArgs = doubleDashIndex !== -1 ? process.argv.slice(doubleDashIndex + 1) : [];
|
|
334
|
+
|
|
335
|
+
const viteArgs = ["exec", "vite", ...passthroughArgs];
|
|
336
|
+
|
|
337
|
+
console.log(chalk.yellow.bold("Starting Vite dev server...\n"));
|
|
338
|
+
|
|
339
|
+
const viteProcess = spawn("pnpm", viteArgs, {
|
|
340
|
+
cwd: webPath,
|
|
341
|
+
stdio: "inherit",
|
|
342
|
+
});
|
|
234
343
|
|
|
235
|
-
|
|
344
|
+
viteProcess.on("exit", (code) => {
|
|
345
|
+
process.exit(code ?? 0);
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
// SIGINT/SIGTERM 시 Vite 프로세스를 gracefully 종료합니다.
|
|
349
|
+
for (const signal of ["SIGINT", "SIGTERM"] as const) {
|
|
350
|
+
process.on(signal, () => {
|
|
351
|
+
viteProcess.kill(signal);
|
|
352
|
+
});
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
/**
|
|
357
|
+
* SWC 설정 파일 경로를 결정합니다. API 빌드(SWC)에서만 사용됩니다.
|
|
358
|
+
* 프로젝트 루트에 .swcrc가 있으면 그것을, 없으면 sonamu 기본 설정을 사용합니다.
|
|
359
|
+
*/
|
|
360
|
+
async function resolveSwcConfigPath(): Promise<string> {
|
|
236
361
|
let swcFilePath = ".swcrc";
|
|
237
362
|
try {
|
|
238
363
|
if (await exists(swcFilePath)) {
|
|
239
|
-
// 사용자 프로젝트에 .swcrc가 있으면 우선으로 사용합니다.
|
|
240
364
|
console.log(chalk.dim("Using .swcrc from project root..."));
|
|
241
365
|
} else {
|
|
242
|
-
// 아니라면 sonamu가 관리하는 .swcrc.project-default를 가져다 씁니다.
|
|
243
366
|
console.log(chalk.dim("Using default .swcrc from sonamu package..."));
|
|
244
367
|
swcFilePath = path.join(import.meta.dirname, "..", "..", ".swcrc.project-default");
|
|
245
368
|
}
|
|
@@ -247,8 +370,28 @@ async function build() {
|
|
|
247
370
|
console.error(chalk.red("Setting up swc config file failed."), error);
|
|
248
371
|
process.exit(1);
|
|
249
372
|
}
|
|
373
|
+
return swcFilePath;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
/**
|
|
377
|
+
* sonamu build / sonamu build all 하면 실행되는 함수입니다.
|
|
378
|
+
* build_api + build_web의 합성입니다. Web 디렉토리가 없으면 Web 빌드를 스킵합니다.
|
|
379
|
+
*/
|
|
380
|
+
async function build_all() {
|
|
381
|
+
await build_api();
|
|
382
|
+
await build_web({ skipIfMissing: true });
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
/**
|
|
386
|
+
* pnpm build api 하면 실행되는 함수입니다.
|
|
387
|
+
* API 프로젝트만 빌드합니다.
|
|
388
|
+
*
|
|
389
|
+
* Sonamu.init 없이 호출될 것을 상정하여 구현되었습니다.
|
|
390
|
+
*/
|
|
391
|
+
async function build_api() {
|
|
392
|
+
const appRoot = findAppRootPath();
|
|
393
|
+
const swcFilePath = await resolveSwcConfigPath();
|
|
250
394
|
|
|
251
|
-
// API 프로젝트를 빌드합니다.
|
|
252
395
|
const apiStartedAt = Date.now();
|
|
253
396
|
try {
|
|
254
397
|
for (const artifact of API_ARTIFACTS) {
|
|
@@ -258,12 +401,32 @@ async function build() {
|
|
|
258
401
|
await runBuildSteps(artifact, { cwd, buildCommandArgs: { configFilePath: swcFilePath } });
|
|
259
402
|
}
|
|
260
403
|
printBuildSummary("API", true, Date.now() - apiStartedAt);
|
|
261
|
-
} catch {
|
|
404
|
+
} catch (e) {
|
|
262
405
|
printBuildSummary("API", false, Date.now() - apiStartedAt);
|
|
406
|
+
console.error(e);
|
|
407
|
+
process.exit(1);
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
/**
|
|
412
|
+
* pnpm build web 하면 실행되는 함수입니다.
|
|
413
|
+
* Web 프로젝트만 빌드합니다.
|
|
414
|
+
*
|
|
415
|
+
* Sonamu.init 없이 호출될 것을 상정하여 구현되었습니다.
|
|
416
|
+
*/
|
|
417
|
+
async function build_web({ skipIfMissing = false } = {}) {
|
|
418
|
+
const appRoot = findAppRootPath();
|
|
419
|
+
const webPath = path.join(appRoot, "web");
|
|
420
|
+
|
|
421
|
+
if (!(await exists(webPath))) {
|
|
422
|
+
if (skipIfMissing) {
|
|
423
|
+
console.log(chalk.gray("Web 디렉토리가 없으므로 Web 빌드를 건너뜁니다."));
|
|
424
|
+
return;
|
|
425
|
+
}
|
|
426
|
+
console.error(`web 디렉토리를 찾을 수 없습니다: ${webPath}`);
|
|
263
427
|
process.exit(1);
|
|
264
428
|
}
|
|
265
429
|
|
|
266
|
-
// Web 프로젝트를 빌드합니다.
|
|
267
430
|
const webStartedAt = Date.now();
|
|
268
431
|
try {
|
|
269
432
|
for (const artifact of WEB_ARTIFACTS) {
|
|
@@ -273,8 +436,9 @@ async function build() {
|
|
|
273
436
|
await runBuildSteps(artifact, { cwd, buildCommandArgs: {} });
|
|
274
437
|
}
|
|
275
438
|
printBuildSummary("Web", true, Date.now() - webStartedAt);
|
|
276
|
-
} catch {
|
|
439
|
+
} catch (e) {
|
|
277
440
|
printBuildSummary("Web", false, Date.now() - webStartedAt);
|
|
441
|
+
console.error(e);
|
|
278
442
|
process.exit(1);
|
|
279
443
|
}
|
|
280
444
|
}
|
|
@@ -301,9 +465,9 @@ async function runBuildSteps<T>(
|
|
|
301
465
|
printTaskStart(step.name, step.cmd, isLast);
|
|
302
466
|
await execWithLinePrefix(step.cmd, { cwd: options.cwd });
|
|
303
467
|
printTaskSuccess(step.name, isLast);
|
|
304
|
-
} catch {
|
|
468
|
+
} catch (e) {
|
|
305
469
|
printTaskFailed(step.name, isLast);
|
|
306
|
-
throw new Error(`${step.name} failed
|
|
470
|
+
throw new Error(`${step.name} failed`, { cause: e });
|
|
307
471
|
}
|
|
308
472
|
}
|
|
309
473
|
}
|
|
@@ -323,7 +487,7 @@ async function start() {
|
|
|
323
487
|
|
|
324
488
|
if (!(await exists(entryPoint))) {
|
|
325
489
|
console.log(chalk.red(`${entryPoint} not found. Please build your project first.`));
|
|
326
|
-
console.log(chalk.blue("Run:
|
|
490
|
+
console.log(chalk.blue("Run: pnpm sonamu build"));
|
|
327
491
|
return;
|
|
328
492
|
}
|
|
329
493
|
|
|
@@ -470,6 +634,77 @@ async function fixture_sync() {
|
|
|
470
634
|
await FixtureManager.sync();
|
|
471
635
|
}
|
|
472
636
|
|
|
637
|
+
/**
|
|
638
|
+
* fixture gen 명령어
|
|
639
|
+
* 옵션을 process.argv에서 파싱
|
|
640
|
+
*/
|
|
641
|
+
async function fixture_gen() {
|
|
642
|
+
const options = parseOptions(process.argv);
|
|
643
|
+
await fixtureGenCommand(options);
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
/**
|
|
647
|
+
* fixture fetch 명령어
|
|
648
|
+
* 옵션을 process.argv에서 파싱
|
|
649
|
+
*/
|
|
650
|
+
async function fixture_fetch() {
|
|
651
|
+
const options = parseOptions(process.argv);
|
|
652
|
+
await fixtureFetchCommand(options);
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
/**
|
|
656
|
+
* fixture explore 명령어
|
|
657
|
+
* 옵션을 process.argv에서 파싱
|
|
658
|
+
*/
|
|
659
|
+
async function fixture_explore() {
|
|
660
|
+
const options = parseOptions(process.argv);
|
|
661
|
+
await fixtureExploreCommand(options);
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
/**
|
|
665
|
+
* 간단한 옵션 파서
|
|
666
|
+
*/
|
|
667
|
+
function parseOptions(
|
|
668
|
+
argv: string[],
|
|
669
|
+
): Record<string, string | boolean | string[]> & { _: string[] } {
|
|
670
|
+
const options: Record<string, string | boolean | string[]> & { _: string[] } = { _: [] };
|
|
671
|
+
|
|
672
|
+
for (let i = 0; i < argv.length; i++) {
|
|
673
|
+
const arg = argv[i];
|
|
674
|
+
|
|
675
|
+
if (arg.startsWith("--")) {
|
|
676
|
+
const key = arg.slice(2);
|
|
677
|
+
|
|
678
|
+
if (key.includes("=")) {
|
|
679
|
+
const [k, v] = key.split("=");
|
|
680
|
+
options[k] = v;
|
|
681
|
+
} else {
|
|
682
|
+
const next = argv[i + 1];
|
|
683
|
+
if (next && !next.startsWith("--")) {
|
|
684
|
+
options[key] = next;
|
|
685
|
+
i++;
|
|
686
|
+
} else {
|
|
687
|
+
options[key] = true;
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
} else if (arg.startsWith("-")) {
|
|
691
|
+
const key = arg.slice(1);
|
|
692
|
+
const next = argv[i + 1];
|
|
693
|
+
|
|
694
|
+
if (next && !next.startsWith("-")) {
|
|
695
|
+
options[key] = next;
|
|
696
|
+
i++;
|
|
697
|
+
} else {
|
|
698
|
+
options[key] = true;
|
|
699
|
+
}
|
|
700
|
+
} else {
|
|
701
|
+
options._.push(arg);
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
return options;
|
|
706
|
+
}
|
|
707
|
+
|
|
473
708
|
async function stub_practice(name: string) {
|
|
474
709
|
const practiceDir = path.join(Sonamu.apiRootPath, "src", "practices");
|
|
475
710
|
const fileNames = await readdir(practiceDir);
|
|
@@ -523,6 +758,171 @@ async function stub_practice(name: string) {
|
|
|
523
758
|
|
|
524
759
|
async function stub_entity(entityId: string) {
|
|
525
760
|
await Sonamu.syncer.createEntity({ entityId, title: entityId });
|
|
761
|
+
|
|
762
|
+
const { flags } = parseCliOptions();
|
|
763
|
+
const useAI = flags.has("ai");
|
|
764
|
+
const noCones = flags.has("no-cones");
|
|
765
|
+
|
|
766
|
+
// --no-cones: cone 생성 스킵
|
|
767
|
+
if (noCones) {
|
|
768
|
+
console.log(`✓ Entity '${entityId}' created without cones`);
|
|
769
|
+
return;
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
const { EntityManager } = await import("../entity/entity-manager");
|
|
773
|
+
const entity = EntityManager.get(entityId);
|
|
774
|
+
if (!entity) {
|
|
775
|
+
console.error(`Entity not found: ${entityId}`);
|
|
776
|
+
return;
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
// --ai: LLM으로 cone 생성
|
|
780
|
+
if (useAI) {
|
|
781
|
+
console.log(`✓ Entity '${entityId}' created`);
|
|
782
|
+
console.log(`🌟 Generating AI-powered cones...`);
|
|
783
|
+
try {
|
|
784
|
+
const configLocale = Sonamu.config.i18n?.defaultLocale;
|
|
785
|
+
const locale =
|
|
786
|
+
configLocale === "ko" || configLocale === "en" || configLocale === "ja"
|
|
787
|
+
? configLocale
|
|
788
|
+
: "ko";
|
|
789
|
+
|
|
790
|
+
const result = await entity.generateCones({
|
|
791
|
+
preserveExisting: false,
|
|
792
|
+
onlyEmpty: false,
|
|
793
|
+
locale,
|
|
794
|
+
});
|
|
795
|
+
|
|
796
|
+
console.log(`✅ Done (${result.tokensUsed} tokens)`);
|
|
797
|
+
} catch (error) {
|
|
798
|
+
if (error instanceof Error && error.message.includes("ANTHROPIC_API_KEY")) {
|
|
799
|
+
console.error(`\n❌ ${error.message}`);
|
|
800
|
+
console.error(`\n💡 Remove --ai flag to use template cones instead`);
|
|
801
|
+
} else {
|
|
802
|
+
throw error;
|
|
803
|
+
}
|
|
804
|
+
}
|
|
805
|
+
return;
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
// 기본: 템플릿 cone 자동 생성
|
|
809
|
+
// LLM 없이 faker-mappings.ts를 활용하여 기본 cone 메타데이터를 생성합니다.
|
|
810
|
+
// 이를 통해 ANTHROPIC_API_KEY가 없어도 Sonamu를 사용할 수 있으며,
|
|
811
|
+
// 생성된 템플릿 cone은 나중에 'cone gen' 명령어로 AI를 통해 업그레이드할 수 있습니다.
|
|
812
|
+
console.log(`🌟 Generating template cones...`);
|
|
813
|
+
await entity.generateTemplateCones();
|
|
814
|
+
console.log(`✓ Entity '${entityId}' created with template cones`);
|
|
815
|
+
console.log(`💡 Tip: Run 'pnpm sonamu cone gen ${entityId}' to improve with AI`);
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
/**
|
|
819
|
+
* AI를 사용하여 entity의 cone 메타데이터를 생성하거나 업그레이드합니다.
|
|
820
|
+
*
|
|
821
|
+
* 옵션:
|
|
822
|
+
* - --regenerate: 전체 재생성 (기존 cone 덮어쓰기)
|
|
823
|
+
* - --locale <ko|en|ja>: 생성 언어 지정
|
|
824
|
+
* - 기본: onlyEmpty 모드 (기존 fixtureHint 보존)
|
|
825
|
+
*
|
|
826
|
+
* ANTHROPIC_API_KEY 필요 (sonamu.secret.ts 또는 환경변수)
|
|
827
|
+
*/
|
|
828
|
+
async function cone_gen(entityId: string) {
|
|
829
|
+
const { EntityManager } = await import("../entity/entity-manager");
|
|
830
|
+
const { flags, options } = parseCliOptions();
|
|
831
|
+
|
|
832
|
+
// --all 옵션: 모든 entity cone 생성
|
|
833
|
+
if (flags.has("all") || entityId === "all") {
|
|
834
|
+
const allEntities = EntityManager.getAllEntities();
|
|
835
|
+
console.log(`🌟 Generating AI-powered cones for ${allEntities.length} entities...\n`);
|
|
836
|
+
|
|
837
|
+
let totalTokens = 0;
|
|
838
|
+
const errors: string[] = [];
|
|
839
|
+
|
|
840
|
+
for (const entity of allEntities) {
|
|
841
|
+
try {
|
|
842
|
+
console.log(`Processing ${entity.id}...`);
|
|
843
|
+
const configLocale = options.locale || Sonamu.config.i18n?.defaultLocale;
|
|
844
|
+
const locale =
|
|
845
|
+
configLocale === "ko" || configLocale === "en" || configLocale === "ja"
|
|
846
|
+
? configLocale
|
|
847
|
+
: "ko";
|
|
848
|
+
|
|
849
|
+
const result = await entity.generateCones({
|
|
850
|
+
preserveExisting: !flags.has("regenerate"),
|
|
851
|
+
onlyEmpty: !flags.has("regenerate"),
|
|
852
|
+
locale,
|
|
853
|
+
});
|
|
854
|
+
|
|
855
|
+
totalTokens += result.tokensUsed;
|
|
856
|
+
console.log(` ✓ ${entity.id} (${result.tokensUsed} tokens)\n`);
|
|
857
|
+
} catch (error) {
|
|
858
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
859
|
+
errors.push(`${entity.id}: ${message}`);
|
|
860
|
+
console.error(` ✗ ${entity.id}: ${message}\n`);
|
|
861
|
+
}
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
console.log(`\n✅ Done! Total: ${totalTokens} tokens used`);
|
|
865
|
+
const estimatedCost = (totalTokens * 9) / 1_000_000;
|
|
866
|
+
console.log(`💰 Estimated cost: ~$${estimatedCost.toFixed(4)}`);
|
|
867
|
+
|
|
868
|
+
if (errors.length > 0) {
|
|
869
|
+
console.error(`\n❌ Failed entities (${errors.length}):`);
|
|
870
|
+
for (const err of errors) {
|
|
871
|
+
console.error(` - ${err}`);
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
return;
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
// 단일 entity cone 생성
|
|
878
|
+
const entity = EntityManager.get(entityId);
|
|
879
|
+
if (!entity) {
|
|
880
|
+
console.error(`Entity not found: ${entityId}`);
|
|
881
|
+
return;
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
const mode = flags.has("regenerate") ? "regenerating" : "generating";
|
|
885
|
+
console.log(
|
|
886
|
+
`🌟 ${mode === "regenerating" ? "Regenerating" : "Generating"} AI-powered cones for ${entityId}...`,
|
|
887
|
+
);
|
|
888
|
+
|
|
889
|
+
try {
|
|
890
|
+
const configLocale = options.locale || Sonamu.config.i18n?.defaultLocale;
|
|
891
|
+
const locale =
|
|
892
|
+
configLocale === "ko" || configLocale === "en" || configLocale === "ja" ? configLocale : "ko";
|
|
893
|
+
|
|
894
|
+
const result = await entity.generateCones({
|
|
895
|
+
preserveExisting: !flags.has("regenerate"),
|
|
896
|
+
onlyEmpty: !flags.has("regenerate"),
|
|
897
|
+
locale,
|
|
898
|
+
});
|
|
899
|
+
|
|
900
|
+
console.log(`✅ Done! (${result.tokensUsed} tokens used)`);
|
|
901
|
+
|
|
902
|
+
// 토큰 비용 계산 (대략적인 추정)
|
|
903
|
+
// Claude Sonnet 4.5: input $3/M tokens, output $15/M tokens
|
|
904
|
+
// 간단하게 평균 $9/M tokens로 계산
|
|
905
|
+
const estimatedCost = (result.tokensUsed * 9) / 1_000_000;
|
|
906
|
+
console.log(`💰 Estimated cost: ~$${estimatedCost.toFixed(4)}`);
|
|
907
|
+
} catch (error) {
|
|
908
|
+
if (error instanceof Error) {
|
|
909
|
+
if (error.message.includes("ANTHROPIC_API_KEY")) {
|
|
910
|
+
console.error(`\n❌ ${error.message}`);
|
|
911
|
+
console.error(`\n💡 To use AI-powered cone generation:`);
|
|
912
|
+
console.error(` 1. Get an API key from https://console.anthropic.com/`);
|
|
913
|
+
console.error(
|
|
914
|
+
` 2. Add it to sonamu.secret.ts or set ANTHROPIC_API_KEY environment variable`,
|
|
915
|
+
);
|
|
916
|
+
} else if (error.message.includes("Rate limit")) {
|
|
917
|
+
console.error(`\n❌ ${error.message}`);
|
|
918
|
+
console.error(`\n💡 Please wait a moment and try again.`);
|
|
919
|
+
} else {
|
|
920
|
+
console.error(`\n❌ Failed to generate cones: ${error.message}`);
|
|
921
|
+
}
|
|
922
|
+
} else {
|
|
923
|
+
console.error(`\n❌ Failed to generate cones: Unknown error`);
|
|
924
|
+
}
|
|
925
|
+
}
|
|
526
926
|
}
|
|
527
927
|
|
|
528
928
|
async function scaffold_model(entityId: string) {
|
|
@@ -590,6 +990,27 @@ async function skills_sync() {
|
|
|
590
990
|
}
|
|
591
991
|
}
|
|
592
992
|
|
|
993
|
+
// project 디렉토리 초기화 (없으면 생성, 있으면 유지)
|
|
994
|
+
const sourceProjectDir = path.join(sourceBase, "project");
|
|
995
|
+
const targetProjectDir = path.join(claudeDir, "skills", "project");
|
|
996
|
+
|
|
997
|
+
if (await exists(sourceProjectDir)) {
|
|
998
|
+
if (!(await exists(targetProjectDir))) {
|
|
999
|
+
try {
|
|
1000
|
+
await cp(sourceProjectDir, targetProjectDir, { recursive: true });
|
|
1001
|
+
console.log(chalk.green(`✓ Project templates initialized`));
|
|
1002
|
+
} catch (error) {
|
|
1003
|
+
console.error(
|
|
1004
|
+
chalk.red(
|
|
1005
|
+
`✗ Failed to initialize project templates: ${error instanceof Error ? error.message : String(error)}`,
|
|
1006
|
+
),
|
|
1007
|
+
);
|
|
1008
|
+
}
|
|
1009
|
+
} else {
|
|
1010
|
+
console.log(chalk.dim(`⏭ Project templates already exist (preserved)`));
|
|
1011
|
+
}
|
|
1012
|
+
}
|
|
1013
|
+
|
|
593
1014
|
// CLAUDE.md 복사/업데이트
|
|
594
1015
|
if (await exists(sourceClaudeMd)) {
|
|
595
1016
|
try {
|