agentic-dev 0.2.7 → 0.2.8

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 (3) hide show
  1. package/README.md +31 -113
  2. package/lib/scaffold.mjs +88 -25
  3. package/package.json +3 -3
package/README.md CHANGED
@@ -1,135 +1,53 @@
1
- # templates
1
+ # agentic-dev
2
2
 
3
- 제품으로 바로 수렴 가능한 client/server 템플릿 모음이자 downstream 저장소가 그대로 복제하는 canonical template repo다.
3
+ `agentic-dev`는 `say828`의 공개 `template-*` 레포를 설치하는 scaffold CLI다.
4
4
 
5
- 포함 템플릿:
6
-
7
- - [landing](./client/landing): 마케팅/브랜드 랜딩 패턴
8
- - [web](./client/web): 일반 제품형 웹 앱 shell, dashboard/list/detail 패턴
9
- - [mobile](./client/mobile): 다국어/현장 업무형 모바일 IN workspace 패턴
10
- - [admin](./client/admin): 운영 콘솔형 shell, sidebar/topbar/drawer/table 패턴
11
- - [server](./server): HTTP 기반 hexagonal/DDD 서버 패턴
12
-
13
- 공통 원칙:
14
-
15
- - 프론트엔드는 `pnpm workspace + React + Vite + Tailwind` 기반
16
- - `shadcn/ui-style` primitive를 직접 포함
17
- - 제품 DOM은 유지하고, 스타일 조정값은 `theme.ts` + CSS custom properties로 노출
18
- - proof/spec 전용 DOM 복제 대신 fixture data + parameter surface로 정렬
19
- - `server`는 hexagonal architecture 기준으로 `contracts + application + domain + infrastructure`를 사용
20
- - `landing`, `web`, `mobile`, `admin`은 실제 `/api/v1/auth/login`과 `/api/v1/auth/me`를 사용하는 기준 템플릿이다.
21
- - runtime baseline은 루트 `compose.yml`을 기준으로 유지하고, 여기서 4개 frontend surface, `server`, 기본 `postgres`, optional DB profile을 함께 올린다.
22
- - agentic baseline은 `.claude`, `.codex`, `.agent`를 함께 유지하고 downstream repo가 role agent, skill alias, Ralph harness를 그대로 가져가도록 설계한다.
23
- - `sdd/03_build`는 단순 구현 목록이 아니라 실제 runtime assembly를 따라 읽는 AST-style current-state 설명을 기준으로 유지한다.
24
-
25
- SDD / delivery 원칙:
26
-
27
- - 설계, 계획, 구현, 검증, 운영 문서는 모두 `sdd/`가 canonical root다.
28
- - `sdd/`는 history 누적이 아니라 current-state durable 문서만 유지한다.
29
- - `02_plan`은 에이전트의 현재 개발 계획을 관리하고, feature는 `<domain>_todos.md`, screen은 `<service>_todos.md`로 유지한다.
30
- - retained verification summary는 `sdd/03_verify`를 canonical root로 사용한다.
31
- - 템플릿 runtime baseline은 root `compose.yml` dev-focused stack이고, dedicated host용 DEV(개발계)/PROD compose overlay는 `infra/compose/`에 둔다.
32
- - current canonical delivery split은 `AWS edge/domain -> OpenStack backend compute -> AWS data plane`이다.
33
- - DEV(개발계) 반영이 필요한 작업은 `build -> main push -> DEV deploy -> DEV verify` 순서를 기본으로 사용한다.
34
-
35
- 문서:
36
-
37
- - [UI Contract Projection](./sdd/99_toolchain/01_automation/ui-contract-projection.md): 스킬/CLI 공통 projection 계약
38
- - [Infra Compose](./infra/compose/README.md): root compose baseline과 dedicated DEV(개발계)/PROD compose overlay
39
- - [Terraform Layout](./infra/terraform/README.md): provider-first canonical infra layout
40
- - [OpenStack Terraform](./infra/terraform/openstack/README.md): OpenStack compute baseline
41
- - [AST Build Governance](./sdd/02_plan/03_architecture/build_ast_runtime_tree_governance.md): `sdd/03_build` runtime-tree governance
42
-
43
- 설치형 scaffold:
5
+ ## 사용법
44
6
 
45
7
  ```bash
46
8
  npx agentic-dev
47
9
  ```
48
10
 
49
- 또는 비대화형으로:
11
+ 또는 비대화형:
50
12
 
51
13
  ```bash
52
- npx agentic-dev init my-app --template template-web
53
- npx agentic-dev init my-app --template template-web --skip-bootstrap
14
+ npx agentic-dev init my-app --template template-fullstack-mono --yes
15
+ npx agentic-dev init my-app --template template-web --yes --skip-bootstrap
54
16
  ```
