leerness 1.9.445 → 1.10.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/CHANGELOG.md CHANGED
@@ -1,5 +1,78 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.10.0 — 2026-06-08 — 🛡️ [안정화/Stable] 1.10 안정 minor (배포 정책 첫 minor 릴리스)
4
+
5
+ **🛡️ 안정화(Stable) minor — patch 누적(1.9.446~449)을 검증·통합해 npm 에 안정 버전으로 공개.** R-0011 배포 정책(patch 는 누적, minor 만 npm 공개)의 첫 minor 릴리스.
6
+
7
+ ### 이번 minor 에 담긴 개선 (1.9.446~449, 그동안 GitHub 에만 누적)
8
+ - **npm 배포 minor-gate** (UR-0160): patch 는 npm 미배포, minor/major 변동 시에만 안정 배포. `release sync-main . --publish-npm` 강제 옵션.
9
+ - **plan progress 읽기전용 요약** (UR-0145): 완료율% + 상태별 + `--json` + 변경의도 인자 경고(silent ignore 제거).
10
+ - **export/prompt = adapter 별칭** (UR-0154, GPT-5.5 §6.6): `export --target claude|cursor|codex|agents-md`.
11
+ - **plan drop 역할 분리** (UR-0143): scope 드랍을 plan.md(Out of Scope)에만 기록, progress-tracker phantom task 제거.
12
+
13
+ ### 직전 안정(1.9.x)부터의 핵심 (참고)
14
+ - evidence-first 완료 게이트 `completion_claim_allowed` (UR-0153, GPT-5.5 §6.3), CI/PR 턴키 `ci init` (UR-0152, §6.7), task/add-family positional path (UR-0141/0151), 시크릿 스캐너 prefix placeholder 가드(12th 리뷰 Opus P2), README ASCII 배너.
15
+
16
+ ### 검증 (회귀 0)
17
+ - **selftest 194 PASS** · **E2E 365/365 PASS** · npm gate=minor_bump(배포) 확인.
18
+
19
+ ### 안정화 표시 (R-0006)
20
+ CHANGELOG [안정화/Stable] · git tag annotation (Stable) · GitHub release (Stable) · npm dist-tag `stable` 시도.
21
+
22
+ ## 1.9.449 — 2026-06-08 — plan drop: progress-tracker T- 행 미생성 (12th 외부평가 Sonnet P3, UR-0143)
23
+
24
+ **🐛 plan↔progress 역할 분리: scope 드랍이 phantom task 를 만들던 문제.**
25
+
26
+ ### 변경
27
+ - `plan drop` 이 progress-tracker 에 `dropped` 상태의 `T-` task 행을 만들던 동작 제거 — 이제 plan.md `## Out of Scope / Dropped`(D-) 에만 기록. scope 드랍의 단일 출처 = plan.md.
28
+ - 기존엔 scope 드랍 1건이 plan.md D- + progress-tracker T- 양쪽에 생겨 plan↔progress 역할 혼선 + `task list` 노이즈(실제 작업 아닌 phantom T-) 발생.
29
+
30
+ ### 검증 (회귀 0)
31
+ - **selftest 193→194** (planDrop 에 dropped-task upsert 없음 + ok 메시지가 plan.md 가리킴), 행위 재현: plan drop → D-0001 기록 + progress T- 행 미증가.
32
+ - patch(1.9.449, 같은 minor) — R-0011 정책상 npm 미배포, GitHub 만 갱신.
33
+
34
+ ## 1.9.448 — 2026-06-08 — export/prompt = adapter 별칭 (GPT-5.5 전략리뷰 §6.6/7.3, UR-0154)
35
+
36
+ **🔌 GPT-5.5 권고 표면명 정합: `leerness export/prompt --target <agent>`.**
37
+
38
+ ### 변경
39
+ - 신규 `export --target <agent>` / `prompt --target <agent>` — 기존 `adapter <tool>` 의 별칭(도구별 지침/계약 파일 생성: claude/cursor/codex/copilot/goose). `--target` 플래그 또는 positional 모두 지원, 미지정 시 list.
40
+ - `agents-md`/`agents`/`agent` → `codex`(AGENTS.md 생성) 별칭 매핑 — GPT-5.5 가 권고한 `export --target agents-md` 가 그대로 동작.
41
+ - GPT-5.5 전략리뷰가 권고한 명령 표면명(`export`/`prompt --target`)을 기존 adapter 위에 제공 → 외부 사용자 발견성↑.
42
+
43
+ ### 검증 (회귀 0)
44
+ - **selftest 192→193** (와이어), 행위 재현: `export --target claude`→CLAUDE.md, `export --target agents-md`→AGENTS.md.
45
+ - patch(1.9.448, 같은 minor) — R-0011 정책상 npm 미배포, GitHub 만 갱신.
46
+
47
+ ### 보류 메모
48
+ - UR-0146(init --json 순수화): init=install 큰 핸들러의 다중 log(~15) quiet-mode 게이팅 필요 — P3 대비 침투적이라 quiet-mode 리팩터 라운드로 보류. audit --fix --json 의 fixApplied(=fix모드)/fixed(=카운트)는 의미상 일관(by-design).
49
+
50
+ ## 1.9.447 — 2026-06-08 — plan progress 읽기전용 요약 명확화 (12th 외부평가 Codex P3, UR-0145)
51
+
52
+ **🐛 명령명-동작 불일치 해소: `plan progress` 가 인자를 silent ignore 하던 문제.**
53
+
54
+ ### 변경
55
+ - `plan progress` 를 읽기 전용 진행 요약으로 명확화 — **완료율%**(done/total) + 상태별 카운트 + 마일스톤 수 출력. `--json` 구조화 지원.
56
+ - `plan progress M-0002 --status … --progress …` 처럼 변경 의도 인자가 오면 **읽기 전용임을 경고**(기존: silent ignore) — 상태/진행 변경은 `task update`/`plan add|drop` 안내.
57
+ - 기존엔 task status 카운트만 출력하며 명령명이 milestone 변경처럼 오인됨.
58
+
59
+ ### 검증 (회귀 0)
60
+ - **selftest 191→192** (richer 출력 + --json + 변경의도 경고 와이어), 행위 재현: 완료율 1/3(33%)·--json(total/done/percent)·M-id+--status 시 경고.
61
+ - patch(1.9.447, 같은 minor) — R-0011 정책상 npm 미배포, GitHub 만 갱신.
62
+
63
+ ## 1.9.446 — 2026-06-08 — npm 배포 minor-gate (R-0011/UR-0160)
64
+
65
+ **📦 배포 정책 도구화: npm 배포는 minor(x.x) 변동 시에만 — patch(x.x.x) 는 자동 스킵.**
66
+
67
+ ### 변경
68
+ - 순수 `_shouldPublishNpm(current, published, force)` + `_minorKey` (pure-utils): npm latest 와 major.minor 비교 → minor/major ↑ 면 배포, 같은 minor 내 patch 면 스킵. 최초/force 는 배포.
69
+ - `_publishToNpm` 에 minor-gate 추가(1.5단계): `npm view <pkg> version` 으로 latest 확인 후, 같은 minor patch 면 npm publish 스킵(GitHub 커밋·CHANGELOG 는 유지). `release sync-main . --publish-npm` 으로 강제 배포.
70
+ - 사용자 정책(R-0011): 자잘한 patch 는 npm 미배포로 누적, 안정화되면 minor 올려 안정 버전만 npm 노출 → npm latest 안정성 향상.
71
+
72
+ ### 검증 (회귀 0)
73
+ - **selftest 190→191** (순수 7케이스 + 와이어): 1.9.446 vs 1.9.445=스킵(same_minor), 1.10.0=배포(minor_bump), 2.0.0=배포, force/최초=배포.
74
+ - 본 패치(1.9.446)부터 정책 적용 — npm 미배포(같은 minor), GitHub 만 갱신.
75
+
3
76
  ## 1.9.445 — 2026-06-08 — add-family positional path 일관화 (UR-0151, UR-0141 후속)
