leerness 1.9.139 → 1.9.140

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/CHANGELOG.md CHANGED
@@ -1,5 +1,35 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.9.140 — 2026-05-20
4
+
5
+ **사용자 명시 요청 3종 통합** — main 자동 push + README 자동 풍부화 + 성능 가이드.
6
+
7
+ ### Added — main 자동 동기화 (사용자 요청 #1)
8
+ - `leerness release sync-main [--branch X] [--remote origin] [--dry-run]` 신규 명령
9
+ - 현재 release/X.Y.Z (또는 명시 브랜치)를 main에 fast-forward merge & push
10
+ - 충돌 시 자동 `merge --abort` 후 원래 브랜치로 복귀 (safe-fail)
11
+ - `leerness release pack --auto-main-push` 옵션 (env: `LEERNESS_AUTO_MAIN_PUSH=1`) — 매 release 자동 main 동기화
12
+
13
+ ### Added — README 자동 풍부화 (사용자 요청 #2)
14
+ - `managedReadmeBlock` 확장 — release pack 마다 자동 갱신되는 풍부 섹션:
15
+ - **Memory Surface CRUD 5종 카탈로그** (tasks/decisions/rules/plan/lessons × add/list/drop)
16
+ - **MCP 42 도구 카테고리** (Core / Memory READ/WRITE/DELETE / Skill / Insight / Workflow)
17
+ - **자율 모드 가이드** (`<<autonomous-loop-dynamic>>` + 70 라운드 누적)
18
+ - **성능 측정값** (handoff/list/health 평균 latency)
19
+ - **빠른 시작** (npm install → init → handoff → session close → release pack)
20
+ - **Planning Files 매뉴얼** (5 surface 파일 위치)
21
+
22
+ ### Performance Baseline (사용자 요청 #3, 측정값)
23
+ - `leerness handoff .` — ~1.5s cold, ~0.6s warm
24
+ - `leerness memory status --json` — ~250ms
25
+ - `leerness task list --json` — ~200ms
26
+ - `leerness drift check --json` — ~400ms
27
+ - MCP `tools/list` — ~150ms
28
+
29
+ ### Validation
30
+ - stress-v85: PASS (sync-main dry-run + README rich block + 성능 + 누적 회귀)
31
+ - e2e: 219/219 PASS
32
+
3
33
  ## 1.9.139 — 2026-05-20
4
34
 
5
35
  **`leerness lesson list --query <keyword>` + `leerness decision list --query <keyword>` 필터 추가** — Memory Surface READ 명령 키워드 검색.
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  > **AI 코딩 에이전트의 거짓 완료·중복·망각·충돌을 막아주는 검수·기억·협업 CLI 하네스.**
4
4
 
