codex-rule-maker 0.3.0__tar.gz → 0.4.0__tar.gz

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 (22) hide show
  1. {codex_rule_maker-0.3.0 → codex_rule_maker-0.4.0}/PKG-INFO +8 -3
  2. {codex_rule_maker-0.3.0 → codex_rule_maker-0.4.0}/README.md +7 -2
  3. {codex_rule_maker-0.3.0 → codex_rule_maker-0.4.0}/codex_builder/cli.py +2 -2
  4. {codex_rule_maker-0.3.0 → codex_rule_maker-0.4.0}/codex_builder/profiles.py +85 -2
  5. {codex_rule_maker-0.3.0 → codex_rule_maker-0.4.0}/codex_builder/prompt.py +3 -3
  6. {codex_rule_maker-0.3.0 → codex_rule_maker-0.4.0}/codex_builder/template_renderer.py +19 -56
  7. {codex_rule_maker-0.3.0 → codex_rule_maker-0.4.0}/codex_rule_maker.egg-info/PKG-INFO +8 -3
  8. {codex_rule_maker-0.3.0 → codex_rule_maker-0.4.0}/pyproject.toml +1 -1
  9. {codex_rule_maker-0.3.0 → codex_rule_maker-0.4.0}/tests/test_builder.py +40 -0
  10. {codex_rule_maker-0.3.0 → codex_rule_maker-0.4.0}/tests/test_cli.py +9 -1
  11. {codex_rule_maker-0.3.0 → codex_rule_maker-0.4.0}/LICENSE +0 -0
  12. {codex_rule_maker-0.3.0 → codex_rule_maker-0.4.0}/codex_builder/__init__.py +0 -0
  13. {codex_rule_maker-0.3.0 → codex_rule_maker-0.4.0}/codex_builder/builder.py +0 -0
  14. {codex_rule_maker-0.3.0 → codex_rule_maker-0.4.0}/codex_builder/constants.py +0 -0
  15. {codex_rule_maker-0.3.0 → codex_rule_maker-0.4.0}/codex_builder/models.py +0 -0
  16. {codex_rule_maker-0.3.0 → codex_rule_maker-0.4.0}/codex_builder/validator.py +0 -0
  17. {codex_rule_maker-0.3.0 → codex_rule_maker-0.4.0}/codex_rule_maker.egg-info/SOURCES.txt +0 -0
  18. {codex_rule_maker-0.3.0 → codex_rule_maker-0.4.0}/codex_rule_maker.egg-info/dependency_links.txt +0 -0
  19. {codex_rule_maker-0.3.0 → codex_rule_maker-0.4.0}/codex_rule_maker.egg-info/entry_points.txt +0 -0
  20. {codex_rule_maker-0.3.0 → codex_rule_maker-0.4.0}/codex_rule_maker.egg-info/requires.txt +0 -0
  21. {codex_rule_maker-0.3.0 → codex_rule_maker-0.4.0}/codex_rule_maker.egg-info/top_level.txt +0 -0
  22. {codex_rule_maker-0.3.0 → codex_rule_maker-0.4.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: codex-rule-maker
3
- Version: 0.3.0
3
+ Version: 0.4.0
4
4
  Summary: CLI tool that generates a .codex folder with AI developer rules and project reference documents.
5
5
  Author: codex-rule-maker
6
6
  Project-URL: Homepage, https://github.com/Sharon77770/codex_rule_maker
@@ -30,6 +30,8 @@ Dynamic: license-file
30
30
 
31
31
  # codex-rule-maker
32
32
 
33
+ 현재 버전: `0.4.0`
34
+
33
35
  `codex-rule-maker`는 프로젝트 루트에 `.codex` 규칙 폴더와 `docs/` 프로젝트 문서 템플릿을 자동 구성하는 Python CLI 도구입니다. 사용자가 프로젝트 이름, 설명, 스택, DB, 인증 여부, 외부 API 여부, 문서화 수준, 문서 언어를 입력하면 Codex가 작업 전에 읽을 개발 규칙과 프로젝트 문서 구조를 생성합니다.
34
36
 
35
37
  ## 설치
@@ -225,7 +227,8 @@ docs/
225
227
  ## 지원 프레임워크 프로필
226
228
 
227
229
  - `fastapi`: 기능 폴더 하위 controller/service/repository/schema/entity 분리
228
- - `python`: 기능/도메인 폴더 하위 service/adapter/model/CLI 경계 분리
230
+ - `python`: 프레임워크 없는 Python 프로젝트의 기능/도메인 폴더 하위 service/adapter/model/CLI 경계 분리
231
+ - `typescript-javascript`: 프레임워크 없는 TypeScript/JavaScript 프로젝트의 기능/도메인 폴더 하위 service/adapter/model 경계 분리
229
232
  - `springboot`: 기능 package 하위 controller/service/repository/entity/dto 분리
230
233
  - `react`: 기능 폴더 하위 page/component/hook/service/store 분리
231
234
  - `nextjs`: App Router 유지, 기능 폴더 하위 component/service/repository/type 분리
@@ -237,6 +240,8 @@ docs/
237
240
  ```bash
238
241
  codex-init --stack fastapi,react
239
242
  codex-init --stack python
243
+ codex-init --stack typescript
244
+ codex-init --stack javascript
240
245
  codex-init --stack fullstack-fastapi-react
241
246
  codex-init --stack nextjs
242
247
  ```
@@ -247,7 +252,7 @@ codex-init --stack nextjs
247
252
  - `--language en`을 사용하면 영어 문서를 생성합니다.
248
253
  - `--docs strict`는 코드 변경 후 문서 업데이트 필수 규칙을 포함합니다.
249
254
  - `--auth yes`는 인증/권한 규칙을 포함합니다.
250
- - `--external-api yes`는 외부 연동 계층 분리 규칙을 포함합니다.
255
+ - `--external-api yes`는 확인된 계약을 기준으로 실제 외부 연동을 구현하기 위한 client/adapter 및 계약 문서 규칙을 포함합니다.
251
256
  - `--db mysql`처럼 DB를 지정하면 DB, Repository, Schema 관련 규칙을 포함합니다.
252
257
  - 프로젝트 명세 템플릿은 `.codex/ref_docs`가 아니라 `docs/architecture`, `docs/api`, `docs/database`에 생성됩니다.
253
258
 
@@ -1,5 +1,7 @@
1
1
  # codex-rule-maker
2
2
 
3
+ 현재 버전: `0.4.0`
4
+
3
5
  `codex-rule-maker`는 프로젝트 루트에 `.codex` 규칙 폴더와 `docs/` 프로젝트 문서 템플릿을 자동 구성하는 Python CLI 도구입니다. 사용자가 프로젝트 이름, 설명, 스택, DB, 인증 여부, 외부 API 여부, 문서화 수준, 문서 언어를 입력하면 Codex가 작업 전에 읽을 개발 규칙과 프로젝트 문서 구조를 생성합니다.
4
6
 
5
7
  ## 설치
@@ -195,7 +197,8 @@ docs/
195
197
  ## 지원 프레임워크 프로필
196
198
 
197
199
  - `fastapi`: 기능 폴더 하위 controller/service/repository/schema/entity 분리
198
- - `python`: 기능/도메인 폴더 하위 service/adapter/model/CLI 경계 분리
200
+ - `python`: 프레임워크 없는 Python 프로젝트의 기능/도메인 폴더 하위 service/adapter/model/CLI 경계 분리
201
+ - `typescript-javascript`: 프레임워크 없는 TypeScript/JavaScript 프로젝트의 기능/도메인 폴더 하위 service/adapter/model 경계 분리
199
202
  - `springboot`: 기능 package 하위 controller/service/repository/entity/dto 분리
200
203
  - `react`: 기능 폴더 하위 page/component/hook/service/store 분리
201
204
  - `nextjs`: App Router 유지, 기능 폴더 하위 component/service/repository/type 분리
@@ -207,6 +210,8 @@ docs/
207
210
  ```bash
208
211
  codex-init --stack fastapi,react
209
212
  codex-init --stack python
213
+ codex-init --stack typescript
214
+ codex-init --stack javascript
210
215
  codex-init --stack fullstack-fastapi-react
211
216
  codex-init --stack nextjs
212
217
  ```
@@ -217,7 +222,7 @@ codex-init --stack nextjs
217
222
  - `--language en`을 사용하면 영어 문서를 생성합니다.
218
223
  - `--docs strict`는 코드 변경 후 문서 업데이트 필수 규칙을 포함합니다.
219
224
  - `--auth yes`는 인증/권한 규칙을 포함합니다.
220
- - `--external-api yes`는 외부 연동 계층 분리 규칙을 포함합니다.
225
+ - `--external-api yes`는 확인된 계약을 기준으로 실제 외부 연동을 구현하기 위한 client/adapter 및 계약 문서 규칙을 포함합니다.
221
226
  - `--db mysql`처럼 DB를 지정하면 DB, Repository, Schema 관련 규칙을 포함합니다.
222
227
  - 프로젝트 명세 템플릿은 `.codex/ref_docs`가 아니라 `docs/architecture`, `docs/api`, `docs/database`에 생성됩니다.
223
228
 
@@ -10,7 +10,7 @@ from typing import Optional
10
10
  from codex_builder.builder import CodexBuilder, CodexBuildError, ExistingCodexError
11
11
  from codex_builder.models import ConfigError
12
12
  from codex_builder.prompt import PromptAbort, PromptSession
13
- from codex_builder.profiles import UnknownProfileError, supported_profile_names
13
+ from codex_builder.profiles import UnknownProfileError, supported_profile_labels
14
14
 
15
15
 
16
16
  def build_parser() -> argparse.ArgumentParser:
@@ -22,7 +22,7 @@ def build_parser() -> argparse.ArgumentParser:
22
22
  parser.add_argument("--description", help="Short project description.")
23
23
  parser.add_argument(
24
24
  "--stack",
25
- help=f"Comma-separated stack profiles. Supported: {', '.join(supported_profile_names())}.",
25
+ help=f"Comma-separated stack profiles. Supported: {', '.join(supported_profile_labels())}.",
26
26
  )
27
27
  parser.add_argument("--db", "--database", dest="database", help="Database name, for example mysql or postgres.")
28
28
  parser.add_argument("--auth", help="Whether authentication is used: yes/no.")
@@ -109,6 +109,72 @@ PYTHON_PROFILE = FrameworkProfile(
109
109
  )
110
110
 
111
111
 
112
+ TYPESCRIPT_JAVASCRIPT_PROFILE = FrameworkProfile(
113
+ key="typescript-javascript",
114
+ display_name="TypeScript/JavaScript",
115
+ philosophy_ko="일반 TypeScript/JavaScript 프로젝트는 프레임워크 전제 없이 기능/도메인 폴더를 우선하고, 각 기능 내부에서 service, adapter, model 경계를 분리한다.",
116
+ philosophy_en="General TypeScript/JavaScript projects should prefer feature/domain folders first, then separate service, adapter, and model boundaries without assuming a framework.",
117
+ architecture_ko=(
118
+ "패키지는 기능 또는 도메인 책임 기준으로 나누고 각 기능 폴더 하위에 services, adapters, models/types 등을 둔다.",
119
+ "공통 모듈은 여러 기능에서 공유하는 정책, 설정, utility에만 사용한다.",
120
+ "실행 진입점은 입력 파싱과 출력 변환만 담당하고 실제 판단은 application/service 계층에 위임한다.",
121
+ "핵심 도메인 로직은 filesystem, network, environment, process 전역 객체에 직접 의존하지 않게 한다.",
122
+ "파일, DB, 외부 API, subprocess 연동은 adapter 또는 infrastructure 모듈 뒤에 둔다.",
123
+ "권장 흐름: Entrypoint -> Application Service -> Domain/Adapter -> External System.",
124
+ ),
125
+ architecture_en=(
126
+ "Split modules by feature or domain responsibility and place services, adapters, and models/types under each feature folder.",
127
+ "Use shared modules only for policies, settings, and utilities reused by multiple features.",
128
+ "Runtime entrypoints should parse input and map output only, then delegate decisions to application/services.",
129
+ "Keep core domain logic independent from filesystem, network, environment, and process globals.",
130
+ "Put filesystem, database, external API, and subprocess integrations behind adapter or infrastructure modules.",
131
+ "Recommended flow: Entrypoint -> Application Service -> Domain/Adapter -> External System.",
132
+ ),
133
+ framework_rules_ko=(
134
+ "프레임워크 전역 객체와 import 시점 부수효과에 의존하지 않는 모듈을 작성한다.",
135
+ "TypeScript는 공개 함수와 클래스의 타입을 명시하고, JavaScript는 필요한 경우 JSDoc으로 계약을 표현한다.",
136
+ "비동기 오류는 호출자가 처리할 수 있는 명확한 Error 타입과 메시지로 전달한다.",
137
+ "표준 런타임과 기존 dependency로 충분한 문제에 불필요한 패키지를 추가하지 않는다.",
138
+ "순수 계산 로직과 I/O 로직을 분리해 테스트와 재사용이 가능하게 한다.",
139
+ ),
140
+ framework_rules_en=(
141
+ "Write modules that do not depend on framework globals or import-time side effects.",
142
+ "Use explicit types for public TypeScript functions and classes, and express JavaScript contracts with JSDoc when useful.",
143
+ "Propagate async failures with clear Error types and messages that callers can handle.",
144
+ "Do not add dependencies when the runtime and existing packages are sufficient.",
145
+ "Separate pure computation from I/O so logic stays testable and reusable.",
146
+ ),
147
+ api_rules_ko=(
148
+ "공개 함수, 모듈 export, CLI 옵션은 외부 계약으로 보고 이름과 반환 형식을 안정적으로 관리한다.",
149
+ "외부 입력은 진입점에서 검증하고 내부 model로 변환한 뒤 service 계층에 전달한다.",
150
+ "공개 모듈의 오류와 비동기 동작은 호출자가 예측할 수 있게 문서화한다.",
151
+ ),
152
+ api_rules_en=(
153
+ "Treat public functions, module exports, and CLI options as external contracts with stable names and return shapes.",
154
+ "Validate external input at the entrypoint and convert it into internal models before passing it to services.",
155
+ "Document public module errors and async behavior so callers can predict them.",
156
+ ),
157
+ test_rules_ko=(
158
+ "순수 로직 테스트와 filesystem/network/environment I/O 테스트를 분리한다.",
159
+ "외부 의존성은 명시적인 test double과 임시 디렉토리로 격리한다.",
160
+ "CLI 인자, module export, 비동기 오류 경로는 회귀 테스트로 고정한다.",
161
+ ),
162
+ test_rules_en=(
163
+ "Separate pure logic tests from filesystem, network, and environment I/O tests.",
164
+ "Isolate external dependencies with explicit test doubles and temporary directories.",
165
+ "Lock down CLI arguments, module exports, and async failure paths with regression tests.",
166
+ ),
167
+ directories=(
168
+ "src/<feature>/services",
169
+ "src/<feature>/adapters",
170
+ "src/<feature>/models",
171
+ "src/shared",
172
+ "tests",
173
+ "scripts",
174
+ ),
175
+ )
176
+
177
+
112
178
  FASTAPI_PROFILE = FrameworkProfile(
113
179
  key="fastapi",
114
180
  display_name="FastAPI",
@@ -484,12 +550,12 @@ FULLSTACK_FASTAPI_REACT_PROFILE = FrameworkProfile(
484
550
  test_rules_ko=(
485
551
  "백엔드 API 테스트와 프론트엔드 service 테스트가 같은 계약을 검증하게 한다.",
486
552
  "주요 사용자 흐름은 E2E 또는 통합 테스트 대상으로 둔다.",
487
- "API mock은 실제 docs/api/specification.md와 불일치하지 않게 관리한다.",
553
+ "API contract test는 실제 docs/api/specification.md와 불일치하지 않게 관리한다.",
488
554
  ),
489
555
  test_rules_en=(
490
556
  "Backend API tests and frontend service tests should verify the same contract.",
491
557
  "Cover major user flows with E2E or integration tests.",
492
- "Keep API mocks aligned with docs/api/specification.md.",
558
+ "Keep API contract tests aligned with docs/api/specification.md.",
493
559
  ),
494
560
  directories=(
495
561
  "backend/app/features/<feature>/controllers",
@@ -512,6 +578,7 @@ PROFILES: dict[str, FrameworkProfile] = {
512
578
  for profile in (
513
579
  FASTAPI_PROFILE,
514
580
  PYTHON_PROFILE,
581
+ TYPESCRIPT_JAVASCRIPT_PROFILE,
515
582
  SPRINGBOOT_PROFILE,
516
583
  REACT_PROFILE,
517
584
  NEXTJS_PROFILE,
@@ -526,6 +593,16 @@ PROFILE_ALIASES: dict[str, str] = {
526
593
  "plain-python": "python",
527
594
  "vanilla-python": "python",
528
595
  "general-python": "python",
596
+ "ts": "typescript-javascript",
597
+ "js": "typescript-javascript",
598
+ "typescript": "typescript-javascript",
599
+ "javascript": "typescript-javascript",
600
+ "ts-js": "typescript-javascript",
601
+ "ts/js": "typescript-javascript",
602
+ "plain-typescript": "typescript-javascript",
603
+ "plain-javascript": "typescript-javascript",
604
+ "vanilla-typescript": "typescript-javascript",
605
+ "vanilla-javascript": "typescript-javascript",
529
606
  "fast-api": "fastapi",
530
607
  "spring": "springboot",
531
608
  "spring-boot": "springboot",
@@ -545,6 +622,12 @@ def supported_profile_names() -> tuple[str, ...]:
545
622
  return tuple(PROFILES)
546
623
 
547
624
 
625
+ def supported_profile_labels() -> tuple[str, ...]:
626
+ """Return user-facing labels for supported profile choices."""
627
+
628
+ return tuple(f"{profile.key} ({profile.display_name})" for profile in PROFILES.values())
629
+
630
+
548
631
  def canonical_profile_name(name: str) -> str:
549
632
  """Normalize a user-provided stack name to a supported profile key."""
550
633
 
@@ -14,7 +14,7 @@ from codex_builder.constants import (
14
14
  DEFAULT_STACK,
15
15
  )
16
16
  from codex_builder.models import ConfigError, ProjectConfig, parse_yes_no
17
- from codex_builder.profiles import supported_profile_names
17
+ from codex_builder.profiles import supported_profile_labels
18
18
  from codex_builder.validator import (
19
19
  validate_docs_level,
20
20
  validate_existing_directory,
@@ -149,8 +149,8 @@ class PromptSession:
149
149
 
150
150
  def prompt_stack(self) -> tuple[str, ...]:
151
151
  self._write("지원 프로필:")
152
- for profile_name in supported_profile_names():
153
- self._write(f"- {profile_name}")
152
+ for profile_label in supported_profile_labels():
153
+ self._write(f"- {profile_label}")
154
154
 
155
155
  while True:
156
156
  raw_stack = self.prompt_text("사용 스택", ",".join(DEFAULT_STACK))
@@ -85,7 +85,7 @@ class TemplateRenderer:
85
85
  "- Do not put all logic in one file for convenience.",
86
86
  "- Do not place business logic in controllers, route handlers, or UI components.",
87
87
  "- Do not return persistence entities directly from public APIs.",
88
- "- Do not complete external integrations with fake implementations.",
88
+ "- Implement external integrations against their confirmed contracts and keep failure behavior explicit.",
89
89
  "- Do not add core code without documenting the intent when the behavior is non-obvious.",
90
90
  ]
91
91
  )
@@ -119,7 +119,7 @@ class TemplateRenderer:
119
119
  "- 편의를 위해 모든 로직을 한 파일에 몰아넣지 않는다.",
120
120
  "- controller, route handler, UI component에 비즈니스 로직을 넣지 않는다.",
121
121
  "- persistence entity를 public API 응답으로 직접 반환하지 않는다.",
122
- "- 외부 연동을 가짜 구현으로 완성한 것처럼 만들지 않는다.",
122
+ "- 외부 연동은 확인된 계약을 기준으로 구현하고 실패 동작을 명시한다.",
123
123
  "- 동작이 비명시적인 핵심 코드에 의도 설명 없이 코드를 추가하지 않는다.",
124
124
  ]
125
125
  )
@@ -139,7 +139,7 @@ class TemplateRenderer:
139
139
  lines.extend(
140
140
  [
141
141
  "- External API calls must go through a dedicated client/adapter layer.",
142
- "- Do not fake completed external integrations. Leave clear TODOs when credentials or contracts are missing.",
142
+ "- Implement confirmed credentials, contracts, schemas, and failure handling together.",
143
143
  ]
144
144
  )
145
145
  if config.database:
@@ -160,7 +160,7 @@ class TemplateRenderer:
160
160
  lines.extend(
161
161
  [
162
162
  "- 외부 API 호출은 반드시 전용 client/adapter 계층을 통해 수행한다.",
163
- "- 계약이나 인증 정보가 없는 외부 연동은 완성된 것처럼 꾸미지 말고 명확한 TODO를 남긴다.",
163
+ "- 외부 연동은 인증 정보, 계약, schema, 실패 처리를 실제 구현과 함께 관리한다.",
164
164
  ]
165
165
  )
166
166
  if config.database:
@@ -263,7 +263,7 @@ class TemplateRenderer:
263
263
  "[Spacing Rules]",
264
264
  "- Keep method boundaries visually obvious. Use the repository's formatter when it enforces exact blank lines.",
265
265
  "- When the formatter allows manual spacing, keep five blank-line units between methods.",
266
- "- Inside a method, separate unrelated logic blocks with two blank-line units when the formatter allows it.",
266
+ "- Inside a method, separate unrelated logic blocks with three blank-line units when the formatter allows it.",
267
267
  "- If a function signature, expression, query, JSX block, or builder chain spans multiple lines, leave a blank line before starting the next logic block.",
268
268
  "- Do not compress validation, transformation, persistence, and response mapping into one dense block.",
269
269
  "",
@@ -323,7 +323,7 @@ class TemplateRenderer:
323
323
  "[공백 규칙]",
324
324
  "- 메서드 경계는 눈으로 분명히 구분되어야 한다. 정확한 공백 수는 저장소 formatter가 강제하면 formatter를 따른다.",
325
325
  "- formatter가 수동 공백을 허용하면 메서드 간 5칸 공백을 둔다.",
326
- "- 메서드 내부의 연관 없는 로직 블록 간에는 formatter가 허용하는 범위에서 2칸 공백을 둔다.",
326
+ "- 메서드 내부의 연관 없는 로직 블록 간에는 formatter가 허용하는 범위에서 3칸 공백을 둔다.",
327
327
  "- 함수 시그니처, 표현식, 쿼리, JSX block, builder chain이 여러 줄에 걸쳐 작성되면 다음 로직 블록 전에는 반드시 공백을 둔다.",
328
328
  "- validation, transformation, persistence, response mapping을 하나의 빽빽한 블록으로 압축하지 않는다.",
329
329
  "",
@@ -787,34 +787,16 @@ class TemplateRenderer:
787
787
  "- Third-party HTTP APIs or SDKs",
788
788
  "- Any system outside the current repository process",
789
789
  "",
790
- "[Rules]",
791
- "- Do not implement an integration as complete unless credentials, contract, timeout behavior, and failure mapping are known.",
792
- "- When the contract is missing, write only the class/method boundary and leave the body as `pass` or the language equivalent.",
793
- "- Add TODO comments that state required input, expected output, upstream endpoint or SDK method, timeout, retry, and error mapping.",
790
+ "[Implementation]",
791
+ "- Implement external calls with the confirmed credentials, contract, timeout behavior, and failure mapping.",
794
792
  "- Services call integrations through narrow methods that describe business intent.",
795
793
  "- Convert upstream DTOs into internal DTOs before returning data to callers.",
796
- "",
797
- "[Python Skeleton]",
798
- "```python",
799
- "def request_external_job(self, request_dto: ExternalJobRequestDto) -> ExternalJobResponseDto:",
800
- ' """Request a job from the external system."""',
801
- " # TODO: define upstream endpoint, request fields, response fields, timeout, retry, and failure mapping.",
802
- " pass",
803
- "```",
794
+ "- Keep request/response schemas and integration documentation synchronized with the implementation.",
804
795
  "",
805
796
  "[Prohibited]",
806
- "- Fake API implementations.",
807
- "- Random sample data that pretends to be upstream data.",
797
+ "- Fabricated upstream responses or behavior that bypasses the confirmed contract.",
808
798
  "- Calling external HTTP or SDK code directly from controllers or UI components.",
809
799
  ]
810
- if not config.external_api_enabled:
811
- lines.extend(
812
- [
813
- "",
814
- "[When External APIs Are Added Later]",
815
- "- Update project configuration and docs before introducing the integration.",
816
- ]
817
- )
818
800
  for profile in profiles:
819
801
  lines.extend(["", f"[{profile.display_name} Integration Notes]"])
820
802
  lines.extend(self._bullets(self._profile_external_rules(profile, config.language)))
@@ -831,34 +813,15 @@ class TemplateRenderer:
831
813
  "- Third-party HTTP API 또는 SDK",
832
814
  "- 현재 저장소 프로세스 밖의 모든 시스템",
833
815
  "",
834
- "[규칙]",
835
- "- 인증 정보, 계약, timeout, 실패 매핑이 확인되지 않은 연동은 완성 구현으로 작성하지 않는다.",
836
- "- 계약이 없으면 class/method 경계만 작성하고 본문은 `pass` 또는 해당 언어의 미구현 표현으로 둔다.",
837
- "- TODO 주석에는 필요한 입력, 기대 출력, upstream endpoint 또는 SDK method, timeout, retry, error mapping을 명확히 적는다.",
816
+ "[구현 규칙]",
817
+ "- 확인된 인증 정보, 계약, timeout, 실패 매핑을 기준으로 외부 호출을 구현한다.",
838
818
  "- Service는 비즈니스 의도를 드러내는 좁은 메서드로 외부 연동을 호출한다.",
839
819
  "- Upstream DTO는 내부 DTO로 변환한 뒤 호출자에게 반환한다.",
840
- "",
841
- "[Python 뼈대]",
842
- "```python",
843
- "def request_external_job(self, request_dto: ExternalJobRequestDto) -> ExternalJobResponseDto:",
844
- ' """외부 시스템에 작업 생성을 요청한다."""',
845
- " # TODO: upstream endpoint, request field, response field, timeout, retry, failure mapping 정의 필요.",
846
- " pass",
847
- "```",
820
+ "- Request/Response schema와 연동 문서는 실제 구현과 함께 갱신한다.",
848
821
  "",
849
822
  "[금지]",
850
- "- 외부 API fake 구현",
851
- "- upstream 데이터처럼 보이는 임의 샘플 데이터 생성",
852
823
  "- controller 또는 UI component에서 외부 HTTP/SDK 직접 호출",
853
824
  ]
854
- if not config.external_api_enabled:
855
- lines.extend(
856
- [
857
- "",
858
- "[나중에 외부 API가 추가되는 경우]",
859
- "- 연동을 도입하기 전에 프로젝트 설정과 문서를 먼저 갱신한다.",
860
- ]
861
- )
862
825
  for profile in profiles:
863
826
  lines.extend(["", f"[{profile.display_name} 연동 메모]"])
864
827
  lines.extend(self._bullets(self._profile_external_rules(profile, config.language)))
@@ -1606,7 +1569,7 @@ class TemplateRenderer:
1606
1569
  " - API design",
1607
1570
  " - Service logic",
1608
1571
  " - Controller/route/UI boundary work",
1609
- " - External integration skeleton",
1572
+ " - External integration",
1610
1573
  " - Refactoring",
1611
1574
  " - Documentation",
1612
1575
  "5. Apply the `.codex` rules that match the task type before editing files.",
@@ -1620,7 +1583,7 @@ class TemplateRenderer:
1620
1583
  "- Do not invent behavior that is not defined by the request or reference documents.",
1621
1584
  "- Do not treat `.codex/ref_docs` as generated project documentation; it is a user-managed reference space.",
1622
1585
  "- Keep project specs in root `docs/`.",
1623
- "- For external integrations without a confirmed contract, write only class/method boundaries and TODOs; leave the body unimplemented.",
1586
+ "- For external integrations, implement the confirmed contract through a dedicated client/adapter and keep its documentation synchronized.",
1624
1587
  "- After code changes, update required documentation in the same task.",
1625
1588
  "",
1626
1589
  "Response behavior:",
@@ -1659,7 +1622,7 @@ class TemplateRenderer:
1659
1622
  " - API 설계",
1660
1623
  " - 서비스 로직 작성",
1661
1624
  " - 컨트롤러/라우트/UI 경계 작업",
1662
- " - 외부 연동 메서드 뼈대 작성",
1625
+ " - 외부 연동 구현",
1663
1626
  " - 리팩토링",
1664
1627
  " - 문서화",
1665
1628
  "5. 판단한 작업 유형에 맞는 `.codex` 규칙을 우선 적용하라.",
@@ -1674,7 +1637,7 @@ class TemplateRenderer:
1674
1637
  "- 요청이나 참고 문서에 없는 기능을 임의로 추가하지 않는다.",
1675
1638
  "- `.codex/ref_docs`를 생성된 프로젝트 명세 위치로 취급하지 않는다. 이 위치는 사용자 관리 참고자료 공간이다.",
1676
1639
  "- 프로젝트 명세는 프로젝트 루트의 `docs/`에 유지한다.",
1677
- "- 계약이 확인되지 않은 외부 연동은 class/method 경계와 TODO만 작성하고 본문은 미구현으로 둔다.",
1640
+ "- 외부 연동은 확인된 계약을 전용 client/adapter로 구현하고 관련 문서를 실제 동작과 함께 갱신한다.",
1678
1641
  "- 코드 수정 후 필요한 문서도 같은 작업 안에서 함께 수정한다.",
1679
1642
  "",
1680
1643
  "응답 방식도 아래를 따라라.",
@@ -1853,7 +1816,7 @@ class TemplateRenderer:
1853
1816
  "fullstack-fastapi-react": (
1854
1817
  "Backend owns private upstream integrations; frontend calls backend services only.",
1855
1818
  "Document any backend-to-upstream mapping in docs/api/specification.md when it affects public behavior.",
1856
- "Keep frontend mocks aligned with backend API contracts.",
1819
+ "Keep frontend API contract tests aligned with backend API contracts.",
1857
1820
  ),
1858
1821
  }
1859
1822
  return rules.get(profile.key, ("Keep external integrations behind framework-appropriate adapter boundaries.",))
@@ -1892,7 +1855,7 @@ class TemplateRenderer:
1892
1855
  "fullstack-fastapi-react": (
1893
1856
  "Private upstream integration은 backend가 소유하고 frontend는 backend service만 호출한다.",
1894
1857
  "공개 동작에 영향을 주는 backend-to-upstream mapping은 docs/api/specification.md에 문서화한다.",
1895
- "Frontend mock은 backend API contract와 불일치하지 않게 관리한다.",
1858
+ "Frontend API contract tests는 backend API contract와 불일치하지 않게 관리한다.",
1896
1859
  ),
1897
1860
  }