4
77
 
5
78
  **🐛 데이터 오염 일관화: `decision/lesson/rule add` 도 positional path 인식 (task 와 동일).**
package/README.md CHANGED
@@ -168,7 +168,7 @@ MIT
168
168
  <!-- leerness:project-readme:start -->
169
169
  ## Leerness Project Harness
170
170
 
171
- 이 프로젝트는 Leerness v1.9.445 하네스를 사용합니다. AI 에이전트는 작업 전 `leerness handoff`로 컨텍스트를 적재하고, 작업 후 `leerness check`/`leerness audit`/`leerness session close`를 수행해야 합니다.
171
+ 이 프로젝트는 Leerness v1.10.0 하네스를 사용합니다. AI 에이전트는 작업 전 `leerness handoff`로 컨텍스트를 적재하고, 작업 후 `leerness check`/`leerness audit`/`leerness session close`를 수행해야 합니다.
172
172
 
173
173
  ### 정체성 — AI 에이전트 운영 레이어 (UR-0030)
174
174
 
@@ -222,7 +222,7 @@ leerness memory restore decision <date|title>
222
222
 
223
223
  ### MCP server (외부 AI 통합)
224
224
 
225
- Leerness v1.9.445는 stdio JSON-RPC MCP server를 내장합니다 — Claude Code · Cursor · Codex CLI 등 외부 AI에 **85개 도구**를 노출:
225
+ Leerness v1.10.0는 stdio JSON-RPC MCP server를 내장합니다 — Claude Code · Cursor · Codex CLI 등 외부 AI에 **85개 도구**를 노출:
226
226
 