55
17
 
56
- 설치 프로세스:
18
+ ## 동작
57
19
 
58
- 1. `npx agentic-dev` 또는 `npx agentic-dev init <dir>`
59
- - 프로젝트 디렉터리를 입력받는다.
60
- 2. 공개 `say828/template-*` 레포 목록에서 템플릿을 선택한다.
61
- - repo name 또는 숫자 선택을 모두 지원한다.
62
- 3. 선택한 template repo를 새 폴더로 clone/copy 한다.
63
- - `template-*` 패턴이 아닌 값은 거부한다.
20
+ 1. GitHub에서 공개 `say828/template-*` 레포 목록을 조회한다.
21
+ 2. 사용자가 프로젝트 디렉터리와 템플릿 레포를 고른다.
22
+ 3. 선택한 레포를 디렉터리로 복제한다.
64
23
  4. `.env.example`이 있으면 `.env`를 자동 생성한다.
65
- 5. `pnpm install`과 `pnpm exec playwright install chromium`을 자동 실행한다.
66
- 6. `npm run ui:parity:bootstrap`을 자동 실행한다.
67
- - `--skip-bootstrap`을 주면 단계만 건너뛴다.
68
-
69
- CLI가 하는 일:
70
-
71
- - 공개 `say828/template-*` 레포를 GitHub API로 조회한다.
72
- - 사용자 입력을 받아 template repo를 선택한다.
73
- - 선택된 repo를 target directory에 설치하고 `.env`, dependencies, Chromium, bootstrap까지 자동 처리한다.
74
- - invalid repo name이나 `template-*`가 아닌 값은 즉시 거부한다.
75
- - `--skip-bootstrap`을 주면 설치까지만 하고 bootstrap은 멈춘다.
24
+ 5. `pnpm install`을 자동 실행한다.
25
+ 6. 템플릿의 `repo-contract.json`에서 `frontend.default_target`을 읽는다.
26
+ 7. target에 대해 `playwright install chromium`을 실행한다.
27
+ 8. 그 target에 대해 parity bootstrap을 실행한다.
76
28
 
77
- Parity 명령:
29
+ `frontend.default_target`이 있으면 multi-surface 템플릿도 그대로 지원한다. 예를 들어 `template-fullstack-mono`는 `client/web`과 `client/admin`을 함께 포함하지만 기본 bootstrap 대상은 `web`이다.
78
30
 
79
- - `npm run ui:parity:init`
80
- - repo contract alias, parity contract, route-gap 산출물을 초기화한다.
81
- - `npm run ui:parity:bootstrap`
82
- - `init -> build -> preview -> materialize reference -> plan_audit gate -> proof gate`를 한 번에 실행한다.
83
- - `npm run ui:parity:proof`
84
- - 기존 parity contract를 기준으로 proof만 다시 실행한다.
85
-
86
- 주요 parity 산출물:
87
-
88
- - contract: `sdd/02_plan/10_test/templates/ui_parity_web_contract.yaml`
89
- - route-gap report: `sdd/02_plan/99_generated/from_planning/ui_parity/`
90
- - verification summary: `sdd/03_verify/10_test/ui_parity/`
91
- - preview log: `sdd/03_verify/10_test/ui_parity/web-preview.log`
92
-
93
- GitHub token 운영:
94
-
95
- - 실제 token 값은 repo 파일에 저장하지 않는다.
96
- - GitHub CLI나 자동화는 `GH_TOKEN` 또는 별도 wrapper가 있다면 `AGENTIC_GITHUB_TOKEN` 같은 환경변수에서 읽도록 운영한다.
97
- - 이미 대화나 로그에 노출된 token은 재사용하지 않고 즉시 폐기 후 새로 발급하는 것이 맞다.
98
-
99
-
100
- 개발용 compose baseline:
31
+ ## 예시
101
32
 
102
33
  ```bash
103
- cp .env.example .env
104
- docker compose up --build
34
+ mkdir my-fullstack-app
35
+ cd my-fullstack-app
36
+ npx agentic-dev init . --template template-fullstack-mono --yes
105
37
  ```
106
38
 
107
- 기본 compose 포트:
108
-
109
- - `client/landing`: `3000`
110
- - `client/web`: `3001`
111
- - `client/mobile`: `3002`
112
- - `client/admin`: `4000`
113
- - `server/http`: `8000`
114
-
115
- 기본 로그인 계정:
116
-
117
- - `admin@example.com` / `<CHANGE_ME>`
118
- - `operator@example.com` / `<CHANGE_ME>`
119
-
120
- DB adapter 전환:
39
+ 설치가 끝나면 CLI가 아래까지 자동 처리한다.
121
40
 