1898
1861
  return rules.get(profile.key, ("외부 연동은 framework에 맞는 adapter 경계 뒤에 둔다.",))
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: codex-rule-maker
3
- Version: 0.3.0
3
+ Version: 0.4.0
4
4
  Summary: CLI tool that generates a .codex folder with AI developer rules and project reference documents.
5
5
  Author: codex-rule-maker
6
6
  Project-URL: Homepage, https://github.com/Sharon77770/codex_rule_maker
@@ -30,6 +30,8 @@ Dynamic: license-file
30
30
 
31
31
  # codex-rule-maker
32
32
 
33
+ 현재 버전: `0.4.0`
34
+
33
35
  `codex-rule-maker`는 프로젝트 루트에 `.codex` 규칙 폴더와 `docs/` 프로젝트 문서 템플릿을 자동 구성하는 Python CLI 도구입니다. 사용자가 프로젝트 이름, 설명, 스택, DB, 인증 여부, 외부 API 여부, 문서화 수준, 문서 언어를 입력하면 Codex가 작업 전에 읽을 개발 규칙과 프로젝트 문서 구조를 생성합니다.
34
36
 
35
37
  ## 설치
@@ -225,7 +227,8 @@ docs/
225
227
  ## 지원 프레임워크 프로필
226
228
 