227
227
  ```jsonc
228
228
  // 카테고리별
@@ -243,7 +243,7 @@ Leerness v1.9.445는 stdio JSON-RPC MCP server를 내장합니다 — Claude Cod
243
243
  `<<autonomous-loop-dynamic>>` 신호만 보내면 AI가:
244
244
  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) 다음 라운드 예약.
245
245
 
246
- 현재 누적: **70 라운드 (1.9.40 → 1.9.445)** · 매 라운드 GitHub release/태그 생성 · _reports/는 비공개 보존.
246
+ 현재 누적: **70 라운드 (1.9.40 → 1.10.0)** · 매 라운드 GitHub release/태그 생성 · _reports/는 비공개 보존.
247
247
 
248
248
  ### 성능 가이드 (1.9.140 측정)
249
249
 
@@ -281,6 +281,6 @@ leerness release pack --close --auto-main-push
281
281
  - `.harness/session-handoff.md`: 다음 세션 인수인계 (자동 작성)
282
282
  - `.harness/lessons.md` / `decisions.md` / `rules.md`: 영구 메모리 (5 surface)
283
283
 
284
- Last synced by Leerness v1.9.445: 2026-06-08
284
+ Last synced by Leerness v1.10.0: 2026-06-08
285
285
  <!-- leerness:project-readme:end -->
286
286
 
package/bin/leerness.js CHANGED
@@ -25,13 +25,13 @@ const { _isSecretKey, _isPlaceholderSecret, _looksSecretLike, _mergeLines, _merg
25
25
  _withBuiltinSource, _esc, _roadmapTokenStyles, _parseSkillMd,
26
26
  _migrationGuideText, _parseContractSpec, _gitignoreMatch,
27
27
  _featureGraphTemplate, _parseFeatureGraph, _nextFeatureId, _featureBlock, _featureImpactBfs,
28
- _parseChangelogBetween, _cellSafe, _cellUnescape, _lineSafe, _parseLimit, _parseAddTitle, _parseImplExports, _taskPositionalPath, _completionClaimAllowed } = require('../lib/pure-utils'); // 1.9.318~443 (UR-0025/0053/0075/0086/0087/0104/0122/0141/0153): 순수 유틸 모듈 분리
28
+ _parseChangelogBetween, _cellSafe, _cellUnescape, _lineSafe, _parseLimit, _parseAddTitle, _parseImplExports, _taskPositionalPath, _completionClaimAllowed, _minorKey, _shouldPublishNpm } = require('../lib/pure-utils'); // 1.9.318~446 (UR-0025/.../0153/0160): 순수 유틸 모듈 분리
29
29
  // 1.9.304 (UR-0025): 순수 분석/검증 함수 모듈 분리.
30
30
  const { _evidenceQuality, _parseEvidenceStats, _shellGuardAnalyze, _claimFileInGit, _epistemicHonestyCheck } = require('../lib/analyzers');
31
31
  // 1.9.295 (UR-0025 4단계): 정적 데이터 카탈로그 모듈 분리 (비파괴, require-based).
32
32
  const { CAPABILITY_SURFACE, POWERFUL_COMMANDS, ADAPTERS, REUSE_CATEGORIES, REUSE_CHECKLIST, _DEFAULT_PLATFORM_CONSTRAINTS, _DEFAULT_DOMAIN_CATALOG, _LSP_LANG_PATTERNS, OPTIMISM_PATTERNS, BUILT_IN_PERSONAS, STRINGS, BUILTIN_CATALOG, ROADMAP_STATUS_LABEL, ROADMAP_STATUS_COLOR, SECRET_PATTERNS, MERGE_OVERWRITE_FILES, MINIMAL_SKIP_KEYS, REQUIRED_WORKSPACE_FILES, KEYWORD_STOPWORDS, SKILL_CATALOG_PRESETS } = require('../lib/catalogs'); // 1.9.344/368/369 (UR-0025): catalog 분리 (MERGE_OVERWRITE_FILES/MINIMAL_SKIP_KEYS 포함)
33
33
 
34
- const VERSION = '1.9.445';
34
+ const VERSION = '1.10.0';
35
35
 
36
36
  // 1.9.290 (UR-0037, Codex gpt-5.5 #4 수렴): CLI 전용 부작용은 require 시 실행하지 않는다.
37
37
  // 이전: warning listener 제거 / NODE_OPTIONS 변경 / chcp IIFE 가 top-level 즉시 실행 → require('harness') 시 호스트 프로세스 오염.
@@ -3366,6 +3366,45 @@ function _selfTestCases() {
3366
3366
  && m._taskPositionalPath(['rule', 'add', '룰', '--trigger', 'every-update'], 2) === null;
3367
3367
  return rule && lesson && decision && trig;
3368
3368
  } },
3369
+ { name: 'R-0011/UR-0160: npm 배포 minor-gate _shouldPublishNpm + _publishToNpm 와이어 (1.9.446)', run: () => {
3370
+ const m = require('../lib/pure-utils');
3371
+ if (typeof m._shouldPublishNpm !== 'function' || m._shouldPublishNpm !== _shouldPublishNpm) return false;
3372
+ const f = m._shouldPublishNpm;
3373
+ const pure = f('1.9.446', '1.9.445', false).publish === false // 같은 minor patch → 미배포
3374
+ && f('1.9.446', '1.9.445', false).reason === 'same_minor'
3375
+ && f('1.10.0', '1.9.445', false).publish === true // minor ↑ → 배포
3376
+ && f('1.10.0', '1.9.445', false).reason === 'minor_bump'
3377
+ && f('2.0.0', '1.9.445', false).publish === true // major ↑ → 배포
3378
+ && f('1.9.446', '1.9.445', true).publish === true // force → 배포
3379
+ && f('1.9.0', null, false).publish === true // 최초 → 배포
3380
+ && m._minorKey('1.9.445') === '1.9' && m._minorKey('1.10.0') === '1.10';
3381
+ const src = read(__filename);
3382
+ const wired = src.includes('const gate = _shouldPublishNpm(pkgVersion, publishedLatest, false);')
3383
+ && src.includes("forcePublish: has('--publish-npm')");
3384
+ return pure && wired;
3385
+ } },
3386
+ { name: '12th 외부평가 Codex P3 (UR-0145): plan progress 읽기전용 요약(완료율%/--json) + 변경의도 인자 경고 (1.9.447)', run: () => {
3387
+ const src = read(__filename);
3388
+ const richer = src.includes('const percent = total ? Math.round((done / total) * 100) : 0;') && src.includes("log(`# plan progress (읽기 전용 요약)`);");
3389
+ const jsonOut = src.includes("log(JSON.stringify({ ok: true, total, done, percent, milestones, counts }, null, 2)); return;");
3390
+ const intentWarn = src.includes('if (opts.updateIntent) warn(') && src.includes("updateIntent: args.slice(2).some(a => /^M-\\d/i.test(a)) || has('--status') || arg('--progress', null) != null");
3391
+ return richer && jsonOut && intentWarn;
3392
+ } },
3393
+ { name: 'GPT-5.5 전략리뷰 §6.6 (UR-0154): export/prompt = adapter 별칭 (--target + agents-md→codex) (1.9.448)', run: () => {
3394
+ const src = read(__filename);
3395
+ const wired = src.includes("if (cmd === 'export' || cmd === 'prompt') {")
3396
+ && src.includes("arg('--target', null)")
3397
+ && src.includes("'agents-md': 'codex'")
3398
+ && src.includes('return adapterCmd(arg(\'--path\', process.cwd()), _xTool);');
3399
+ return wired;
3400
+ } },
3401
+ { name: '12th 외부평가 Sonnet P3 (UR-0143): plan drop 은 plan.md(D-)만 기록, progress-tracker T- 행 미생성 (1.9.449)', run: () => {
3402
+ const src = read(__filename);
3403
+ // planDrop 에서 upsertProgress(dropped task) 제거 + ok 메시지가 plan.md 가리킴
3404
+ const noTaskRow = !/function planDrop[\s\S]*?upsertProgress\(root, \{ id: tid, status: 'dropped'/.test(src);
3405
+ const dropsToPlan = src.includes("ok(`plan dropped: ${id} → .harness/plan.md (Out of Scope / Dropped)`);");
3406
+ return noTaskRow && dropsToPlan;
3407
+ } },
3369
3408
  { name: 'VERSION 형식 (x.y.z)', run: () => /^\d+\.\d+\.\d+$/.test(VERSION) }
3370
3409
  ];
3371
3410
  }
