{"id":"f657179d-f883-43ae-89b5-136f0e17016a","shortId":"GGgPJs","kind":"skill","title":"line-locator","tagline":"Định vị dòng trước khi đọc file hoặc tìm file trong cây thư mục — tránh đọc mù, tiết kiệm token. Dùng khi cần tìm hàm, class, symbol, hoặc bất kỳ pattern nào trong source code trước khi gọi view_range. Hai công cụ: findtree.py (tìm file nào có chứa pattern) và findtool.py (tìm dò","description":"# Line-Locator\n\nHai script phối hợp để định vị chính xác trước khi đọc:\n\n| Script | Phạm vi | Câu hỏi trả lời |\n|---|---|---|\n| `findtree.py` | Cả cây thư mục | *File nào* chứa pattern này? |\n| `findtool.py` | Một file duy nhất | *Dòng nào* trong file này? |\n\n**Workflow:**\n```\nfindtree.py (shortlist files) → findtool.py (locate lines) → view_range (read)\n```\n\nScript nằm tại: `skills/line-locator/scripts/`\n\n---\n\n## Output contract\n\n**Tất cả pattern dùng Python regex.**\n\n**findtool — success (stdout):**\n```json\n{\"matches\": {\"processOrder\": [247, 312]}}\n{\"line\": 248}\n{\"matched\": true}\n```\n\n**findtree — success (stdout):**\n```json\n{\"matched_files\": [\"src/order.js\", \"tests/order.test.js\"]}\n```\n\n**Failure — cả hai tool (stderr, exit 1):**\n```json\n{\"ok\": false, \"error\": \"No line matching pattern 'foo' was found after line 0.\"}\n```\n\n**Parse nhanh:**\n```python\nimport json, subprocess\nout = subprocess.check_output([...])\ndata = json.loads(out)\n\n# findtool\nlines   = data[\"matches\"][\"pat\"]   # -mr  → list[int]\nline    = data[\"line\"]             # -n / -b / -c / -o → int\nmatched = data[\"matched\"]          # -e   → bool\n\n# findtree\nfiles   = data[\"matched_files\"]    # list[str] relative paths\n```\n\n---\n\n## findtree — tìm file\n\n```bash\npython findtree.py --root ROOT --pattern PAT [options]\n```\n\n| Option | Mặc định | Mô tả |\n|---|---|---|\n| `--root` | *(required)* | Thư mục gốc |\n| `--pattern` | *(required)* | Regex pattern |\n| `--include GLOB...` | *(tất cả)* | Chỉ tìm file khớp glob |\n| `--exclude GLOB...` | *(không)* | Bỏ qua file/thư mục khớp glob |\n| `--ignore-case` | off | Case-insensitive |\n| `--max-results N` | *(không giới hạn)* | Dừng sau N file |\n| `--show` | `matched` | `matched` / `errors` / `both` / `summary` / `all` |\n| `--max-file-size` | *(không)* | Bỏ qua file lớn hơn (VD: `64K`, `10M`) |\n| `--no-default-dir-excludes` | off | Tắt auto-skip `.git`, `node_modules`, v.v. |\n| `--text` | off | Output text thay vì JSON |\n\n**Auto-excluded dirs:** `.git`, `.hg`, `node_modules`, `venv`, `.venv`, `__pycache__`, `dist`, `build`, `target`, `.mypy_cache`, `.pytest_cache`, `.tox`, `coverage`\n\n```bash\npython findtree.py --root ./src --pattern \"processOrder\"\npython findtree.py --root ./src --pattern \"class\\s+\\w+Service\"\npython findtree.py --root . --pattern \"TODO\" --include \"*.ts\" \"*.js\" --exclude \"dist/**\"\npython findtree.py --root . --pattern \"deprecated_api\" --max-results 1\n```\n\n---\n\n## findtool — tìm dòng\n\n```bash\npython findtool.py --file FILE [--ignore-case] [-s] FLAG... [--text]\n```\n\n| Flag | Args | Mô tả | `result` key |\n|---|---|---|---|\n| `-mr` | `PAT [PAT ...]` | Tất cả dòng khớp một hoặc nhiều pattern | `{\"matches\": {\"pat\": [1,5]}}` |\n| `-n` | `PAT LINE` | Dòng đầu tiên khớp **sau** LINE (0 = từ đầu file) | `{\"line\": 45}` |\n| `-b` | `PAT LINE` | Dòng cuối cùng khớp **trước** LINE (999999 = cuối file) | `{\"line\": 12}` |\n| `-e` | `PAT` | File có chứa pattern không? | `{\"matched\": true}` |\n| `-c` | `OPEN CLOSE LINE N` | Dòng đóng khớp với OPEN thứ N trên LINE (scan xuôi) | `{\"line\": 89}` |\n| `-o` | `OPEN CLOSE LINE N` | Dòng mở khớp với CLOSE thứ N trên LINE (scan ngược) | `{\"line\": 34}` |\n\nFlag `-s` (chỉ dùng với `-c`/`-o`): bỏ qua nội dung string và comment khi đếm depth.\n\n```bash\npython findtool.py --file app.js -mr \"processOrder\"\npython findtool.py --file app.js -mr \"processOrder\" \"cancelOrder\" \"getUser\"\npython findtool.py --file app.js -n \"function\\s+\\w+\" 0\npython findtool.py --file app.js -b \"^import\\s\" 999999\npython findtool.py --file app.js -e \"TODO\"\npython findtool.py --file app.js -c \"\\{\" \"\\}\" 248 1\npython findtool.py --file app.js -c \"\\{\" \"\\}\" 248 1 -s\npython findtool.py --file app.js -o \"\\{\" \"\\}\" 298 1\n```\n\n---\n\n## Pair matching (-c / -o)\n\nCả hai flag đều nhận `OPEN CLOSE LINE N` theo cùng thứ tự:\n\n```\n-c  OPEN  CLOSE  LINE  N  →  anchor tại OPEN thứ N trên LINE, scan xuôi  → trả về dòng CLOSE\n-o  OPEN  CLOSE  LINE  N  →  anchor tại CLOSE thứ N trên LINE, scan ngược → trả về dòng OPEN\n```\n\n**Algorithm:** depth-tracking. Mỗi dòng tiếp theo: `depth += count(OPEN) - count(CLOSE)`. Khi `depth == 0` → trả về dòng đó.\n\n**Flag `-s`:** trước khi đếm, mask toàn bộ string literals và comments (`//`, `#`, `/* */`, `'...'`, `\"...\"`, backtick, triple-quote). Dùng khi file có nhiều delimiter trong string/comment.\n\n### Pairs phổ biến theo ngôn ngữ\n\n| Ngôn ngữ | Block mở | Block đóng | Ghi chú |\n|---|---|---|---|\n| JS/TS/Java/Go/Rust/C/C++/C# | `\\{` | `\\}` | Dùng `-s` nếu file có `{` trong string |\n| Bất kỳ — argument list | `\\(` | `\\)` | Áp dụng mọi ngôn ngữ |\n| Bất kỳ — array/list | `\\[` | `\\]` | Áp dụng mọi ngôn ngữ |\n| HTML/XML | `<div\\b[^>]*>` | `</div>` | Thay `div` bằng tên tag |\n| Ruby | `\\bdo\\b` | `\\bend\\b` | Hoặc `\\bdef\\b` / `\\bend\\b` |\n| Lua / Pascal-like | `\\bdo\\b` | `\\bend\\b` | |\n| Shell (bash) | `\\bthen\\b\\|\\bdo\\b` | `\\bfi\\b\\|\\bdone\\b` | Phức tạp hơn |\n| Python | *(không có bracket)* | *(xem note bên dưới)* | Dùng `-n` tìm def tiếp theo |\n\n> **Python note:** Python dùng indentation thay vì `{}`. Để tìm cuối hàm, dùng `-n \"^(def\\|class)\\s\" FUNC_LINE` tìm `def`/`class` tiếp theo cùng cấp, hoặc đọc từ `FUNC_LINE` đến dòng trước đó. Với argument list nhiều dòng: `-c \"\\(\" \"\\)\" FUNC_LINE 1` vẫn hoạt động.\n\n```bash\n# JS/TS function\npython findtool.py --file service.ts -c \"\\{\" \"\\}\" 248 1 -s\n# → {\"line\": 298}\n\n# HTML div\npython findtool.py --file index.html -c \"<div\\b[^>]*>\" \"</div>\" 10 1\n# → {\"line\": 25}\n\n# Ruby method\npython findtool.py --file user.rb -c \"\\bdef\\b\" \"\\bend\\b\" 42 1\n# → {\"line\": 67}\n\n# Argument list dài nhiều dòng (mọi ngôn ngữ)\npython findtool.py --file builder.java -c \"\\(\" \"\\)\" 120 1\n# → {\"line\": 128}\n\n# -o: đang ở dòng }, tìm dòng {\npython findtool.py --file app.go -o \"\\{\" \"\\}\" 298 1\n# → {\"line\": 248}\n```\n\n---\n\n## Workflows\n\n### 1. Đọc một hàm đã biết tên\n\n```bash\n# Bước 1: Tìm dòng định nghĩa\npython findtool.py --file app.js -mr \"processOrder\"\n# → {\"matches\": {\"processOrder\": [247, 312]}}  → 247 là định nghĩa\n\n# Bước 2: Tìm dòng OPEN thực sự (KHÔNG đoán cùng dòng hay dòng dưới)\npython findtool.py --file app.js -n \"\\{\" 247\n# → {\"line\": 248}\n\n# Bước 3: Tìm dòng đóng\npython findtool.py --file app.js -c \"\\{\" \"\\}\" 248 1\n# → {\"line\": 298}\n\n# Bước 4: Đọc\nview_range [247, 298]\n```\n\n### 2. Từ repository lạ → đọc hàm\n\n```bash\npython findtree.py --root ./src --pattern \"processOrder\"\n# → {\"matched_files\": [\"services/order.js\"]}\n\npython findtool.py --file services/order.js -mr \"processOrder\"\n# → tiếp tục Workflow 1\n```\n\n### 3. Scan cấu trúc tổng thể file\n\n```bash\n# JS/TS/Java/Go/C#\npython findtool.py --file service.ts -mr \"class\\s+\\w+\" \"function\\s+\\w+\" \"\\bexport\\b\"\n\n# Python\npython findtool.py --file service.py -mr \"^class\\s+\\w+\" \"^def\\s+\\w+\" \"^    def\\s+\\w+\"\n\n# Ruby\npython findtool.py --file user.rb -mr \"^\\s*def\\s+\\w+\" \"^\\s*class\\s+\\w+\"\n\n# Java/C#\npython findtool.py --file Service.java -mr \"public\\s+\\w\" \"private\\s+\\w\" \"protected\\s+\\w\"\n```\n\n### 4. Tìm nhiều symbol cùng lúc\n\n```bash\npython findtool.py --file app.js -mr \"processOrder\" \"cancelOrder\" \"getUser\"\n# → {\"matches\": {\"processOrder\": [247], \"cancelOrder\": [312], \"getUser\": [89]}}\n# Lên kế hoạch đọc toàn bộ từ một lần call\n```\n\n### 5. Đọc tất cả imports\n\n```bash\n# JS/TS\npython findtool.py --file app.ts -mr \"^import\\s\"\n# → {\"matches\": {\"^import\\\\s\": [1,2,3,14,15]}} → view_range [1, 15]\n\n# Python\npython findtool.py --file app.py -mr \"^import\\s\" \"^from\\s\"\n\n# Java/C#\npython findtool.py --file App.java -mr \"^import\\s\" \"^using\\s\"\n\n# Go\npython findtool.py --file main.go -mr \"^\\s*\\\"\" \n# (lines inside import block — hoặc tìm block import trước)\n```\n\n### 6. Xác định dòng đang thuộc scope nào (ngôn ngữ có `{}`)\n\n```bash\npython findtool.py --file dao.js -b \"\\{\" X    # → OPEN_LINE\npython findtool.py --file dao.js -c \"\\{\" \"\\}\" OPEN_LINE 1  # verify X trong scope này\nview_range [OPEN_LINE - 1, OPEN_LINE]         # đọc tên scope\n```\n\n### 7. Leo scope chain\n\n```bash\npython findtool.py --file app.js -b \"\\{\" 245  →  198\npython findtool.py --file app.js -b \"\\{\" 198  →  134\npython findtool.py --file app.js -b \"\\{\" 134  →  12\npython findtool.py --file app.js -b \"\\{\" 12   →  error → top-level\n```\n\n### 8. Tìm decorator / annotation\n\n```bash\n# Python decorator\npython findtool.py --file routes.py -b \"@\\w+\" FUNC_LINE\n# → nếu kết quả >= FUNC_LINE - 3 → có decorator trực tiếp\n\n# Java/C# annotation\npython findtool.py --file Controller.java -b \"@\\w+\" FUNC_LINE\n\n# JS/TS decorator\npython findtool.py --file service.ts -b \"@\\w+\" FUNC_LINE\n```\n\n### 9. Tìm else / catch / finally\n\n```bash\npython findtool.py --file handler.js -c \"\\{\" \"\\}\" IF_LINE 1  # → close of if-block\npython findtool.py --file handler.js -n \"else|catch|finally\" CLOSE_LINE\n# → nếu ngay sau CLOSE_LINE → đây là else/catch của block đó\n```\n\n---\n\n## ⚠️ Sai lầm phổ biến\n\n### 1. Gọi `-c` trên dòng function name thay vì dòng `{`\n\n```bash\n# ❌ SAI — dòng 247 có tên hàm nhưng chưa chắc có {\npython findtool.py --file app.js -c \"\\{\" \"\\}\" 247 1\n# → error: \"Line 247 contains only 0 occurrence(s) of open pattern '\\{'\"\n\n# ✅ ĐÚNG — tìm dòng { trước, rồi mới -c\npython findtool.py --file app.js -n \"\\{\" 247   # → {\"line\": 248}\npython findtool.py --file app.js -c \"\\{\" \"\\}\" 248 1\n```\n\nLý do: Trong nhiều ngôn ngữ, `{` có thể ở dòng tiếp theo sau tên hàm (Allman style). **Không bao giờ đoán.**\n\n---\n\n### 2. Nhầm lẫn kết quả đầu tiên của `-mr` là định nghĩa\n\n```bash\npython findtool.py --file app.js -mr \"processOrder\"\n# → {\"matches\": {\"processOrder\": [89, 247, 312]}}\n#   89  = call site hoặc comment\n#   247 = định nghĩa hàm (def/function)\n#   312 = call site khác\n```\n\nSố nhỏ nhất chưa chắc là định nghĩa. Đọc thêm vài dòng context để xác nhận, hoặc dùng pattern cụ thể hơn:\n\n```bash\npython findtool.py --file app.js -mr \"function processOrder\" \"processOrder\\s*\\(\"\n# → pattern cụ thể hơn → ít kết quả giả hơn\n```\n\n---\n\n### 3. Pattern có ký tự đặc biệt không escape\n\n```bash\n# ❌ SAI — regex error vì ( không được escape\npython findtool.py --file app.py -mr \"foo(bar)\"\n# → {\"ok\": false, \"error\": \"Invalid regex pattern 'foo(bar)': missing ), ...\"}\n\n# ✅ ĐÚNG\npython findtool.py --file app.py -mr \"foo\\(bar\\)\"\n# hoặc dùng word boundary thay vì match toàn bộ call:\npython findtool.py --file app.py -mr \"foo\"\n```\n\nKý tự cần escape trong regex: `. ^ $ * + ? { } [ ] \\ | ( )`\n\n---\n\n### 4. Dùng Python `{}` để match scope hàm\n\nPython không dùng `{}` cho function/class body. Dùng `-c \"\\{\" \"\\}\"` sẽ chỉ match dict/set literals.\n\n```bash\n# ❌ Không có tác dụng cho Python function body\npython findtool.py --file service.py -c \"\\{\" \"\\}\" 42 1\n\n# ✅ Python: tìm def/class tiếp theo cùng level\npython findtool.py --file service.py -n \"^def \\|^class \" 42\n# → dòng tiếp theo ở cùng indent level = kết thúc hàm hiện tại\n\n# ✅ Python method trong class:\npython findtool.py --file service.py -n \"^    def \" 42\n```\n\n---\n\n### 5. Quên rằng `-n` là **sau** LINE, không phải **tại** LINE\n\n```bash\npython findtool.py --file app.js -n \"def \" 247\n# → Tìm match STRICTLY AFTER dòng 247, không phải tại 247\n# Nếu def ở dòng 247 → sẽ không được trả về\n\n# Để bao gồm chính dòng đó:\npython findtool.py --file app.js -n \"def \" 246  # tìm sau dòng 246\n```\n\n---\n\n### 6. Bỏ qua `-s` khi file có nhiều `{` trong string/comment\n\n```bash\n# File có: const tmpl = `SELECT * FROM t WHERE col = '{value}'`\n# ❌ Không -s: depth tracking đếm sai vì { trong template string\npython findtool.py --file query.ts -c \"\\{\" \"\\}\" 50 1\n# → kết quả sai\n\n# ✅ Dùng -s để bỏ qua string/comment\npython findtool.py --file query.ts -c \"\\{\" \"\\}\" 50 1 -s\n```\n\nNên dùng `-s` khi: file là template (`.html`, `.ejs`, `.hbs`), SQL inline, hoặc bất kỳ file nào có nhiều `{` không phải code.\n\n---\n\n### 7. Dùng findtool trực tiếp mà không biết file ở đâu\n\n```bash\n# ❌ Tốn thời gian — không biết file nào\npython findtool.py --file src/auth/service.js -mr \"validateToken\"\n# → File not found\n\n# ✅ findtree trước\npython findtree.py --root ./src --pattern \"validateToken\"\n# → {\"matched_files\": [\"src/auth/service.js\"]}\n```\n\n---\n\n### 8. Không biết ngôn ngữ dùng `{` hay không → kiểm tra trước\n\nTrước khi dùng `-c \"\\{\" \"\\}\"`, xác nhận file có `{` không:\n```bash\npython findtool.py --file service.py -e \"\\{\"\n# → {\"matched\": false} → Python file, không có {-based scope\n# → {\"matched\": true}  → file có {, tiến hành bình thường\n```\n\n### 9. Dùng `\\|` thay vì `|` cho alternation trong Python regex\n\n```bash\n# ❌ SAI — \\| trong Python regex là ký tự pipe literal, không phải alternation\npython findtool.py --file app.java -mr \"focusLost\\|hidePopup\\|showPopup\"\n# → {\"matches\": {\"focusLost\\\\|hidePopup\\\\|showPopup\": []}}  ← tìm chuỗi literal   \"focusLost|hidePopup|showPopup\"\n\n# ✅ ĐÚNG — | không cần escape trong Python regex\npython findtool.py --file app.java -mr \"focusLost|hidePopup|showPopup\"\n# → {\"matches\": {\"focusLost|hidePopup|showPopup\": [192, 723, 701]}}\n\nLý do nhầm: grep basic mode (BRE) dùng \\| cho alternation. Python dùng ERE-style — | đã là   alternation, \\| là literal pipe.\n\nKhi nào \\| hợp lệ: không bao giờ trong Python regex nếu mục đích là alternation.\n```\n\n---\n\n## Bảng quyết định nhanh\n\n| Tình huống | Dùng gì |\n|---|---|\n| Chưa biết file nào | `findtree --root ... --pattern ...` |\n| Biết tên hàm, muốn đọc body (ngôn ngữ có `{}`) | `-mr \"name\"` → `-n \"\\{\" LINE` → `-c \"\\{\" \"\\}\" OPEN 1` |\n| Ngôn ngữ không có `{}` (Python...) | `-mr \"name\"` → `-n \"^def\\|^class\" LINE` |\n| Nhiều hàm cùng lúc | `-mr \"fn1\" \"fn2\" \"fn3\"` |\n| Pattern có ký tự đặc biệt | escape: `\\(`, `\\)`, `\\{`, `\\.`, v.v. |\n| File có nhiều `{` trong string | thêm `-s` vào `-c`/`-o` |\n| Duyệt từng hàm không biết tên | `-mr \"\\{\"` → `-c \"\\{\" \"\\}\"` → `-n \"\\{\"` → lặp |\n| Ở dòng X, muốn biết thuộc hàm nào | `-b \"\\{\" X` → `-c \"\\{\" \"\\}\" OPEN 1` verify |\n| Đọc hết imports | `-mr \"^import\\s\"` → min/max → `view_range` |\n| Argument list nhiều dòng | `-c \"\\(\" \"\\)\" LINE 1` |\n| Tìm else/catch/finally | `-c \"\\{\" \"\\}\" IF_LINE 1` → `-n \"else\\|catch\\|finally\"` |\n| Có decorator/annotation không? | `-b \"@\\w+\" FUNC_LINE` → check khoảng cách |\n| HTML tag pair | `-c \"<tag\\b[^>]*>\" \"</tag>\" LINE 1` |\n| Ruby/Lua method body | `-c \"\\bdef\\b\" \"\\bend\\b\" LINE 1` |\n| Scope ngoài cùng | `-b \"\\{\"` lặp đến error |\n| File có chứa pattern không? | `-e \"pattern\"` |\n| Chỉ tìm trong file .ts .js | findtree `--include \"*.ts\" \"*.js\"` |\n| Dừng sớm khi tìm đủ | findtree `--max-results 1` |\n\n---\n\n## Xử lý lỗi\n\n| Lỗi | Nguyên nhân | Cách xử lý |\n|---|---|---|\n| `\"For -n, LINE must be >= 0\"` | Truyền số âm vào `-n` | Dùng 0 để tìm từ đầu file |\n| `\"For -b, LINE must be >= 1\"` | Truyền 0 vào `-b` | Dùng 999999 để tìm từ cuối file |\n| `\"Line X contains only 0 occurrence(s) of open pattern\"` | `{` không ở dòng đó | Dùng `-n \"\\{\" FUNC_LINE` để tìm dòng `{` thực tế |\n| `\"No closing match for open pattern\"` | Không tìm thấy CLOSE trong file | File chưa đóng bracket, hoặc dùng thêm `-s` |\n| `\"No line matching pattern ... was found\"` | Pattern không khớp trong phạm vi | Kiểm tra lại regex; với `-b` có thể tăng LINE |\n| `\"Invalid regex pattern\"` | Regex sai cú pháp | Escape: `\\(`, `\\)`, `\\{`, `\\.` |\n| `\"Root directory not found\"` | `--root` không tồn tại | Kiểm tra lại đường dẫn |\n| `\"N must be >= 1\"` | N = 0 trong `-c`/`-o` | N bắt đầu từ 1 |\n\n---\n\n## Ví dụ end-to-end\n\n**Bài toán:** Đọc hàm `validateToken` trong codebase 50 file, không biết nó nằm ở đâu.\n\n```bash\n# 1. Tìm file\npython findtree.py --root ./src --pattern \"validateToken\"\n# → {\"matched_files\": [\"auth/service.ts\"]}\n\n# 2. Tìm dòng định nghĩa\npython findtool.py --file auth/service.ts -mr \"validateToken\"\n# → {\"matches\": {\"validateToken\": [312, 467]}}  → 312 là định nghĩa\n\n# 3. Kiểm tra decorator\npython findtool.py --file auth/service.ts -b \"@\\w+\" 312\n# → {\"line\": 310}  → có decorator ở dòng 310\n\n# 4. Tìm dòng {\npython findtool.py --file auth/service.ts -n \"\\{\" 312\n# → {\"line\": 313}\n\n# 5. Tìm dòng đóng (dùng -s vì file TS hay có template string)\npython findtool.py --file auth/service.ts -c \"\\{\" \"\\}\" 313 1 -s\n# → {\"line\": 389}\n\n# 6. Đọc\nview_range [310, 389]\n```\n\n**Token tiêu thụ:** ~80 dòng thay vì hàng nghìn. Tiết kiệm >90%.","tags":["line","locator","unkluco","agent-skills","claude","claude-ai","claude-code","python3"],"capabilities":["skill","source-unkluco","skill-line-locator","topic-agent-skills","topic-claude","topic-claude-ai","topic-claude-code","topic-python3"],"categories":["line-locator"],"synonyms":[],"warnings":[],"endpointUrl":"https://skills.sh/unkluco/line-locator","protocol":"skill","transport":"skills-sh","auth":{"type":"none","details":{"cli":"npx skills add unkluco/line-locator","source_repo":"https://github.com/unkluco/line-locator","install_from":"skills.sh"}},"qualityScore":"0.453","qualityRationale":"deterministic score 0.45 from registry signals: · indexed on github topic:agent-skills · 7 github stars · SKILL.md body (15,915 chars)","verified":false,"liveness":"unknown","lastLivenessCheck":null,"agentReviews":{"count":0,"score_avg":null,"cost_usd_avg":null,"success_rate":null,"latency_p50_ms":null,"narrative_summary":null,"summary_updated_at":null},"enrichmentModel":"deterministic:skill-github:v1","enrichmentVersion":1,"enrichedAt":"2026-05-18T19:14:01.146Z","embedding":null,"createdAt":"2026-05-18T13:21:31.162Z","updatedAt":"2026-05-18T19:14:01.146Z","lastSeenAt":"2026-05-18T19:14:01.146Z","tsv":"'/c':662 '/src':332,338,941,1749,2247 '0':162,408,513,618,1318,2089,2096,2109,2123,2210 '1':148,363,397,534,541,549,782,795,809,824,841,856,860,869,921,956,1072,1079,1144,1154,1254,1285,1312,1345,1544,1676,1692,1925,1985,2002,2008,2030,2040,2074,2107,2208,2218,2241,2320 '10':808 '10m':286 '12':427,1185,1191 '120':840 '128':843 '134':1178,1184 '14':1075 '15':1076,1080 '192':1856 '198':1171,1177 '2':889,931,1073,1367,2253 '245':1170 '246':1634,1638 '247':128,882,884,907,929,1040,1298,1311,1315,1336,1389,1396,1601,1607,1611,1616 '248':131,533,540,794,858,909,920,1338,1344 '25':811 '298':548,798,855,923,930 '3':911,957,1074,1216,1446,2272 '310':2284,2289,2328 '312':129,883,1042,1390,1401,2266,2268,2282,2298 '313':2300,2319 '34':472 '389':2323,2329 '4':925,1023,1509,2290 '42':823,1543,1559,1582 '45':413 '467':2267 '5':398,1055,1583,2301 '50':1675,1691,2232 '6':1117,1639,2324 '64k':285 '67':826 '7':1160,1716 '701':1858 '723':1857 '8':1196,1755 '80':2333 '89':454,1044,1388,1391 '9':1241,1797 '90':2341 '999999':423,521,2113 'algorithm':603 'allman':1361 'altern':1802,1818,1868,1876,1894 'anchor':572,590 'annot':1199,1222 'api':359 'app.go':853 'app.java':1095,1822,1847 'app.js':494,500,508,517,525,531,538,546,877,905,918,1033,1168,1175,1182,1189,1309,1334,1342,1383,1431,1598,1631 'app.py':1085,1466,1483,1500 'app.ts':1065 'arg':379 'argument':672,775,827,1996 'array/list':681 'auth/service.ts':2252,2261,2279,2296,2317 'auto':295,309 'auto-exclud':308 'auto-skip':294 'b':187,414,518,689,697,699,702,704,710,712,716,718,720,722,807,820,822,978,1133,1169,1176,1183,1190,1207,1227,1237,1981,2016,2028,2036,2038,2044,2103,2111,2179,2280 'backtick':635 'bao':1364,1623,1885 'bar':1469,1477,1486 'base':1787 'bash':208,328,367,490,714,786,867,937,964,1029,1060,1128,1164,1200,1246,1295,1379,1427,1455,1529,1594,1649,1727,1775,1806,2240 'basic':1863 'bdef':701,819,2035 'bdo':696,709,717 'bdone':721 'bend':698,703,711,821,2037 'bexport':977 'bfi':719 'biến':649,1284 'biết':865,1723,1732,1757,1904,1910,1967,1977,2235 'biệt':1452,1950 'block':655,657,1111,1114,1259,1279 'bodi':1521,1537,1915,2033 'bool':195 'boundari':1490 'bracket':729,2157 'bre':1865 'bthen':715 'build':320 'builder.java':838 'bài':2225 'bên':732 'bình':1795 'bước':868,888,910,924 'bảng':1895 'bất':32,670,679,1707 'bắt':2215 'bằng':692 'bỏ':242,279,480,1640,1683 'bộ':630,1050,1495 'c':188,437,478,532,539,552,567,779,793,805,818,839,919,1141,1251,1287,1310,1330,1343,1523,1542,1674,1690,1769,1923,1961,1970,1983,2000,2005,2026,2034,2212,2318 'cach':323,325 'call':1054,1392,1402,1496 'cancelord':503,1036,1041 'case':251,254,374 'case-insensit':253 'catch':1244,1266,2011 'chain':1163 'check':2020 'cho':1519,1534,1801,1867 'chuỗi':1832 'chính':68,1625 'chú':660 'chưa':1303,1408,1903,2155 'chắc':1304,1409 'chỉ':234,475,1525,2055 'chứa':52,87,432,2050 'class':29,340,754,760,971,985,1005,1558,1575,1935 'close':439,457,464,560,569,584,587,592,615,1255,1268,1273,2143,2151 'code':38,1715 'codebas':2231 'col':1658 'comment':486,634,1395 'const':1652 'contain':1316,2121 'context':1417 'contract':115 'controller.java':1226 'count':612,614 'coverag':327 'cuối':418,424,749,2117 'cách':2022,2081 'câi':15,82 'câu':76 'có':51,431,642,667,728,1127,1217,1299,1305,1352,1448,1531,1645,1651,1711,1773,1786,1792,1918,1929,1946,1954,2013,2049,2180,2285,2311 'công':45 'cùng':419,564,763,897,1027,1550,1564,1939,2043 'cú':2189 'cả':81,117,143,233,388,554,1058 'cấp':764 'cấu':959 'cần':26,1505,1839 'cụ':46,1424,1438 'của':1278,1374 'dao.js':1132,1140 'data':172,177,184,192,198 'decor':1198,1202,1218,1232,2275,2286 'decorator/annotation':2014 'def':737,753,759,988,991,1001,1557,1581,1600,1613,1633,1934 'def/class':1547 'def/function':1400 'default':289 'delimit':644 'deprec':358 'depth':489,605,611,617,1662 'depth-track':604 'dict/set':1527 'dir':290,311 'directori':2193 'dist':319,353 'div':688,691,800,806 'dung':483 'duy':93 'duyệt':1963 'dài':829 'dò':57 'dòng':6,95,366,389,402,417,442,460,583,601,608,621,771,778,831,847,849,871,891,898,900,913,1120,1289,1294,1297,1326,1355,1416,1560,1606,1615,1626,1637,1974,1999,2131,2139,2255,2288,2292,2303,2334 'dùng':24,119,476,639,663,734,743,751,1422,1488,1510,1518,1522,1680,1695,1717,1760,1768,1798,1866,1870,1901,2095,2112,2133,2159,2305 'dưới':733,901 'dẫn':2204 'dụ':2220 'dụng':675,683,1533 'dừng':263,2065 'e':194,428,526,1780,2053 'ej':1702 'els':1243,1265,2010 'else/catch':1277 'else/catch/finally':2004 'end':2222,2224 'end-to-end':2221 'ere':1872 'ere-styl':1871 'error':152,270,1192,1313,1458,1472,2047 'escap':1454,1462,1506,1840,1951,2191 'exclud':239,291,310,352 'exit':147 'failur':142 'fals':151,1471,1782 'file':10,13,49,85,92,98,103,139,197,200,207,236,266,276,281,370,371,411,425,430,493,499,507,516,524,530,537,545,641,666,791,803,816,837,852,876,904,917,945,949,963,968,982,997,1011,1032,1064,1084,1094,1104,1131,1139,1167,1174,1181,1188,1205,1225,1235,1249,1262,1308,1333,1341,1382,1430,1465,1482,1499,1540,1554,1578,1597,1630,1644,1650,1672,1688,1698,1709,1724,1733,1737,1741,1753,1772,1778,1784,1791,1821,1846,1905,1953,2048,2058,2101,2118,2153,2154,2233,2243,2251,2260,2278,2295,2308,2316 'file/th':244 'final':1245,1267,2012 'findtool':122,175,364,1718 'findtool.py':55,90,104,369,492,498,506,515,523,529,536,544,790,802,815,836,851,875,903,916,948,967,981,996,1010,1031,1063,1083,1093,1103,1130,1138,1166,1173,1180,1187,1204,1224,1234,1248,1261,1307,1332,1340,1381,1429,1464,1481,1498,1539,1553,1577,1596,1629,1671,1687,1736,1777,1820,1845,2259,2277,2294,2315 'findtre':134,196,205,1744,1907,2061,2070 'findtree.py':47,80,101,210,330,336,345,355,939,1747,2245 'flag':376,378,473,556,623 'fn1':1942 'fn2':1943 'fn3':1944 'focuslost':1824,1828,1834,1849,1853 'foo':157,1468,1476,1485,1502 'found':159,1743,2167,2195 'func':756,768,780,1209,1214,1229,1239,2018,2135 'function':510,788,974,1290,1433,1536 'function/class':1520 'getus':504,1037,1043 'ghi':659 'gian':1730 'git':297,312 'giả':1444 'giới':261 'giờ':1365,1886 'glob':231,238,240,248 'go':1101 'grep':1862 'gì':1902 'gọi':41,1286 'gốc':225 'gồm':1624 'hai':44,61,144,555 'handler.js':1250,1263 'hay':899,1761,2310 'hbs':1703 'hg':313 'hidepopup':1825,1829,1835,1850,1854 'hiện':1570 'hoạch':1047 'hoạt':784 'hoặc':11,31,392,700,765,1112,1394,1421,1487,1706,2158 'html':799,1701,2023 'html/xml':687 'huống':1900 'hàm':28,750,863,936,1301,1360,1399,1515,1569,1912,1938,1965,1979,2228 'hàng':2337 'hành':1794 'hơn':283,725,1426,1440,1445 'hạn':262 'hết':1988 'hỏi':77 'hợp':64,1882 'if-block':1257 'ignor':250,373 'ignore-cas':249,372 'import':166,519,1059,1067,1070,1087,1097,1110,1115,1989,1991 'includ':230,349,2062 'indent':744,1565 'index.html':804 'inlin':1705 'insensit':255 'insid':1109 'int':182,190 'invalid':1473,2184 'java/c':1008,1091,1221 'js':351,2060,2064 'js/ts':787,1061,1231 'js/ts/java/go/c':965 'js/ts/java/go/rust/c/c':661 'json':125,137,149,167,307 'json.loads':173 'key':383 'khi':8,25,40,71,487,616,626,640,1643,1697,1767,1880,2067 'khoảng':2021 'khác':1404 'không':241,260,278,434,727,895,1363,1453,1460,1517,1530,1590,1608,1618,1660,1713,1722,1731,1756,1762,1774,1785,1816,1838,1884,1928,1966,2015,2052,2129,2148,2169,2197,2234 'khớp':237,247,390,405,420,444,462,2170 'kiểm':1763,2174,2200,2273 'kiệm':22,2340 'ký':1449,1503,1812,1947 'kế':1046 'kết':1212,1370,1442,1567,1677 'kỳ':33,671,680,1708 'leo':1161 'level':1195,1551,1566 'like':708 'line':2,59,106,130,154,161,176,183,185,401,407,412,416,422,426,440,450,453,458,468,471,561,570,578,588,596,757,769,781,797,810,825,842,857,908,922,1108,1136,1143,1153,1156,1210,1215,1230,1240,1253,1269,1274,1314,1337,1589,1593,1922,1936,2001,2007,2019,2029,2039,2086,2104,2119,2136,2163,2183,2283,2299,2322 'line-loc':1,58 'list':181,201,673,776,828,1997 'liter':632,1528,1815,1833,1878 'locat':3,60,105 'lua':705 'là':885,1276,1376,1410,1587,1699,1811,1875,1877,1893,2269 'lên':1045 'lúc':1028,1940 'lý':1346,1859,2076,2083 'lạ':934 'lại':2176,2202 'lầm':1282 'lần':1053 'lẫn':1369 'lặp':1972,2045 'lệ':1883 'lỗi':2077,2078 'lớn':282 'lời':79 'main.go':1105 'mask':628 'match':126,132,138,155,178,191,193,199,268,269,395,435,551,880,944,1038,1069,1386,1493,1513,1526,1603,1752,1781,1789,1827,1852,2144,2164,2250,2264 'max':257,275,361,2072 'max-file-s':274 'max-result':256,360,2071 'method':813,1573,2032 'min/max':1993 'miss':1478 'mode':1864 'modul':299,315 'mr':180,384,495,501,878,951,970,984,999,1013,1034,1066,1086,1096,1106,1375,1384,1432,1467,1484,1501,1739,1823,1848,1919,1931,1941,1969,1990,2262 'must':2087,2105,2206 'muốn':1913,1976 'mypi':322 'mà':1721 'mô':219,380 'mù':20 'mặc':217 'mọi':676,684,832 'mỗi':607 'một':91,391,862,1052 'mới':1329 'mở':461,656 'mục':17,84,224,246,1891 'n':186,259,265,399,441,448,459,466,509,562,571,576,589,594,735,752,906,1264,1335,1556,1580,1586,1599,1632,1921,1933,1971,2009,2085,2094,2134,2205,2209,2214,2297 'name':1291,1920,1932 'ngay':1271 'nghìn':2338 'nghĩa':873,887,1378,1398,1412,2257,2271 'ngoài':2042 'nguyên':2079 'ngôn':651,653,677,685,833,1125,1350,1758,1916,1926 'ngược':470,598 'ngữ':652,654,678,686,834,1126,1351,1759,1917,1927 'nhanh':164,1898 'nhiều':393,643,777,830,1025,1349,1646,1712,1937,1955,1998 'nhân':2080 'nhưng':1302 'nhất':94,1407 'nhầm':1368,1861 'nhận':558,1420,1771 'nhỏ':1406 'no-default-dir-exclud':287 'node':298,314 'note':731,741 'nài':89,99,1149 'nào':35,50,86,96,1124,1710,1734,1881,1906,1980 'nên':1694 'nó':2236 'nằm':111,2237 'nếu':665,1211,1270,1612,1890 'nội':482 'o':189,455,479,547,553,585,844,854,1962,2213 'occurr':1319,2124 'ok':150,1470 'open':438,446,456,559,568,574,586,602,613,892,1135,1142,1152,1155,1322,1924,1984,2127,2146 'option':215,216 'output':114,171,303 'pair':550,647,2025 'pars':163 'pascal':707 'pascal-lik':706 'pat':179,214,385,386,396,400,415,429 'path':204 'pattern':34,53,88,118,156,213,226,229,333,339,347,357,394,433,942,1323,1423,1437,1447,1475,1750,1909,1945,2051,2054,2128,2147,2165,2168,2186,2248 'pháp':2190 'phạm':74,2172 'phải':1591,1609,1714,1817 'phối':63 'phổ':648,1283 'phức':723 'pipe':1814,1879 'privat':1017 'processord':127,334,496,502,879,881,943,952,1035,1039,1385,1387,1434,1435 'protect':1020 'public':1014 'pycach':318 'pytest':324 'python':120,165,209,329,335,344,354,368,491,497,505,514,522,528,535,543,726,740,742,789,801,814,835,850,874,902,915,938,947,966,979,980,995,1009,1030,1062,1081,1082,1092,1102,1129,1137,1165,1172,1179,1186,1201,1203,1223,1233,1247,1260,1306,1331,1339,1380,1428,1463,1480,1497,1511,1516,1535,1538,1545,1552,1572,1576,1595,1628,1670,1686,1735,1746,1776,1783,1804,1809,1819,1842,1844,1869,1888,1930,2244,2258,2276,2293,2314 'qua':243,280,481,1641,1684 'query.ts':1673,1689 'quot':638 'quyết':1896 'quên':1584 'quả':1213,1371,1443,1678 'rang':43,108,928,1078,1151,1995,2327 'read':109 'regex':121,228,1457,1474,1508,1805,1810,1843,1889,2177,2185,2187 'relat':203 'repositori':933 'requir':222,227 'result':258,362,382,2073 'root':211,212,221,331,337,346,356,940,1748,1908,2192,2196,2246 'routes.py':1206 'rubi':695,812,994 'ruby/lua':2031 'rằng':1585 'rồi':1328 'sai':1281,1296,1456,1665,1679,1807,2188 'sau':264,406,1272,1358,1588,1636 'scan':451,469,579,597,958 'scope':1123,1148,1159,1162,1514,1788,2041 'script':62,73,110 'select':1654 'servic':343 'service.java':1012 'service.py':983,1541,1555,1579,1779 'service.ts':792,969,1236 'services/order.js':946,950 'shell':713 'shortlist':102 'show':267 'showpopup':1826,1830,1836,1851,1855 'site':1393,1403 'size':277 'skill' 'skill-line-locator' 'skills/line-locator/scripts':113 'skip':296 'sourc':37 'source-unkluco' 'sql':1704 'src/auth/service.js':1738,1754 'src/order.js':140 'stderr':146 'stdout':124,136 'str':202 'strict':1604 'string':484,631,669,1669,1957,2313 'string/comment':646,1648,1685 'style':1362,1873 'subprocess':168 'subprocess.check':170 'success':123,135 'summari':272 'symbol':30,1026 'sẽ':1524,1617 'số':1405,2091 'sớm':2066 'sự':894 'tag':694,2024,2027 'target':321 'templat':1668,1700,2312 'tests/order.test.js':141 'text':301,304,377 'thay':305,690,745,1292,1491,1799,2335 'theo':563,610,650,739,762,1357,1549,1562 'thuộc':1122,1978 'thêm':1414,1958,2160 'thúc':1568 'thư':16,83,223 'thường':1796 'thấi':2150 'thể':962,1353,1425,1439,2181 'thời':1729 'thụ':2332 'thứ':447,465,565,575,593 'thực':893,2140 'tiên':404,1373 'tiêu':2331 'tiến':1793 'tiếp':609,738,761,953,1220,1356,1548,1561,1720 'tiết':21,2339 'tmpl':1653 'todo':348,527 'token':23,2330 'tool':145 'top':1194 'top-level':1193 'topic-agent-skills' 'topic-claude' 'topic-claude-ai' 'topic-claude-code' 'topic-python3' 'tox':326 'toàn':629,1049,1494 'toán':2226 'tra':1764,2175,2201,2274 'track':606,1663 'tripl':637 'triple-quot':636 'trong':14,36,97,645,668,1147,1348,1507,1574,1647,1667,1803,1808,1841,1887,1956,2057,2152,2171,2211,2230 'true':133,436,1790 'truyền':2090,2108 'tránh':18 'trên':449,467,577,595,1288 'trúc':960 'trước':7,39,70,421,625,772,1116,1327,1745,1765,1766 'trả':78,581,599,619,1620 'trực':1219,1719 'ts':350,2059,2063,2309 'tác':1532 'tên':693,866,1158,1300,1359,1911,1968 'tìm':12,27,48,56,206,235,365,736,748,758,848,870,890,912,1024,1113,1197,1242,1325,1546,1602,1635,1831,2003,2056,2068,2098,2115,2138,2149,2242,2254,2291,2302 'tình':1899 'tăng':2182 'tại':112,573,591,1571,1592,1610,2199 'tạp':724 'tả':220,381 'tất':116,232,387,1057 'tắt':293 'tế':2141 'tốn':1728 'tồn':2198 'tổng':961 'tục':954 'từ':409,767,932,1051,2099,2116,2217 'từng':1964 'tự':566,1450,1504,1813,1948 'use':1099 'user.rb':817,998 'v.v':300,1952 'validatetoken':1740,1751,2229,2249,2263,2265 'valu':1659 'vd':284 'venv':316,317 'verifi':1145,1986 'vi':75,2173 'view':42,107,927,1077,1150,1994,2326 'và':54,485,633 'vài':1415 'vào':1960,2093,2110 'vì':306,746,1293,1459,1492,1666,1800,2307,2336 'ví':2219 'vẫn':783 'về':582,600,620,1621 'vị':5,67 'với':445,463,477,774,2178 'w':342,512,973,976,987,990,993,1003,1007,1016,1019,1022,1208,1228,1238,2017,2281 'word':1489 'workflow':100,859,955 'x':1134,1146,1975,1982,2120 'xem':730 'xuôi':452,580 'xác':69,1118,1419,1770 'xử':2075,2082 'áp':674,682 'âm':2092 'ít':1441 'đang':845,1121 'đoán':896,1366 'đâi':1275 'đâu':1726,2239 'đã':864,1874 'đích':1892 'đó':622,773,1280,1627,2132 'đóng':443,658,914,2156,2304 'đúng':1324,1479,1837 'đường':2203 'được':1461,1619 'đầu':403,410,1372,2100,2216 'đặc':1451,1949 'đếm':488,627,1664 'đến':770,2046 'đều':557 'để':65,747,1418,1512,1622,1682,2097,2114,2137 'định':4,66,218,872,886,1119,1377,1397,1411,1897,2256,2270 'đọc':9,19,72,766,861,926,935,1048,1056,1157,1413,1914,1987,2227,2325 'động':785 'đủ':2069 'ư':245 'ở':846,1354,1563,1614,1725,1973,2130,2238,2287","prices":[{"id":"138f490d-ea58-40fe-a366-cb999f0cd002","listingId":"f657179d-f883-43ae-89b5-136f0e17016a","amountUsd":"0","unit":"free","nativeCurrency":null,"nativeAmount":null,"chain":null,"payTo":null,"paymentMethod":"skill-free","isPrimary":true,"details":{"org":"unkluco","category":"line-locator","install_from":"skills.sh"},"createdAt":"2026-05-18T13:21:31.162Z"}],"sources":[{"listingId":"f657179d-f883-43ae-89b5-136f0e17016a","source":"github","sourceId":"unkluco/line-locator","sourceUrl":"https://github.com/unkluco/line-locator","isPrimary":false,"firstSeenAt":"2026-05-18T13:21:31.162Z","lastSeenAt":"2026-05-18T19:14:01.146Z"}],"details":{"listingId":"f657179d-f883-43ae-89b5-136f0e17016a","quickStartSnippet":null,"exampleRequest":null,"exampleResponse":null,"schema":null,"openapiUrl":null,"agentsTxtUrl":null,"citations":[],"useCases":[],"bestFor":[],"notFor":[],"kindDetails":{"org":"unkluco","slug":"line-locator","github":{"repo":"unkluco/line-locator","stars":7,"topics":["agent-skills","claude","claude-ai","claude-code","python3"],"license":"mit","html_url":"https://github.com/unkluco/line-locator","pushed_at":"2026-04-04T10:07:53Z","description":"Agent skill for precise code navigation: locate functions fast, read less, save tokens.","skill_md_sha":"94e1e257ae6d4b7a4bffce1aaef62054c69ccf8c","skill_md_path":"SKILL.md","default_branch":"master","skill_tree_url":"https://github.com/unkluco/line-locator"},"layout":"root","source":"github","category":"line-locator","frontmatter":{"name":"line-locator","description":"Định vị dòng trước khi đọc file hoặc tìm file trong cây thư mục — tránh đọc mù, tiết kiệm token. Dùng khi cần tìm hàm, class, symbol, hoặc bất kỳ pattern nào trong source code trước khi gọi view_range. Hai công cụ: findtree.py (tìm file nào có chứa pattern) và findtool.py (tìm dòng nào trong một file)."},"skills_sh_url":"https://skills.sh/unkluco/line-locator"},"updatedAt":"2026-05-18T19:14:01.146Z"}}