227
229
  - `fastapi`: 기능 폴더 하위 controller/service/repository/schema/entity 분리
228
- - `python`: 기능/도메인 폴더 하위 service/adapter/model/CLI 경계 분리
230
+ - `python`: 프레임워크 없는 Python 프로젝트의 기능/도메인 폴더 하위 service/adapter/model/CLI 경계 분리
231
+ - `typescript-javascript`: 프레임워크 없는 TypeScript/JavaScript 프로젝트의 기능/도메인 폴더 하위 service/adapter/model 경계 분리
229
232
  - `springboot`: 기능 package 하위 controller/service/repository/entity/dto 분리
230
233
  - `react`: 기능 폴더 하위 page/component/hook/service/store 분리
231
234
  - `nextjs`: App Router 유지, 기능 폴더 하위 component/service/repository/type 분리
@@ -237,6 +240,8 @@ docs/
237
240
  ```bash
238
241
  codex-init --stack fastapi,react
239
242
  codex-init --stack python
243
+ codex-init --stack typescript
244
+ codex-init --stack javascript
240
245
  codex-init --stack fullstack-fastapi-react
241
246
  codex-init --stack nextjs
242
247
  ```
@@ -247,7 +252,7 @@ codex-init --stack nextjs
247
252
  - `--language en`을 사용하면 영어 문서를 생성합니다.