@@ -3945,6 +3984,7 @@ function commandsCmd(root) {
3945
3984
  { cmd: 'state show|start|record|verify|handoff', desc: '.leerness/ JSON 상태 substrate (에이전트 간 인수인계 표준) — 1.9.278' },
3946
3985
  { cmd: 'adapter <tool>|list [--dry-run]', desc: '도구별 지침/.mcp.json 선택 생성 (claude/cursor/codex/goose/...) — 1.9.280' },
3947
3986
  { cmd: 'ci init [path] [--force]', desc: 'PR 마다 leerness gate 실행하는 GitHub Actions 워크플로 생성 (.github/workflows/leerness-gate.yml) — 1.9.444' },
3987
+ { cmd: 'export|prompt --target <agent>', desc: 'adapter 별칭 — 도구별 지침/계약 파일 생성 (claude/cursor/codex/agents-md/...) — 1.9.448' },
3948
3988
  { cmd: 'policy show|set|check', desc: '권한 등급 (read-only…publish) — opt-in enforced (위험 명령 차단) — 1.9.281' },
3949
3989
  { cmd: 'reuse-check "<기능>"', desc: '외부 OSS 빌드 vs 재사용 결정 게이트 (오프라인 카테고리+체크리스트) — 1.9.285' },
3950
3990
  { cmd: 'skill impact', desc: '스킬 설치 영향 경량 상관추적 (사용 빈도 ↔ 검증 통과율, advisory) — 1.9.286' },
@@ -6321,15 +6361,26 @@ function planDrop(root, text) {
6321
6361
  } else {
6322
6362
  append(planFile, `\n${droppedHeader}\n| ID | Item | Reason | Date |\n|---|---|---|---|\n| ${id} | ${text} | ${reason} | ${today()} |\n`);
6323
6363
  }
6324
- const tid = nextId(root, 'T');
6325
- upsertProgress(root, { id: tid, status: 'dropped', request: text, evidence: `drop:${reason}`, nextAction: '없음' });
6326
- ok(`plan dropped: ${id} → progress: ${tid}`);
6364
+ // 1.9.449 (12th 외부평가 Sonnet P3, UR-0143): progress-tracker 에 dropped task(T-) 행 생성 제거 — plan drop 은 plan.md "Out of Scope / Dropped"(D-) 에만 기록.
6365
+ // 기존엔 scope 드랍이 phantom T- task 로도 생겨 plan↔progress 역할 혼선 + task list 노이즈. 드랍 기록의 단일 출처 = plan.md.
6366
+ ok(`plan dropped: ${id} → .harness/plan.md (Out of Scope / Dropped)`);
6327
6367
  }
