projectops 4.49.0 → 4.51.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/README.md CHANGED
@@ -11,7 +11,7 @@
11
11
  **Status: actively maintained.** npm `latest` is exactly what is on the `main` branch; work in progress on `develop` is never published. Versions can still ship several times a day. To stay on a version you have tested, run `npx projectops@<version>` ([releases](https://github.com/Cassiiopeia/projectops/releases)).
12
12
 
13
13
  <!-- AUTO-VERSION-SECTION: DO NOT EDIT MANUALLY -->
14
- ## Latest version : v4.48.1 (2026-10-12)
14
+ ## Latest version : v4.50.0 (2026-10-15)
15
15
 
16
16
  [View full version history](CHANGELOG.md)
17
17
 
@@ -183,7 +183,7 @@ What it changed: descriptions were cut to short English triggers, a shared contr
183
183
  | `/pro-ssh` | Connect to a remote server over SSH and run commands (AWS EC2, Synology NAS, Linux, and more) |
184
184
  | `/pro-skill-creator` | Create, review, and improve a Skill (CREATE / REVIEW / IMPROVE modes) |
185
185
 
186
- **Extras** (optional plugin): `/pro-synology-expose` — `claude plugin install projectops-extras@projectops-marketplace --scope user`
186
+ **Extras** (optional plugin): `/pro-architecture-consult` (keep AI-written code maintainable: audit, refactor one item at a time, check each diff, freeze violations), `/pro-synology-expose` — `claude plugin install projectops-extras@projectops-marketplace --scope user`
187
187
 
188
188
  </details>
189
189
 
package/bin/projectops.js CHANGED
@@ -15,4 +15,6 @@ const indexPath = join(here, "..", "src", "index.js");
15
15
  const { run } = await import(pathToFileURL(indexPath).href);
16
16
 
17
17
  const code = await run(process.argv.slice(2), { cwd: process.cwd() });
18
- process.exit(code);
18
+ // stdout 이 파이프면 쓰기가 비동기라, 바로 exit 하면 큰 출력(--mode options --json)이 8KB 근처에서 잘린다.
19
+ // 빈 write 의 콜백은 앞선 쓰기가 모두 넘겨진 뒤에 불리므로, 거기서 종료한다.
20
+ process.stdout.write("", () => process.exit(code));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "projectops",
3
- "version": "4.49.0",
3
+ "version": "4.51.0",
4
4
  "description": "ProjectOps: installer CLI for a fully automated GitHub project management template (versioning, CI/CD, release notes, agent skills)",
5
5
  "keywords": [
6
6
  "devops",
@@ -154,7 +154,7 @@ export function localChecks(cwd = ".") {
154
154
  }
155
155
 
156
156
  // 은퇴한 구세대 워크플로우 (#809) — 업데이트는 감지만 하고 남겨 두므로 신형과 함께 돈다.
157
- // 예전엔 로그에만 남아 doctor 가 "문제 없음"이라 했다.
157
+ // 로그에만 남기면 doctor 가 "문제 없음"으로 보고하므로 여기서 잡는다.
158
158
  const legacy = detectMigrations(cwd).confirm;
159
159
  add({
160
160
  name: t("doctor.legacy.name"), purpose: t("doctor.legacy.purpose"),
@@ -235,7 +235,7 @@ export async function askAllOptionalWorkflows({
235
235
  if (force || !tty || typeof io.select !== "function") {
236
236
  // 비대화형: CLI intent 미지정이면 deploy/publish에서 역추론, 그래도 없으면 manual(기존 동작)
237
237
  // 축이 아직 안 정해졌으면 비대화형(resolve-options.js)과 같은 기본 축으로 추론한다 (#851).
238
- // 예전에는 null 로 추론해 "manual" 이 기록되어 같은 레포에서 두 경로의 결과가 갈렸다.
238
+ // null 로 추론하면 "manual" 이 기록되어 같은 레포에서 두 경로의 결과가 갈린다.
239
239
  const defaultDeploy = applicable.deploy.includes("docker-ssh") ? "docker-ssh" : "none";
240
240
  intent = intent ?? inferIntent(deploy ?? defaultDeploy, publish ?? []) ?? "manual";
241
241
  } else {
@@ -1,8 +1,8 @@
1
1
  // 설치 옵션 값을 정하는 단 한 곳 (#851).
2
2
  //
3
- // 예전에는 비대화형(src/index.js)과 대화형(src/commands/interactive.js)이 같은 옵션을
4
- // 각자 정했다. 그 사이 규칙이 갈라져 대화형에서 PR 요약 선택이 버려지고(aiPrSummary),
5
- // 질문을 건너뛰는 version 모드가 모바일 단독 레포에 deploy: docker-ssh 를 남겼다.
3
+ // 비대화형(src/index.js)과 대화형(src/commands/interactive.js)이 같은 결과를 쓴다.
4
+ // 각자 정하면 규칙이 갈라진다: 대화형 PR 요약 선택 유실(aiPrSummary),
5
+ // 질문을 건너뛰는 version 모드가 모바일 단독 레포에 deploy: docker-ssh 를 남김.
6
6
  // 규칙은 모든 옵션에 같다: CLI 플래그 > version.yml 저장값 > 기본값.
7
7
  // 대화형은 이 결과를 초기값으로 쓰고, 사용자가 답한 것만 그 위에 덮어쓴다.
8
8
  import { existsSync } from "node:fs";
@@ -7,7 +7,7 @@ import { DEPLOY_TARGETS, LABEL_STYLES } from "./constants.js";
7
7
  import { REPO_LANGUAGES } from "./repo-language.js";
8
8
 
9
9
  // 값 목록으로 만든 매칭 패턴 — 목록에 언어·표기를 추가하면 파서가 저절로 읽는다.
10
- // (예전엔 `(en|ko)` 가 박혀 있어 세 번째 언어를 저장하면 다음 업데이트에서 못 읽고 ko 로 되돌아갔다.)
10
+ // (언어를 패턴에 박아 두면 새 언어를 저장한 뒤 다음 업데이트에서 못 읽고 ko 로 되돌아간다.)
11
11
  const alt = (values) => values.map((v) => v.replace(/[.*+?^${}()|[\]\\-]/g, "\\$&")).join("|");
12
12
  const LANGUAGE_RE = new RegExp(`^\\s+language:\\s*["']?(${alt(REPO_LANGUAGES)})["']?`);
13
13
  const LABEL_STYLE_RE = new RegExp(`^\\s+label_style:\\s*["']?(${alt(LABEL_STYLES)})["']?`);
@@ -140,7 +140,7 @@ const COMMENTS = {
140
140
  const commentsFor = (lang) => COMMENTS[lang === "ko" ? "ko" : "en"];
141
141
 
142
142
  // last_updated_by 결정 (#811): 실행한 git 사용자 → 기존 값 → template_integrator.
143
- // 예전엔 업데이트마다 "template_integrator"로 덮어써 누가 바꿨는지가 사라졌다.
143
+ // 매번 "template_integrator"로 덮어쓰면 누가 바꿨는지가 사라진다.
144
144
  export function resolveUpdatedBy(existingContent = "", cwd = ".") {
145
145
  try {
146
146
  const name = execFileSync("git", ["config", "user.name"],
@@ -1,7 +1,7 @@
1
1
  // 선택형 워크플로 그룹의 켜짐/꺼짐을 정하는 단 한 곳 (#851).
2
2
  //
3
- // 예전에는 복사(copy/workflows.js), 충돌 목록(listWorkflowConflicts), 고아 감지(orphan-workflows.js)가
4
- // 같은 조건을 각자 들고 있었다. 한쪽만 고치면 "켰는데 안 깔림" 또는 "껐는데 계속 돎"이 된다 (#567).
3
+ // 복사(copy/workflows.js), 충돌 목록(listWorkflowConflicts), 고아 감지(orphan-workflows.js)가 같은 조건을 쓴다.
4
+ // 각자 들고 있으면 한쪽만 고쳐 "켰는데 안 깔림" 또는 "껐는데 계속 돎"이 된다 (#567).
5
5
  // 새 조건부 폴더를 만들면 여기에 한 줄을 넣는다. 세 곳이 함께 따라온다.
6
6
  import { readdirSync } from "node:fs";
7
7
  import { join } from "node:path";