122
- - 기본: `SERVER_DATABASE_BACKEND=postgres`
123
- - 선택 가능: `postgres`, `mysql`, `mariadb`, `mongodb`, `memory`
124
- - optional DB 컨테이너는 compose profile로 포함돼 있다:
125
- - `docker compose --profile mysql up --build`
126
- - `docker compose --profile mariadb up --build`
127
- - `docker compose --profile mongo up --build`
41
+ - `.env.example -> .env`
42
+ - `pnpm install`
43
+ - `pnpm --dir client/web exec playwright install chromium`
44
+ - `bash sdd/99_toolchain/01_automation/agentic-dev/bootstrap_frontend_parity.sh . web`
128
45
 
129
- Agentic baseline:
46
+ ## 옵션
130
47
 
131
- - `.claude/agents/`: Claude role agent prompt surface
132
- - `.claude/skills/sdd`: Claude SDD canonical skill
133
- - `.codex/skills/SKILL.md`: Codex root skill index
134
- - `.codex/skills/sdd/`: Codex SDD canonical skill
135
- - `.agent/ralph.sh`, `.agent/ralph-supervisor.sh`: bounded Ralph loop runner
48
+ - `--template`, `-t`: template repo name 또는 suffix
49
+ - `--owner`: GitHub owner. 기본값 `say828`
50
+ - `--force`: 비어 있지 않은 디렉터리 허용
51
+ - `--yes`, `-y`: interactive prompt 생략
52
+ - `--skip-bootstrap`: install까지만 하고 bootstrap은 생략
53
+ - `--help`, `-h`: 도움말 출력
package/lib/scaffold.mjs CHANGED
@@ -255,6 +255,57 @@ function detectClientSurfaces(destinationRoot) {
255
255
  .sort();
256
256
  }
257
257
 