6328
- function planProgress(root) {
6368
+ function planProgress(root, opts = {}) {
6369
+ // 1.9.447 (12th 외부평가 Codex P3, UR-0145): 읽기 전용 진행 요약 — 완료율%+상태별+마일스톤 수. --json 지원.
6370
+ // 기존엔 task status 카운트만 출력하며 명령명이 milestone 변경처럼 오인됨 + M-id/--status/--progress 를 silent ignore → 변경의도 인자 시 경고.
6329
6371
  const rows = readProgressRows(root);
6372
+ const tasks = rows.filter(r => /^T-/.test(r.id));
6330
6373
  const counts = {}; for (const s of STATUSES) counts[s] = 0;
6331
- for (const r of rows) if (counts[r.status] != null) counts[r.status]++;
6332
- log(JSON.stringify(counts, null, 2));
6374
+ for (const r of tasks) if (counts[r.status] != null) counts[r.status]++;
6375
+ const total = tasks.length;
6376
+ const done = counts['done'] || 0;
6377
+ const percent = total ? Math.round((done / total) * 100) : 0;
6378
+ const milestones = rows.filter(r => /^M-/.test(r.id)).length;
6379
+ if (opts.json) { log(JSON.stringify({ ok: true, total, done, percent, milestones, counts }, null, 2)); return; }
6380
+ log(`# plan progress (읽기 전용 요약)`);
6381
+ log(` 완료율: ${done}/${total} (${percent}%)${milestones ? ` · 마일스톤 ${milestones}개` : ''}`);
6382
+ for (const s of STATUSES) if (counts[s]) log(` ${s}: ${counts[s]}`);
6383
+ if (opts.updateIntent) warn('plan progress 는 읽기 전용 요약입니다 — 상태/진행 변경은 task update <T-ID> --status … 또는 plan add|drop 을 사용하세요.');
6333
6384
  }
6334
6385
  // 1.9.126: plan remove — milestone 블록을 plan.md에서 제거 + archive 보존
6335
6386
  // Memory Surface DELETE 5종 완전 완성 (task drop / decision drop / lesson drop / rule remove / plan remove)
@@ -13028,7 +13079,7 @@ function releaseSyncMainCmd(root) {
13028
13079
  // opt-out: --no-npm 또는 LEERNESS_NO_NPM_PUBLISH=1
13029
13080
  // 토큰 미설정 시 친절한 안내 후 skip (실패 X).
13030
13081
  if (!has('--no-npm') && process.env.LEERNESS_NO_NPM_PUBLISH !== '1') {
13031
- try { _publishToNpm(root, { dryRun: has('--dry-run-npm') }); } catch (e) { warn('npm publish 시도 실패 (계속): ' + e.message); }
13082
+ try { _publishToNpm(root, { dryRun: has('--dry-run-npm'), forcePublish: has('--publish-npm') }); } catch (e) { warn('npm publish 시도 실패 (계속): ' + e.message); } // 1.9.446 (UR-0160): --publish-npm 으로 minor-gate 강제 우회
13032
13083
  }
13033
13084
  }
13034
13085
 
@@ -13197,6 +13248,21 @@ function _publishToNpm(root, opts = {}) {
13197
13248
  }
13198
13249
  } catch {} // 네트워크 실패 시 그냥 publish 시도
