projectops 4.6.0 → 4.6.1
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 +1 -1
- package/package.json +1 -1
- package/src/commands/interactive.js +12 -10
- package/src/index.js +37 -41
- package/src/ui/summary.js +13 -17
package/README.md
CHANGED
package/package.json
CHANGED
|
@@ -41,6 +41,11 @@ export async function runInteractive(baseCtx, { cwd = process.cwd(), source = {
|
|
|
41
41
|
// finally에서 기록할 때 쓰는 값 — try 안에서 확정되기 전에 취소될 수 있으므로 바깥에 둔다 (#561).
|
|
42
42
|
let traceFrom = "";
|
|
43
43
|
let traceTo = "";
|
|
44
|
+
// 기록 파일을 남기는 모드인지 — 모드 선택 전에 취소될 수 있어 기본값은 false.
|
|
45
|
+
let recordArtifacts = false;
|
|
46
|
+
// 기록을 남기지 않고 끝낼 경우(version/issues 모드의 정상 완주)에만 true.
|
|
47
|
+
// 취소·예외는 모드와 무관하게 남긴다 — 끊겼을 때가 "어디까지 갔는지"가 가장 궁금한 순간이다.
|
|
48
|
+
let skipRecord = false;
|
|
44
49
|
if (io === prompts) trace.mirrorStart();
|
|
45
50
|
try {
|
|
46
51
|
// 템플릿 먼저 획득 — 배너에 실제 템플릿 버전을 표시 (.sh는 원격 version.yml fetch L4270~4280 등가)
|
|
@@ -378,7 +383,7 @@ export async function runInteractive(baseCtx, { cwd = process.cwd(), source = {
|
|
|
378
383
|
|
|
379
384
|
// 마이그레이션 기록 (#493/#494) — Layer 2/3 트레이스 파일 + Layer 1 가이드 엔트리 (full/workflows만)
|
|
380
385
|
let migrationGuidePath = null;
|
|
381
|
-
|
|
386
|
+
recordArtifacts = mode === "full" || mode === "workflows";
|
|
382
387
|
// 경로는 먼저 계산하고 실제 쓰기는 완료 화면 뒤로 미룬다 — 요약까지 터미널 미러에 담기 위함 (#561)
|
|
383
388
|
const files = recordArtifacts
|
|
384
389
|
? trace.paths({ fromVersion: existing?.templateVersion || "", toVersion: templateVersion, now })
|
|
@@ -406,16 +411,12 @@ export async function runInteractive(baseCtx, { cwd = process.cwd(), source = {
|
|
|
406
411
|
}, cwd);
|
|
407
412
|
io.outro?.(`통합 완료 — ${mode} 모드로 설치했습니다.`);
|
|
408
413
|
|
|
409
|
-
// 완료 화면까지
|
|
414
|
+
// 완료 화면까지 출력한 뒤 finally에서 닫는다 (#561) — 여기서 닫으면 이 아래 화면이 안 담긴다.
|
|
410
415
|
trace.event("run", "end", mode || "", {
|
|
411
416
|
workflowsCopied: result?.workflows?.copied ?? 0,
|
|
412
417
|
workflowsSkipped: result?.workflows?.skipped ?? 0,
|
|
413
418
|
});
|
|
414
|
-
|
|
415
|
-
trace.finalize({ targetRoot: cwd, fromVersion: existing?.templateVersion || "", toVersion: templateVersion, now });
|
|
416
|
-
} else {
|
|
417
|
-
trace.mirrorStop();
|
|
418
|
-
}
|
|
419
|
+
skipRecord = !recordArtifacts;
|
|
419
420
|
return 0;
|
|
420
421
|
} catch (err) {
|
|
421
422
|
trace.event("run", "error", "interactive", {
|
|
@@ -424,9 +425,10 @@ export async function runInteractive(baseCtx, { cwd = process.cwd(), source = {
|
|
|
424
425
|
});
|
|
425
426
|
throw err;
|
|
426
427
|
} finally {
|
|
427
|
-
// 어떤 경로로 빠져나가든 기록을 남긴다 (#561) — 중간
|
|
428
|
-
//
|
|
429
|
-
trace.
|
|
428
|
+
// 어떤 경로로 빠져나가든 기록을 남긴다 (#561) — 중간 취소·예외·Ctrl+C 포함.
|
|
429
|
+
// 완료 화면 출력이 try 안에 있어야 그 화면까지 미러에 담긴 채로 여기서 닫힌다.
|
|
430
|
+
if (skipRecord) trace.mirrorStop();
|
|
431
|
+
else trace.finalize({ targetRoot: cwd, fromVersion: traceFrom, toVersion: traceTo, now: clock?.now || "" });
|
|
430
432
|
disarmSignals();
|
|
431
433
|
remove(tempDir);
|
|
432
434
|
}
|
package/src/index.js
CHANGED
|
@@ -294,6 +294,39 @@ export async function run(argv, { cwd = process.cwd(), source = { type: "git" },
|
|
|
294
294
|
// 알 수 없는 모드 → .sh와 동일하게 복사 0건, 에러 아님
|
|
295
295
|
break;
|
|
296
296
|
}
|
|
297
|
+
// 마이그레이션 기록 (#493/#494) — Layer 2/3 트레이스 파일 + Layer 1 가이드 엔트리
|
|
298
|
+
let migrationGuidePath = null;
|
|
299
|
+
// 기록 파일 경로는 먼저 계산하고(가이드가 참조), 실제 쓰기는 완료 화면 출력 뒤로 미룬다 —
|
|
300
|
+
// 그래야 터미널 미러에 완료 화면까지 담긴다 (#561).
|
|
301
|
+
const files = recordArtifacts
|
|
302
|
+
? trace.paths({ fromVersion: existing?.templateVersion || "", toVersion: context.templateVersion, now })
|
|
303
|
+
: null;
|
|
304
|
+
if (recordArtifacts) {
|
|
305
|
+
migrationGuidePath = appendGuideEntry(cwd, {
|
|
306
|
+
now, mode: opts.mode, types, repoName,
|
|
307
|
+
templateFrom: existing?.templateVersion || "", templateTo: context.templateVersion,
|
|
308
|
+
options: { deploy: deployTarget, publish: publishTargets, secretBackup: context.includeSecretBackup, coderabbit: context.codeReviewCoderabbit, changelogProvider: context.changelogProvider, intent, semverAuto: context.semverAuto , appRelease: context.appRelease },
|
|
309
|
+
branches: { defaultBranch: branch, deployBranch: context.deployBranch || "develop", ready: null, created: null },
|
|
310
|
+
breaking: breakingReport, migrations: migrationsResult, orphans: { cleaned: [], pending: orphanPending },
|
|
311
|
+
events: trace.events, counters: { skipped: result?.workflows?.skipped ?? 0 },
|
|
312
|
+
traceFile: files?.traceFile ?? "", logFile: files?.logFile ?? "",
|
|
313
|
+
}).guidePath;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
// 완료 요약 (.sh print_summary — CLI 모드에서도 출력)
|
|
317
|
+
printSummary({
|
|
318
|
+
mode: opts.mode, types, version, deployBranch: context.deployBranch, migrationGuidePath,
|
|
319
|
+
counters: { workflows: result?.workflows?.copied ?? 0, workflowFiles: result?.workflows?.copiedFiles ?? [], utilModules: 0 },
|
|
320
|
+
verification: result?.verification, // #549 설치 후 검증 결과 (full/workflows 모드에서만 존재)
|
|
321
|
+
logDir: files ? MIGRATION_DIR : null, // #561 기록 위치 안내
|
|
322
|
+
logFile: files?.logFile ?? null,
|
|
323
|
+
traceFile: files?.traceFile ?? null,
|
|
324
|
+
}, cwd);
|
|
325
|
+
|
|
326
|
+
trace.event("run", "end", opts.mode || "", {
|
|
327
|
+
workflowsCopied: result?.workflows?.copied ?? 0,
|
|
328
|
+
workflowsSkipped: result?.workflows?.skipped ?? 0,
|
|
329
|
+
});
|
|
297
330
|
} catch (err) {
|
|
298
331
|
// 실패 원인을 로그에 남긴다 (#561) — 서버 로그처럼 사후에 바로 짚을 수 있어야 한다.
|
|
299
332
|
trace.event("run", "error", opts.mode || "", {
|
|
@@ -302,53 +335,16 @@ export async function run(argv, { cwd = process.cwd(), source = { type: "git" },
|
|
|
302
335
|
});
|
|
303
336
|
throw err;
|
|
304
337
|
} finally {
|
|
305
|
-
//
|
|
306
|
-
//
|
|
338
|
+
// 어떤 경로로 빠져나가든 기록을 남긴다 (#561) — 조기 return·중간 취소·예외 포함.
|
|
339
|
+
// 완료 화면 출력이 try 안에 있어야 그 화면까지 미러에 담긴 채로 여기서 닫힌다.
|
|
307
340
|
if (recordArtifacts) {
|
|
308
341
|
trace.finalize({ targetRoot: cwd, fromVersion: existing?.templateVersion || "", toVersion: context.templateVersion, now });
|
|
342
|
+
} else {
|
|
343
|
+
trace.mirrorStop();
|
|
309
344
|
}
|
|
310
345
|
disarmSignals();
|
|
311
346
|
remove(tempDir);
|
|
312
347
|
}
|
|
313
348
|
|
|
314
|
-
// 마이그레이션 기록 (#493/#494) — Layer 2/3 트레이스 파일 + Layer 1 가이드 엔트리
|
|
315
|
-
let migrationGuidePath = null;
|
|
316
|
-
// 기록 파일 경로는 먼저 계산하고(가이드가 참조), 실제 쓰기는 완료 화면 출력 뒤로 미룬다 —
|
|
317
|
-
// 그래야 터미널 미러에 완료 화면까지 담긴다 (#561).
|
|
318
|
-
const files = recordArtifacts
|
|
319
|
-
? trace.paths({ fromVersion: existing?.templateVersion || "", toVersion: context.templateVersion, now })
|
|
320
|
-
: null;
|
|
321
|
-
if (recordArtifacts) {
|
|
322
|
-
migrationGuidePath = appendGuideEntry(cwd, {
|
|
323
|
-
now, mode: opts.mode, types, repoName,
|
|
324
|
-
templateFrom: existing?.templateVersion || "", templateTo: context.templateVersion,
|
|
325
|
-
options: { deploy: deployTarget, publish: publishTargets, secretBackup: context.includeSecretBackup, coderabbit: context.codeReviewCoderabbit, changelogProvider: context.changelogProvider, intent, semverAuto: context.semverAuto , appRelease: context.appRelease },
|
|
326
|
-
branches: { defaultBranch: branch, deployBranch: context.deployBranch || "develop", ready: null, created: null },
|
|
327
|
-
breaking: breakingReport, migrations: migrationsResult, orphans: { cleaned: [], pending: orphanPending },
|
|
328
|
-
events: trace.events, counters: { skipped: result?.workflows?.skipped ?? 0 },
|
|
329
|
-
traceFile: files?.traceFile ?? "", logFile: files?.logFile ?? "",
|
|
330
|
-
}).guidePath;
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
// 완료 요약 (.sh print_summary — CLI 모드에서도 출력)
|
|
334
|
-
printSummary({
|
|
335
|
-
mode: opts.mode, types, version, deployBranch: context.deployBranch, migrationGuidePath,
|
|
336
|
-
counters: { workflows: result?.workflows?.copied ?? 0, workflowFiles: result?.workflows?.copiedFiles ?? [], utilModules: 0 },
|
|
337
|
-
verification: result?.verification, // #549 설치 후 검증 결과 (full/workflows 모드에서만 존재)
|
|
338
|
-
logDir: files ? MIGRATION_DIR : null, // #561 기록 위치 안내
|
|
339
|
-
logFile: files?.logFile ?? null,
|
|
340
|
-
traceFile: files?.traceFile ?? null,
|
|
341
|
-
}, cwd);
|
|
342
|
-
|
|
343
|
-
// 완료 화면까지 캡처한 뒤 종료하고 기록한다 (#561)
|
|
344
|
-
trace.event("run", "end", opts.mode || "", {
|
|
345
|
-
workflowsCopied: result?.workflows?.copied ?? 0,
|
|
346
|
-
workflowsSkipped: result?.workflows?.skipped ?? 0,
|
|
347
|
-
});
|
|
348
|
-
if (recordArtifacts) {
|
|
349
|
-
trace.finalize({ targetRoot: cwd, fromVersion: existing?.templateVersion || "", toVersion: context.templateVersion, now });
|
|
350
|
-
} else {
|
|
351
|
-
trace.mirrorStop();
|
|
352
|
-
}
|
|
353
349
|
return 0;
|
|
354
350
|
}
|
package/src/ui/summary.js
CHANGED
|
@@ -131,23 +131,6 @@ export function printSummary(ctx, targetRoot = ".") {
|
|
|
131
131
|
err(" 📚 워크플로우 가이드: .github/workflows/project-types/README.md");
|
|
132
132
|
// #493 — 이번 실행의 마이그레이션 기록. "뭐가 남았고 AI에게 어떻게 시키는지"가 바로 보이게 행동 유도형으로 안내.
|
|
133
133
|
// 실행 기록 위치 (#561) — 무슨 일이 있었는지 나중에 확인할 자리를 알린다.
|
|
134
|
-
// 폴더가 아니라 이번 실행의 파일을 정확히 짚어준다 — 실행이 쌓이면 어느 것이 이번 건인지
|
|
135
|
-
// 모른다. 붙여넣어 바로 열 수 있는 경로가 목적이다.
|
|
136
|
-
if (ctx?.logFile || ctx?.logDir) {
|
|
137
|
-
err(` 📁 실행 로그: ${ctx.logFile || `${ctx.logDir}/`}`);
|
|
138
|
-
if (ctx.traceFile) err(` 이벤트(JSONL): ${ctx.traceFile}`);
|
|
139
|
-
err(" 이번 실행에서 무엇을 어떤 근거로 정했는지 전부 기록돼 있습니다.");
|
|
140
|
-
err(" 문제가 생기면 이 파일을 확인하세요 (저장소에 추적되지 않습니다).");
|
|
141
|
-
err(" 💡 AI Agent에게 \"실행 로그 확인해줘\"라고 요청하면 원인을 짚어줍니다.");
|
|
142
|
-
err("");
|
|
143
|
-
}
|
|
144
|
-
if (ctx?.migrationGuidePath) {
|
|
145
|
-
err(` 🧭 마이그레이션 가이드: ${ctx.migrationGuidePath}`);
|
|
146
|
-
err(" 이번 설치에서 바뀐 내용과 직접 확인해야 할 작업이 이 파일에 정리되어 있습니다.");
|
|
147
|
-
err(" 💡 AI Agent(Claude, Cursor 등)에게 \"마이그레이션 가이드 확인하고");
|
|
148
|
-
err(" 남은 작업 처리해줘\"라고 요청하면 이 문서를 읽고 대신 진행합니다.");
|
|
149
|
-
}
|
|
150
|
-
err("");
|
|
151
134
|
|
|
152
135
|
// 설치 후 검증 결과 (#549) — 문제가 있을 때만 펼치고, 정상이면 한 줄로 압축한다.
|
|
153
136
|
const verification = ctx?.verification;
|
|
@@ -215,4 +198,17 @@ export function printSummary(ctx, targetRoot = ".") {
|
|
|
215
198
|
err(`${CYAN}📖 자세한 설정 방법은 다음 파일을 참고하세요:${NC}`);
|
|
216
199
|
err(" → PROJECTOPS-SETUP-GUIDE.md");
|
|
217
200
|
err("");
|
|
201
|
+
// 기록 안내는 완료 화면의 맨 끝에 둔다 (#561) — Secret 목록이 길면 위쪽은 스크롤에 묻혀
|
|
202
|
+
// 사용자가 "로그 얘기가 없다"고 느낀다. 문제가 생겼을 때 가장 먼저 찾는 것이므로 마지막 자리다.
|
|
203
|
+
if (ctx?.logFile || ctx?.logDir || ctx?.migrationGuidePath) {
|
|
204
|
+
err(`${CYAN}📁 이번 실행 기록${NC}`);
|
|
205
|
+
if (ctx?.logFile || ctx?.logDir) {
|
|
206
|
+
err(` 로그: ${ctx.logFile || `${ctx.logDir}/`}`);
|
|
207
|
+
if (ctx.traceFile) err(` 이벤트: ${ctx.traceFile}`);
|
|
208
|
+
}
|
|
209
|
+
if (ctx?.migrationGuidePath) err(` 가이드: ${ctx.migrationGuidePath}`);
|
|
210
|
+
err(" 무엇을 어떤 근거로 정했는지 전부 남아 있습니다 (저장소에 추적되지 않음).");
|
|
211
|
+
err(" 💡 문제가 생기면 AI Agent에게 \"실행 로그 확인해줘\"라고 요청하세요.");
|
|
212
|
+
err("");
|
|
213
|
+
}
|
|
218
214
|
}
|