@byh3071/vhk 2.3.2 → 2.4.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.
@@ -874,7 +874,10 @@ var ko = {
874
874
  testFailed: "\uD14C\uC2A4\uD2B8 \uC2E4\uD328",
875
875
  publishing: "npm \uBC30\uD3EC \uC911...",
876
876
  publishSuccess: "npm \uBC30\uD3EC \uC131\uACF5!",
877
- publishFailed: "npm \uBC30\uD3EC \uC2E4\uD328"
877
+ publishFailed: "npm \uBC30\uD3EC \uC2E4\uD328",
878
+ // 발행 전 안전 가드 — feature 브랜치/미커밋 발행로 픽스 누락본이 latest 로 나가는 사고 방지(v2.3.1 사례)
879
+ preflightWrongBranch: (branch, def) => `\uBC1C\uD589 \uC911\uB2E8 \u2014 \uD604\uC7AC '${branch}' \uBE0C\uB79C\uCE58\uC785\uB2C8\uB2E4. \uBC1C\uD589\uC740 '${def}' \uC5D0\uC11C\uB9CC \uD558\uC138\uC694 (feature \uBE0C\uB79C\uCE58 \uBC1C\uD589 \u2192 \uD53D\uC2A4 \uB204\uB77D\uBCF8\uC774 npm latest \uB85C \uB098\uAC00\uB294 \uC0AC\uACE0 \uBC29\uC9C0). git checkout ${def} && git pull \uD6C4 \uC7AC\uC2DC\uB3C4.`,
880
+ preflightDirty: "\uBC1C\uD589 \uC911\uB2E8 \u2014 \uCEE4\uBC0B \uC548 \uB41C \uBCC0\uACBD\uC774 \uC788\uC2B5\uB2C8\uB2E4. \uBC1C\uD589 \uC804 \uCEE4\uBC0B/\uC815\uB9AC\uD558\uC138\uC694 (untracked \uD30C\uC77C\uC740 \uBB34\uC2DC)."
878
881
  },
