project-auto-wizard 0.3.0 → 0.3.3

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/README.md CHANGED
@@ -17,7 +17,7 @@ npx project-auto-wizard
17
17
  [![node](https://img.shields.io/badge/node-%3E%3D20.12-brightgreen)](package.json)
18
18
 
19
19
  <!-- AUTO-VERSION-SECTION: DO NOT EDIT MANUALLY -->
20
- ## 최신 버전 : v0.2.1 (2026-08-10)
20
+ ## 최신 버전 : v0.3.1 (2026-08-18)
21
21
 
22
22
  [전체 버전 기록 보기](CHANGELOG.md)
23
23
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "project-auto-wizard",
3
- "version": "0.3.0",
3
+ "version": "0.3.3",
4
4
  "description": "One command DevOps: npx wizard that installs GitHub-native AI Release Automation into any project",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -9,13 +9,15 @@
9
9
  # changelog (user API key -> GitHub Models -> rule-based fallback).
10
10
  # The prompt includes commit subjects plus a capped `git diff --stat`.
11
11
  #
12
- # Independent from PROJECT-COMMON-AUTO-CHANGELOG-CONTROL: on release
13
- # PRs both workflows may call the AI engine once each, and when
14
- # semver_auto is on, AUTO-CHANGELOG-CONTROL's bump classification may
15
- # add a third AI-assisted call to resolve an ambiguous patch->minor
16
- # escalation (up to 3 LLM calls total). This is an accepted trade-off
17
- # for simplicity GitHub Models is free-tier and rule-based fallback
18
- # is instant either way.
12
+ # On release PRs (head branch == {{DEVELOP_BRANCH}}) this job is skipped.
13
+ # PROJECT-COMMON-AUTO-CHANGELOG-CONTROL owns that case: it confirms
14
+ # the version first, then posts the AI summary itself using the
15
+ # confirmed version. Running this workflow too would post a comment
16
+ # with the pre-bump version it always checks out the head branch
17
+ # before AUTO-CHANGELOG-CONTROL's version-confirm commit lands, and
18
+ # that commit is pushed with GITHUB_TOKEN, which GitHub does not use
19
+ # to retrigger pull_request events, so there would be no later run to
20
+ # correct it.
19
21
  # ===================================================================
20
22
 
21
23
  name: PROJECT-AI-PR-SUMMARY
@@ -33,7 +35,9 @@ permissions:
33
35
  jobs:
34
36
  ai-pr-summary:
35
37
  name: Post AI summary comment
36
- if: github.event.pull_request.head.repo.full_name == github.repository
38
+ if: >-
39
+ github.event.pull_request.head.repo.full_name == github.repository &&
40
+ github.event.pull_request.head.ref != '{{DEVELOP_BRANCH}}'
37
41
  runs-on: ubuntu-latest
38
42
  steps:
39
43
  - name: Checkout PR head
@@ -17,9 +17,14 @@
17
17
  # - The AI prompt includes commit subjects plus a capped
18
18
  # `git diff --stat` (file-level change summary, no diff body)
19
19
  # for richer context without token-cost blowup.
20
- # 3. Updates CHANGELOG.json / CHANGELOG.md and commits to the PR head
20
+ # 3. Posts the same summary as a PR comment (this replaces
21
+ # PROJECT-COMMON-AI-PR-SUMMARY for release PRs, which skips them —
22
+ # that workflow would otherwise post the pre-bump version, since it
23
+ # runs before this job's version-confirm commit lands and that
24
+ # commit's GITHUB_TOKEN push doesn't retrigger pull_request events)
25
+ # 4. Updates CHANGELOG.json / CHANGELOG.md and commits to the PR head
21
26
  # branch with [skip ci]
22
- # 4. Enables automerge (gh pr merge --auto --merge)
27
+ # 5. Enables automerge (gh pr merge --auto --merge)
23
28
  #
24
29
  # The merge-commit subject carries the release-confirm pattern
25
30
  # "chore(release):" — keep in sync with PROJECT-COMMON-VERSION-CONTROL
@@ -152,6 +157,28 @@ jobs:
152
157
  # update-from-summary reads ./pr_body.md
153
158
  cp summary.md pr_body.md
154
159
 
160
+ - name: Post AI summary comment
161
+ continue-on-error: true
162
+ run: |
163
+ PR_NUMBER=${{ github.event.pull_request.number }}
164
+
165
+ {
166
+ echo "🤖 **AI Summary (project-auto-wizard)**"
167
+ echo ""
168
+ cat summary.md
169
+ } > comment_body.md
170
+
171
+ python3 -c 'import json; print(json.dumps({"body": open("comment_body.md", encoding="utf-8").read()}))' > comment_payload.json
172
+
173
+ curl -sf -H "Authorization: token ${{ github.token }}" \
174
+ -H "Content-Type: application/json" \
175
+ -X POST \
176
+ -d @comment_payload.json \
177
+ "https://api.github.com/repos/${{ github.repository }}/issues/${PR_NUMBER}/comments" > /dev/null \
178
+ || echo "comment post failed — continuing (this workflow never blocks the release)"
179
+
180
+ rm -f comment_body.md comment_payload.json
181
+
155
182
  - name: Update CHANGELOG from summary
156
183
  run: |
157
184
  # note: `grep | sed || echo default` never fires the default (the
@@ -174,7 +201,7 @@ jobs:
174
201
  VERSION="${{ steps.bump.outputs.new_version }}"
175
202
 
176
203
  # Working files must not land in the repo
177
- rm -f pr_body.md summary.md commits.txt diff_stat.txt
204
+ rm -f pr_body.md summary.md commits.txt diff_stat.txt comment_body.md comment_payload.json
178
205
 
179
206
  git add -A
180
207
 
@@ -9,7 +9,7 @@ import { detectTypes, detectVersion, detectDefaultBranch, detectRepoName, makeRe
9
9
  import { parseExisting } from "../core/version-yml.js";
10
10
  import { runBreakingCheck } from "../core/breaking-check.js";
11
11
  import { resolveProjectPaths } from "../core/paths-resolve.js";
12
- import { resolveBranchConfig, detectRemoteBranches, ensureDevelopBranch } from "../core/branches.js";
12
+ import { resolveBranchConfig, detectRemoteBranches, ensureDevelopBranch, sortBranchesForSelection } from "../core/branches.js";
13
13
  import { askAllOptionalWorkflows } from "../core/options-ask.js";
14
14
  import { promptEnvPlan } from "../ui/env-plan.js";
15
15
  import { surveyWorkflows } from "../core/copy/workflows.js";
@@ -305,13 +305,16 @@ export async function runInteractive(baseCtx, { cwd = process.cwd(), payloadRoot
305
305
  }
306
306
 
307
307
  // 브랜치 선택 — 원격 목록이 있으면 select(+직접 입력), 없으면 텍스트 입력. ESC/빈값 = 기본값.
308
- async function pickBranch(io, message, def, remoteBranches, isCancel) {
308
+ // 이슈 #85: def 최우선으로, main/develop을 그다음으로 정렬하고 커서를 def에 고정한다.
309
+ export async function pickBranch(io, message, def, remoteBranches, isCancel) {
309
310
  if (io.engineIo?.select && remoteBranches.length) {
311
+ const sorted = sortBranchesForSelection(remoteBranches, def);
310
312
  const options = [];
311
- if (!remoteBranches.includes(def)) options.push({ value: def, label: `${def} (기본값 — 없으면 새로 생성)` });
312
- for (const b of remoteBranches) options.push({ value: b, label: b === def ? `${b} (기본값)` : b });
313
+ if (!sorted.includes(def)) options.push({ value: def, label: `${def} (기본값 — 없으면 새로 생성)` });
314
+ for (const b of sorted) options.push({ value: b, label: b === def ? `${b} (기본값)` : b });
313
315
  options.push({ value: "__custom__", label: "직접 입력..." });
314
- const sel = await io.engineIo.select({ message, options });
316
+ const initialIndex = Math.max(0, options.findIndex((o) => o.value === def));
317
+ const sel = await io.engineIo.select({ message, options, initialIndex });
315
318
  if (sel === "__custom__") {
316
319
  const v = await io.askText("브랜치 이름", def);
317
320
  return isCancel(v) || !v ? def : v;
@@ -34,6 +34,16 @@ export function resolveBranchConfig({ mainBranch = "", developBranch = "", defau
34
34
  return { main, develop, mode: main === develop ? "trunk-based" : "pr-flow" };
35
35
  }
36
36
 
37
+ // 브랜치 선택 프롬프트용 정렬 (이슈 #85). def를 최우선으로, 그다음 priority(main/develop)
38
+ // 순서로 목록 앞에 배치한다. 나머지는 remoteBranches의 원래 순서(git이 준 알파벳순)를 유지한다.
39
+ // 순수 함수 — remoteBranches 원본은 변경하지 않는다.
40
+ export function sortBranchesForSelection(remoteBranches, def, priority = ["main", "develop"]) {
41
+ const priorityOrder = [def, ...priority].filter((b, i, arr) => arr.indexOf(b) === i);
42
+ const inPriority = priorityOrder.filter((b) => remoteBranches.includes(b));
43
+ const rest = remoteBranches.filter((b) => !inPriority.includes(b));
44
+ return [...inPriority, ...rest];
45
+ }
46
+
37
47
  // 생성: develop이 원격에 없으면 현 HEAD 기준으로 생성 + push.
38
48
  // confirm: async(message)→bool — 대화형 확인 질문. null이면(--force) 질문 없이 자동 생성.
39
49
  // exec 주입 가능 (테스트 mock). 반환 { created, pushed?, skipped? }.