leerness 1.36.60 → 1.36.62

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,23 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.36.62 — 2026-07-21 — commands/AX/잔여 참조층 en 완역 (F-05 4회차) — R-0001 검수 7회전
4
+
5
+ en init 한글 잔존 23/61 → **9/61**. 잔여 9개는 성격이 다른 대상(스킬 카탈로그 한국어 데이터 5·파서-결합 헤더 2·README 관리 섹션·skill-index 데이터 컬럼) — 별도 판단 대상으로 명시.
6
+
7
+ - **en 오버라이드 14종**: .claude/commands 5·skills/leerness.md·AX 가이드 4·test-evidence/review-evidence·skill-index·context-routing·feature-graph.
8
+ - (검수 #1) **/update 한국어 되덮기**: auto-update 훅 설치기가 en 템플릿을 한국어로 재작성 — 언어 인지 렌더. (검수 #2) **feature add 가 en 그래프를 한국어로 회귀+frontmatter 소실**: _writeFeatureGraph 가 매 저장마다 ko 템플릿 전체 재생성 — 기존 서두를 '## Nodes' 까지 보존. (검수 #3) 전환 누락 4종: AX_PLAN/test-evidence 는 managed 편입, review-evidence 는 _USER_STATE 편입(검증 이력=사용자 데이터), feature-graph 는 #2 경로가 커버. (검수 #4) verify-code 증거 마커 en 프로젝트에서 `(auto)`.
9
+ - 검증: en /update·feature add 후 그래프 무한글+frontmatter 보존+파싱 실측, ko 15종 바이트 무회귀(검수), selftest 332.
10
+
11
+ ## 1.36.61 — 2026-07-21 — .harness 정책·시드 문서군 en 완역 (F-05 3회차) — R-0001 검수 6회전
12
+
13
+ en init 한글 잔존 53/61 → **23/61** (1·3회차 누적). 검수 계약 대조: 6개 대표 문서 규칙 전량 보존 확인.
14
+
15
+ - **en 오버라이드 27종**: guideline/guardrails/anti-lazy/writeback/session-close/secret/encoding/consistency/testing/checklists/plan·brief·current-state·decisions·task-log·handoff 시드 등 — read-order 참조층 전체.
16
+ - **자가 선검**: en brief placeholder 문구가 감지 regex 와 미스매치(작성됨 오판) → 문구 정합 (anchors status true/true 실측).
17
+ - (검수 High) **정책문서 12종 managed 편입** — 언어 전환 시 구 언어로 방치되던 것 (사용자 상태 문서는 의도 제외). 실측: en→ko 전환 시 guardrails 한국어 재생성 + 커스텀 1회 + 영어 잔재 0.
18
+ - (검수 Medium) **en 센티널 인식**: audit/lazy detect 의 `(자동)`, design-token `(실제 값으로 업데이트)` 만 알던 감시자들에 `(auto)`/`(update with real value)` 병기 — KO/EN audit 발견 동수(5=5) 회복, --fix 양 언어.
19
+ - 검증: e2e en 케이스 10종 무한글로 확대, selftest 332, 검수 통과 프로브(파서 소비자 전수·integrity en 12종·전환 왕복).
20
+
3
21
  ## 1.36.60 — 2026-07-21 — 언어 전환 현지화 병합 (F-05 2회차, 전 검수 High 해소) — R-0001 검수 5회전
4
22
 
5
23
  KO→EN(역방향 포함) 전환 시 지시 레이어가 새 언어로 재생성되고 사용자 커스텀만 정확히 1회 이월된다.
package/README.md CHANGED
@@ -122,7 +122,7 @@ MIT
122
122
  <!-- leerness:project-readme:start -->
123
123
  ## Leerness Project Harness
124
124
 
125
- 이 프로젝트는 Leerness v1.36.60 하네스를 사용합니다. AI 에이전트는 작업 전 `leerness handoff`로 컨텍스트를 적재하고, 작업 후 `leerness check`/`leerness audit`/`leerness session close`를 수행해야 합니다.
125
+ 이 프로젝트는 Leerness v1.36.62 하네스를 사용합니다. AI 에이전트는 작업 전 `leerness handoff`로 컨텍스트를 적재하고, 작업 후 `leerness check`/`leerness audit`/`leerness session close`를 수행해야 합니다.
126
126
 
127
127
  ### 정체성 — AI 에이전트 운영 레이어 (UR-0030)
128
128
 
@@ -176,7 +176,7 @@ leerness memory restore decision <date|title>
176
176
 
177
177
  ### MCP server (외부 AI 통합)
178
178
 
179
- Leerness v1.36.60는 stdio JSON-RPC MCP server를 내장합니다 — Claude Code · Cursor · Codex CLI 등 외부 AI에 **86개 도구**를 노출:
179
+ Leerness v1.36.62는 stdio JSON-RPC MCP server를 내장합니다 — Claude Code · Cursor · Codex CLI 등 외부 AI에 **86개 도구**를 노출:
180
180
 
181
181
  ```jsonc
182
182
  // 카테고리별
@@ -197,7 +197,7 @@ Leerness v1.36.60는 stdio JSON-RPC MCP server를 내장합니다 — Claude Cod
197
197
  `<<autonomous-loop-dynamic>>` 신호만 보내면 AI가:
198
198
  1) 다음 라운드 후보 선정 → 2) 코드 변경 → 3) 회귀 테스트 갱신 → 4) 전체 e2e 스위트 통과 → 5) npm publish + git tag → 6) main push → 7) session close → 8) 다음 라운드 예약.
199
199
 
200
- 현재 누적: **v1.9.x → 1.36.60 릴리스 태그 이력** (수백 라운드) · _reports/는 비공개 보존.
200
+ 현재 누적: **v1.9.x → 1.36.62 릴리스 태그 이력** (수백 라운드) · _reports/는 비공개 보존.
201
201
 
202
202
  ### 성능 가이드
203
203
 
@@ -235,6 +235,6 @@ leerness release pack --close --auto-main-push
235
235
  - `.harness/session-handoff.md`: 다음 세션 인수인계 (자동 작성)
236
236
  - `.harness/lessons.md` / `decisions.md` / `rules.md`: 영구 메모리 (5 surface)
237
237
 
238
- Last synced by Leerness v1.36.60: 2026-07-22
238
+ Last synced by Leerness v1.36.62: 2026-07-22
239
239
  <!-- leerness:project-readme:end -->
240
240
 
package/bin/leerness.js CHANGED
@@ -34,7 +34,7 @@ const { CAPABILITY_SURFACE, POWERFUL_COMMANDS, ADAPTERS, REUSE_CATEGORIES, REUSE
34
34
  const { tokenizeForRank: _tokenizeForRank, expandQuery: _expandQuery, scoreHits: _scoreHits, suggestTerms: _suggestTerms } = require('../lib/search-core'); // 1.36.23: memory search 랭킹 코어(순수·0-deps)
35
35
  const { findCorruptedStateJson: _findCorruptedStateJson } = require('../lib/state-integrity'); // 1.36.1 (클린룸 리뷰 FN): .harness/*.json 상태 무결성 (audit/health/check 공유)
36
36
 
37
- const VERSION = '1.36.60';
37
+ const VERSION = '1.36.62';
38
38
 
39
39
  // 1.9.290 (UR-0037, Codex gpt-5.5 #4 수렴): CLI 전용 부작용은 require 시 실행하지 않는다.
40
40
  // 이전: warning listener 제거 / NODE_OPTIONS 변경 / chcp IIFE 가 top-level 즉시 실행 → require('harness') 시 호스트 프로세스 오염.
@@ -667,6 +667,50 @@ leerness memory restore <surface> <target> # archive → active 복귀 (DELETE
667
667
  if (lang === 'en') {
668
668
  _files['AGENTS.md'] = `${MARK}\n# Leerness Agent Instructions\n\n## ⭐ First action every session\n**Read \`.harness/session-workflow.md\` first and follow its 6-step workflow**: analyze request → plan → distribute → sub-agent work → integrated verification → close. Keep the same flow regardless of round length/complexity — that is what prevents drift.\n\n## Static vs dynamic — the leerness boundary\n**AGENTS.md = static project instructions** (coding rules, test commands, prohibitions, deploy steps — rarely change).\n**leerness = dynamic work state, memory, verification, handoff** (current goal, changed files, failed attempts, verification results, next-agent handoff — change every task).\n- Put rules/commands/prohibitions here in AGENTS.md.\n- Dynamic state (decisions/lessons/plan/progress/verification/handoff) is recorded by leerness in the **default workspace \`.harness/\`** (decisions.md / lessons.md / plan.md / progress-tracker.md / session-handoff.md) via \`leerness handoff\`, \`decision add\`, \`lesson save\`, etc.\n- (Optional) the JSON state substrate of \`leerness state show|start|record|verify|handoff\` (or MCP \`leerness_state_*\`) lives in \`.leerness/\` — the cross-agent handoff standard, separate from the main workspace.\n- leerness **complements** AGENTS.md, it does not replace it. Static instructions here, dynamic state in leerness.\n\n## Mandatory read order (session start)\n1. **.harness/session-workflow.md** (6-step workflow — highest priority)\n2. .harness/context-routing.md\n3. .harness/session-handoff.md\n4. .harness/current-state.md\n5. .harness/plan.md\n6. .harness/progress-tracker.md\n7. .harness/guideline.md\n8. .harness/protected-files.md\n9. .harness/writeback-policy.md\n10. .harness/anti-lazy-work-policy.md\n11. **.harness/rules.md** (user-defined standing rules — follow every session)\n\n## Required behavior\n- Run \`leerness handoff .\` at session start to load context (handoff prints active rules automatically).\n- **Ask-on-ambiguity duty**: if the user's request has parts open to interpretation (vague qualifiers, pronouns, multiple alternatives, unclear scope), **ask the user instead of guessing**. Ask the questions produced by \`leerness clarify "<request>"\` verbatim. Even without detected signals, when your own judgment is split, asking wins.\n- **Preview-approval duty (new features)**: when the user asks for a new feature, **do not write code first**. ① Register a preview with \`leerness preview add "<feature>" --design "<design/UX>" --features "<list>"\`, ② present it and ask for approval or revisions, ③ on approval run \`leerness preview approve <P-ID>\`; on revision \`leerness preview revise <P-ID> --note "..."\` and re-present. **Never write the feature's code before approve.**\n- Classify work with \`leerness route <task-type>\` (planning, feature, bugfix, refactor, research, consistency, release, migration, session-start, session-close, harness-maintenance).\n- Never delete protected files/managed sections — merge, archive, or mark deprecated instead.\n- After meaningful changes update progress-tracker, current-state, task-log, session-handoff.\n- Before claiming completion, self-verify with \`leerness check .\` or \`leerness lazy detect .\` and answer the \`leerness lens\` self-questions per domain (code: "would a senior developer find this needlessly complex?" / design: "would a senior designer and an ordinary user find this pretty and intuitive?").\n- Before changes run the guards: \`leerness scan secrets .\`, \`leerness encoding check .\`.\n- Before duplicating a capability check design-system.md, consistency-policy.md, reuse-map.md.\n- Close every session with \`leerness session close .\` — 9 categories (done/in-progress/incomplete/planned/waiting/on-hold/blocked/dropped/verification) + active-rule verification.\n- Updates: \`leerness update --check\` (detect) → \`leerness update --yes\` (auto-migrate).\n\n## Natural-language retro/insights/brainstorm\n| User phrase | Run immediately |\n|---|---|\n| "retrospective / look back / wrap up" | \`leerness retro\` |\n| "retro for last N days" | \`leerness retro --days N\` |\n| "stats / cumulative metrics / insights" | \`leerness insights\` |\n| "brainstorm about X / materials on X / review before starting X" | \`leerness brainstorm "X"\` |\n\nsession close prints a one-line summary automatically every time and runs a deep retrospective every 5 sessions; call the commands immediately when the user asks explicitly.\n\n## Natural-language standing rules\nWhen the user states a standing rule ("do Y every X"), register it immediately:\n\n| User phrase | Run immediately |\n|---|---|\n| "bump the version every update" | \`leerness rule add "bump version (patch)" --trigger every-update\` |\n| "add patch notes every commit" | \`leerness rule add "add patch notes" --trigger every-commit\` |\n| "deploy at session close" | \`leerness rule add "deploy (release publish)" --trigger session-close\` |\n| "pause/stop rule X" | \`leerness rule pause <ID>\` (find the ID with \`rule list\`) |\n| "remove rule X" | \`leerness rule remove <ID>\` |\n| "stop all rules" | \`leerness rule stop\` |\n| "resume rules" | \`leerness rule resume-all\` or \`leerness rule resume <ID>\` |\n\nAfter registering, report the result (ID + trigger + description) and apply it every session until the user explicitly says stop/remove.\n\n## Automatic rule verification\n- **every-update / version rules**: checks package.json version change.\n- **CHANGELOG / patch-note rules**: checks CHANGELOG.md mtime.\n- **test / verify rules**: checks today's verify traces in review-evidence.md.\n- **deploy / publish / push rules**: not auto-verifiable → guides \`leerness release publish\`.\n\nAutomate verifiable rules with \`leerness release bump\`, \`leerness release note "..."\`, and \`leerness release publish\`.\n`;
669
669
  _files['CLAUDE.md'] = `${MARK}\n# Claude Code Instructions\n\nFollow AGENTS.md. Always run \`leerness handoff .\` at the start and \`leerness session close .\` before ending a session.\n\n**⭐ First action every session**: follow the 6-step workflow in \`.harness/session-workflow.md\` (analyze → plan → distribute → sub-agent → verify → close). On drift critical, recover with \`leerness drift check --auto-fix\`.\n\nProtected files must not be deleted. Read .harness/anti-lazy-work-policy.md before claiming completion.\n\n## Natural-language standing rules\nWhen the user states "do Y every X", immediately run \`leerness rule add "Y" --trigger every-X\`. Registered rules are printed by every \`handoff\` and verified by \`session close\`. Only \`rule pause/remove\` when the user explicitly says stop/remove.\n\nSee the "Natural-language standing rules" table in AGENTS.md for the full mapping.\n`;
670
+ // 1.36.62 (F-05 4회차): commands/AX/잔여 참조층 en 완역
671
+ _files['.harness/test-evidence-policy.md'] = fm('test-evidence-policy', ['recording verification results'], ['verification format changes'], `# Test Evidence Policy\n\nEvery verification is appended to \`.harness/review-evidence.md\`.\n\n## Format\n\`\`\`\n## YYYY-MM-DD HH:MM\nTask: T-XXXX\nCommand: <command>\nExit: <code>\nNote: <key result summary>\nArtifacts: <screenshot/log paths>\n\`\`\`\n`, 'en');
672
+ _files['.harness/review-evidence.md'] = fm('review-evidence', ['progress reports', 'release review'], ['verification results recorded'], `# Review Evidence\n\nVerification command/result history. Append-only.\n`, 'en');
673
+ _files['.harness/AX_PLAN_GUIDE.md'] = fm('ax-plan-guide', ['planning/plan changes', 'new project'], ['plan guide changes'], `# AX Plan Guide\n\n1. Check whether the user's request is within the current plan.md scope.\n2. If it is new scope, add it to both plan.md (milestone) and progress-tracker.md (T-id).\n3. When the user drops scope, mark it dropped instead of deleting.\n4. For new projects, fill plan.md/project-brief.md before coding.\n`, 'en');
674
+ _files['.harness/AX_MIGRATION_GUIDE.md'] = fm('ax-migration-guide', ['before migration'], ['migration policy changes'], `# AX Migration Guide\n\n- Back up before changes (\`.harness/archive/\`).\n- Preserve existing project memory (preserve-by-default).\n- Merge .env.example/.gitignore line by line.\n- Never delete protected files.\n- Migration report: \`.harness/migration-report.md\`.\n- Automatic: \`leerness update --yes\` performs backup, merge, and verification in one step.\n`, 'en');
675
+ _files['.harness/AX_NEW_PROJECT_GUIDE.md'] = fm('ax-new-project-guide', ['new project detected'], ['fresh-install policy changes'], `# AX New Project Guide\n\nBefore coding, ask or infer the project goal, users, scope, out-of-scope, stack, deployment target, and milestones. Then fill plan.md and project-brief.md.\n`, 'en');
676
+ _files['.harness/AX_SKILL_LIBRARY_GUIDE.md'] = fm('ax-skill-library-guide', ['skill learning/verification/upload'], ['skill policy changes'], `# AX Skill Library Guide\n\nValidated skills require metadata, sensitive data scan, AI verification, dry-run publish, and explicit execute approval.\n`, 'en');
677
+ _files['.harness/skill-index.md'] = fm('skill-index', ['choosing skills per task'], ['skills added/removed'], `# Skill Index\n\n| ID | Korean Name | Capabilities | Last Updated | Verification |\n|---|---|---|---|---|\n${skillRows}\n`, 'en');
678
+ _files['.harness/context-routing.md'] = fm('context-routing', ['before all work', 'judging task type'], ['task types added', 'reference files change'], `# Context Routing\n\n${Object.entries(routes).map(([k, v]) => `## ${k}\nRead:\n${v.read.map(x => '- ' + x).join('\n')}\n\nUpdate:\n${v.update.map(x => '- ' + x).join('\n')}`).join('\n\n')}\n`, 'en');
679
+ _files['.harness/feature-graph.md'] = fm('feature-graph', ['before adding features', 'before data-format changes', 'before external-API mapping work'], ['feature register / link / impact recall'], `# Feature Graph\n\n> **Purpose**: track each feature's causal relations so impact scope is known before writing code.\n> Before new features, format changes, or external-API mapping, run \`leerness feature impact <id>\`.\n> handoff auto-matches the current task keywords and recalls affected features.\n\n## How to use\n\n\`\`\`bash\nleerness feature add "User Auth" # F-0001 auto-assigned\nleerness feature link F-0002 --depends-on F-0001 # dependency\nleerness feature link F-0001 --affects F-0002,F-0005 # impact (multiple)\nleerness feature link F-0001 --co-changes-with F-0011 # must change together\nleerness feature impact F-0001 # full transitive impact\nleerness feature list --json # graph JSON\nleerness feature show F-0001 # single detail\n\`\`\`\n\n## Nodes\n\n`, 'en');
680
+ _files['.claude/commands/handoff.md'] = `# /handoff\n\nLoad the current project's context.\n\n\`\`\`\n!leerness handoff .\n\`\`\`\n`;
681
+ _files['.claude/commands/session-close.md'] = `# /session-close\n\nGenerate the end-of-session report and update session-handoff.md.\n\n\`\`\`\n!leerness session close .\n\`\`\`\n`;
682
+ _files['.claude/commands/audit.md'] = `# /audit\n\nCheck plan-progress alignment, design/reuse consistency, secrets, and encoding in one pass.\n\n\`\`\`\n!leerness audit .\n!leerness scan secrets .\n!leerness encoding check .\n\`\`\`\n`;
683
+ _files['.claude/commands/lazy-detect.md'] = `# /lazy-detect\n\nRun the lazy-work (false-done) automatic evaluation.\n\n\`\`\`\n!leerness lazy detect .\n\`\`\`\n`;
684
+ _files['.claude/commands/update.md'] = `# /update\n\nRun the leerness auto-update (detect → migrate → verify).\n\n\`\`\`\n!leerness update --yes\n\`\`\`\n`;
685
+ _files['.claude/skills/leerness.md'] = `---\nname: leerness\ndescription: Leerness harness commands - handoff, audit, scan secrets, encoding check, lazy detect, session close, update. Use when the user asks to load project context, verify work quality, scan secrets, check encoding, or end a session.\n---\n\n# leerness skill\n\n## When to use\n- When the user asks to load project context\n- When self-verification is requested before claiming completion\n- When ending a session or asked for a handoff\n- When secret/encoding checks are requested\n- When applying a new leerness version\n\n## Commands\n\n\`\`\`bash\nleerness handoff . # load context\nleerness check . # pre-action check\nleerness audit . # consistency/plan-alignment audit\nleerness scan secrets . # secret pattern scan\nleerness encoding check . # UTF-8/BOM/NUL\nleerness lazy detect . # lazy-work evaluation\nleerness memory search "key" # search decisions/history\nleerness session close . # close report + auto handoff\nleerness update --yes # auto-update\n\`\`\`\n`;
686
+ // 1.36.61 (F-05 3회차): .harness 정책·시드 문서군 en 완역 — 지시 5종(1.36.59)에 이어 read-order 가 가리키는 참조층.
687
+ _files['.harness/project-brief.md'] = fm('project-brief', ['confirming project purpose', 'judging new features', 'planning'], ['project purpose changes', 'users/scope change'], `# Project Brief\n\n## Project\n${project}\n\n## Purpose\n- Update this with the real purpose of the project.\n\n## Users\n-\n\n## Success Criteria\n-\n`, 'en');
688
+ _files['.harness/plan.md'] = fm('plan', ['before starting work', 'new request received', 'scope change', 'new project detected'], ['plan add/update/drop', 'milestone changes', 'goal changes'], `# Plan\n\n## Goal\n- Maintain the overall plan around the user's purpose.\n\n## Scope\n- Record what is in scope.\n\n## Out of Scope / Dropped\n| ID | Item | Reason | Date |\n|---|---|---|---|\n\n## Milestones\n\n### M-0001. Organize the project plan\nStatus: planned\nProgress: 0%\n\nTasks:\n- [ ] Fill project-brief.md with the real project purpose\n- [ ] Fill context-map.md with the real file structure\n`, 'en');
689
+ _files['.harness/guideline.md'] = fm('guideline', ['checking quality bar before implementing', 'checking plan-execution criteria'], ['dev standards change', 'verification routine changes'], `# Guideline\n\n## Operating Principle\n- Work against the goal and scope in plan.md.\n- Judge done/not-done by request status in progress-tracker.md.\n- Never record progress percentages here — plan.md/progress-tracker.md are the single source.\n\n## Quality Gate\n- Check the relevant route before changes (\`leerness route <task-type>\`).\n- After changes run \`leerness verify\`, \`leerness audit\`, \`leerness check\`.\n- Before claiming completion run \`leerness lazy detect\`.\n- Close every session with \`leerness session close\`.\n`, 'en');
690
+ _files['.harness/plan-progress-boundary.md'] = fm('plan-progress-boundary', ['when plan and progress overlap', 'work-tracking structure changes'], ['role-separation criteria change'], `# Plan / Progress Boundary\n\n## plan.md\n- Overall goal, milestones, in/out of scope, plan-change history.\n\n## progress-tracker.md\n- Per-request status, evidence, next action.\n- ID rule: T-0001 monotonically increasing; IDs from plan add are unique across plan/progress.\n\n## guideline.md\n- The execution standards to follow while doing plan/progress work.\n`, 'en');
691
+ _files['.harness/current-state.md'] = fm('current-state', ['session start', 'taking over work'], ['current state changes', 'next work changes'], `# Current State\n\nUpdated: ${today()}\n\n## Now\n-\n\n## Next\n-\n\n## Blockers\n-\n`, 'en');
692
+ _files['.harness/writeback-policy.md'] = fm('writeback-policy', ['before finishing work', 'deciding what to update'], ['record targets change'], `# Writeback Policy\n\n- plan.md: user purpose, milestones, scope additions/exclusions\n- progress-tracker.md: per-request status and evidence (updated in place)\n- current-state.md: current state and next work\n- task-log.md: execution history (auto-appended)\n- session-handoff.md: next-session handoff (written by \`session close\`)\n- decisions.md: hard-to-reverse decisions\n- design-system.md: UI/UX/component standards\n- feature-contracts.md: input/output/state/error contracts\n- review-evidence.md: verification results (auto-accumulated)\n`, 'en');
693
+ _files['.harness/task-type-map.md'] = fm('task-type-map', ['classifying user requests'], ['task types added'], `# Task Type Map\n\n| User Request | Task Type | Route |\n|---|---|---|\n| plan this / draft a roadmap | planning | leerness route planning |\n| implement / build a feature | feature | leerness route feature |\n| fix a bug | bugfix | leerness route bugfix |\n| refactor / clean up | refactor | leerness route refactor |\n| research / compare | research | leerness route research |\n| unify design / consistency | consistency | leerness route consistency |\n| deploy / release | release | leerness route release |\n| migration | migration | leerness route migration |\n| session start / resume | session-start | leerness route session-start |\n| session end | session-close | leerness route session-close |\n`, 'en');
694
+ _files['.harness/protected-files.md'] = fm('protected-files', ['before deleting/cleaning/migrating files'], ['protected targets change'], `# Protected Files\n\nAI agents must not delete or reset these files without explicit user approval.\n\n- .harness/\n- .harness/skills/\n- .harness/library/\n- AGENTS.md\n- CLAUDE.md\n- .cursor/rules/leerness.mdc\n- .github/copilot-instructions.md\n- .claude/commands/\n- .claude/skills/\n- README.md Leerness managed section\n\nUse merge, archive, or deprecated markers instead of deletion.\n`, 'en');
695
+ _files['.harness/guardrails.md'] = fm('guardrails', ['before all work', 'before security/permissions/refactoring'], ['prohibition rules change'], `# Guardrails\n\n- Never store tokens/keys/passwords — record only environment-variable names.\n- No unrequested large refactors (user pre-approval when changing 5+ files).\n- Record the impact of API/DB/env-var changes in task-log.\n- Never delete Leerness protected files/managed sections.\n- Keep Korean text as UTF-8 without BOM.\n- Destructive Git operations (\`git reset --hard\`, \`git push --force\`, …) only after explicit user approval.\n`, 'en');
696
+ _files['.harness/consistency-policy.md'] = fm('consistency-policy', ['before duplicating UI/features', 'judging reuse'], ['consistency policy changes'], `# Consistency Policy\n\nBefore building something that does the same job, find and reuse/extend/connect the existing implementation.\n\n## Recursive Reuse Rule\n1. Find existing elements with the same capability.\n2. Check whether self-reference/base rules/recursive flow is needed.\n3. Reuse or extend the existing element.\n4. If you must build new, record why in reuse-map.md.\n\n## Audit Trigger\n\`leerness audit\` checks:\n- duplicate design-guide files\n- undefined design-system.md tokens\n- empty reuse-map.md with 3+ components/utils found\n- plan vs progress alignment\n`, 'en');
697
+ _files['.harness/testing-strategy.md'] = fm('testing-strategy', ['before verification', 'before release'], ['test strategy changes'], `# Testing Strategy\n\n- Typecheck (\`tsc --noEmit\` or equivalent)\n- Lint (\`npm run lint\` etc.)\n- Unit/Integration/E2E\n- Manual smoke test\n- Browser/UI smoke (on frontend changes)\n\n## Evidence Format\nEach completed task must reference an evidence ID stored in .harness/review-evidence.md.\n`, 'en');
698
+ _files['.harness/review-checklist.md'] = fm('review-checklist', ['before PR/review'], ['review criteria change'], `# Review Checklist\n\n- [ ] Aligned with the plan\n- [ ] progress-tracker updated\n- [ ] No protected files deleted\n- [ ] Design/feature reuse checked\n- [ ] No secrets in code (\`leerness scan secrets\`)\n- [ ] Korean encoding OK (\`leerness encoding check\`)\n- [ ] Lazy-work check passed (\`leerness lazy detect\`)\n`, 'en');
699
+ _files['.harness/release-checklist.md'] = fm('release-checklist', ['before deploy'], ['deploy conditions/env vars/rollback change'], `# Release Checklist\n\n- [ ] \`leerness verify .\`\n- [ ] \`leerness audit .\`\n- [ ] \`leerness scan secrets .\`\n- [ ] \`leerness encoding check .\`\n- [ ] project typecheck/lint/test\n- [ ] env vars (.env.example) synced\n- [ ] rollback path confirmed\n- [ ] CHANGELOG updated\n`, 'en');
700
+ _files['.harness/session-close-policy.md'] = fm('session-close-policy', ['before session end'], ['session-close format changes'], `# Session Close Policy\n\nEvery session must list:\n- Completed\n- In progress\n- Incomplete\n- Planned\n- Waiting\n- On hold\n- Blocked\n- Dropped\n- Verification (commands run, results)\n- Recommended next direction\n- Next exact step\n\n\`leerness session close\` extracts the 9 categories automatically and writes the handoff block for the next session into session-handoff.md.\n`, 'en');
701
+ _files['.harness/anti-lazy-work-policy.md'] = fm('anti-lazy-work-policy', ['before claiming completion'], ['lazy-work prevention criteria change'], `# Anti Lazy Work Policy\n\n## Rules\n1. **No completion without evidence**: claiming "done" requires command output/test results/screenshot paths in progress-tracker's evidence column.\n2. **No empty handoff**: if Completed/In Progress/Next Exact Step are all empty at session end, close is marked "insufficient".\n3. **Honest partial implementation**: if not fully implemented, set status \`incomplete\` and write one line in Next Exact Step describing what remains.\n4. **Verification records**: accumulate typecheck/lint/test results in review-evidence.md.\n5. **TODO tracking**: any new \`TODO\`/\`FIXME\`/\`XXX\` in code gets a same-ID row in progress-tracker.\n6. **Automatic false-done detection**: \`leerness lazy detect\` checks done rows without evidence, empty handoffs, untracked new TODOs, and missing test-run traces.\n7. **Quality-lens self-questions**: before claiming done, answer \`leerness lens\` per domain — code: "would a senior developer find this needlessly complex?" / design: "would a senior designer and an ordinary user find it pretty, comfortable, intuitive?". If you cannot answer "yes (pass)", it is not done. When changing one domain, re-check the causally linked domains (↔ in \`lens\` output).\n`, 'en');
702
+ _files['.harness/session-handoff.md'] = fm('session-handoff', ['session start', 'taking over next work'], ['session end'], `# Session Handoff\n\nLast generated: (auto)\n\n## Completed\n-\n\n## In Progress\n-\n\n## Incomplete / Waiting / On Hold / Blocked\n-\n\n## Dropped\n-\n\n## Verification\n-\n\n## Recommended Direction\n-\n\n## Next Exact Step\n-\n`, 'en');
703
+ _files['.harness/leerness-maintenance.md'] = fm('leerness-maintenance', ['work start', 'before migration/release'], ['version policy changes'], `# Leerness Maintenance\n\nAI agents should check:\n\n\`\`\`bash\nleerness --version\nleerness self check .\nleerness update --check # auto-detect with 24h cache\nleerness update --yes # auto-migrate when a new version is found\ncat .harness/HARNESS_VERSION\nnpm view leerness version\n\`\`\`\n`, 'en');
704
+ _files['.harness/language-policy.md'] = fm('language-policy', ['before writing documents'], ['language changes'], `# Language Policy\n\nSelected language: ${lang}\n\nAll Leerness notes, skill notes, session reports, and task lists default to the language above (except when the user explicitly requests another language).\n`, 'en');
705
+ _files['.harness/secret-policy.md'] = fm('secret-policy', ['before skill/deploy/config changes'], ['sensitive-data policy changes'], `# Secret Policy\n\n## Rules\n- Record only environment-variable names; move values to .env.local, CI secrets, or a cloud secret manager.\n- Never leave tokens/passwords/cookies/IDs/card numbers in plaintext in code/docs/logs.\n- Run \`leerness scan secrets .\` before changes.\n\n## Patterns scanned\n- AWS Access Key (\`AKIA[0-9A-Z]{16}\`)\n- GitHub PAT (\`ghp_[A-Za-z0-9]{36}\`)\n- OpenAI key (\`sk-[A-Za-z0-9]{20,}\`)\n- Anthropic key (\`sk-ant-[A-Za-z0-9-]{20,}\`)\n- Google API key, Slack token, generic private key, hardcoded password\n`, 'en');
706
+ _files['.harness/encoding-policy.md'] = fm('encoding-policy', ['before creating files', 'garbled-Korean reports', 'before deploy'], ['encoding policy changes'], `# Encoding Policy\n\n## Rules\n- All text files are **UTF-8 without BOM**.\n- Windows .bat files start with \`chcp 65001 >nul\`.\n- PowerShell .ps1 files start with \`[Console]::OutputEncoding = [System.Text.Encoding]::UTF8\`.\n- Python files may need \`# -*- coding: utf-8 -*-\` (for Python 2 compat).\n- LF line endings recommended (unify via .gitattributes on Windows too).\n\n## Auto check\n\`leerness encoding check\` verifies BOM, NUL, chcp 65001 in .bat, and Korean round-trip.\n`, 'en');
707
+ _files['.harness/architecture.md'] = fm('architecture', ['feature work', 'refactoring', 'migration'], ['structure changes'], `# Architecture\n\n## Overview\n- Record the real structure.\n\n## Data Flow\n-\n\n## External Dependencies\n-\n`, 'en');
708
+ _files['.harness/context-map.md'] = fm('context-map', ['exploring related files', 'before implementing features'], ['file structure changes'], `# Context Map\n\n| Area | Files | Notes |\n|---|---|---|\n| App | src/** | update with real paths |\n| Tests | tests/** | verification paths |\n`, 'en');
709
+ _files['.harness/decisions.md'] = fm('decisions', ['checking design decisions'], ['important decisions made'], `# Decisions\n\n## Template (example — add real decisions below, outside the code block)\n\n\`\`\`md\n### ${today()} — Decision title\n- Decision:\n- Reason:\n- Alternatives:\n- Impact:\n\`\`\`\n`, 'en');
710
+ _files['.harness/task-log.md'] = fm('task-log', ['checking work history'], ['after every meaningful task'], `# Task Log\n\n## ${today()}\n- Leerness v${VERSION} initialized.\n`, 'en');
711
+ _files['.harness/design-system.md'] = fm('design-system', ['UI changes', 'adding components', 'merging design guides'], ['design standards change', 'reusable patterns found'], `# Design System\n\n## Canonical File\nThis file is the canonical design guide (over designguide.md, design-guide.md, etc.).\n\n## Tokens\n| Token | Value | Notes |\n|---|---|---|\n| color.primary | (update with real value) | |\n| color.surface | | |\n| spacing.unit | | |\n| typography.body | | |\n\n## Reusable Patterns\n| Pattern | Where | Reuse Rule |\n|---|---|---|\n`, 'en');
712
+ _files['.harness/reuse-map.md'] = fm('reuse-map', ['before creating new components/APIs/helpers', 'duplicate capability detected'], ['reusable elements added'], `# Reuse Map\n\n| Capability | Existing Element | Reuse Method | Notes |\n|---|---|---|---|\n`, 'en');
713
+ _files['.harness/feature-contracts.md'] = fm('feature-contracts', ['before implementing/changing features'], ['feature IO/state/error changes'], `# Feature Contracts\n\n## Template\n- Feature:\n- Input:\n- Output:\n- States:\n- Errors:\n- Related files:\n- Test evidence ID:\n`, 'en');
670
714
  _files['.cursor/rules/leerness.mdc'] = `${MARK}\n---\nalwaysApply: true\n---\nFollow AGENTS.md and .harness/context-routing.md.\nRun: \`leerness handoff .\` at session start.\nRun: \`leerness session close .\` at session end.\nPreserve Leerness protected files.\n`;
671
715
  _files['.github/copilot-instructions.md'] = `${MARK}\n# Copilot Instructions\n\nUse AGENTS.md and .harness/ as project memory.\nDo not remove protected Leerness files.\nBefore completion, ensure plan.md, progress-tracker.md, current-state.md, session-handoff.md are updated.\n`;
672
716
  _files['.harness/session-workflow.md'] = fm('session-workflow', ['session start', 'new user request arrives', 'before distributing complex work'], ['workflow step changes'], `# Session Workflow — 6 steps of AI harness engineering\n\n> **At the start of every session the main agent reads this document first and follows the 6 steps as written.**\n> Same flow regardless of round length/complexity — that is what prevents drift.\n\n## Step 1. Analyze the request + check the environment\n\`\`\`bash\nleerness handoff . # load context + automatic drift warning\nleerness drift check . # signals + 4-level verdict\n\`\`\`\n- Decompose the request (5W1H). If ambiguous, ask clarifying questions (except autonomous mode).\n- On drift critical, run \`leerness session close .\` or \`drift check --auto-fix\` first.\n\n## Step 2. Plan\n- 3+ steps → use TodoWrite or \`leerness plan add\`.\n- New capability → search existing assets first via \`leerness reuse-map\` / \`reuse find <query>\`.\n- Multiple modules → define an integration spec up front (e.g. TICK_SPEC.md).\n\n## Step 3. Distribute — sub-agent mapping\n\`\`\`bash\nleerness agents list # ready CLIs\nleerness agents quota # limits\nleerness agents dispatch "<task>" --to <id>\n\`\`\`\n- Best sub-agent by task type: text/translation/analysis → claude · deep code reasoning → codex · direct file edits → agy --yolo · security review → \`leerness review --persona security\`.\n- **Conflict-prevention rules (mandatory)**: give each sub-agent *the exact files only it may modify*; require mtime-verification reports (concurrent writes risk last-writer-wins); verify against the spec afterwards with \`leerness contract verify\`.\n\n## Step 4. Sub-agent work + individual self-verification\n- Each sub-agent reports only after passing its own module tests.\n- Report format: line counts, tests N/N PASS, issues found, mtime verification.\n\n## Step 5. Integrated verification\n\`\`\`bash\nleerness contract verify SPEC.md src/<mod>.js\nleerness verify-claim T-XXX --run-tests --strict-claims\nleerness review <file> --persona security,performance,ux\n\`\`\`\n- The main agent writes and runs its own integration scenario (independent verification).\n- Cross-check that sub-agent verification and main verification *agree*.\n\n## Step 6. Close + handoff + next-round suggestion\n\`\`\`bash\nleerness session close . # --suggest on by default\nleerness session close . --no-suggest\n\n# or separately:\nleerness skill suggest .\nleerness drift check .\nleerness audit . --fix\n\`\`\`\n\n## 🧠 Memory CRUD Quick Reference\n\n| Surface | CREATE | READ | DELETE | RESTORE |\n|---|---|---|---|---|\n| **tasks** | task add | task list --json | task drop | task update |\n| **decisions** | decision add | decision list --json | decision drop | memory restore decisions |\n| **lessons** | lesson save | lesson list [--tag] | lesson drop | memory restore lessons |\n| **plan** | plan add | plan list --json | plan remove | memory restore plan |\n| **rules** | rule add | rule list --json | rule remove | (rule pause/resume) |\n\n\`\`\`bash\nleerness memory status [--json]\nleerness memory archive list [--surface s]\nleerness memory restore <surface> <target>\n\`\`\`\n\n**Recovering a wrongly saved item**:\n1. \`memory archive list\` — list restore candidates\n2. \`memory restore decisions "PostgreSQL"\` — archive → active\n3. handoff automatically notes archive activity within 24h every session\n\n## Auto-recovery & security\n- A skipped session close triggers drift critical at the next session start — recover with \`drift check --auto-fix\` (runs session close automatically on critical).\n- handoff auto-recalls past lessons (by current task keywords) and auto-suggests installed skills.\n- handoff prints a 1–2 line security summary (.env ↔ .env.example sync + .gitignore secret gaps); a missing .env in .gitignore is 🚨 CRITICAL — \`LEERNESS_AUTO_SECURITY_FIX=1\` runs \`audit --fix\` automatically.\n- \`leerness health\` gives a one-line combined check (drift + security + skills + usage + tasks).\n\n---\n\n## Quick checklist (before the session ends)\n- [ ] This round's tasks are registered in plan/progress-tracker (or task sync)\n- [ ] Every done item has evidence attached (verify-claim PASS)\n- [ ] contract verify PASS when sub-agents were used\n- [ ] drift score ≤ 30 — \`leerness drift check\`\n- [ ] session close was run\n- [ ] \`leerness health\` overall check\n- [ ] If .env is used: .gitignore secret patterns OK + .env.example synced\n- [ ] On security critical: \`LEERNESS_AUTO_SECURITY_FIX=1\` or \`audit --fix\`\n\n## Anti-patterns (drift signals)\n- ⚠ "work is done, just report and stop" → missed session close → drift critical next session\n- ⚠ "only TodoWrite updated, leerness unused" → \`task sync --from\` or \`task add\` is mandatory\n- ⚠ distributing to sub-agents without explicit file paths → concurrent-write conflicts\n- ⚠ self-reported "tests ran, PASS" only → verify-claim --run-tests not executed\n- ⚠ skipping contract verify → spec-mismatch bugs reach the user\n`, 'en');
@@ -1010,6 +1054,13 @@ async function install(root, opts = {}) {
1010
1054
  const managedOverwrite = new Set([
1011
1055
  'AGENTS.md','CLAUDE.md','.cursor/rules/leerness.mdc','.github/copilot-instructions.md',
1012
1056
  '.harness/session-workflow.md', // 1.36.60 (검수 #1): managed 편입 — 종전엔 재init 시 구 언어/구 버전 그대로 방치
1057
+ // 1.36.61 (검수 High): 순수 정책-문서 전체를 managed 병합 경로에 — 언어 전환 시 구 언어로 방치되던 나머지
1058
+ // (사용자 상태 문서 plan/brief/decisions 등은 제외 — 구조-인지 전략 필요, 데이터라 raw 교체 금지)
1059
+ '.harness/guideline.md','.harness/plan-progress-boundary.md','.harness/guardrails.md',
1060
+ '.harness/consistency-policy.md','.harness/testing-strategy.md','.harness/review-checklist.md',
1061
+ '.harness/AX_PLAN_GUIDE.md','.harness/test-evidence-policy.md', // 1.36.62 (검수 #3): 누락 편입 (review-evidence/feature-graph 는 사용자 데이터 — _USER_STATE)
1062
+ '.harness/release-checklist.md','.harness/session-close-policy.md','.harness/anti-lazy-work-policy.md',
1063
+ '.harness/secret-policy.md','.harness/encoding-policy.md','.harness/language-policy.md',
1013
1064
  '.harness/HARNESS_VERSION','.harness/manifest.json','.harness/LANGUAGE','.harness/skills-lock.json',
1014
1065
  '.harness/context-routing.md','.harness/writeback-policy.md','.harness/task-type-map.md',
1015
1066
  '.harness/leerness-maintenance.md','.harness/protected-files.md','.harness/AX_MIGRATION_GUIDE.md',
@@ -1033,7 +1084,7 @@ async function install(root, opts = {}) {
1033
1084
  let _done = 0;
1034
1085
  // 1.36.33 (codex 3차 #1, P1 데이터 유실): --force 가 사용자 상태 파일(진행 task/plan/결정/로그/인계 등)까지 새 템플릿으로
1035
1086
  // 덮어써 활성 기록이 archive 에만 남았다. force 는 가이드/템플릿 문서에만 적용 — 상태 파일은 force 여도 보존.
1036
- const _USER_STATE = new Set(['.harness/progress-tracker.md', '.harness/plan.md', '.harness/task-log.md', '.harness/decisions.md', '.harness/current-state.md', '.harness/session-handoff.md', '.harness/rules.md', '.harness/feature-graph.md', '.harness/reuse-map.md', '.harness/feature-contracts.md', '.harness/project-brief.md', '.harness/architecture.md', '.harness/context-map.md', '.harness/design-system.md']);
1087
+ const _USER_STATE = new Set(['.harness/progress-tracker.md', '.harness/plan.md', '.harness/task-log.md', '.harness/decisions.md', '.harness/current-state.md', '.harness/session-handoff.md', '.harness/rules.md', '.harness/feature-graph.md', '.harness/reuse-map.md', '.harness/feature-contracts.md', '.harness/project-brief.md', '.harness/architecture.md', '.harness/context-map.md', '.harness/design-system.md', '.harness/review-evidence.md']); // 1.36.62 (검수 #3): 검증 이력도 사용자 데이터
1037
1088
  for (const [f, c] of Object.entries(files)) {
1038
1089
  const existsNow = exists(path.join(root, f));
1039
1090
  const mergeManaged = managedOverwrite.has(f);
@@ -10122,7 +10173,7 @@ function lazyDetect(root, opts = {}) {
10122
10173
  if (rows.length === 0) { issues++; _warn('progress-tracker is empty (no tasks tracked)',
10123
10174
  { kind: 'progress_empty', severity: 'warn' }); }
10124
10175
  const handoff = exists(handoffPath(root)) ? read(handoffPath(root)) : '';
10125
- if (!handoff.includes('Last generated:') || handoff.includes('Last generated: (자동)')) {
10176
+ if (!handoff.includes('Last generated:') || handoff.includes('Last generated: (자동)') || handoff.includes('Last generated: (auto)')) { // 1.36.61 (검수): en 센티널 병기
10126
10177
  issues++; _warn('session-handoff.md never auto-generated',
10127
10178
  { kind: 'handoff_never_generated', severity: 'warn' });
10128
10179
  }
@@ -16960,7 +17011,7 @@ function verifyCodeCmd(root) {
16960
17011
  }
16961
17012
  const evBlock = [
16962
17013
  ``,
16963
- `## ${now().slice(0, 16)} verify-code (자동)`,
17014
+ `## ${now().slice(0, 16)} verify-code ${_uiLang(root) === 'en' ? '(auto)' : '(자동)'}`, // 1.36.62 (검수 #4): en 프로젝트 증거 마커 영어 (파서 비의존, 표기용)
16964
17015
  `Command: leerness verify-code`,
16965
17016
  `Tasks: ${tasks.map(t => t.name).join(', ')}`,
16966
17017
  ...results.map(r => `- ${r.name}: exit=${r.exit} (${r.durMs}ms) — \`${r.cmd}\``),
@@ -17094,7 +17145,14 @@ function _ensureFeatureGraph(root) {
17094
17145
  }
17095
17146
  function _writeFeatureGraph(root, nodes) {
17096
17147
  const p = _ensureFeatureGraph(root);
17097
- const header = _featureGraphTemplate();
17148
+ // 1.36.62 (검수 #2): 기존 파일의 서두(frontmatter+가이드, en 포함)를 '## Nodes' 까지 보존 —
17149
+ // 종전엔 매 저장마다 한국어 템플릿으로 전체 재생성해 en 그래프가 한국어로 회귀하고 frontmatter 가 사라졌다.
17150
+ let header = _featureGraphTemplate();
17151
+ try {
17152
+ const cur = read(p);
17153
+ const i = cur.indexOf('## Nodes');
17154
+ if (i >= 0) header = cur.slice(0, i + '## Nodes'.length) + '\n\n';
17155
+ } catch {}
17098
17156
  const body = nodes.map(_featureBlock).join('');
17099
17157
  writeUtf8(p, header + body);
17100
17158
  }
@@ -17251,7 +17309,7 @@ function uiConsistency(root) {
17251
17309
  if (!m) continue;
17252
17310
  const key = m[1].trim();
17253
17311
  const val = m[2].trim();
17254
- if (key === 'Token' || /^-+$/.test(key) || val === 'Value' || /실제 값으로 업데이트/.test(val) || !val) continue;
17312
+ if (key === 'Token' || /^-+$/.test(key) || val === 'Value' || /실제 값으로 업데이트|update with real value/i.test(val) || !val) continue; // 1.36.61: en placeholder 병기
17255
17313
  tokens[key] = val;
17256
17314
  }
17257
17315
  const tokenSet = new Set(Object.values(tokens).map(v => v.toLowerCase()));
@@ -17500,8 +17558,11 @@ function autoUpdateInstall(root) {
17500
17558
  settings.hooks.SessionStart.push({ matcher: 'startup|clear|compact', command: 'leerness hook session-start' });
17501
17559
  }
17502
17560
  writeUtf8(settingsFile, JSON.stringify(settings, null, 2) + '\n');
17503
- writeUtf8(path.join(root, '.claude/commands/update.md'),
17504
- `# /update\n\nleerness 자동 업데이트 (감지 마이그레이션 검증).\n\n\`\`\`\n!leerness update --yes\n\`\`\`\n\n체크만:\n\n\`\`\`\n!leerness update --check\n\`\`\`\n`);
17561
+ // 1.36.62 (검수 #1): en 프로젝트의 /update 를 한국어로 되덮던 것 — 언어 인지 렌더
17562
+ const _updLang = (() => { try { return read(path.join(root, '.harness', 'LANGUAGE')).trim().toLowerCase(); } catch { return 'ko'; } })();
17563
+ writeUtf8(path.join(root, '.claude/commands/update.md'), _updLang === 'en'
17564
+ ? `# /update\n\nRun the leerness auto-update (detect → migrate → verify).\n\n\`\`\`\n!leerness update --yes\n\`\`\`\n\nCheck only:\n\n\`\`\`\n!leerness update --check\n\`\`\`\n`
17565
+ : `# /update\n\nleerness 자동 업데이트 (감지 → 마이그레이션 → 검증).\n\n\`\`\`\n!leerness update --yes\n\`\`\`\n\n체크만:\n\n\`\`\`\n!leerness update --check\n\`\`\`\n`);
17505
17566
  ok('auto-update SessionStart hook installed (.claude/settings.local.json)');
17506
17567
  if (removedLegacy) ok(`legacy hook 제거: ${removedLegacy}건 (leerness-plus → leerness 통합)`);
17507
17568
  if (upgradedQuiet) ok(`hook 업그레이드: ${upgradedQuiet}건 → --quiet (up-to-date 시 무음, 1.9.364)`);
package/lib/audit.js CHANGED
@@ -55,7 +55,7 @@ function audit(root, opts = {}, deps = {}) {
55
55
  const naMarker = '<!-- leerness:na';
56
56
  const ds = exists(path.join(root,'.harness/design-system.md')) ? read(path.join(root,'.harness/design-system.md')) : '';
57
57
  if (ds.includes(naMarker)) ok('design-system.md marked NA (skipped)');
58
- else if (!/\| color\.primary \|/.test(ds) || /\(실제 값으로 업데이트\)/.test(ds)) { warnings++; warn('design-system.md tokens not customized'); _finding('design_system_default', 'warn', 'design-system.md tokens not customized'); }
58
+ else if (!/\| color\.primary \|/.test(ds) || /\(실제 값으로 업데이트\)|\(update with real value\)/i.test(ds)) { warnings++; warn('design-system.md tokens not customized'); _finding('design_system_default', 'warn', 'design-system.md tokens not customized'); } // 1.36.61: en placeholder 병기
59
59
  else ok('design-system tokens populated');
60
60
  const reuse = exists(path.join(root,'.harness/reuse-map.md')) ? read(path.join(root,'.harness/reuse-map.md')) : '';
61
61
  const reuseLines = reuse.split('\n').filter(l => l.startsWith('|') && !/Capability|---/.test(l)).length;
@@ -87,12 +87,12 @@ function audit(root, opts = {}, deps = {}) {
87
87
  }
88
88
  else if (milestoneIds.length) ok('all milestones linked in progress-tracker');
89
89
  const handoff = exists(handoffPath(root)) ? read(handoffPath(root)) : '';
90
- if (handoff.includes('Last generated: (자동)')) {
90
+ if (handoff.includes('Last generated: (자동)') || handoff.includes('Last generated: (auto)')) { // 1.36.61: en 센티널 병기
91
91
  warnings++; warn('session-handoff.md never auto-generated (run: leerness session close .)');
92
92
  _finding('handoff_not_generated', 'warn', 'session-handoff.md never auto-generated');
93
93
  // 1.9.35 #5: --fix → session-handoff.md 자동 생성 마커 갱신
94
94
  if (fix) {
95
- const stamped = handoff.replace('Last generated: (자동)', `Last generated: ${today()} (leerness audit --fix)`);
95
+ const stamped = handoff.replace(/Last generated: \((자동|auto)\)/, `Last generated: ${today()} (leerness audit --fix)`); // 1.36.61: 양 언어 --fix
96
96
  writeUtf8(handoffPath(root), stamped);
97
97
  ok(' ↳ fixed: session-handoff.md timestamp 갱신');
98
98
  fixed++;
package/lib/pure-utils.js CHANGED
@@ -352,7 +352,7 @@ function _roadmapParseTokens(text) {
352
352
  const m = line.match(/^\|\s*([\w.\-]+)\s*\|\s*([^|]+?)\s*\|/);
353
353
  if (!m) continue;
354
354
  const key = m[1].trim(), val = m[2].trim();
355
- if (!key || !val || key === 'Token' || /^-+$/.test(key) || val === 'Value' || /\(실제 값으로 업데이트\)/.test(val)) continue;
355
+ if (!key || !val || key === 'Token' || /^-+$/.test(key) || val === 'Value' || /\(실제 값으로 업데이트\)|\(update with real value\)/i.test(val)) continue; // 1.36.61: en placeholder 병기
356
356
  if (val.length > 80) continue;
357
357
  tokens[key] = val;
358
358
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "leerness",
3
- "version": "1.36.60",
3
+ "version": "1.36.62",
4
4
  "description": "The AI-coding operations layer that makes \"done\" require evidence — persistent memory, evidence-gated completion checks, and clean handoffs for any AI agent (Claude Code, Codex, Cursor). State lives as plain files in your repo. CLI + MCP, 0 runtime dependencies.",
5
5
  "keywords": [
6
6
  "leerness",
package/scripts/e2e.js CHANGED
@@ -7083,7 +7083,9 @@ total++;
7083
7083
  const H = /[가-힣]/;
7084
7084
  const de = fs.mkdtempSync(path.join(os.tmpdir(), 'leerness-en5-')); _dirs.push(de);
7085
7085
  const r1 = cp.spawnSync(process.execPath, [CLI, 'init', de, '--yes', '--language', 'en', '--no-env'], { encoding: 'utf8', timeout: 30000 });
7086
- const five = ['AGENTS.md', 'CLAUDE.md', '.harness/session-workflow.md', '.cursor/rules/leerness.mdc', '.github/copilot-instructions.md'];
7086
+ // 1.36.61 (3회차): 정책·시드 문서군까지 확대 대표 10종 무한글
7087
+ const five = ['AGENTS.md', 'CLAUDE.md', '.harness/session-workflow.md', '.cursor/rules/leerness.mdc', '.github/copilot-instructions.md',
7088
+ '.harness/guideline.md', '.harness/guardrails.md', '.harness/anti-lazy-work-policy.md', '.harness/plan.md', '.harness/secret-policy.md'];
7087
7089
  const enOk = r1.status === 0 && five.every(p => { const t = fs.readFileSync(path.join(de, p), 'utf8'); return t.length > 100 && !H.test(t); });
7088
7090
  // en 지시 본문의 핵심 계약 존재(번역이 빈 껍데기가 아님) — 검수 #2 반영: lens 질문/체크리스트/안티패턴/자동화 지시까지
7089
7091
  const ag = fs.readFileSync(path.join(de, 'AGENTS.md'), 'utf8');