leerness 1.9.172 β†’ 1.9.173

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,65 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.9.173 β€” 2026-05-21
4
+
5
+ **🌐 LSP μ–΄λŒ‘ν„° λ‹€κ΅­μ–΄ ν™•μž₯ β€” JavaScript + Python + Go + Rust + Java (5개 μ–Έμ–΄ regex fallback).**
6
+
7
+ 자율 λͺ¨λ“œ 103 λΌμš΄λ“œ. 1.9.167 codeIntel (JS/TS only) β†’ 5개 μ–Έμ–΄ ν™•μž₯.
8
+
9
+ ### `_LSP_LANG_PATTERNS` β€” 5개 μ–Έμ–΄ νŒ¨ν„΄
10
+ | μ–Έμ–΄ | μΆ”μΆœ κ°€λŠ₯ |
11
+ |---|---|
12
+ | **javascript** (.ts/.tsx/.js/.jsx/.mjs/.cjs) | function, class, interface, type, enum, arrow function |
13
+ | **python** (.py/.pyw/.pyi) | def, async def, class |
14
+ | **go** (.go) | func (receiver 포함), type struct/interface, type alias |
15
+ | **rust** (.rs) | fn (pub/async), struct, enum, trait, impl, type |
16
+ | **java** (.java/.kt/.scala) | class (public/private/abstract), interface, enum, method |
17
+
18
+ ### `_detectLspLang(file)` β€” ν™•μž₯자 μžλ™ λΌμš°νŒ…
19
+ 파일 ν™•μž₯자 기반 μ–Έμ–΄ μžλ™ 감지. 미지원 ν™•μž₯μžλŠ” javascript κΈ°λ³Έ (1.9.167 ν˜Έν™˜).
20
+
21
+ ### μ‚¬μš© μ˜ˆμ‹œ
22
+ ```bash
23
+ $ leerness lsp symbols src/api.py
24
+ # leerness lsp symbols (1.9.173 λ‹€κ΅­μ–΄)
25
+ file: src/api.py Β· lang: python
26
+ mode: regex-fallback (python) Β· 12 symbols Β· 4ms
27
+ 1:function parse_request
28
+ 8:function fetch_data
29
+ 15:class Handler
30
+ 16:function __init__
31
+ ...
32
+
33
+ $ leerness lsp symbols src/main.rs
34
+ # leerness lsp symbols (1.9.173 λ‹€κ΅­μ–΄)
35
+ file: src/main.rs Β· lang: rust
36
+ mode: regex-fallback (rust) Β· 9 symbols Β· 5ms
37
+ 1:function hello
38
+ 5:struct User
39
+ 9:impl User
40
+ 15:trait Greeter
41
+ ...
42
+ ```
43
+
44
+ ### ν‚€μ›Œλ“œ false-positive 제거
45
+ Java method μ •κ·œμ‹μ΄ `if(`, `for(`, `while(`, `switch(`, `catch(`, `return(`, `throw(`, `new(` λ“± ν‚€μ›Œλ“œμ— λ§€μΉ˜λ˜λŠ” 경우 ν•„ν„°.
46
+
47
+ ### references λ‹€κ΅­μ–΄ 파일 μŠ€μΊ”
48
+ `leerness lsp references <name>` κ°€ `.py/.go/.rs/.java/.kt/.scala` νŒŒμΌλ„ μŠ€μΊ” (κΈ°μ‘΄ `.ts/.js/.md` 에 μΆ”κ°€).
49
+
50
+ ### μ‹€μΈ‘ (regex fallback)
51
+ - Python (5 symbols): 472ms
52
+ - Go (4 symbols): 566ms
53
+ - Rust (6 symbols): 531ms
54
+ - Java (4 symbols): 1229ms
55
+
56
+ ### Verified
57
+ - e2e 217/217 baseline μœ μ§€
58
+ - stress-v118: **15/15** (νŒ¨ν„΄ μ •μ˜ 4 + Python 1 + Go 1 + Rust 1 + Java 1 + JS ν˜Έν™˜ 1 + references 1 + λˆ„μ  νšŒκ·€ 5)
59
+ - VERSION = 1.9.173 / autonomous-rounds = 103 / main μžλ™ push 34 λΌμš΄λ“œ 연속
60
+
61
+ ---
62
+
3
63
  ## 1.9.172 β€” 2026-05-21