13199
13250
 
13251
+ // 1.5) R-0011/UR-0160: npm 배포는 minor(x.x) 변동 시에만 — 같은 minor 내 patch 는 스킵(GitHub/CHANGELOG 는 유지). --publish-npm 으로 강제.
13252
+ if (!opts.forcePublish) {
13253
+ let publishedLatest = null;
13254
+ try {
13255
+ const latestR = cp.spawnSync('npm', ['view', pkgName, 'version'], { cwd: root, encoding: 'utf8', shell: true, timeout: 15000 });
13256
+ if (latestR.status === 0) publishedLatest = (latestR.stdout || '').trim();
13257
+ } catch {}
13258
+ const gate = _shouldPublishNpm(pkgVersion, publishedLatest, false);
13259
+ if (!gate.publish) {
13260
+ log(` ⏸ npm 배포 스킵 (R-0011): patch(${pkgVersion}) 는 npm 미배포 — 직전 npm minor(${_minorKey(publishedLatest) || '?'}) 와 동일. minor 올릴 때만 안정 버전으로 배포. (강제: release sync-main . --publish-npm)`);
13261
+ return;
13262
+ }
13263
+ if (gate.reason === 'minor_bump') log(` ▶ minor 변동(${_minorKey(publishedLatest)} → ${_minorKey(pkgVersion)}) — npm 안정 배포 진행`);
13264
+ }
13265
+
13200
13266
  // 2) 임시 .npmrc 생성 (토큰 노출 방지)