258
+ function repoContractPath(destinationRoot) {
259
+ return path.join(
260
+ destinationRoot,
261
+ "sdd/99_toolchain/01_automation/agentic-dev/repo-contract.json",
262
+ );
263
+ }
264
+
265
+ function readJsonFile(filePath) {
266
+ if (!fs.existsSync(filePath)) {
267
+ return null;
268
+ }
269
+
270
+ try {
271
+ return JSON.parse(fs.readFileSync(filePath, "utf-8"));
272
+ } catch (error) {
273
+ throw new Error(`Failed to parse JSON file: ${filePath}`);
274
+ }
275
+ }
276
+
277
+ function resolveBootstrapTarget(destinationRoot) {
278
+ const contract = readJsonFile(repoContractPath(destinationRoot));
279
+ const defaultTargetName = contract?.frontend?.default_target;
280
+ const targetConfig =
281
+ typeof defaultTargetName === "string"
282
+ ? contract?.frontend?.targets?.[defaultTargetName]
283
+ : null;
284
+
285
+ if (typeof targetConfig?.dir === "string" && targetConfig.dir.length > 0) {
286
+ return {
287
+ name: defaultTargetName,
288
+ dir: targetConfig.dir,
289
+ };
290
+ }
291
+
292
+ const clientSurfaces = detectClientSurfaces(destinationRoot);
293
+ if (clientSurfaces.length === 1) {
294
+ return {
295
+ name: clientSurfaces[0],
296
+ dir: path.join("client", clientSurfaces[0]),
297
+ };
298
+ }
299
+
300
+ if (clientSurfaces.length > 1) {
301
+ throw new Error(
302
+ "Template repo has multiple client surfaces. Add frontend.default_target to sdd/99_toolchain/01_automation/agentic-dev/repo-contract.json.",
303
+ );
304
+ }
305
+
306
+ return null;
307
+ }
308
+
258
309
  function validateTemplateRepoContents(destinationRoot, templateRepo) {
259
310
  const requiredPaths = [
260
311
  ".env.example",
@@ -272,13 +323,8 @@ function validateTemplateRepoContents(destinationRoot, templateRepo) {
272
323
  }
273
324
  }
274
325
 
275
- function runInstallSteps(destinationRoot) {
326
+ function runInstallSteps(destinationRoot, bootstrapTarget) {
276
327
  maybeCreateEnvFile(destinationRoot);
277
- const clientSurfaces = detectClientSurfaces(destinationRoot);
278
- if (clientSurfaces.length !== 1) {
279
- throw new Error(`Expected exactly one client surface in template repo, found ${clientSurfaces.length}.`);
280
- }
281
- const clientDir = path.join("client", clientSurfaces[0]);
282
328
 
283
329
  const pnpmCommand = ensurePnpm();
284
330
  runCommand(pnpmCommand[0], [...pnpmCommand.slice(1), "install"], {
@@ -286,19 +332,32 @@ function runInstallSteps(destinationRoot) {
286
332
  label: "Installing workspace dependencies",
287
333
  });
288
334
 
289
- runCommand(
290
- pnpmCommand[0],
291
- [...pnpmCommand.slice(1), "--dir", clientDir, "exec", "playwright", "install", "chromium"],
292
- {
293
- cwd: destinationRoot,
294
- label: "Installing Playwright Chromium",
295
- },
296
- );
335
+ const executedSteps = ["pnpm install"];
336
+
337
+ if (bootstrapTarget) {
338
+ runCommand(
339
+ pnpmCommand[0],
340
+ [
341
+ ...pnpmCommand.slice(1),
342
+ "--dir",
343
+ bootstrapTarget.dir,
344
+ "exec",
345
+ "playwright",
346
+ "install",
347
+ "chromium",
348
+ ],
349
+ {
350
+ cwd: destinationRoot,
351
+ label: `Installing Playwright Chromium for ${bootstrapTarget.name}`,
352
+ },
353
+ );
354
+ executedSteps.push(`pnpm --dir ${bootstrapTarget.dir} exec playwright install chromium`);
355
+ }
297
356
 
298
- return ["pnpm install", "pnpm exec playwright install chromium"];
357
+ return executedSteps;
299
358
  }
300
359
 
301
- function runBootstrapStep(destinationRoot) {
360
+ function runBootstrapStep(destinationRoot, bootstrapTarget) {
302
361
  const bootstrapScript = bootstrapScriptPath(destinationRoot);
303
362
  if (!fs.existsSync(bootstrapScript)) {
304
363
  throw new Error(
@@ -306,12 +365,17 @@ function runBootstrapStep(destinationRoot) {
306
365
  );
307
366
  }
308
367
 
309
- runCommand("bash", [bootstrapScript, "."], {
368
+ const args = [bootstrapScript, "."];
369
+ if (bootstrapTarget?.name) {
370
+ args.push(bootstrapTarget.name);
371
+ }
372
+
373
+ runCommand("bash", args, {
310
374
  cwd: destinationRoot,
311
375
  label: "Running frontend parity bootstrap",
312
376
  });
313
377
 
314
- return ["bootstrap_frontend_parity.sh ."];
378
+ return [bootstrapTarget?.name ? `bootstrap_frontend_parity.sh . ${bootstrapTarget.name}` : "bootstrap_frontend_parity.sh ."];
315
379
  }
316
380
 
317
381
  export function scaffoldFromTemplateRepo({ destinationRoot, templateRepo }) {
@@ -335,16 +399,15 @@ export function installTemplateRepo({
335
399
  }) {
336
400
  scaffoldFromTemplateRepo({ destinationRoot, templateRepo });
337
401
  validateTemplateRepoContents(destinationRoot, templateRepo);
402
+ const bootstrapTarget = resolveBootstrapTarget(destinationRoot);
338
403
 
339
- const executedSteps = runInstallSteps(destinationRoot);
404
+ const executedSteps = runInstallSteps(destinationRoot, bootstrapTarget);
340
405
  if (!skipBootstrap) {
341
- executedSteps.push(...runBootstrapStep(destinationRoot));
406
+ executedSteps.push(...runBootstrapStep(destinationRoot, bootstrapTarget));
342
407
  }
343
- const clientSurfaces = detectClientSurfaces(destinationRoot);
344
- const bootstrapHint =
345
- clientSurfaces.length === 1
346
- ? `cd client/${clientSurfaces[0]} && npm run ui:parity:bootstrap`
347
- : "npm run ui:parity:bootstrap";
408
+ const bootstrapHint = bootstrapTarget
409
+ ? `cd ${bootstrapTarget.dir} && npm run ui:parity:bootstrap`
410
+ : "bash sdd/99_toolchain/01_automation/agentic-dev/bootstrap_frontend_parity.sh .";
348
411
  return {
349
412
  destinationRoot,
350
413
  templateRepo: templateRepo.name,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "agentic-dev",
3
- "version": "0.2.7",
4
- "description": "Scaffold an agentic template repo with the selected frontend surface and shared toolchain assets.",
3
+ "version": "0.2.8",
4
+ "description": "Scaffold a public say828/template-* repo and run install/bootstrap automatically.",
5
5
  "type": "module",
6
6
  "packageManager": "pnpm@10.32.0",
7
7
  "bin": {
@@ -28,7 +28,7 @@
28
28
  "pnpm-workspace.yaml"
29
29
  ],
30
30
  "scripts": {
31
- "smoke:init": "node ./bin/agentic-dev.mjs init ./.tmp-agentic-smoke --template template-web --yes --force"
31
+ "smoke:init": "node ./bin/agentic-dev.mjs init ./.tmp-agentic-smoke --template template-fullstack-mono --yes --force"
32
32
  },
33
33
  "keywords": [
34
34
  "agentic",