4
64
 
5
65
  **🎨 슀트리밍 UX κ°•ν™” β€” spinner + Claude tool_use κ°€μ‹œν™” + diff νŒ¨ν„΄ μžλ™ 색깔 (μ‚¬μš©μž λͺ…μ‹œ κ°•ν™”).**
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.172-green)]() [![tests](https://img.shields.io/badge/e2e-217%2F217-success)]() [![stress](https://img.shields.io/badge/stress--v117-20%2F20-success)]() [![mcp](https://img.shields.io/badge/MCP--tools-53-brightgreen)]() [![rounds](https://img.shields.io/badge/autonomous--rounds-102-blueviolet)]() [![main-push](https://img.shields.io/badge/release--main--push-33_rounds-success)]() [![stream-ux](https://img.shields.io/badge/슀트리밍-spinner%2Btool__use%2Bdiff_색깔-success)]() [![repl-tab](https://img.shields.io/badge/REPL-Tab_cycle%2Bμ‹€μ‹œκ°„_슀트리밍-success)]() [![mcp-bridge](https://img.shields.io/badge/MCP_bridge-web%2Fpc%2Flsp_λ…ΈμΆœ-success)]() [![capability](https://img.shields.io/badge/6_capability-72%25_production--ready-brightgreen)]() [![sandbox](https://img.shields.io/badge/runCommandSafe-cwd_jail%2Benv_scrub-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.173-green)]() [![tests](https://img.shields.io/badge/e2e-217%2F217-success)]() [![stress](https://img.shields.io/badge/stress--v118-15%2F15-success)]() [![mcp](https://img.shields.io/badge/MCP--tools-53-brightgreen)]() [![rounds](https://img.shields.io/badge/autonomous--rounds-103-blueviolet)]() [![main-push](https://img.shields.io/badge/release--main--push-34_rounds-success)]() [![lsp-multi](https://img.shields.io/badge/LSP_λ‹€κ΅­μ–΄-JS%2FPython%2FGo%2FRust%2FJava-success)]() [![stream-ux](https://img.shields.io/badge/슀트리밍-spinner%2Btool__use%2Bdiff_색깔-success)]() [![mcp-bridge](https://img.shields.io/badge/MCP_bridge-web%2Fpc%2Flsp_λ…ΈμΆœ-success)]() [![capability](https://img.shields.io/badge/6_capability-72%25_production--ready-brightgreen)]() [![sandbox](https://img.shields.io/badge/runCommandSafe-cwd_jail%2Benv_scrub-success)]() [![license](https://img.shields.io/badge/license-MIT-lightgrey)]()
6
6
 
7
7
  ```
8
8
  ╔══════════════════════════════════════════════════════════════╗
@@ -12,9 +12,9 @@
12
12
  β•‘ β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•”β•β•β• β–ˆβ–ˆβ•”β•β•β• β–ˆβ–ˆβ•”β•β•β–ˆβ–ˆβ•—β–ˆβ–ˆβ•‘β•šβ–ˆβ–ˆβ•—β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•”β•β•β• β•šβ•β•β•β•β–ˆβ–ˆβ•‘ β•‘
13
13
  β•‘ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•‘ β•šβ–ˆβ–ˆβ–ˆβ–ˆβ•‘β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•‘ β•‘
14
14
  β•‘ β•šβ•β•β•β•β•β•β•β•šβ•β•β•β•β•β•β•β•šβ•β•β•β•β•β•β•β•šβ•β• β•šβ•β•β•šβ•β• β•šβ•β•β•β•β•šβ•β•β•β•β•β•β•β•šβ•β•β•β•β•β•β• β•‘
15
- β•‘ v1.9.172 AI Agent Reliability Harness + Sandbox β•‘
15
+ β•‘ v1.9.173 AI Agent Reliability Harness + Sandbox β•‘
16
16
  β•‘ verify Β· remember Β· orchestrate Β· audit Β· sandbox Β· drift β•‘
17
- β•‘ 🎨 슀트리밍 spinner + tool_use κ°€μ‹œν™” + diff μžλ™ 색깔 β•‘
17
+ β•‘ 🌐 LSP λ‹€κ΅­μ–΄ 5μ’… (JS/Python/Go/Rust/Java regex fallback) β•‘
18
18
  β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•
19
19
  ```
20
20
 
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.172';
9
+ const VERSION = '1.9.173';
10
10
  const MARK = '<!-- leerness:managed -->';
11
11
  const README_START = '<!-- leerness:project-readme:start -->';
12
12
  const README_END = '<!-- leerness:project-readme:end -->';
@@ -12560,22 +12560,69 @@ function _tryLoadLSP() {
12560
12560
  return { ok: false, error: 'typescript λ―Έμ„€μΉ˜ β€” `npm i -g typescript` ν›„ λ‹€μ‹œ μ‹œλ„ (λ˜λŠ” μ •κ·œμ‹ fallback μ‚¬μš©)' };
12561
12561
  }
12562
12562
 
12563
- // μ •κ·œμ‹ fallback β€” TypeScript/JavaScript symbol μΆ”μΆœ (LSP 없이도 λ™μž‘)
12564
- function _lspRegexSymbols(content) {
12565
- const symbols = [];
12566
- const lines = content.split(/\r?\n/);
12567
- const patterns = [
12563
+ // 1.9.173: λ‹€κ΅­μ–΄ ν™•μž₯ β€” Python/Go/Rust/Java νŒ¨ν„΄ μΆ”κ°€ (regex fallback)
12564
+ // 파일 ν™•μž₯자 기반 μžλ™ λΌμš°νŒ…. TypeScript Compiler API λ―Έμ„€μΉ˜ μ‹œμ—λ„ 5개 μ–Έμ–΄ 지원.
12565
+ const _LSP_LANG_PATTERNS = {
12566
+ javascript: [
12568
12567
  { re: /^\s*(?:export\s+)?(?:async\s+)?function\s+([A-Za-z_$][\w$]*)\s*\(/, kind: 'function' },
12569
12568
  { re: /^\s*(?:export\s+)?class\s+([A-Za-z_$][\w$]*)/, kind: 'class' },
12570
12569
  { re: /^\s*(?:export\s+)?interface\s+([A-Za-z_$][\w$]*)/, kind: 'interface' },
12571
12570
  { re: /^\s*(?:export\s+)?(?:const|let|var)\s+([A-Za-z_$][\w$]*)\s*=\s*(?:async\s+)?(?:function|\()/, kind: 'function' },
12572
12571
  { re: /^\s*(?:export\s+)?type\s+([A-Za-z_$][\w$]*)\s*=/, kind: 'type' },
12573
- { re: /^\s*(?:export\s+)?enum\s+([A-Za-z_$][\w$]*)/, kind: 'enum' },
12574
- ];
12572
+ { re: /^\s*(?:export\s+)?enum\s+([A-Za-z_$][\w$]*)/, kind: 'enum' }
12573
+ ],
12574
+ python: [
12575
+ { re: /^\s*async\s+def\s+([A-Za-z_][\w]*)\s*\(/, kind: 'function' },
12576
+ { re: /^\s*def\s+([A-Za-z_][\w]*)\s*\(/, kind: 'function' },
12577
+ { re: /^\s*class\s+([A-Za-z_][\w]*)\s*[(:]/, kind: 'class' }
12578
+ ],
12579
+ go: [
12580
+ { re: /^\s*func\s+(?:\([^)]*\)\s+)?([A-Za-z_][\w]*)\s*\(/, kind: 'function' },
12581
+ { re: /^\s*type\s+([A-Za-z_][\w]*)\s+struct\b/, kind: 'struct' },
12582
+ { re: /^\s*type\s+([A-Za-z_][\w]*)\s+interface\b/, kind: 'interface' },
12583
+ { re: /^\s*type\s+([A-Za-z_][\w]*)\s+[A-Za-z]/, kind: 'type' }
12584
+ ],
12585
+ rust: [
12586
+ { re: /^\s*(?:pub(?:\([^)]+\))?\s+)?(?:async\s+)?fn\s+([A-Za-z_][\w]*)/, kind: 'function' },
12587
+ { re: /^\s*(?:pub(?:\([^)]+\))?\s+)?struct\s+([A-Za-z_][\w]*)/, kind: 'struct' },
12588
+ { re: /^\s*(?:pub(?:\([^)]+\))?\s+)?enum\s+([A-Za-z_][\w]*)/, kind: 'enum' },
12589
+ { re: /^\s*(?:pub(?:\([^)]+\))?\s+)?trait\s+([A-Za-z_][\w]*)/, kind: 'trait' },
12590
+ { re: /^\s*impl\s+(?:[^{]+\s+for\s+)?([A-Za-z_][\w]*)/, kind: 'impl' },
12591
+ { re: /^\s*(?:pub(?:\([^)]+\))?\s+)?type\s+([A-Za-z_][\w]*)\s*=/, kind: 'type' }
12592
+ ],
12593
+ java: [
12594
+ { re: /^\s*(?:public|private|protected)?\s*(?:final\s+)?(?:abstract\s+)?class\s+([A-Za-z_][\w]*)/, kind: 'class' },
12595
+ { re: /^\s*(?:public|private|protected)?\s*(?:abstract\s+)?interface\s+([A-Za-z_][\w]*)/, kind: 'interface' },
12596
+ { re: /^\s*(?:public|private|protected)?\s*(?:static\s+)?(?:final\s+)?enum\s+([A-Za-z_][\w]*)/, kind: 'enum' },
12597
+ // method: visibility + return type + name( (heuristic β€” 첫 번째 ( λ§€μΉ­, ν‚€μ›Œλ“œ ν•„ν„°)
12598
+ { re: /^\s*(?:public|private|protected)\s+(?:static\s+)?(?:final\s+)?(?:[A-Za-z_<>,\s\[\]]+\s+)?([A-Za-z_][\w]*)\s*\(/, kind: 'method' }
12599
+ ]
12600
+ };
12601
+
12602
+ function _detectLspLang(file) {
12603
+ const ext = (file.match(/\.[a-zA-Z0-9]+$/) || [''])[0].toLowerCase();
12604
+ if (/^\.(py|pyw|pyi)$/.test(ext)) return 'python';
12605
+ if (ext === '.go') return 'go';
12606
+ if (ext === '.rs') return 'rust';
12607
+ if (/^\.(java|kt|scala)$/.test(ext)) return 'java';
12608
+ if (/^\.(ts|tsx|js|jsx|mjs|cjs)$/.test(ext)) return 'javascript';
12609
+ return 'javascript'; // default β€” κΈ°λ³Έ JS νŒ¨ν„΄ (.txt/.md λ“± 미지원 ν™•μž₯자)
12610
+ }
12611
+
12612
+ // μ •κ·œμ‹ fallback β€” 5개 μ–Έμ–΄ (JS/TS/Python/Go/Rust/Java) symbol μΆ”μΆœ (LSP 없이도 λ™μž‘)
12613
+ // 1.9.173: lang 인자 μΆ”κ°€ β€” λ―Έμ§€μ • μ‹œ javascript νŒ¨ν„΄ (1.9.167 ν˜Έν™˜).
12614
+ function _lspRegexSymbols(content, lang) {
12615
+ const symbols = [];
12616
+ const lines = content.split(/\r?\n/);
12617
+ const patterns = _LSP_LANG_PATTERNS[lang || 'javascript'] || _LSP_LANG_PATTERNS.javascript;
12575
12618
  lines.forEach((line, idx) => {
12576
12619
  for (const p of patterns) {
12577
12620
  const m = line.match(p.re);
12578
- if (m) { symbols.push({ name: m[1], kind: p.kind, line: idx + 1 }); break; }
12621
+ // ν‚€μ›Œλ“œ false-positive 제거 (예: java method μ •κ·œμ‹μ΄ `if(`, `for(` 등에 λ§€μΉ˜λ˜λŠ” 경우)
12622
+ if (m && !/^(if|for|while|switch|catch|return|throw|new)$/.test(m[1])) {
12623
+ symbols.push({ name: m[1], kind: p.kind, line: idx + 1 });
12624
+ break;
12625
+ }
12579
12626
  }
12580
12627
  });
12581
12628
  return symbols;
@@ -12641,31 +12688,32 @@ function lspCmd(root, sub, ...args) {
12641
12688
  if (!fs.existsSync(file)) return fail(`파일 μ—†μŒ: ${file}`);
12642
12689
  const content = fs.readFileSync(file, 'utf8');
12643
12690
  const t0 = Date.now();
12691
+ const lang = _detectLspLang(file); // 1.9.173: μ–Έμ–΄ μžλ™ 감지
12644
12692
  const r = _tryLoadLSP();
12645
12693
  let symbols, mode;
12646
12694
  try {
12647
- if (r.ok && /\.(ts|tsx|js|jsx|mjs|cjs)$/.test(file)) {
12695
+ if (r.ok && lang === 'javascript' && /\.(ts|tsx|js|jsx|mjs|cjs)$/.test(file)) {
12648
12696
  symbols = _lspTsSymbols(r.lib, content, file);
12649
12697
  mode = 'typescript-compiler';
12650
12698
  } else {
12651
- symbols = _lspRegexSymbols(content);
12652
- mode = 'regex-fallback';
12699
+ symbols = _lspRegexSymbols(content, lang); // 1.9.173: lang 전달
12700
+ mode = `regex-fallback (${lang})`;
12653
12701
  }
12654
12702
  } catch (e) {
12655
- symbols = _lspRegexSymbols(content);
12656
- mode = 'regex-fallback (after error: ' + e.message + ')';
12703
+ symbols = _lspRegexSymbols(content, lang);
12704
+ mode = `regex-fallback (${lang}, after error: ${e.message})`;
12657
12705
  }
12658
12706
  const dt = Date.now() - t0;
12659
12707
  if (has('--json')) {
12660
- log(JSON.stringify({ file, symbols, count: symbols.length, mode, durationMs: dt }, null, 2));
12708
+ log(JSON.stringify({ file, lang, symbols, count: symbols.length, mode, durationMs: dt }, null, 2));
12661
12709
  } else {
12662
- log(`# leerness lsp symbols (1.9.167)`);
12663
- log(`file: ${file}`);
12710
+ log(`# leerness lsp symbols (1.9.173 λ‹€κ΅­μ–΄)`);
12711
+ log(`file: ${file} Β· lang: ${lang}`);
12664
12712
  log(`mode: ${mode} Β· ${symbols.length} symbols Β· ${dt}ms`);
12665
12713
  symbols.slice(0, 50).forEach(s => log(` ${String(s.line).padStart(5)}:${s.kind.padEnd(10)} ${s.name}`));
12666
12714
  if (symbols.length > 50) log(` ... ${symbols.length - 50} more`);
12667
12715
  }
12668
- try { _recordRun(root, { kind: 'lsp_symbols', file, count: symbols.length, mode, durationMs: dt, ok: true }); } catch {}
12716
+ try { _recordRun(root, { kind: 'lsp_symbols', file, lang, count: symbols.length, mode, durationMs: dt, ok: true }); } catch {}
12669
12717
  return;
12670
12718
  }
12671
12719
  if (sub === 'references') {
@@ -12683,7 +12731,7 @@ function lspCmd(root, sub, ...args) {
12683
12731
  if (e.name.startsWith('.') || e.name === 'node_modules' || e.name === 'dist' || e.name === 'build') continue;
12684
12732
  const p = path.join(d, e.name);
12685
12733
  if (e.isDirectory()) walk(p);
12686
- else if (/\.(ts|tsx|js|jsx|mjs|cjs|md)$/.test(e.name)) {
12734
+ else if (/\.(ts|tsx|js|jsx|mjs|cjs|md|py|pyw|pyi|go|rs|java|kt|scala)$/.test(e.name)) {
12687
12735
  try {
12688
12736
  const lines = fs.readFileSync(p, 'utf8').split(/\r?\n/);
12689
12737
  lines.forEach((ln, idx) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "leerness",
3
- "version": "1.9.172",
3
+ "version": "1.9.173",
4
4
  "description": "Leerness: λΉ„νŒŒκ΄΄ λ§ˆμ΄κ·Έλ ˆμ΄μ…˜, μžλ™ 버전 κ°μ§€Β·μ—…λ°μ΄νŠΈ, κ³„νš/μ§„ν–‰/ν•Έλ“œμ˜€ν”„ μžλ™ν™”, κ²ŒμœΌλ¦„Β·μ‹œν¬λ¦ΏΒ·μΈμ½”λ”© μžλ™ κ°€λ“œ, Claude Code μŠ¬λž˜μ‹œ 톡합을 κ°–μΆ˜ ν•œκ΅­μ–΄ μš°μ„  AI 개발 ν•˜λ„€μŠ€.",
5
5
  "keywords": [
6
6
  "leerness",