e2e-agent-runner 1.0.0 → 1.0.2

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.
Files changed (3) hide show
  1. package/git.mjs +19 -2
  2. package/package.json +1 -1
  3. package/runner.mjs +13 -3
package/git.mjs CHANGED
@@ -41,13 +41,23 @@ export async function probeFolder(cwd) {
41
41
  }
42
42
  }
43
43
 
44
- /** 실행 전 검증 — 폴더 존재·git 저장소·클린 워킹트리(사용자 미커밋 변경 보호). */
44
+ /** 실행 전 검증 — 폴더 존재·git 저장소·클린 워킹트리(사용자 미커밋 변경 보호).
45
+ * dirty 거부 시 어떤 파일이 걸렸는지 목록을 에러에 포함(porcelain 행, ≤8건 표시+외 N건)
46
+ * — 원인 파일을 바로 알게 해 "정리"의 실행 오류를 줄인다. */
45
47
  export async function preflight(cwd) {
46
48
  if (!existsSync(cwd)) throw new GitError(`프로젝트 폴더가 없습니다: ${cwd}`);
47
49
  const inside = await run(cwd, 'rev-parse', '--is-inside-work-tree');
48
50
  if (inside !== 'true') throw new GitError('git 저장소가 아닙니다(작업 브랜치·병합 불가).');
49
51
  const dirty = await run(cwd, 'status', '--porcelain');
50
- if (dirty) throw new GitError('커밋되지 않은 변경이 있어 작업을 시작할 수 없습니다 — 폴더를 정리(커밋/stash)한 뒤 다시 시도하세요.');
52
+ if (dirty) {
53
+ const files = dirty.split('\n').filter(Boolean).map((l) => l.trim().slice(0, 80));
54
+ const shown = files.slice(0, 8);
55
+ const more = files.length - shown.length;
56
+ const list = shown.join(', ') + (more > 0 ? ` 외 ${more}건` : '');
57
+ throw new GitError(
58
+ `커밋되지 않은 변경(${files.length}건)이 있어 작업을 시작할 수 없습니다 — 폴더를 정리(커밋/stash)한 뒤 다시 시도하세요. 대상: ${list}`,
59
+ );
60
+ }
51
61
  }
52
62
 
53
63
  export async function currentBranch(cwd) {
@@ -77,6 +87,13 @@ export function taskBranchName(taskId) {
77
87
  return `e2e-task/${String(taskId).slice(0, 8)}`;
78
88
  }
79
89
 
90
+ /** 작업 브랜치가 base 에 쌓은 커밋 수 — 0이면 무변경(질문·조사) 과제.
91
+ * 서버 상태머신이 테스트/리뷰/배포 생략(short-circuit)을 결정하는 결정론 신호다. */
92
+ export async function commitCount(cwd, base) {
93
+ const n = await run(cwd, 'rev-list', '--count', `${base}..HEAD`);
94
+ return Number(n) || 0;
95
+ }
96
+
80
97
  /** 작업 브랜치 생성(있으면 체크아웃) — implement 단계 전 1회. */
81
98
  export async function ensureTaskBranch(cwd, taskId) {
82
99
  const branch = taskBranchName(taskId);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "e2e-agent-runner",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "suseona e2e 작업 에이전트 로컬 러너 — 내 컴퓨터의 Claude Code 로 구현→테스트→리뷰→배포를 자동 수행",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",
package/runner.mjs CHANGED
@@ -18,7 +18,7 @@ import { dirname, join } from 'node:path';
18
18
  import { api, runnerIdFromToken, sleep } from './api.mjs';
19
19
  import { parsePhaseMarker, probeClaude, runClaude } from './claude.mjs';
20
20
  import {
21
- ensureTaskBranch, escapeTaskBranch, GitError, mergeToBase, preflight, probeFolder, taskBranchName,
21
+ commitCount, ensureTaskBranch, escapeTaskBranch, GitError, mergeToBase, preflight, probeFolder, taskBranchName,
22
22
  } from './git.mjs';
23
23
 
24
24
  // runner/.env.local 자동 로드 — 이미 설정된 env 는 덮지 않는다(셀 export 우선).
@@ -176,6 +176,8 @@ async function handleStep({ step, task, project }) {
176
176
  session_id: result.sessionId ?? null,
177
177
  error: cancelledNow ? 'cancelled' : (result.error ?? null),
178
178
  cancelled: Boolean(cancelledNow),
179
+ // implement 전용 — 작업 브랜치 커밋 수(무변경 단축 신호). 다른 페이즈는 미첨부.
180
+ commits: result.commits,
179
181
  usage: result.usage ?? undefined,
180
182
  });
181
183
  log(`단계 종결: ${task.id.slice(0, 8)}/${step.phase} → ${cancelledNow ? 'cancelled' : result.ok ? 'done' : 'fail'}`);
@@ -194,14 +196,22 @@ async function handleStep({ step, task, project }) {
194
196
  }
195
197
 
196
198
  /** implement — git 프리플라이트 → (이전 작업 브랜치 탈출) → 작업 브랜치 → claude(신규 세션).
197
- * base_branch 를 서버에 보고(유실 방지: EventBuffer 가 재전송한다). */
199
+ * base_branch 를 서버에 보고(유실 방지: EventBuffer 가 재전송한다).
200
+ * 종결 시 작업 브랜치의 커밋 수(base..HEAD)를 함께 보고 — 0이면 서버가 무변경 단축한다. */
198
201
  async function runImplement({ step, task, project, buf, cancelled }) {
199
202
  await preflight(project.folder_path);
200
203
  const base = await escapeTaskBranch(project.folder_path);
201
204
  const branch = await ensureTaskBranch(project.folder_path, task.id);
202
205
  buf.taskMeta = { base_branch: base, branch };
203
206
  log(`브랜치 준비: ${branch} (base ${base})`);
204
- return runPhase({ step, task, project, buf, cancelled, extraMeta: buf.taskMeta });
207
+ const result = await runPhase({ step, task, project, buf, cancelled, extraMeta: buf.taskMeta });
208
+ let commits;
209
+ try {
210
+ commits = await commitCount(project.folder_path, base);
211
+ } catch {
212
+ /* 커밋 수 계산 실패 — 미보고 시 서버는 기존 전체 파이프라인으로 동작 */
213
+ }
214
+ return { ...result, commits };
205
215
  }
206
216
 
207
217
  /** test/remediate/review 공통 — prompt_md + resume 세션. */