13201
13267
  let tmpDir;
13202
13268
  try {
@@ -19039,6 +19105,13 @@ async function main() {
19039
19105
  const _aRoot = (args[2] && !args[2].startsWith('-')) ? args[2] : arg('--path', process.cwd());
19040
19106
  return adapterCmd(_aRoot, _aTool);
19041
19107
  }
19108
+ // 1.9.448 (GPT-5.5 전략리뷰 §6.6/7.3, UR-0154): export/prompt = adapter 별칭 — GPT-5.5 권고 표면명 정합(도구별 지침/계약 파일 생성).
19109
+ if (cmd === 'export' || cmd === 'prompt') {
19110
+ const _ADAPTER_ALIAS = { 'agents-md': 'codex', 'agents': 'codex', 'agent': 'codex', 'agents.md': 'codex' };
19111
+ let _xTool = arg('--target', null) || (args[1] && !args[1].startsWith('-') ? args[1] : 'list');
19112
+ _xTool = _ADAPTER_ALIAS[String(_xTool).toLowerCase()] || _xTool;
19113
+ return adapterCmd(arg('--path', process.cwd()), _xTool);
19114
+ }
19042
19115
  // 1.9.245: API skill cache — 공식 문서·관련링크 자동 정리 (사용자 명시 UR-0015)
19043
19116
  if (cmd === 'api-skill') return apiSkillCmd(arg('--path', process.cwd()), args[1] || 'help');
19044
19117
  // 1.9.208: leerness constraints <list|check|add> — 플랫폼/API 제약 사전 체크 (사용자 명시)
@@ -19095,7 +19168,7 @@ async function main() {
19095
19168
  if (sub==='add') return planAdd(root, args.slice(2).join(' ') || '새 계획');
19096
19169
  if (sub==='drop') return planDrop(root, args.slice(2).join(' ') || '드랍 항목');
19097
19170
  if (sub==='remove') return planRemoveCmd(root, args[2]);
19098
- if (sub==='progress') return planProgress(root);
19171
+ if (sub==='progress') return planProgress(root, { json: has('--json'), updateIntent: args.slice(2).some(a => /^M-\d/i.test(a)) || has('--status') || arg('--progress', null) != null }); // 1.9.447 (UR-0145): --json + 변경의도 인자 경고
19099
19172
  if (sub==='sync') return planSync(root);
19100
19173
  // 1.9.119: plan list — 모든 milestone JSON/verbose
19101
19174
  if (sub==='list') return planListCmd(absRoot(_resolveRoot(args[2])), { json: has('--json') }); // 1.9.412 (UR-0100): positional path 지원
package/lib/pure-utils.js CHANGED
@@ -1025,7 +1025,9 @@ module.exports = {
1025
1025
  // 1.9.442 (12th 외부평가, UR-0141): task 계열 positional path 안전 추출
1026
1026
  _taskPositionalPath,
1027
1027
  // 1.9.443 (GPT-5.5 전략리뷰 §6.3, UR-0153): evidence-first 완료 게이트
1028
- _completionClaimAllowed
1028
+ _completionClaimAllowed,
1029
+ // 1.9.446 (R-0011/UR-0160): npm 배포 minor-gate
1030
+ _minorKey, _shouldPublishNpm
1029
1031
  };
1030
1032
 
1031
1033
  // 1.9.355 (UR-0075 Phase A): AI 에이전트용 크로스버전 마이그레이션 안전 워크플로 가이드 (순수 텍스트). 임시설치 + --path + 백업 + diff 검증.
@@ -1288,6 +1290,21 @@ function _lineSafe(s) { return String(s == null ? '' : s).replace(/\r\n|\r|\n/g,
1288
1290
  // 1.9.407 (8번째 버그헌트, UR-0111): --limit 안전 파싱 — NaN(예: '--limit abc')/음수/0 은 slice(0,NaN)=[] 로 모든 결과를 조용히 숨김 → 기본값으로 폴백.
1289
1291
  function _parseLimit(raw, def) { const n = parseInt(raw, 10); return (Number.isFinite(n) && n > 0) ? n : def; }
1290
1292
 
1293
+ // 1.9.446 (R-0011/UR-0160): npm 배포 minor-gate. current(현재 버전) vs published(npm latest) 의 major.minor 비교.
1294
+ // minor 가 올라갔으면(또는 최초/major↑) publish, 같은 minor 내 patch 면 skip. force 면 무조건 publish.
1295
+ function _minorKey(v) { const m = String(v || '').match(/^(\d+)\.(\d+)/); return m ? `${m[1]}.${m[2]}` : null; }
1296
+ function _shouldPublishNpm(current, published, force) {
1297
+ if (force) return { publish: true, reason: 'forced' };
1298
+ const cm = String(current || '').match(/^(\d+)\.(\d+)/);
1299
+ if (!cm) return { publish: false, reason: 'invalid_current' };
1300
+ const pm = String(published || '').match(/^(\d+)\.(\d+)/);
1301
+ if (!pm) return { publish: true, reason: 'no_published' }; // 최초 배포
1302
+ const c = [Number(cm[1]), Number(cm[2])], p = [Number(pm[1]), Number(pm[2])];
1303
+ if (c[0] > p[0] || (c[0] === p[0] && c[1] > p[1])) return { publish: true, reason: 'minor_bump' }; // major/minor ↑
1304
+ if (c[0] === p[0] && c[1] === p[1]) return { publish: false, reason: 'same_minor' }; // patch — 미배포
1305
+ return { publish: false, reason: 'not_ahead' }; // 동일/하위
1306
+ }
1307
+
1291
1308
  // 1.9.416 (9th 외부평가 Sonnet/Codex, UR-0122): add 류(task/requests/decision) 제목 파싱 단일 출처.
1292
1309
  // positional 을 join 하되 첫 --flag 또는 경로형 토큰(/x, C:\x, ./x, ../x)에서 멈춤 →
1293
1310
  // `task add "제목" /some/path` 가 경로를 제목에 흡수하던 오염(decision add 는 이미 차단)을 일관 적용.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "leerness",
3
- "version": "1.9.445",
3
+ "version": "1.10.0",
4
4
  "description": "Leerness: 비파괴 마이그레이션, 자동 버전 감지·업데이트, 계획/진행/핸드오프 자동화, 게으름·시크릿·인코딩 자동 가드, Claude Code 슬래시 통합을 갖춘 한국어 우선 AI 개발 하네스.",
5
5
  "keywords": [
6
6
  "leerness",
package/scripts/e2e.js CHANGED
@@ -1457,7 +1457,7 @@ total++;
1457
1457
  const r = cp.spawnSync(process.execPath, [CLI, 'migrate', tmpC, '--yes', '--no-banner', '--no-stale-check'], { encoding: 'utf8', timeout: 60000 });
1458
1458
  const ok = r.status === 0
1459
1459
  && /AI must re-read/.test(r.stdout)
1460
- && /1\.9\.36 → 1\.9\.\d+/.test(r.stdout)
1460
+ && /1\.9\.36 → \d+\.\d+\.\d+/.test(r.stdout)
1461
1461
  && /신규 명령/.test(r.stdout);
1462
1462
  console.log(ok ? '✓ B(1.9.41) migrate stdout: AI must re-read 차분 자동 출력' : `✗ migrate 차분 출력 실패`);
1463
1463
  if (!ok) { failed++; console.log(r.stdout.slice(-800)); }
@@ -1902,7 +1902,7 @@ total++;
1902
1902
  && /███████╗/.test(r.stdout)
1903
1903
  && /verify · remember/.test(r.stdout)
1904
1904
  && /AI 에이전트 검수.기억.드리프트 방지 하네스/.test(r.stdout)
1905
- && /v1\.9\.\d+/.test(r.stdout);
1905
+ && /v\d+\.\d+\.\d+/.test(r.stdout);
1906
1906
  console.log(ok ? '✓ B(1.9.34) 배너 색상 + ASCII + 한국어' : `✗ 배너 색상 실패`);
1907
1907
  if (!ok) { failed++; console.log(r.stdout.slice(0, 500)); }
1908
1908
  }