leerness 1.9.182 → 1.9.184
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 +167 -0
- package/README.md +3 -3
- package/bin/harness.js +72 -6
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,172 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.9.184 — 2026-05-21
|
|
4
|
+
|
|
5
|
+
**🎨 설치 UX 4종 — Ctrl+C 확인 prompt + 로딩바 + skillpack 제외 + DEP0190 억제 (사용자 명시).**
|
|
6
|
+
|
|
7
|
+
자율 모드 114 라운드. 사용자 명시 4종:
|
|
8
|
+
1. *"설치 가이드에서 Ctrl+C 입력 시 설치 종료 여부 확인 로직 추가"* → SIGINT handler (2단계 confirm)
|
|
9
|
+
2. *"leerness 파일 설치 시작 시 로딩바로 구현 + 생성 목록 나열 X"* → progress bar (TTY)
|
|
10
|
+
3. *"leerness-skillpack 미사용 예정 → 제외"* → 안내 메시지 제거
|
|
11
|
+
4. *"REPL agent 모드 진입 시 DEP0190 deprecation warning 제거"* → process warning handler
|
|
12
|
+
|
|
13
|
+
### Fix #1 — Ctrl+C 종료 확인 prompt
|
|
14
|
+
```js
|
|
15
|
+
// 1.9.184 (사용자 명시): 설치 도중 Ctrl+C 시 종료 확인 prompt.
|
|
16
|
+
// 첫 Ctrl+C → 안내 (2초 이내 한 번 더 → 종료, 그 외 → 계속).
|
|
17
|
+
let _sigintCount = 0; let _sigintTimer = null;
|
|
18
|
+
const _sigintHandler = () => {
|
|
19
|
+
_sigintCount++;
|
|
20
|
+
if (_sigintCount === 1) {
|
|
21
|
+
process.stdout.write('\n\n ⚠ 설치 중단하시겠습니까? Ctrl+C 를 2초 이내에 한 번 더 누르면 종료됩니다. (그 외 → 계속 진행)\n');
|
|
22
|
+
_sigintTimer = setTimeout(() => { _sigintCount = 0; }, 2000);
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
process.exit(130);
|
|
26
|
+
};
|
|
27
|
+
```
|
|
28
|
+
install 시작에 등록, 종료/REPL 진입 시 cleanup.
|
|
29
|
+
|
|
30
|
+
### Fix #2 — 파일 설치 progress bar (생성 목록 미표시)
|
|
31
|
+
**Before** (line by line):
|
|
32
|
+
```
|
|
33
|
+
✓ create: AGENTS.md
|
|
34
|
+
✓ create: CLAUDE.md
|
|
35
|
+
✓ create: .harness/HARNESS_VERSION
|
|
36
|
+
✓ create: .harness/manifest.json
|
|
37
|
+
... (수십 줄)
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
**After** (single progress bar):
|
|
41
|
+
```
|
|
42
|
+
████████████████░░░░ 24/30 (80%) .harness/skills/office/SKILL.md
|
|
43
|
+
```
|
|
44
|
+
완료 시:
|
|
45
|
+
```
|
|
46
|
+
✓ leerness 파일 설치 완료 (30개)
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Fix #3 — leerness-skillpack 안내 제거
|
|
50
|
+
```diff
|
|
51
|
+
- if (SKILLPACK_SOURCE === 'builtin') log(`Skill catalog source: builtin (leerness-skillpack 미설치 — npm i leerness-skillpack 로 확장 가능)`);
|
|
52
|
+
- else log(`Skill catalog source: ${SKILLPACK_SOURCE} (leerness-skillpack${SKILLPACK_META ? ` v${SKILLPACK_META.version}` : ''})`);
|
|
53
|
+
+ // 1.9.184 (사용자 명시): leerness-skillpack 미사용 정책 — 안내 메시지 제거. builtin catalog 만 사용.
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Fix #4 — DEP0190 DeprecationWarning 억제
|
|
57
|
+
파일 최상단에서 process warning handler 등록:
|
|
58
|
+
```js
|
|
59
|
+
// 1.9.184: DEP0190 (child_process shell: true) deprecation warning 억제 (사용자 명시).
|
|
60
|
+
// leerness 는 cross-platform PATH resolution 을 위해 shell: true 를 의도적으로 사용.
|
|
61
|
+
process.removeAllListeners('warning');
|
|
62
|
+
process.on('warning', (w) => {
|
|
63
|
+
if (w && (w.code === 'DEP0190' || /DEP0190/.test(String(w.message || '')))) return;
|
|
64
|
+
process.stderr.write(`(node:${process.pid}) ${w.name || 'Warning'}: ${w.message || w}\n`);
|
|
65
|
+
});
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
**Before** (REPL 진입 시):
|
|
69
|
+
```
|
|
70
|
+
agent[claude/actor/▶]> (node:54076) [DEP0190] DeprecationWarning: Passing args to a child process with shell option true...
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
**After** (REPL 진입 시):
|
|
74
|
+
```
|
|
75
|
+
agent[claude/actor/▶]> _
|
|
76
|
+
```
|
|
77
|
+
깔끔.
|
|
78
|
+
|
|
79
|
+
### Verified
|
|
80
|
+
- stress-v129: **14/14 PASS** (사용자 명시 4 + live install 3 + 누적 7)
|
|
81
|
+
- e2e 217/217 baseline 유지
|
|
82
|
+
- live install 검증:
|
|
83
|
+
- DEP0190 출력 안 됨 ✓
|
|
84
|
+
- "Skill catalog source: builtin" 안내 없음 ✓
|
|
85
|
+
- 파일 생성 목록 0건 (non-TTY) ✓
|
|
86
|
+
- VERSION = 1.9.184 · autonomous-rounds = 114 · main 자동 push 45 라운드 연속
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## 1.9.183 — 2026-05-21
|
|
91
|
+
|
|
92
|
+
**📦 npm i leerness + 구버전 자동 감지/경고/업데이트 명령어 안내 (사용자 명시 3종).**
|
|
93
|
+
|
|
94
|
+
자율 모드 113 라운드. 사용자 명시:
|
|
95
|
+
1. *"(vercel/anthropic) 표기는 제거"* → 일반화
|
|
96
|
+
2. *"vercel/anthropic 포함한 다른 공식 스킬도 자동 탐색하는 게 맞는지 확인"* → 검증 통과
|
|
97
|
+
3. *"npm i leerness 사용 가능하게 + 구버전 감지/경고/업데이트 명령어 안내"* → 모든 명령에 stale check 진입
|
|
98
|
+
|
|
99
|
+
### 1. 표기 일반화
|
|
100
|
+
```diff
|
|
101
|
+
- 🌐 공식 catalog 자동 탐색 (vercel/anthropic) · 자가 성장형
|
|
102
|
+
+ 🌐 공식 catalog 자동 탐색 · 자가 성장형 · 구버전 감지/안내
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### 2. 다른 공식 catalog 자동 탐색 확인 (live)
|
|
106
|
+
```bash
|
|
107
|
+
$ leerness skill discover --all-presets
|
|
108
|
+
fetching vercel-labs/agent-skills...
|
|
109
|
+
✓ vercel-labs/agent-skills: 8개 skill 발견
|
|
110
|
+
fetching anthropics/skills...
|
|
111
|
+
✓ anthropics/skills: 17개 skill 발견
|
|
112
|
+
전체 25건
|
|
113
|
+
```
|
|
114
|
+
**vercel + anthropic 모두 정상 작동**. 다른 공식 organization은 `--github <owner/repo>` 옵션으로 즉시 추가 가능 (`vercel-labs/agent-skills`, `anthropics/skills` 외에 새 공식 등장 시 preset 등록).
|
|
115
|
+
|
|
116
|
+
조사 결과 — 1.9.183 시점 표준 SKILL.md 카탈로그를 갖춘 공식 organization:
|
|
117
|
+
- `vercel-labs/agent-skills` (8개) ← preset `vercel`
|
|
118
|
+
- `anthropics/skills` (17개) ← preset `anthropic`
|
|
119
|
+
- `modelcontextprotocol/servers` — SKILL.md 형식 아님 (MCP server 구현 — leerness skill 호환성 X)
|
|
120
|
+
- 기타 — 미발견. 새 공식 등장 시 즉시 preset 등록 가능.
|
|
121
|
+
|
|
122
|
+
### 3. 구버전 자동 감지 강화 (모든 명령)
|
|
123
|
+
**Before**: init/migrate 시점만 stale check (다른 명령은 skip)
|
|
124
|
+
**After**: 거의 모든 명령 시점에 stale check (init/migrate/mcp/release/version/help 제외 — 출력 민감 명령은 skip)
|
|
125
|
+
|
|
126
|
+
```js
|
|
127
|
+
// 1.9.183 (사용자 명시): 모든 명령 시점에서 구버전 감지 + 경고 + 업데이트 명령어 안내
|
|
128
|
+
const _staleSkip = new Set(['init', 'migrate', 'usage', 'mcp', 'release', 'session-close', '--version', '--help', 'help', 'update', 'whats-new']);
|
|
129
|
+
if (!_staleSkip.has(cmd) && process.env.LEERNESS_NO_STALE_CHECK !== '1' && !has('--no-stale-check')) {
|
|
130
|
+
const cached = readUpdateCache(root);
|
|
131
|
+
if (cacheFresh(cached, 24) && cached.nextLeerness && compareVer(cached.nextLeerness, VERSION) > 0) {
|
|
132
|
+
process.stderr.write(` ⚠ leerness v${VERSION} → v${cached.nextLeerness} 사용 가능 · npm i leerness@latest 권장 ...`);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
**실 동작 검증** (캐시 시뮬레이션):
|
|
138
|
+
```
|
|
139
|
+
$ leerness audit .
|
|
140
|
+
⚠ leerness v1.9.183 → v1.9.999 사용 가능 · npm i leerness@latest 권장 (LEERNESS_NO_STALE_CHECK=1 로 끄기)
|
|
141
|
+
✓ no duplicate design guide candidates
|
|
142
|
+
[...]
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### 4. `npm i leerness` 첫 권장 (글로벌 → 로컬 우선)
|
|
146
|
+
init 시점 stale 메시지도 갱신:
|
|
147
|
+
```
|
|
148
|
+
해결 — 셋 중 하나 실행 후 다시 시도:
|
|
149
|
+
npm i leerness@latest # 프로젝트 로컬 설치 (1.9.183 권장)
|
|
150
|
+
npm i -g leerness@latest # 글로벌 설치
|
|
151
|
+
npx --yes clear-npx-cache && npx leerness@latest init .
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### npm registry 상태
|
|
155
|
+
```bash
|
|
156
|
+
$ npm view leerness version
|
|
157
|
+
1.9.182 ← 직전 publish
|
|
158
|
+
$ npm view leerness dist-tags
|
|
159
|
+
{ latest: '1.9.182' }
|
|
160
|
+
```
|
|
161
|
+
이번 라운드 release sync-main 후 `latest: '1.9.183'` 으로 자동 갱신.
|
|
162
|
+
|
|
163
|
+
### Verified
|
|
164
|
+
- stress-v128: **16/16** (사용자 명시 3 + 구버전 감지 4 + npm 배포 2 + VERSION+누적 7)
|
|
165
|
+
- e2e 217/217 baseline 유지
|
|
166
|
+
- VERSION = 1.9.183 · autonomous-rounds = 113 · main 자동 push 44 라운드 연속
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
3
170
|
## 1.9.182 — 2026-05-21
|
|
4
171
|
|
|
5
172
|
**🌐 공식 조직 스킬 catalog 자동 탐색 — vercel-labs/agent-skills + anthropics/skills 직접 통합 (사용자 명시).**
|
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
> **AI 코딩 에이전트의 거짓 완료·중복·망각·충돌을 막아주는 검수·기억·협업 CLI 하네스.**
|
|
4
4
|
|
|
5
|
-
[](https://www.npmjs.com/package/leerness) [](https://www.npmjs.com/package/leerness) []() []() []() []() []() []() []() []() []() []() []() []()
|
|
6
6
|
|
|
7
7
|
```
|
|
8
8
|
╔══════════════════════════════════════════════════════════════╗
|
|
@@ -12,9 +12,9 @@
|
|
|
12
12
|
║ ██║ ██╔══╝ ██╔══╝ ██╔══██╗██║╚██╗██║██╔══╝ ╚════██║ ║
|
|
13
13
|
║ ███████╗███████╗███████╗██║ ██║██║ ╚████║███████╗███████║ ║
|
|
14
14
|
║ ╚══════╝╚══════╝╚══════╝╚═╝ ╚═╝╚═╝ ╚═══╝╚══════╝╚══════╝ ║
|
|
15
|
-
║ v1.9.
|
|
15
|
+
║ v1.9.184 AI Agent Reliability Harness + Sandbox ║
|
|
16
16
|
║ verify · remember · orchestrate · audit · sandbox · drift ║
|
|
17
|
-
║
|
|
17
|
+
║ 🎨 설치 UX 개선 (로딩바·Ctrl+C확인·DEP0190 억제·깨끗한 REPL) ║
|
|
18
18
|
╚══════════════════════════════════════════════════════════════╝
|
|
19
19
|
```
|
|
20
20
|
|
package/bin/harness.js
CHANGED
|
@@ -7,7 +7,17 @@ const cp = require('child_process');
|
|
|
7
7
|
const os = require('os'); // 1.9.178: _publishToNpm 에서 os.tmpdir() 사용 (전역 import)
|
|
8
8
|
const readline = require('readline');
|
|
9
9
|
|
|
10
|
-
const VERSION = '1.9.
|
|
10
|
+
const VERSION = '1.9.184';
|
|
11
|
+
|
|
12
|
+
// 1.9.184: DEP0190 (child_process shell: true) deprecation warning 억제 (사용자 명시).
|
|
13
|
+
// leerness 는 cross-platform PATH resolution 을 위해 shell: true 를 의도적으로 사용 (claude.cmd / ollama.cmd 등 Windows .cmd 처리).
|
|
14
|
+
// 인자 escape 가 필요한 위치는 검증된 입력만 spawnSync 에 전달. REPL agent 진입 시 _checkAgent 가 발산하는 노이즈 제거.
|
|
15
|
+
process.removeAllListeners('warning');
|
|
16
|
+
process.on('warning', (w) => {
|
|
17
|
+
if (w && (w.code === 'DEP0190' || /DEP0190/.test(String(w.message || '')))) return;
|
|
18
|
+
process.stderr.write(`(node:${process.pid}) ${w.name || 'Warning'}: ${w.message || w}\n`);
|
|
19
|
+
});
|
|
20
|
+
|
|
11
21
|
const MARK = '<!-- leerness:managed -->';
|
|
12
22
|
const README_START = '<!-- leerness:project-readme:start -->';
|
|
13
23
|
const README_END = '<!-- leerness:project-readme:end -->';
|
|
@@ -767,6 +777,26 @@ async function resolveInstallOptions(root, opts = {}) {
|
|
|
767
777
|
|
|
768
778
|
async function install(root, opts = {}) {
|
|
769
779
|
root = absRoot(root); mkdirp(root);
|
|
780
|
+
// 1.9.184 (사용자 명시): 설치 도중 Ctrl+C 시 종료 확인 prompt.
|
|
781
|
+
// 첫 Ctrl+C → 안내 (2초 이내 한 번 더 → 종료, 그 외 → 계속).
|
|
782
|
+
// readline raw mode 시 readline 이 'SIGINT' 이벤트로 흡수할 수 있어 process-level + finally 해제.
|
|
783
|
+
let _sigintCount = 0; let _sigintTimer = null;
|
|
784
|
+
const _sigintHandler = () => {
|
|
785
|
+
_sigintCount++;
|
|
786
|
+
if (_sigintCount === 1) {
|
|
787
|
+
try { process.stdout.write('\n\n ⚠ 설치 중단하시겠습니까? Ctrl+C 를 2초 이내에 한 번 더 누르면 종료됩니다. (그 외 → 계속 진행)\n'); } catch {}
|
|
788
|
+
clearTimeout(_sigintTimer);
|
|
789
|
+
_sigintTimer = setTimeout(() => { _sigintCount = 0; }, 2000);
|
|
790
|
+
return;
|
|
791
|
+
}
|
|
792
|
+
clearTimeout(_sigintTimer);
|
|
793
|
+
try { process.stdout.write('\n ✗ 설치 중단됨 (사용자 요청)\n'); } catch {}
|
|
794
|
+
process.exit(130);
|
|
795
|
+
};
|
|
796
|
+
if (!opts.migration && !opts.nonInteractive && process.stdin.isTTY) {
|
|
797
|
+
process.on('SIGINT', _sigintHandler);
|
|
798
|
+
}
|
|
799
|
+
const _cleanupSigint = () => { try { process.removeListener('SIGINT', _sigintHandler); clearTimeout(_sigintTimer); } catch {} };
|
|
770
800
|
// 1.9.41: migrate 직전 이전 버전 캡처 — 차분 안내에 사용
|
|
771
801
|
try {
|
|
772
802
|
const hv = path.join(root, '.harness', 'HARNESS_VERSION');
|
|
@@ -796,8 +826,7 @@ async function install(root, opts = {}) {
|
|
|
796
826
|
if (resolved.startRepl) log(`REPL 자동 시작: 예 (설치 완료 후 \`leerness agent\` 진입)`);
|
|
797
827
|
if (resolved.permissionMode) log(`Agent 권한 모드: ${resolved.permissionMode} (1.9.174 — REPL에서 \`:permissions extended|full\` 로 즉시 변경 가능)`);
|
|
798
828
|
// 1.9.10: 스킬 카탈로그 출처 안내
|
|
799
|
-
|
|
800
|
-
else log(`Skill catalog source: ${SKILLPACK_SOURCE} (leerness-skillpack${SKILLPACK_META ? ` v${SKILLPACK_META.version}` : ''})`);
|
|
829
|
+
// 1.9.184 (사용자 명시): leerness-skillpack 미사용 정책 — 안내 메시지 제거. builtin catalog 만 사용.
|
|
801
830
|
const files = coreFiles(root, lang, skills);
|
|
802
831
|
const backup = createBackup(root, opts.force ? 'force' : (opts.migration ? 'migration' : 'init'), files, opts.dry);
|
|
803
832
|
if (opts.dry) {
|
|
@@ -816,7 +845,20 @@ async function install(root, opts = {}) {
|
|
|
816
845
|
'.claude/commands/handoff.md','.claude/commands/session-close.md','.claude/commands/audit.md','.claude/commands/lazy-detect.md','.claude/commands/update.md',
|
|
817
846
|
'.claude/skills/leerness.md'
|
|
818
847
|
]);
|
|
848
|
+
// 1.9.184 (사용자 명시): 파일 설치 — 생성 목록 나열 X, 로딩바 + 단일 완료 메시지.
|
|
819
849
|
const actions = [];
|
|
850
|
+
const totalFiles = Object.keys(files).length;
|
|
851
|
+
const isTty = process.stdout.isTTY && !opts.dry;
|
|
852
|
+
const drawProgress = (done, file) => {
|
|
853
|
+
if (!isTty) return;
|
|
854
|
+
const pct = Math.round(done * 100 / totalFiles);
|
|
855
|
+
const filled = Math.floor(pct / 5);
|
|
856
|
+
const bar = '\x1b[36m' + '█'.repeat(filled) + '\x1b[2m' + '░'.repeat(20 - filled) + '\x1b[0m';
|
|
857
|
+
const truncFile = (file || '').length > 32 ? '...' + file.slice(-29) : (file || '');
|
|
858
|
+
process.stdout.write(`\r ${bar} \x1b[1m${done}/${totalFiles}\x1b[0m (${pct}%) \x1b[2m${truncFile}\x1b[0m\x1b[K`);
|
|
859
|
+
};
|
|
860
|
+
drawProgress(0, '');
|
|
861
|
+
let _done = 0;
|
|
820
862
|
for (const [f, c] of Object.entries(files)) {
|
|
821
863
|
const existsNow = exists(path.join(root, f));
|
|
822
864
|
const mergeManaged = managedOverwrite.has(f);
|
|
@@ -828,7 +870,12 @@ async function install(root, opts = {}) {
|
|
|
828
870
|
}
|
|
829
871
|
const r = writeIfSafe(root, f, c, { force: opts.force, mergeManaged, archiveDir: backup.archiveDir });
|
|
830
872
|
actions.push(r);
|
|
831
|
-
|
|
873
|
+
_done++;
|
|
874
|
+
drawProgress(_done, f);
|
|
875
|
+
}
|
|
876
|
+
if (isTty) {
|
|
877
|
+
process.stdout.write('\r\x1b[K'); // clear progress line
|
|
878
|
+
log(` \x1b[32m✓\x1b[0m leerness 파일 설치 완료 (${totalFiles}개)`);
|
|
832
879
|
}
|
|
833
880
|
if (!opts.dry) {
|
|
834
881
|
mergeLinesFile(path.join(root, '.gitignore'), [
|
|
@@ -943,11 +990,13 @@ async function install(root, opts = {}) {
|
|
|
943
990
|
log('');
|
|
944
991
|
log('🚀 설치 완료 — REPL agent 모드를 시작합니다...');
|
|
945
992
|
log('');
|
|
993
|
+
_cleanupSigint(); // 1.9.184: REPL 진입 전 SIGINT handler 해제 (readline 이 자체 처리)
|
|
946
994
|
try {
|
|
947
995
|
await _agentRepl(root, { role: 'actor' }); // provider 미지정 → _agentRepl 의 auto-select 동작 (1.9.181 fix)
|
|
948
996
|
} catch (e) { warn('REPL 진입 실패: ' + e.message); }
|
|
949
997
|
}
|
|
950
998
|
}
|
|
999
|
+
_cleanupSigint(); // 1.9.184: install 함수 종료 시 SIGINT handler 해제 (모든 종료 경로)
|
|
951
1000
|
}
|
|
952
1001
|
|
|
953
1002
|
function installSkills(root, skills) { for (const name of skills) addSkill(root, name, true); }
|
|
@@ -5102,9 +5151,10 @@ async function _warnIfStale(root, opts = {}) {
|
|
|
5102
5151
|
log(C.d(' npm registry latest: ') + C.b(`v${latest}`));
|
|
5103
5152
|
log(C.d(' 이 CLI가 실행한 버전: ') + C.b(`v${VERSION}`) + C.d(' (npx 캐시 또는 글로벌 설치 stale)'));
|
|
5104
5153
|
log('');
|
|
5105
|
-
log(C.d(' 해결 —
|
|
5154
|
+
log(C.d(' 해결 — 셋 중 하나 실행 후 다시 시도:'));
|
|
5155
|
+
log(' ' + C.b('npm i leerness@latest') + C.d(' # 프로젝트 로컬 설치 (1.9.183 권장)'));
|
|
5156
|
+
log(' ' + C.b('npm i -g leerness@latest') + C.d(' # 글로벌 설치'));
|
|
5106
5157
|
log(' ' + C.b('npx --yes clear-npx-cache && npx leerness@latest init .'));
|
|
5107
|
-
log(' ' + C.b('npm i -g leerness@latest → leerness init .'));
|
|
5108
5158
|
log('');
|
|
5109
5159
|
log(C.d(' (이 경고는 LEERNESS_NO_STALE_CHECK=1 또는 --no-stale-check로 끌 수 있습니다)'));
|
|
5110
5160
|
log('');
|
|
@@ -13622,6 +13672,22 @@ async function main() {
|
|
|
13622
13672
|
if (exists(path.join(root, '.harness'))) _bumpUsage(root, cmd);
|
|
13623
13673
|
} catch {}
|
|
13624
13674
|
}
|
|
13675
|
+
// 1.9.183 (사용자 명시): 모든 명령 시점에서 구버전 감지 + 경고 + 업데이트 명령어 안내.
|
|
13676
|
+
// init/migrate 는 이미 _warnIfStale 호출하므로 제외. mcp/version/help 등 출력 민감 명령도 제외.
|
|
13677
|
+
// 24h 캐시 (.harness/cache/update-check.json) 활용 — 네트워크 비차단.
|
|
13678
|
+
const _staleSkip = new Set(['init', 'migrate', 'usage', 'mcp', 'release', 'session-close', '--version', '--help', 'help', 'update', 'whats-new']);
|
|
13679
|
+
if (!_staleSkip.has(cmd) && process.env.LEERNESS_NO_STALE_CHECK !== '1' && !has('--no-stale-check')) {
|
|
13680
|
+
try {
|
|
13681
|
+
const root = absRoot(arg('--path', args[1] && !args[1].startsWith('-') ? args[1] : process.cwd()));
|
|
13682
|
+
// 캐시 fresh 시에만 즉시 비교 (네트워크 호출 X — 비차단). offline + cache 없으면 skip.
|
|
13683
|
+
const cached = readUpdateCache(root);
|
|
13684
|
+
if (cacheFresh(cached, 24) && cached.nextLeerness && compareVer(cached.nextLeerness, VERSION) > 0) {
|
|
13685
|
+
const isTty = process.stdout && process.stdout.isTTY;
|
|
13686
|
+
const C = isTty ? { y: s => `\x1b[33m${s}\x1b[0m`, b: s => `\x1b[1m${s}\x1b[0m`, d: s => `\x1b[2m${s}\x1b[0m` } : { y: s => s, b: s => s, d: s => s };
|
|
13687
|
+
process.stderr.write(C.y(' ⚠ ') + C.b(`leerness v${VERSION} → v${cached.nextLeerness} 사용 가능`) + C.d(` · ${C.b('npm i leerness@latest')} 권장 (LEERNESS_NO_STALE_CHECK=1 로 끄기)`) + '\n');
|
|
13688
|
+
}
|
|
13689
|
+
} catch {}
|
|
13690
|
+
}
|
|
13625
13691
|
if (cmd === 'init') return await install(args[1] || process.cwd(), { force:false, dry:false, migration:false });
|
|
13626
13692
|
// 1.9.64: install <skill-id-or-url> 별칭 (= skill install). 자주 쓰는 명령 단축형.
|
|
13627
13693
|
// 단, init이 leerness install . 같은 형태로도 동작하던 옛 호환은 유지 — args[1]이 디렉토리면 init으로 라우팅.
|