248
253
  - `--docs strict`는 코드 변경 후 문서 업데이트 필수 규칙을 포함합니다.
249
254
  - `--auth yes`는 인증/권한 규칙을 포함합니다.
250
- - `--external-api yes`는 외부 연동 계층 분리 규칙을 포함합니다.
255
+ - `--external-api yes`는 확인된 계약을 기준으로 실제 외부 연동을 구현하기 위한 client/adapter 및 계약 문서 규칙을 포함합니다.
251
256
  - `--db mysql`처럼 DB를 지정하면 DB, Repository, Schema 관련 규칙을 포함합니다.
252
257
  - 프로젝트 명세 템플릿은 `.codex/ref_docs`가 아니라 `docs/architecture`, `docs/api`, `docs/database`에 생성됩니다.
253
258
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "codex-rule-maker"
7
- version = "0.3.0"
7
+ version = "0.4.0"
8
8
  description = "CLI tool that generates a .codex folder with AI developer rules and project reference documents."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.9"
@@ -72,6 +72,46 @@ def test_python_profile_generation(tmp_path):
72
72
  assert "CLI 입력은 domain/service logic에 전달하기 전에 별도 input model로 변환한다" in domain_rules
73
73
 
74
74
 
75
+ def test_typescript_javascript_profile_generation(tmp_path):
76
+ config = ProjectConfig(project_name="sample-script", stack=("typescript",))
77
+
78
+ CodexBuilder().build(config, target_dir=tmp_path)
79
+
80
+ architecture_rules = (tmp_path / ".codex" / "ai_rule_developer" / "ARCHITECTURE_RULES.md").read_text(encoding="utf-8")
81
+ service_rules = (tmp_path / ".codex" / "ai_rule_developer" / "SERVICE_LAYER_RULES.md").read_text(encoding="utf-8")
82
+
83
+ assert "TypeScript/JavaScript" in service_rules
84
+ assert "Entrypoint -> Application Service -> Domain/Adapter -> External System" in architecture_rules
85
+ assert "프레임워크 전역 객체" in service_rules
86
+
87
+
88
+ def test_spacing_rules_use_three_and_five_units(tmp_path):
89
+ config = ProjectConfig(project_name="sample-spacing")
90
+
91
+ CodexBuilder().build(config, target_dir=tmp_path)
92
+
93
+ code_style = (tmp_path / ".codex" / "ai_rule_developer" / "CODE_STYLE_RULES.md").read_text(encoding="utf-8")
94
+
95
+ assert "메서드 간 5칸 공백" in code_style
96
+ assert "로직 블록 간에는 formatter가 허용하는 범위에서 3칸 공백" in code_style
97
+ assert "2칸 공백" not in code_style
98
+
99
+
100
+ def test_external_integration_rules_do_not_defer_to_mock_or_skeleton(tmp_path):
101
+ config = ProjectConfig(project_name="sample-integration", external_api_enabled=True)
102
+
103
+ CodexBuilder().build(config, target_dir=tmp_path)
104
+
105
+ integration_rules = (tmp_path / ".codex" / "ai_rule_developer" / "EXTERNAL_INTEGRATION_RULES.md").read_text(encoding="utf-8").lower()
106
+ start_prompt = (tmp_path / ".codex" / "codex_start_prompt.txt").read_text(encoding="utf-8").lower()
107
+
108
+ assert "mock" not in integration_rules
109
+ assert "skeleton" not in integration_rules
110
+ assert "pass" not in integration_rules
111
+ assert "외부 연동 구현" in start_prompt
112
+ assert "external integration skeleton" not in start_prompt
113
+
114
+
75
115
  def test_react_profile_generation(tmp_path):
76
116
  config = ProjectConfig(project_name="sample-web", stack=("react",))
77
117
 
@@ -3,7 +3,7 @@ from __future__ import annotations
3
3
  from pathlib import Path
4
4
  from typing import Optional
5
5
 
6
- from codex_builder.cli import main
6
+ from codex_builder.cli import build_parser, main
7
7
 
8
8
 
9
9
  def test_cli_generates_with_options_only(tmp_path):
@@ -32,6 +32,14 @@ def test_cli_generates_with_options_only(tmp_path):
32
32
  assert (tmp_path / "docs" / "api" / "specification.md").exists()
33
33
 
34
34
 
35
+ def test_cli_profile_choices_include_plain_python_and_typescript_javascript():
36
+ help_text = build_parser().format_help()
37
+
38
+ assert "python (Python)" in help_text
39
+ assert "typescript-javascript" in help_text
40
+ assert "TypeScript/JavaScript" in help_text
41
+
42
+
35
43
  def test_cli_generates_python_profile(tmp_path):
36
44
  result = main(
37
45
  [