projectops 4.77.3 → 4.78.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.77.2 (2026-10-28)
14
+ ## Latest version : v4.77.4 (2026-10-29)
15
15
 
16
16
  [View full version history](CHANGELOG.md)
17
17
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "projectops",
3
- "version": "4.77.3",
3
+ "version": "4.78.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",
@@ -8,6 +8,7 @@ import { existsSync, readFileSync } from "node:fs";
8
8
  import { PATHS } from "../core/paths.js";
9
9
  import { remove } from "../core/fsutil.js";
10
10
  import { acquireTemplate, readTemplateVersion } from "../core/assets.js";
11
+ import { SHARED_SCRIPTS_DIR_NAME } from "../core/ide/skills-copy.js";
11
12
  import { detectTypes, detectVersion, detectDefaultBranch, detectRepoName, makeResolvers } from "../core/detect-fs.js";
12
13
  import { parseExisting } from "../core/version-yml.js";
13
14
  import { runBreakingCheck } from "../core/breaking-check.js";
@@ -54,7 +55,8 @@ export async function runInteractive(baseCtx, { cwd = process.cwd(), source = {
54
55
  if (io === prompts) trace.mirrorStart();
55
56
  try {
56
57
  // 템플릿 먼저 획득 — 배너에 실제 템플릿 버전을 표시
57
- trace.step("acquire-template", () => acquireTemplate({ tempDir, source }), { source: source?.type || "git" });
58
+ // 대화형도 끝에 스킬 설치·업데이트 > scripts/common 유지 (#994)
59
+ trace.step("acquire-template", () => acquireTemplate({ tempDir, source, keep: [SHARED_SCRIPTS_DIR_NAME] }), { source: source?.type || "git" });
58
60
  const templateVersion = readTemplateVersion(tempDir);
59
61
  traceTo = templateVersion;
60
62
 
@@ -12,9 +12,10 @@ import { TEMPLATE_REPO } from "./paths.js";
12
12
  // {type:'git', repo?} → git clone --depth 1 (기본 repo=TEMPLATE_REPO)
13
13
  // {type:'local', path} → 로컬 트리 복사 (네트워크 없는 등가 검증용)
14
14
  // 이미 tempDir/.github 있으면 스킵(중복 호출 방지). 획득 후 applyExclusions 자동 호출.
15
- export function acquireTemplate({ tempDir, source = { type: "git" } }) {
15
+ // keep: 제외 목록 중 남길 항목 (스킬 설치 경로: scripts/common 필요 > ["scripts"], #994)
16
+ export function acquireTemplate({ tempDir, source = { type: "git" }, keep = [] }) {
16
17
  if (exists(join(tempDir, ".github"))) {
17
- applyExclusions(tempDir);
18
+ applyExclusions(tempDir, { keep });
18
19
  return;
19
20
  }
20
21
  remove(tempDir);
@@ -27,13 +28,15 @@ export function acquireTemplate({ tempDir, source = { type: "git" } }) {
27
28
  mkdirSync(tempDir, { recursive: true });
28
29
  execFileSync("git", ["clone", "--depth", "1", "--quiet", repo, tempDir], { stdio: "ignore" });
29
30
  }
30
- applyExclusions(tempDir);
31
+ applyExclusions(tempDir, { keep });
31
32
  }
32
33
 
33
- // DOCS_TO_REMOVE + PLUGIN_ITEMS_TO_REMOVE 삭제. skills/ 는 보존.
34
- export function applyExclusions(tempDir) {
34
+ // DOCS_TO_REMOVE + PLUGIN_ITEMS_TO_REMOVE 삭제 (keep 항목 제외). skills/ 는 보존.
35
+ // 통합 복사는 .github 등 명시 경로만 읽음 > tempDir 에 남긴 scripts/ 는 사용자 레포로 안 감
36
+ export function applyExclusions(tempDir, { keep = [] } = {}) {
37
+ const keptItems = new Set(keep);
35
38
  for (const doc of DOCS_TO_REMOVE) remove(join(tempDir, doc));
36
- for (const item of PLUGIN_ITEMS_TO_REMOVE) remove(join(tempDir, item));
39
+ for (const item of PLUGIN_ITEMS_TO_REMOVE) if (!keptItems.has(item)) remove(join(tempDir, item));
37
40
  }
38
41
 
39
42
  // tempDir/version.yml 의 ^version: 값. 없으면 DEFAULT_VERSION.
@@ -14,7 +14,7 @@ export const TEST_PATH = /(^|[\\/])(tests?|__pycache__)([\\/]|$)/;
14
14
  const OWNED_SKILL_NAME = /^(pro|suh)-/;
15
15
  // 공용 파이썬 패키지 표식: scripts/common/__init__.py
16
16
  const SHARED_SCRIPTS_MARKER = join("common", "__init__.py");
17
- const SHARED_SCRIPTS_DIR_NAME = "scripts";
17
+ export const SHARED_SCRIPTS_DIR_NAME = "scripts";
18
18
  const PYTHON_CACHE_DIR_NAME = "__pycache__";
19
19
  // 공용 파이썬 중 저장소 관리자만 쓰는 최상위 항목 3개: 안내 문서, 트러블슈팅 색인 생성기, extras 사본 동기화 (#988)
20
20
  // 허용 목록이 아니라 제외 목록인 이유: 새 런타임 모듈을 빠뜨리면 스킬이 import 에서 죽지만,
package/src/index.js CHANGED
@@ -11,6 +11,7 @@ import { createContext } from "./context.js";
11
11
  import { PATHS } from "./core/paths.js";
12
12
  import { remove } from "./core/fsutil.js";
13
13
  import { acquireTemplate, readTemplateVersion } from "./core/assets.js";
14
+ import { SHARED_SCRIPTS_DIR_NAME } from "./core/ide/skills-copy.js";
14
15
  import { detectTypes, detectVersion, detectDefaultBranch, detectRepoName, makeResolvers } from "./core/detect-fs.js";
15
16
  import { parseExisting } from "./core/version-yml.js";
16
17
  import { runBreakingCheck } from "./core/breaking-check.js";
@@ -99,7 +100,8 @@ async function runCore(argv, { cwd = process.cwd(), source = { type: "git" }, cl
99
100
  const tempDir = join(cwd, PATHS.tempDir);
100
101
  const interactive = !opts.force && process.stdout.isTTY;
101
102
  try {
102
- acquireTemplate({ tempDir, source });
103
+ // skills 모드: 스킬 CLI 가 import 하는 scripts/common 필요 > 제외 대상에서 유지 (#994)
104
+ acquireTemplate({ tempDir, source, keep: [SHARED_SCRIPTS_DIR_NAME] });
103
105
  const templateVersion = readTemplateVersion(tempDir);
104
106
  return await runSkills({ templateVersion, tempDir, interactive });
105
107
  } finally {