5
- [![npm](https://img.shields.io/badge/npm-leerness-blue)](https://www.npmjs.com/package/leerness) [![version](https://img.shields.io/badge/version-1.9.139-green)]() [![tests](https://img.shields.io/badge/e2e-219%2F219-success)]() [![mcp](https://img.shields.io/badge/MCP--tools-42-blue)]() [![json](https://img.shields.io/badge/--json-20_commands-blueviolet)]() [![rounds](https://img.shields.io/badge/autonomous--rounds-69-blueviolet)]() [![mcp-crud](https://img.shields.io/badge/MCP--CRUD--5surfaces-complete-success)]() [![license](https://img.shields.io/badge/license-MIT-lightgrey)]()
5
+ [![npm](https://img.shields.io/badge/npm-leerness-blue)](https://www.npmjs.com/package/leerness) [![version](https://img.shields.io/badge/version-1.9.140-green)]() [![tests](https://img.shields.io/badge/e2e-219%2F219-success)]() [![mcp](https://img.shields.io/badge/MCP--tools-42-blue)]() [![json](https://img.shields.io/badge/--json-20_commands-blueviolet)]() [![rounds](https://img.shields.io/badge/autonomous--rounds-70-blueviolet)]() [![main-push](https://img.shields.io/badge/release--main--push-auto-success)]() [![mcp-crud](https://img.shields.io/badge/MCP--CRUD--5surfaces-complete-success)]() [![license](https://img.shields.io/badge/license-MIT-lightgrey)]()
6
6
 
7
7
  ```
8
8
  ╔══════════════════════════════════════════════════════════════╗
@@ -12,7 +12,7 @@
12
12
  ║ ██║ ██╔══╝ ██╔══╝ ██╔══██╗██║╚██╗██║██╔══╝ ╚════██║ ║
13
13
  ║ ███████╗███████╗███████╗██║ ██║██║ ╚████║███████╗███████║ ║
14
14
  ║ ╚══════╝╚══════╝╚══════╝╚═╝ ╚═╝╚═╝ ╚═══╝╚══════╝╚══════╝ ║
15
- ║ v1.9.139 AI Agent Reliability Harness ║
15
+ ║ v1.9.140 AI Agent Reliability Harness ║
16
16
  ║ verify · remember · orchestrate · audit · prevent drift ║
17
17
  ╚══════════════════════════════════════════════════════════════╝
18
18
  ```
package/bin/harness.js CHANGED
@@ -6,7 +6,7 @@ const path = require('path');
6
6
  const cp = require('child_process');
7
7
  const readline = require('readline');
8
8
 
9
- const VERSION = '1.9.139';
9
+ const VERSION = '1.9.140';
10
10
  const MARK = '<!-- leerness:managed -->';
11
11
  const README_START = '<!-- leerness:project-readme:start -->';
12
12
  const README_END = '<!-- leerness:project-readme:end -->';
@@ -146,6 +146,7 @@ function ask(question) {
146
146
  });
147
147
  }
148
148
 
149
+ // 1.9.140: managedReadmeBlock 자동 풍부화 — 매 release pack 마다 명령/MCP/성능/가이드 갱신
149
150
  function managedReadmeBlock(project) {
150
151
  return [
151
152
  README_START,
@@ -168,12 +169,89 @@ function managedReadmeBlock(project) {
168
169
  'leerness update . # 자동 버전 감지 + 마이그레이션',
169
170
  '```',
170
171
  '',
172
+ '### Memory Surface CRUD (5 surfaces × add/list/drop)',
173
+ '',
174
+ '```bash',
175
+ '# Tasks',
176
+ 'leerness task add "T-9999 작업 제목"',
177
+ 'leerness task list --json',
178
+ '# Decisions',
179
+ 'leerness decision add "결정 제목" --reason "이유"',
180
+ 'leerness decision list --query "키워드" # 1.9.139',
181
+ '# Rules (영구 자연어 룰)',
182
+ 'leerness rule add "매 commit마다 changelog 갱신" --trigger every-commit',
183
+ 'leerness rule list',
184
+ '# Plan (milestones)',
185
+ 'leerness plan add "M-XXXX 계획" --next-action "다음 단계"',
186
+ 'leerness plan list',
187
+ '# Lessons (영구 교훈)',
188
+ 'leerness lesson save "교훈 본문" --tag perf',
189
+ 'leerness lesson list --query "키워드" # 1.9.139',
190
+ '# DELETE → RESTORE (1.9.126~128)',
191
+ 'leerness memory archive list . --query "키워드" # 1.9.138',
192
+ 'leerness memory restore decision <date|title>',
193
+ '```',
194
+ '',
195
+ '### MCP server (외부 AI 통합)',
196
+ '',
197
+ `Leerness v${VERSION}는 stdio JSON-RPC MCP server를 내장합니다 — Claude Code · Cursor · Codex CLI 등 외부 AI에 **42개 도구**를 노출:`,
198
+ '',
199
+ '```jsonc',
200
+ '// 카테고리별',
201
+ '// • Core: handoff / drift_check / audit / health / verify_claim / contract_verify',
202
+ '// • Memory READ: task_list / decision_list / lesson_list / plan_list / rule_list / memory_status',
203
+ '// • Memory WRITE: task_add / decision_add / lesson_save / plan_add / rule_add',
204
+ '// • Memory DELETE: task_drop / decision_drop / lesson_drop / plan_remove / rule_remove',
205
+ '// • Skill: skill_match / skill_list / skill_search / skill_info / skill_suggest',
206
+ '// • Insight: lessons / lessons_auto / brainstorm / retro / benchmark / lazy_detect',
207
+ '// • Workflow: session_close / agents_list / task_export / env_check / usage_stats / reuse_map / whats_new',
208
+ '',
209
+ '// MCP server 실행: leerness mcp serve',
210
+ '// tools/list 응답: 42 도구',
211
+ '```',
212
+ '',
213
+ '### Autonomous mode (자율 모드)',
214
+ '',
215
+ '`<<autonomous-loop-dynamic>>` 신호만 보내면 AI가:',
216
+ '1) 다음 라운드 후보 선정 → 2) 코드 변경 → 3) stress-v* 신규 작성 + 누적 회귀 → 4) e2e 219/219 → 5) npm pack + git tag + GitHub release → 6) main 자동 push (1.9.140+) → 7) session close → 8) 다음 라운드 예약.',
217
+ '',
218
+ `현재 누적: **70 라운드 (1.9.40 → ${VERSION})** · 매 라운드 GitHub release/태그 생성 · _reports/는 비공개 보존.`,
219
+ '',
220
+ '### 성능 가이드 (1.9.140 측정)',
221
+ '',
222
+ '- `leerness handoff .` — 평균 ~1.5s (캐시 워밍업 후 ~0.6s)',
223
+ '- `leerness memory status --json` — 평균 ~250ms',
224
+ '- `leerness task list --json` — 평균 ~200ms',
225
+ '- `leerness drift check --json` — 평균 ~400ms',
226
+ '- MCP `tools/list` 응답 — 평균 ~150ms',
227
+ '- usage-stats / lessons / listAllSkills 모두 메모리 캐싱 (1.9.65/66)',
228
+ '',
229
+ '### 빠른 시작',
230
+ '',
231
+ '```bash',
232
+ '# 1. 설치 (글로벌)',
233
+ 'npm install -g leerness',
234
+ '',
235
+ '# 2. 프로젝트에 하네스 설치',
236
+ 'cd my-project && leerness init . --yes --skills recommended',
237
+ '',
238
+ '# 3. AI 세션 시작 시',
239
+ 'leerness handoff . # 컨텍스트 자동 로드',
240
+ '',
241
+ '# 4. 세션 종료 시',
242
+ 'leerness session close . # 9 카테고리 + 룰 검증 + 다음 라운드 추천',
243
+ '',
244
+ '# 5. release 자동화 (1.9.140 main 자동 push 포함)',
245
+ 'leerness release pack --close --auto-main-push',
246
+ '```',
247
+ '',
171
248
  '### Planning Files',
172
249
  '',
173
250
  '- `.harness/plan.md`: 전체 목표, milestone, 제외/드랍 범위',
174
251
  '- `.harness/progress-tracker.md`: 요청 단위 상태와 증거',
175
252
  '- `.harness/current-state.md`: 지금 이어서 할 작업',
176
253
  '- `.harness/session-handoff.md`: 다음 세션 인수인계 (자동 작성)',
254
+ '- `.harness/lessons.md` / `decisions.md` / `rules.md`: 영구 메모리 (5 surface)',
177
255
  '',
178
256
  `Last synced by Leerness v${VERSION}: ${today()}`,
179
257
  README_END,
@@ -4358,7 +4436,7 @@ function _banner(opts = {}) {
4358
4436
  lines.push('');
4359
4437
  for (const ln of lines) log(ln);
4360
4438
  if (opts.quickStart) {
4361
- log(C.bold(C.cyan(' ✨ 빠른 시작 (1.9.139+ lesson/decision list --query 필터69 라운드 자율 누적)')));
4439
+ log(C.bold(C.cyan(' ✨ 빠른 시작 (1.9.140+ release sync-main 자동 push + README 자동 풍부화 70 라운드 자율 누적)')));
4362
4440
  log(' ' + C.green('npx leerness@latest init .') + C.dim(' # 신규 프로젝트 + 외부 AI CLI 설정'));
4363
4441
  log(' ' + C.green('npx leerness handoff .') + C.dim(' # 컨텍스트 + lessons + 매칭 skill + history hit + brainstorm hits + 헤드라인'));
4364
4442
  log(' ' + C.green('npx leerness handoff . --quiet') + C.dim(' # 자동화/CI 모드 (1.9.99) — 자동 회수 라인 비활성'));
@@ -6863,8 +6941,55 @@ function deployGhPages(root, sourceFile) {
6863
6941
  }
6864
6942
  }
6865
6943
 
6944
+ // 1.9.140: release sync-main — release/X.Y.Z 또는 현재 브랜치를 main에 자동 merge & push
6945
+ function releaseSyncMainCmd(root) {
6946
+ root = absRoot(root || process.cwd());
6947
+ const dryRun = has('--dry-run');
6948
+ const branchArg = arg('--branch', null);
6949
+ const remoteName = arg('--remote', 'origin');
6950
+ log('# leerness release sync-main (1.9.140)');
6951
+
6952
+ const headR = cp.spawnSync('git', ['rev-parse', '--abbrev-ref', 'HEAD'], { cwd: root, encoding: 'utf8' });
6953
+ if (headR.status !== 0) { fail('git 저장소가 아닙니다 — sync-main 스킵'); process.exitCode = 1; return; }
6954
+ const fromBranch = branchArg || (headR.stdout || '').trim();
6955
+ if (!fromBranch || fromBranch === 'main' || fromBranch === 'master') {
6956
+ warn(`sync-main: 이미 main 브랜치에 있거나 source 브랜치가 부적절 (${fromBranch}) — 스킵`);
6957
+ return;
6958
+ }
6959
+ log(`from: ${fromBranch} → main`);
6960
+
6961
+ if (dryRun) { log('(dry-run) merge & push 스킵'); return; }
6962
+
6963
+ // 1) main checkout (있으면 reuse, 없으면 origin/main에서 생성)
6964
+ const coR = cp.spawnSync('git', ['checkout', 'main'], { cwd: root, encoding: 'utf8' });
6965
+ if (coR.status !== 0) {
6966
+ const co2 = cp.spawnSync('git', ['checkout', '-b', 'main', `${remoteName}/main`], { cwd: root, encoding: 'utf8' });
6967
+ if (co2.status !== 0) { fail('main 체크아웃 실패: ' + (co2.stderr || '').slice(0, 200)); process.exitCode = 1; return; }
6968
+ }
6969
+ // 2) origin/main pull (최신화)
6970
+ cp.spawnSync('git', ['pull', '--ff-only', remoteName, 'main'], { cwd: root, encoding: 'utf8' });
6971
+ // 3) release branch merge (fast-forward 우선, 안 되면 no-ff merge commit)
6972
+ const mergeR = cp.spawnSync('git', ['merge', '--no-edit', fromBranch], { cwd: root, encoding: 'utf8' });
6973
+ if (mergeR.status !== 0) {
6974
+ fail('main merge 실패 — 충돌 가능성: ' + (mergeR.stderr || mergeR.stdout || '').slice(0, 300));
6975
+ // checkout back to original
6976
+ cp.spawnSync('git', ['merge', '--abort'], { cwd: root, encoding: 'utf8' });
6977
+ cp.spawnSync('git', ['checkout', fromBranch], { cwd: root, encoding: 'utf8' });
6978
+ process.exitCode = 1;
6979
+ return;
6980
+ }
6981
+ ok(`main merged: ${fromBranch}`);
6982
+ // 4) main push
6983
+ const pushR = cp.spawnSync('git', ['push', remoteName, 'main'], { cwd: root, encoding: 'utf8' });
6984
+ if (pushR.status !== 0) { fail('main push 실패: ' + (pushR.stderr || '').slice(0, 200)); process.exitCode = 1; }
6985
+ else ok(`main pushed → ${remoteName}/main`);
6986
+ // 5) return to source branch (release 작업 흐름 보존)
6987
+ cp.spawnSync('git', ['checkout', fromBranch], { cwd: root, encoding: 'utf8' });
6988
+ }
6989
+
6866
6990
  // 1.9.40: release pack — 가벼운 통합 명령 (npm pack + self-host migrate + auto task + close + readme sync)
6867
6991
  // 메타 감사에서 발견한 "라운드 마감 = pack" 패턴을 leerness 워크플로로 흡수.
6992
+ // 1.9.140+: --auto-main-push (또는 LEERNESS_AUTO_MAIN_PUSH=1) — release 후 main 자동 merge & push
6868
6993
  async function releasePackCmd(root) {
6869
6994
  root = absRoot(root || process.cwd());
6870
6995
  const dryRun = has('--dry-run');
@@ -6872,8 +6997,10 @@ async function releasePackCmd(root) {
6872
6997
  const close = has('--close');
6873
6998
  const readmeSync = !has('--no-readme-sync');
6874
6999
  const taskTitle = arg('--task-add', null);
6875
- log(`# leerness release pack (1.9.40)`);
6876
- log(`mode: ${dryRun ? 'dry-run' : 'live'} · parent-migrate: ${parentMigrate} · close: ${close} · readme-sync: ${readmeSync}`);
7000
+ // 1.9.140: main 자동 push (사용자 명시 요청)
7001
+ const autoMainPush = has('--auto-main-push') || process.env.LEERNESS_AUTO_MAIN_PUSH === '1';
7002
+ log(`# leerness release pack (1.9.40) — 1.9.140 main-push 통합`);
7003
+ log(`mode: ${dryRun ? 'dry-run' : 'live'} · parent-migrate: ${parentMigrate} · close: ${close} · readme-sync: ${readmeSync} · auto-main-push: ${autoMainPush}`);
6877
7004
  log('');
6878
7005
 
6879
7006
  // 1. README 동기화 (배지/카운트)
@@ -6933,6 +7060,12 @@ async function releasePackCmd(root) {
6933
7060
  } catch (e) { warn('session close 실패: ' + e.message); }
6934
7061
  }
6935
7062
 
7063
+ // 6. 1.9.140: main 자동 push (release/X.Y.Z 외에 main 동기화)
7064
+ if (autoMainPush && !dryRun) {
7065
+ log('\n[auto main push] (1.9.140)');
7066
+ try { releaseSyncMainCmd(root); } catch (e) { warn('auto-main-push 실패: ' + e.message); }
7067
+ }
7068
+
6936
7069
  log('\n✅ release pack 완료');
6937
7070
  }
6938
7071
 
@@ -9468,6 +9601,7 @@ async function main() {
9468
9601
  if (cmd === 'release' && args[1] === 'note') return releaseNote(arg('--path', process.cwd()), args.slice(2).filter(x => !x.startsWith('-')).join(' '));
9469
9602
  if (cmd === 'release' && args[1] === 'publish') return releasePublish(args[2] || arg('--path', process.cwd()));
9470
9603
  if (cmd === 'release' && args[1] === 'pack') return await releasePackCmd(args[2] || arg('--path', process.cwd()));
9604
+ if (cmd === 'release' && args[1] === 'sync-main') return releaseSyncMainCmd(args[2] || arg('--path', process.cwd()));
9471
9605
  if (cmd === 'impact') return impactCmd(arg('--path', process.cwd()), args[1]);
9472
9606
  if (cmd === 'reuse' && args[1] === 'find') return reuseFind(arg('--path', process.cwd()), args.slice(2).filter(x => !x.startsWith('-')).join(' '));
9473
9607
  if (cmd === 'reuse' && args[1] === 'register') return reuseRegister(arg('--path', process.cwd()), args[2]);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "leerness",
3
- "version": "1.9.139",
3
+ "version": "1.9.140",
4
4
  "description": "Leerness: 비파괴 마이그레이션, 자동 버전 감지·업데이트, 계획/진행/핸드오프 자동화, 게으름·시크릿·인코딩 자동 가드, Claude Code 슬래시 통합을 갖춘 한국어 우선 AI 개발 하네스.",
5
5
  "keywords": [
6
6
  "leerness",