879
882
  harness: {
880
883
  title: "\uD1B5\uD569 \uD488\uC9C8 \uC810\uAC80"
@@ -919,6 +922,10 @@ var ko = {
919
922
  learnTitle: "\u{1F9E0} Learning \uAE30\uB85D",
920
923
  resumeTitle: "\u25B6\uFE0F HARD_STOP \uD574\uC81C"
921
924
  },
925
+ work: {
926
+ workTitle: "\u{1F680} vhk work \u2014 \uC791\uC5C5 \uC2DC\uC791/\uC774\uC5B4\uD558\uAE30",
927
+ handoffTitle: "\u23F8\uFE0F vhk work handoff \u2014 \uC911\uB2E8 \uC815\uB9AC"
928
+ },
922
929
  pattern: {
923
930
  detectTitle: "\uD328\uD134 \uAC10\uC9C0",
924
931
  listTitle: "\uD328\uD134 \uBAA9\uB85D",
@@ -1949,7 +1956,7 @@ async function envCheck() {
1949
1956
  }
1950
1957
 
1951
1958
  // src/commands/publish.ts
1952
- import { existsSync as existsSync4, writeFileSync as writeFileSync2 } from "fs";
1959
+ import { existsSync as existsSync4, readFileSync as readFileSync4, writeFileSync as writeFileSync2 } from "fs";
1953
1960
  import chalk6 from "chalk";
1954
1961
  import inquirer3 from "inquirer";
1955
1962
  import ora from "ora";
@@ -1976,8 +1983,26 @@ function bumpVersion(current, type) {
1976
1983
  return `${major}.${minor}.${patch + 1}`;
1977
1984
  }
1978
1985
  }
1986
+ function insertChangelogStub(content, version, date) {
1987
+ const escaped = version.replace(/\./g, "\\.");
1988
+ if (new RegExp(`^## \\[${escaped}\\]`, "m").test(content)) return content;
1989
+ const stub = `## [${version}] - ${date}
1990
+
1991
+ _\uBCC0\uACBD \uB0B4\uC5ED \uC791\uC131 \uD544\uC694._
1992
+
1993
+ `;
1994
+ const firstEntry = content.match(/^## \[\d+\.\d+\.\d+\]/m);
1995
+ if (firstEntry && firstEntry.index !== void 0) {
1996
+ return content.slice(0, firstEntry.index) + stub + content.slice(firstEntry.index);
1997
+ }
1998
+ return content.trimEnd() + "\n\n" + stub;
1999
+ }
2000
+ function bumpClaudeMdVersion(content, newVersion) {
2001
+ return content.replace(/(\*\*버전:\*\*\s*v)\d+\.\d+\.\d+/, `$1${newVersion}`);
2002
+ }
1979
2003
  function gitPostRelease(newVersion) {
1980
- const add = safeExecFile("git", ["add", "package.json"]);
2004
+ const filesToAdd = existsSync4("CHANGELOG.md") ? ["package.json", "CHANGELOG.md"] : ["package.json"];
2005
+ const add = safeExecFile("git", ["add", ...filesToAdd]);
1981
2006
  if (!add.ok) {
1982
2007
  return {
1983
2008
  added: false,
@@ -2018,9 +2043,30 @@ function gitPostRelease(newVersion) {
2018
2043
  pushed: push.ok && pushTags.ok
2019
2044
  };
2020
2045
  }
2046
+ function evaluatePublishPreflight(branch, trackedStatus, defaultBranch) {
2047
+ if (branch !== defaultBranch) return { ok: false, code: "wrong-branch" };
2048
+ if (trackedStatus.trim()) return { ok: false, code: "dirty" };
2049
+ return { ok: true };
2050
+ }
2051
+ function publishPreflight() {
2052
+ const br = safeExecFile("git", ["branch", "--show-current"]);
2053
+ const branch = br.ok ? br.out.trim() : "";
2054
+ const head = safeExecFile("git", ["symbolic-ref", "--short", "refs/remotes/origin/HEAD"]);
2055
+ const defaultBranch = head.ok ? head.out.trim().split("/").pop() || "main" : "main";
2056
+ const st = safeExecFile("git", ["status", "--porcelain", "--untracked-files=no"]);
2057
+ const trackedStatus = st.ok ? st.out : "";
2058
+ return { ...evaluatePublishPreflight(branch, trackedStatus, defaultBranch), branch, defaultBranch };
2059
+ }
2021
2060
  async function publish() {
2022
2061
  console.log(chalk6.bold("\n\u{1F4E6} " + t("publish.title")));
2023
2062
  console.log(chalk6.gray("\u2500".repeat(40)));
2063
+ const pre = publishPreflight();
2064
+ if (!pre.ok) {
2065
+ const msg = pre.code === "wrong-branch" ? t("publish.preflightWrongBranch", pre.branch || "(detached)", pre.defaultBranch) : t("publish.preflightDirty");
2066
+ console.log(chalk6.red(`
2067
+ \u274C ${msg}`));
2068
+ return;
2069
+ }
2024
2070
  if (!existsSync4("package.json")) {
2025
2071
  console.log(chalk6.red("\u274C package.json\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4."));
2026
2072
  return;
@@ -2053,13 +2099,25 @@ async function publish() {
2053
2099
  pkg.version = newVersion;
2054
2100
  writeFileSync2("package.json", JSON.stringify(pkg, null, 2) + "\n", "utf-8");
2055
2101
  console.log(chalk6.green("\u2705 package.json \uBC84\uC804 \uC5C5\uB370\uC774\uD2B8"));
2102
+ const claudeMdOriginal = existsSync4("CLAUDE.md") ? readFileSync4("CLAUDE.md", "utf-8") : null;
2103
+ if (claudeMdOriginal !== null) {
2104
+ const bumped = bumpClaudeMdVersion(claudeMdOriginal, newVersion);
2105
+ if (bumped !== claudeMdOriginal) {
2106
+ writeFileSync2("CLAUDE.md", bumped, "utf-8");
2107
+ console.log(chalk6.green("\u2705 CLAUDE.md \uBC84\uC804\uC904 \uB3D9\uAE30\uD654"));
2108
+ }
2109
+ }
2110
+ const rollbackVersion = () => {
2111
+ pkg.version = currentVersion;
2112
+ writeFileSync2("package.json", JSON.stringify(pkg, null, 2) + "\n", "utf-8");
2113
+ if (claudeMdOriginal !== null) writeFileSync2("CLAUDE.md", claudeMdOriginal, "utf-8");
2114
+ };
2056
2115
  const buildSpinner = ora(t("publish.building")).start();
2057
2116
  const buildResult = safeExecFile("pnpm", ["build"]);
2058
2117
  if (!buildResult.ok) {
2059
2118
  buildSpinner.fail(t("publish.buildFailed"));
2060
2119
  console.log(chalk6.red(buildResult.err.slice(0, 500)));
2061
- pkg.version = currentVersion;
2062
- writeFileSync2("package.json", JSON.stringify(pkg, null, 2) + "\n", "utf-8");
2120
+ rollbackVersion();
2063
2121
  return;
2064
2122
  }
2065
2123
  buildSpinner.succeed(t("publish.buildSuccess"));
@@ -2068,8 +2126,7 @@ async function publish() {
2068
2126
  if (!testResult.ok) {
2069
2127
  testSpinner.fail(t("publish.testFailed"));
2070
2128
  console.log(chalk6.red(testResult.err.slice(0, 500)));
2071
- pkg.version = currentVersion;
2072
- writeFileSync2("package.json", JSON.stringify(pkg, null, 2) + "\n", "utf-8");
2129
+ rollbackVersion();
2073
2130
  return;
2074
2131
  }
2075
2132
  testSpinner.succeed(t("publish.testSuccess"));
@@ -2082,8 +2139,7 @@ async function publish() {
2082
2139
  }
2083
2140
  ]);
2084
2141
  if (!confirm) {
2085
- pkg.version = currentVersion;
2086
- writeFileSync2("package.json", JSON.stringify(pkg, null, 2) + "\n", "utf-8");
2142
+ rollbackVersion();
2087
2143
  console.log(chalk6.gray("\uCDE8\uC18C\uB428. \uBC84\uC804\uC774 \uC6D0\uB798\uB300\uB85C \uBCF5\uAD6C\uB429\uB2C8\uB2E4."));
2088
2144
  return;
2089
2145
  }
@@ -2095,13 +2151,21 @@ async function publish() {
2095
2151
  console.log(chalk6.red(`
2096
2152
  \u2716 ${t("publish.publishFailed")}`));
2097
2153
  console.log(chalk6.red(pubResult.err.slice(0, 500)));
2098
- pkg.version = currentVersion;
2099
- writeFileSync2("package.json", JSON.stringify(pkg, null, 2) + "\n", "utf-8");
2154
+ rollbackVersion();
2100
2155
  console.log(chalk6.gray(`\u{1F4E6} package.json \uBC84\uC804\uC744 v${currentVersion}\uB85C \uBCF5\uAD6C\uD588\uC2B5\uB2C8\uB2E4.`));
2101
2156
  return;
2102
2157
  }
2103
2158
  console.log(chalk6.green(`
2104
2159
  \u2714 ${t("publish.publishSuccess")}`));
2160
+ if (existsSync4("CHANGELOG.md")) {
2161
+ const cl = readFileSync4("CHANGELOG.md", "utf-8");
2162
+ const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
2163
+ const updated = insertChangelogStub(cl, newVersion, date);
2164
+ if (updated !== cl) {
2165
+ writeFileSync2("CHANGELOG.md", updated, "utf-8");
2166
+ console.log(chalk6.green(`\u2705 CHANGELOG.md \uC5D0 [${newVersion}] \uC2A4\uD141 \uCD94\uAC00 \u2014 \uBCF8\uBB38 \uBCF4\uAC15 \uD544\uC694`));
2167
+ }
2168
+ }
2105
2169
  const git = gitPostRelease(newVersion);
2106
2170
  if (git.warning) {
2107
2171
  console.log(chalk6.yellow(`