argo-search 2.9.7 → 2.9.8
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/README.en.md +58 -145
- package/README.es.md +58 -145
- package/README.ja.md +64 -151
- package/README.ko.md +63 -150
- package/README.md +65 -154
- package/SKILL.md +3 -3
- package/assets/readme/hero.svg +2 -2
- package/backends/domain_profiles.json +48 -0
- package/backends/engine_registry.yaml +118 -4
- package/backends/quota_profiles.json +92 -12
- package/backends/source_types_cn.json +27 -1
- package/bin/argo +74 -5
- package/bin/argo.js +33 -2
- package/config.yaml +219 -60
- package/docs/ENGINE_CATALOG.md +50 -39
- package/docs/MCP_SETUP.md +3 -1
- package/docs/RELEASE_NOTES_v2.9.8.md +73 -0
- package/engines/specs/cfets.yaml +41 -0
- package/engines/specs/defillama.yaml +38 -0
- package/engines/specs/firecrawl.yaml +1 -1
- package/engines/specs/fxtwitter.yaml +5 -0
- package/engines/specs/gleif.yaml +55 -0
- package/engines/specs/hkex.yaml +40 -0
- package/engines/specs/keenable_free.yaml +36 -0
- package/engines/specs/shfe.yaml +39 -0
- package/engines/specs/stackexchange.yaml +2 -2
- package/engines/specs/tavily_free.yaml +56 -0
- package/engines/specs/yuanbao.yaml +93 -0
- package/mcp/clients.yaml +32 -0
- package/package.json +6 -2
- package/packages/dsh-plugin/README.md +23 -5
- package/packages/dsh-plugin/dsh/client.js +304 -15
- package/packages/dsh-plugin/dsh/diagnostics.js +54 -0
- package/packages/dsh-plugin/dsh/index.js +112 -1875
- package/packages/dsh-plugin/dsh/native-tools.mjs +7 -1
- package/packages/dsh-plugin/dsh/runner.js +666 -0
- package/packages/dsh-plugin/dsh/wide-research.js +878 -0
- package/packages/dsh-plugin/package.json +2 -2
- package/packages/dsh-plugin/scripts/sync-local.sh +70 -0
- package/packages/dsh-plugin/test/client.test.js +175 -1
- package/packages/dsh-plugin/test/diagnostics.test.js +28 -0
- package/packages/dsh-plugin/test/index.test.js +44 -0
- package/scripts/adaptive.py +24 -1
- package/scripts/article_meta.py +131 -0
- package/scripts/budget.py +247 -0
- package/scripts/budget_cli.py +93 -0
- package/scripts/build_release_assets.sh +65 -0
- package/scripts/cache.py +60 -72
- package/scripts/ci_drift_gate.py +90 -0
- package/scripts/content_boundary.py +46 -0
- package/scripts/content_signals.py +26 -5
- package/scripts/cross_lingual_trace.py +293 -0
- package/scripts/dispatch_result.py +98 -0
- package/scripts/engine_dispatch.py +49 -86
- package/scripts/engine_env.py +5 -0
- package/scripts/engine_families.py +6 -0
- package/scripts/engine_policy.py +7 -7
- package/scripts/engines.py +21 -0
- package/scripts/engines_base.py +3 -3
- package/scripts/engines_builders.py +12 -0
- package/scripts/engines_builders_batch10.py +48 -3
- package/scripts/engines_builders_batch14.py +656 -0
- package/scripts/engines_builders_batch15.py +249 -0
- package/scripts/engines_builders_keyless.py +111 -0
- package/scripts/engines_builders_tech.py +0 -1
- package/scripts/evidence.py +31 -3
- package/scripts/evidence_loop.py +54 -22
- package/scripts/fetch_v3.py +25 -0
- package/scripts/gen_routing_snapshot.py +11 -0
- package/scripts/install.ps1 +18 -0
- package/scripts/install.sh +16 -1
- package/scripts/job.py +3 -3
- package/scripts/local_seek.py +41 -5
- package/scripts/macro_countries.py +15 -0
- package/scripts/matrix_search_eval.py +82 -0
- package/scripts/mcp_compact.py +234 -0
- package/scripts/mcp_handlers.py +60 -642
- package/scripts/mcp_launch.sh +10 -8
- package/scripts/mcp_local.py +241 -0
- package/scripts/mcp_server.py +19 -14
- package/scripts/mcp_setup.py +33 -9
- package/scripts/mcp_tools.py +1 -0
- package/scripts/mcp_transport.py +1 -1
- package/scripts/mcp_warm.py +127 -0
- package/scripts/output_transparency.py +200 -0
- package/scripts/paid_policy.py +98 -0
- package/scripts/quota.py +158 -13
- package/scripts/recovery_runner.py +150 -0
- package/scripts/replay_eval.py +18 -0
- package/scripts/research.py +37 -21
- package/scripts/research_expand.py +24 -1
- package/scripts/retry_policy.py +76 -0
- package/scripts/route.py +6 -6
- package/scripts/route_cache.py +18 -0
- package/scripts/route_combo.py +7 -0
- package/scripts/route_domains.py +32 -19
- package/scripts/search.py +15 -27
- package/scripts/search_attribution.py +100 -3
- package/scripts/search_cli.py +24 -11
- package/scripts/search_entry.py +7 -1
- package/scripts/search_output.py +99 -15
- package/scripts/search_pipeline.py +42 -193
- package/scripts/search_types.py +107 -9
- package/scripts/semantic_evidence.py +179 -3
- package/scripts/serp_guard.py +115 -7
- package/scripts/serp_kill_log.py +25 -2
- package/scripts/stats_cli.py +13 -1
- package/scripts/wide_research.py +45 -0
- package/scripts/zhihu_quota.py +139 -0
- package/sub-skills/local-search/bm25.py +27 -3
- package/sub-skills/local-search/cli_runner.py +331 -0
- package/sub-skills/local-search/parsers.py +328 -0
- package/sub-skills/local-search/search_v3.py +31 -674
- package/sub-skills/local-seek/scripts/seek_rank.py +7 -3
- package/assets/readme/settings-keys.png +0 -0
- package/assets/readme/settings-tools.png +0 -0
- package/scripts/image_vision/vision_probe +0 -0
- package/scripts/local_engines.py +0 -321
- package/sub-skills/ego-search/references/browser-runtime.md +0 -43
- package/sub-skills/ego-search/references/install.md +0 -67
- package/sub-skills/ego-search/references/original-ego-upgrade.md +0 -51
- package/sub-skills/ego-search/tests/test_query_normalize.py +0 -68
- package/sub-skills/js-run/tests/fixtures/challenge_like.js +0 -27
- package/sub-skills/js-run/tests/test_jsrun.py +0 -165
- package/sub-skills/local-seek/references/auto-behaviors.md +0 -24
- package/sub-skills/local-seek/references/fd-mdfind-recipes.md +0 -62
- package/sub-skills/local-seek/references/git-integration.md +0 -54
- package/sub-skills/local-seek/references/remote-handoff.md +0 -46
- package/sub-skills/local-seek/references/rg-recipes.md +0 -96
- package/sub-skills/local-seek/references/strategies.md +0 -52
- package/sub-skills/local-seek/references/structural-search.md +0 -59
- package/sub-skills/local-seek/tests/test_content_rank.py +0 -222
- package/sub-skills/local-seek/tests/test_determinism_20261006.py +0 -145
- package/sub-skills/local-seek/tests/test_noise_tier.py +0 -101
- package/sub-skills/local-seek/tests/test_pcre2_probe.py +0 -136
- package/sub-skills/local-seek/tests/test_rank_pinyin.py +0 -77
- package/sub-skills/local-seek/tests/test_regression_20261003.py +0 -169
- package/sub-skills/local-seek/tests/test_regression_20261006.py +0 -146
- package/sub-skills/local-seek/tests/test_seek_degradation.py +0 -111
- package/sub-skills/local-seek/tests/test_seek_fts.py +0 -313
|
@@ -1,165 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
"""jsrun 最小核测试(金标考卷驱动)。
|
|
3
|
-
|
|
4
|
-
直接运行:python3 tests/test_jsrun.py(也可 pytest 收集)。
|
|
5
|
-
依赖:mini-racer(pip install mini-racer)。
|
|
6
|
-
"""
|
|
7
|
-
from __future__ import annotations
|
|
8
|
-
|
|
9
|
-
import importlib.util
|
|
10
|
-
import sys
|
|
11
|
-
import time
|
|
12
|
-
from pathlib import Path
|
|
13
|
-
|
|
14
|
-
import pytest
|
|
15
|
-
|
|
16
|
-
# mini-racer 是 js-run 的可选依赖(V8 沙箱)。没装的机器上这 10 条用例会
|
|
17
|
-
# 全部 RuntimeError,把主套件染红——而缺依赖本应是 skip,不是失败
|
|
18
|
-
# (2026-10-18 实测:主套件 4236 passed / 4 failed,其中 1 条就是这里)。
|
|
19
|
-
# 用模块级 pytestmark 而不是 importorskip:后者会让收集数为 0,旧版 pytest
|
|
20
|
-
# 返回 rc=5(no tests collected),外层 sub-skills 套件门照样红。
|
|
21
|
-
pytestmark = pytest.mark.skipif(
|
|
22
|
-
importlib.util.find_spec("py_mini_racer") is None,
|
|
23
|
-
reason="js-run 可选依赖 mini-racer 未安装",
|
|
24
|
-
)
|
|
25
|
-
|
|
26
|
-
HERE = Path(__file__).parent
|
|
27
|
-
sys.path.insert(0, str(HERE.parent / "scripts"))
|
|
28
|
-
|
|
29
|
-
from jsrun import JsRun # noqa: E402
|
|
30
|
-
|
|
31
|
-
CHALLENGE = (HERE / "fixtures" / "challenge_like.js").read_text(encoding="utf-8")
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
def test_env_probe():
|
|
35
|
-
with JsRun() as jr:
|
|
36
|
-
out = jr.run("({ua: navigator.userAgent, p: navigator.platform, wd: navigator.webdriver})")
|
|
37
|
-
assert out["ua"].startswith("Mozilla/5.0"), out
|
|
38
|
-
assert out["p"] == "Win32"
|
|
39
|
-
assert out["wd"] is False
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
def test_challenge_token_and_cookie():
|
|
43
|
-
with JsRun() as jr:
|
|
44
|
-
out = jr.run(CHALLENGE)
|
|
45
|
-
assert out["token"], out
|
|
46
|
-
assert out["issued"] is False, "advance 前定时器不该触发"
|
|
47
|
-
jr.advance(3000)
|
|
48
|
-
assert jr.run("issued_global_check()") if False else True
|
|
49
|
-
cookie = jr.get_cookie()
|
|
50
|
-
assert cookie.startswith("__jsl_clearance="), cookie
|
|
51
|
-
assert out["token"] in cookie
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
def test_initial_state_extraction():
|
|
55
|
-
# 数据埋在 JS 里的提取场景:window.__INITIAL_STATE__ 直取
|
|
56
|
-
with JsRun() as jr:
|
|
57
|
-
jr.run("window.__INITIAL_STATE__ = {list: [1,2,3], meta: {title: 'js 数据'}}")
|
|
58
|
-
out = jr.run("window.__INITIAL_STATE__")
|
|
59
|
-
assert out == {"list": [1, 2, 3], "meta": {"title": "js 数据"}}
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
def test_logical_timer_instant():
|
|
63
|
-
with JsRun() as jr:
|
|
64
|
-
jr.run("var x = 0; setTimeout(function(){ x = 42; }, 5000);")
|
|
65
|
-
assert jr.run("x") == 0
|
|
66
|
-
fired = jr.advance(5000)
|
|
67
|
-
assert fired == 1
|
|
68
|
-
assert jr.run("x") == 42
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
def test_entropy_differs_across_contexts():
|
|
72
|
-
with JsRun() as a, JsRun() as b:
|
|
73
|
-
va = a.run("Array.from(crypto.getRandomValues(new Uint8Array(8)))")
|
|
74
|
-
vb = b.run("Array.from(crypto.getRandomValues(new Uint8Array(8)))")
|
|
75
|
-
assert va != vb, "不同上下文的熵应不同"
|
|
76
|
-
assert len(va) == 8 and all(isinstance(x, int) and 0 <= x <= 255 for x in va)
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
def test_environment_override():
|
|
80
|
-
with JsRun(environment={"navigator": {"userAgent": "TestUA/1.0"}}) as jr:
|
|
81
|
-
assert jr.run("navigator.userAgent") == "TestUA/1.0"
|
|
82
|
-
assert jr.run("navigator.platform") == "Win32" # 未覆盖字段保持默认
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
def test_speed_budget():
|
|
86
|
-
# 量化门:上下文创建 + 环境垫片 + 一次求值 < 100ms(iv8 实测 18ms 为基线)
|
|
87
|
-
t0 = time.perf_counter()
|
|
88
|
-
with JsRun() as jr:
|
|
89
|
-
jr.run("navigator.userAgent")
|
|
90
|
-
dt_ms = (time.perf_counter() - t0) * 1000
|
|
91
|
-
assert dt_ms < 100, f"冷启动 {dt_ms:.1f}ms 超预算"
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
def test_atob_rejects_invalid_chars():
|
|
95
|
-
# 非法 base64 字符应报错,不静默映射
|
|
96
|
-
with JsRun() as jr:
|
|
97
|
-
try:
|
|
98
|
-
jr.run('atob("!!invalid!!")')
|
|
99
|
-
assert False, "应抛异常"
|
|
100
|
-
except (RuntimeError, Exception):
|
|
101
|
-
pass # 预期行为
|
|
102
|
-
# 合法 base64 正常
|
|
103
|
-
out = jr.run('atob("aGVsbG8=")')
|
|
104
|
-
assert out == "hello", out
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
def test_run_timeout():
|
|
108
|
-
# 死循环脚本应超时
|
|
109
|
-
with JsRun() as jr:
|
|
110
|
-
try:
|
|
111
|
-
jr.run('while(true){}', timeout_ms=500)
|
|
112
|
-
assert False, "应超时"
|
|
113
|
-
except TimeoutError:
|
|
114
|
-
pass # 预期行为
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
def test_close_releases():
|
|
118
|
-
# close 后上下文应不可用
|
|
119
|
-
jr = JsRun()
|
|
120
|
-
jr.close()
|
|
121
|
-
try:
|
|
122
|
-
jr.run('1+1')
|
|
123
|
-
assert False, "close 后应不可用"
|
|
124
|
-
except (AttributeError, RuntimeError, Exception):
|
|
125
|
-
pass # 预期行为
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
def test_run_in_worker_thread():
|
|
129
|
-
# 回归:此前用 signal.SIGALRM,在工作线程(crawl/research/mcp_server)
|
|
130
|
-
# 必抛 ValueError: signal only works in main thread
|
|
131
|
-
import threading
|
|
132
|
-
|
|
133
|
-
out_box: dict = {}
|
|
134
|
-
|
|
135
|
-
def _worker():
|
|
136
|
-
try:
|
|
137
|
-
with JsRun() as jr:
|
|
138
|
-
out_box["val"] = jr.run("navigator.platform + ':' + (20 + 22)")
|
|
139
|
-
try:
|
|
140
|
-
jr.run("while(true){}", timeout_ms=200)
|
|
141
|
-
out_box["timeout_ok"] = False
|
|
142
|
-
except TimeoutError:
|
|
143
|
-
out_box["timeout_ok"] = True
|
|
144
|
-
except BaseException as e:
|
|
145
|
-
out_box["err"] = e
|
|
146
|
-
|
|
147
|
-
t = threading.Thread(target=_worker)
|
|
148
|
-
t.start()
|
|
149
|
-
t.join(timeout=5)
|
|
150
|
-
assert "err" not in out_box, f"工作线程执行失败: {out_box.get('err')!r}"
|
|
151
|
-
assert out_box.get("val") == "Win32:42"
|
|
152
|
-
assert out_box.get("timeout_ok") is True
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
if __name__ == "__main__":
|
|
156
|
-
fails = 0
|
|
157
|
-
for name, fn in sorted(globals().items()):
|
|
158
|
-
if name.startswith("test_") and callable(fn):
|
|
159
|
-
try:
|
|
160
|
-
fn()
|
|
161
|
-
print(f"PASS {name}")
|
|
162
|
-
except AssertionError as e:
|
|
163
|
-
fails += 1
|
|
164
|
-
print(f"FAIL {name}: {e}")
|
|
165
|
-
sys.exit(1 if fails else 0)
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
# seek.py 自动行为明细(按需读取)
|
|
2
|
-
|
|
3
|
-
这些行为全部自动生效,无需手动指定;排障或想理解「为什么这么搜」时再读。
|
|
4
|
-
从 SKILL.md 挪入(v1.6.0,触发即注入预算 7KB 的口径)。
|
|
5
|
-
|
|
6
|
-
- **固定字符串**:查询是纯字面量时自动用 rg -F;含 regex 元字符但解析失败
|
|
7
|
-
(如 interface{})自动回退 -F。
|
|
8
|
-
- **中文扩展**:中文查询先按原词精确匹配,没命中再拆成 2 字词(2-gram)放宽
|
|
9
|
-
(如「数据抓取」放宽到「数据」「抓取」),这样能多搜到一些;--exact 关闭。
|
|
10
|
-
- **PCRE2 检测**:查询含 look-around 时检查本机 rg 是否支持,不支持给出
|
|
11
|
-
明确提示而非报错。
|
|
12
|
-
- **结构搜索**:--structural 按语义检索代码模式(裸 except、空 catch、
|
|
13
|
-
装饰函数、函数/类定义),中英文别名都认,零安装(rg -U 多行实现)。
|
|
14
|
-
- **Git 联动**:--git-log / --git-blame 直接回答「这行谁改的、最近动过什么」,
|
|
15
|
-
文件不在仓库或未跟踪时给出明确区分,不报错。
|
|
16
|
-
- **BM25F 内容重排**:文件名 2.0 / 目录 0.6 / 行文本 1.0 三字段,BM25+ 下界 +
|
|
17
|
-
逐字短语加成 + 文件级命中数先验;池子按文件轮转配额(每文件 ≤8 行)。
|
|
18
|
-
`ARGO_SEEK_CONTENT_RERANK=0` 关闭。
|
|
19
|
-
- **fzf V2 文件名评分**:驼峰/边界/gap 惩罚,DP 最优对齐(junegunn/fzf 口径)。
|
|
20
|
-
- **FTS5 索引快路**:`ARGO_LOCAL_FTS=1` 后,无正则元字符的内容查询走
|
|
21
|
-
SQLite FTS5 倒排索引(unicode61 + CJK 逐字短语),只在索引过期(TTL 120s)
|
|
22
|
-
时付一次增量刷新(rg --files 清单 + 改动文件重读,预算 1.5s)。rg 永远
|
|
23
|
-
兜底:索引未建成/查询带正则/零命中语义见 seek_fts.py docstring。大树首次
|
|
24
|
-
建索引较慢,先跑 `python3 scripts/seek_fts.py rebuild <目录>` 预热。
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
# fd 与 Spotlight(mdfind)配方
|
|
2
|
-
|
|
3
|
-
## fd — 按文件名查找
|
|
4
|
-
|
|
5
|
-
统一入口用 `seek.py "词" --filename`,手动配方:
|
|
6
|
-
|
|
7
|
-
```bash
|
|
8
|
-
# 文件名模糊匹配(忽略大小写)
|
|
9
|
-
fd "login"
|
|
10
|
-
|
|
11
|
-
# 指定目录
|
|
12
|
-
fd "auth" ~/src
|
|
13
|
-
|
|
14
|
-
# 限定扩展名
|
|
15
|
-
fd -e py "schema"
|
|
16
|
-
fd -e md -e txt "notes"
|
|
17
|
-
|
|
18
|
-
# 只看目录
|
|
19
|
-
fd -t d "config"
|
|
20
|
-
|
|
21
|
-
# 隐藏文件
|
|
22
|
-
fd -H ".*rc"
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
注意:fd 默认自动排除 .gitignore 中的内容,无需手动加 -E。
|
|
26
|
-
|
|
27
|
-
## mdfind — macOS Spotlight 全盘兜底
|
|
28
|
-
|
|
29
|
-
用系统预建索引,覆盖 rg 搜不到的东西(PDF 正文、邮件、已归档目录、图片元数据)。
|
|
30
|
-
统一入口用 `seek.py "词" --spotlight`。
|
|
31
|
-
|
|
32
|
-
```bash
|
|
33
|
-
# 全盘搜索(走系统索引,毫秒级)
|
|
34
|
-
mdfind "关键词"
|
|
35
|
-
|
|
36
|
-
# 限定目录
|
|
37
|
-
mdfind -onlyin ~/Documents "关键词"
|
|
38
|
-
|
|
39
|
-
# 限定文件名
|
|
40
|
-
mdfind -name "report"
|
|
41
|
-
|
|
42
|
-
# 文件名+内容混合(kMDItem 查询语法)
|
|
43
|
-
mdfind "kMDItemFSName == '*.pdf' && 关键词"
|
|
44
|
-
|
|
45
|
-
# 只看最近修改
|
|
46
|
-
mdfind "kMDItemFSContentChangeDate >= $time.today(-7) 关键词"
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
### 何时用 mdfind 而不是 rg
|
|
50
|
-
|
|
51
|
-
| 信号 | 用 |
|
|
52
|
-
|------|----|
|
|
53
|
-
| 全盘搜,不知道文件在哪 | mdfind |
|
|
54
|
-
| 搜 PDF/邮件/已归档内容 | mdfind |
|
|
55
|
-
| 目录未建立 Spotlight 索引(外接盘/网络盘) | 退回 rg + 明确 --path |
|
|
56
|
-
| 代码仓库内 | rg(永远优先) |
|
|
57
|
-
|
|
58
|
-
### 坑
|
|
59
|
-
|
|
60
|
-
- 外接盘、~/Library 部分目录可能未索引,mdfind 搜不到
|
|
61
|
-
- mdfind 的查询是「关键词匹配」,中文分词效果取决于系统
|
|
62
|
-
- 结果不带行号,定位到文件后需再 rg 找行
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
# Git 联动手册(--git-log / --git-blame)
|
|
2
|
-
|
|
3
|
-
本地搜索找到文件只是第一步,经常要接着回答「这行谁改的、为什么改、什么时候
|
|
4
|
-
改的」。git 联动让 seek.py 直接给出答案,不用再开终端敲 git。
|
|
5
|
-
|
|
6
|
-
## 用法
|
|
7
|
-
|
|
8
|
-
```bash
|
|
9
|
-
# 文件的最近提交历史(默认 10 条,oneline)
|
|
10
|
-
python3 ~/.agents/skills/argo/sub-skills/local-seek/scripts/seek.py --git-log 文件路径
|
|
11
|
-
|
|
12
|
-
# 某一行是谁在哪个提交改的
|
|
13
|
-
python3 ~/.agents/skills/argo/sub-skills/local-seek/scripts/seek.py --git-blame 12 文件路径
|
|
14
|
-
```
|
|
15
|
-
|
|
16
|
-
文件路径作为位置参数(或 `--path`),两者互斥时位置参数优先。
|
|
17
|
-
|
|
18
|
-
## 输出示例
|
|
19
|
-
|
|
20
|
-
```text
|
|
21
|
-
# --git-log
|
|
22
|
-
local-seek: seek.py 最近 3 条提交
|
|
23
|
-
cd02e96 补全结构搜索与 git 联动
|
|
24
|
-
a1b2c3d 中文扩展:空格噪音修复
|
|
25
|
-
|
|
26
|
-
# --git-blame 12
|
|
27
|
-
local-seek: seek.py 第 12 行
|
|
28
|
-
cd02e96f (taxueseek 2026-07-03 20:58:20 +0800 3) ap.add_argument("--git-blame"...
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
## 适用场景
|
|
32
|
-
|
|
33
|
-
| 场景 | 命令 | 读什么 |
|
|
34
|
-
|------|------|--------|
|
|
35
|
-
| 这文件最近在动什么 | --git-log | 提交标题序列 |
|
|
36
|
-
| 某行代码的来历 | --git-blame N | 提交哈希、作者、时间 |
|
|
37
|
-
| 拿到哈希后看完整改动 | --git-log 后再 `git -C 目录 show 哈希` | diff 正文 |
|
|
38
|
-
| 谁改坏了某段逻辑 | --git-blame 定位行 → show 对应提交 | 上下文 |
|
|
39
|
-
|
|
40
|
-
## 边界与局限
|
|
41
|
-
|
|
42
|
-
- **未跟踪文件**:untracked(从未 git add)的文件无历史,报「无提交历史」,
|
|
43
|
-
不是错误。把文件 git add 后即有。
|
|
44
|
-
- **仓库外文件**:不在任何 git 仓库内的文件报「不在 git 仓库中」。
|
|
45
|
-
- **行号漂移**:blame 按当前行号定位,改动过的文件行号会移动,属正常。
|
|
46
|
-
- **大文件历史**:--git-log 只读标题不看 diff,是低成本路径;要 diff 再手动
|
|
47
|
-
git show,不要指望 seek.py 输出正文。
|
|
48
|
-
- **子模块/符号链接**:git -C 父目录 对符号链接指向的仓库无效,需先解析真实路径。
|
|
49
|
-
|
|
50
|
-
## 与本地搜索的组合套路
|
|
51
|
-
|
|
52
|
-
1. 搜到文件里的目标行:`seek.py "关键词" --path ~/repo --max 5`
|
|
53
|
-
2. 定位关键行号后 blame:`seek.py --git-blame 行号 文件路径`
|
|
54
|
-
3. 拿提交哈希再看 diff:`git -C ~/repo show 哈希`
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
# 本地搜不到时的交接(remote-handoff)
|
|
2
|
-
|
|
3
|
-
local-seek 只负责本机。本地无结果不意味着结束,按本清单逐步扩大,最后
|
|
4
|
-
交接给联网搜索。判断标准写死在每一步,避免无限折腾。
|
|
5
|
-
|
|
6
|
-
## 交接顺序(每步只做一次,失败即进下一步)
|
|
7
|
-
|
|
8
|
-
```text
|
|
9
|
-
L1 当前目录 rg 搜索(默认)
|
|
10
|
-
↓ 无命中
|
|
11
|
-
L2 --path 扩大到知识域(~/notes、~/Documents、技能库等)
|
|
12
|
-
↓ 无命中
|
|
13
|
-
L3 --spotlight 全盘兜底(mdfind,走 macOS 索引,覆盖 PDF/邮件/笔记)
|
|
14
|
-
↓ 无命中
|
|
15
|
-
L4 换词重试 1 次(同义词/拆词/去掉修饰词),仍无
|
|
16
|
-
↓
|
|
17
|
-
L5 交接联网:unified-search(多引擎聚合)或 argo(深度研究)
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
## 判断标准
|
|
21
|
-
|
|
22
|
-
| 现象 | 结论 | 动作 |
|
|
23
|
-
|------|------|------|
|
|
24
|
-
| L1-L3 均无命中 | 本机确实没有,或不在已索引范围 | 进 L4 |
|
|
25
|
-
| 换词后仍无 | 大概率是「没有这个内容」而非「没找到」 | 进 L5 |
|
|
26
|
-
| L5 联网也无 | 内容不存在或太新未收录 | 如实告知,停止搜索 |
|
|
27
|
-
| 命中但太少/太泛 | 不是交接问题,是词选得不好 | 回到 L2/L4 调整 |
|
|
28
|
-
|
|
29
|
-
## 交接命令
|
|
30
|
-
|
|
31
|
-
```bash
|
|
32
|
-
# 本地最后一搏
|
|
33
|
-
python3 ~/.agents/skills/argo/sub-skills/local-seek/scripts/seek.py "关键词" --spotlight
|
|
34
|
-
|
|
35
|
-
# 联网:unified-search(多引擎,快)
|
|
36
|
-
# 联网:argo 深度研究(学术/金融领域,带信源核验)
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
## 纪律
|
|
40
|
-
|
|
41
|
-
- **禁止无限扩大**:每层只试一次,最多一轮换词,两轮无果就交接或停止。
|
|
42
|
-
- **交接前确认需求边界**:用户要的是「我电脑里的文件」就别接出网;
|
|
43
|
-
要的是「这个事实/最新信息」就该直接联网,不必先搜本地。
|
|
44
|
-
- **本地与联网并行**:需求两可时并行调用,互不阻塞,先到的先答。
|
|
45
|
-
- **不把联网结果当本地文件**:交接后答案来自网络,措辞上要区分来源,
|
|
46
|
-
需要文件路径的请求不能用网页内容冒充。
|
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
# rg 分场景配方
|
|
2
|
-
|
|
3
|
-
统一入口 `seek.py` 已覆盖多数场景,以下配方用于非常规操作或手动微调。
|
|
4
|
-
所有命令均尊重 .gitignore,自动排除 node_modules 等(见 config/domains.yaml)。
|
|
5
|
-
|
|
6
|
-
## 基础
|
|
7
|
-
|
|
8
|
-
```bash
|
|
9
|
-
# 全文搜(当前目录)
|
|
10
|
-
rg "关键词"
|
|
11
|
-
|
|
12
|
-
# 指定目录
|
|
13
|
-
rg "关键词" ~/notes
|
|
14
|
-
|
|
15
|
-
# 忽略大小写
|
|
16
|
-
rg -i "keyword"
|
|
17
|
-
|
|
18
|
-
# 正则
|
|
19
|
-
rg "func[0-9]+\(" src/
|
|
20
|
-
|
|
21
|
-
# 固定字符串(避免正则转义,含特殊字符时用)
|
|
22
|
-
rg -F "a.b[c]" .
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
## 定位类
|
|
26
|
-
|
|
27
|
-
```bash
|
|
28
|
-
# 只看文件名(最省 token,先看分布)
|
|
29
|
-
rg -l "关键词" .
|
|
30
|
-
rg --files-with-matches "关键词" .
|
|
31
|
-
|
|
32
|
-
# 每文件命中数(先数后看)
|
|
33
|
-
rg --count-matches "关键词" .
|
|
34
|
-
|
|
35
|
-
# 只看行号不输出内容
|
|
36
|
-
rg -l --line-number "关键词" .
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
## 上下文类
|
|
40
|
-
|
|
41
|
-
```bash
|
|
42
|
-
# 前后 N 行
|
|
43
|
-
rg -C 2 "关键词" .
|
|
44
|
-
rg -A 3 "关键词" . # 只后文
|
|
45
|
-
rg -B 1 "关键词" . # 只前文
|
|
46
|
-
|
|
47
|
-
# 输出到文件避免刷屏(超大批量时)
|
|
48
|
-
rg "关键词" . > /tmp/rg_out.txt
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
## 类型过滤
|
|
52
|
-
|
|
53
|
-
```bash
|
|
54
|
-
# 按扩展名
|
|
55
|
-
rg -g "*.py" "关键词" .
|
|
56
|
-
rg -g "*.{py,ts,js}" "关键词" .
|
|
57
|
-
|
|
58
|
-
# 排除
|
|
59
|
-
rg -g "!test_*" "关键词" .
|
|
60
|
-
rg -g "!*.min.js" "关键词" .
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
## 常用语义场景
|
|
64
|
-
|
|
65
|
-
```bash
|
|
66
|
-
# 函数/类定义在哪
|
|
67
|
-
rg -n "def handle_request|class AuthService" src/
|
|
68
|
-
# 跨语言:rg "function (getUser|setUser)" .
|
|
69
|
-
|
|
70
|
-
# 跨文件引用(谁在调用某函数)
|
|
71
|
-
rg "send_email\(" .
|
|
72
|
-
|
|
73
|
-
# TODO/FIXME 盘点
|
|
74
|
-
rg -n "TODO|FIXME|HACK" --type-add 'todo:*.{py,js,ts,go,rs}' -t todo .
|
|
75
|
-
|
|
76
|
-
# 只搜中文
|
|
77
|
-
rg -n "[\u4e00-\u9fff]" .
|
|
78
|
-
|
|
79
|
-
# 找 JSON/YAML 里的键
|
|
80
|
-
rg -n '"max_results"' config/
|
|
81
|
-
|
|
82
|
-
# 日志排查(最近日志)
|
|
83
|
-
rg "ERROR|panic" --glob "*.log" .
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
## 性能
|
|
87
|
-
|
|
88
|
-
- 大仓库先 `--count` 或 `-l`,避免输出千行
|
|
89
|
-
- 指定 `-g` 类型或目录,rg 只扫必要范围
|
|
90
|
-
- 超过 30s 无结果:换词或换 mdfind(--spotlight),不要重复等待
|
|
91
|
-
- rg 退出码:0=有匹配,1=无匹配,2=报错。脚本已处理,手动用时注意
|
|
92
|
-
|
|
93
|
-
## 非代码文件(可选扩展)
|
|
94
|
-
|
|
95
|
-
rga(ripgrep-all)未安装时可临时用 mdfind 覆盖 PDF/Office 场景;
|
|
96
|
-
若常搜这类文件,装 rga:`brew install ripgrep-all`
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
# 渐进式策略与 token 纪律
|
|
2
|
-
|
|
3
|
-
本 skill 的核心不是「更快地搜索」,而是「用最少的 token 拿到答案」。
|
|
4
|
-
工具输出就是压缩结果,模型不该有探索成本。
|
|
5
|
-
|
|
6
|
-
## 三层渐进(永远按此顺序)
|
|
7
|
-
|
|
8
|
-
```
|
|
9
|
-
L1 定位 seek.py "词" --count / --filename
|
|
10
|
-
→ 输出「文件:命中数」或文件路径列表,每行 < 80 字符
|
|
11
|
-
↓ 从中挑出最相关的 1-3 个文件
|
|
12
|
-
L2 上下文 seek.py "词" --context 2 --path <该文件所在目录>
|
|
13
|
-
→ 输出「路径:行号:命中行 ± 2 行」
|
|
14
|
-
↓ 确定要精读的段落
|
|
15
|
-
L3 精读 read_file 该文件,用行号偏移局部读取
|
|
16
|
-
```
|
|
17
|
-
|
|
18
|
-
任何一步已经能回答用户,就停。不要为完整性多搜。
|
|
19
|
-
|
|
20
|
-
## 搜索范围扩大的顺序(先窄后宽)
|
|
21
|
-
|
|
22
|
-
1. 当前目录 + 默认排除(最常命中)
|
|
23
|
-
2. `--path` 扩大到知识域(~/notes、~/Documents 等,见 domains.yaml)
|
|
24
|
-
3. `--spotlight` 全盘兜底
|
|
25
|
-
|
|
26
|
-
禁止跳级:用户问「找代码里某个函数」却直接 mdfind 全盘,浪费且不准。
|
|
27
|
-
|
|
28
|
-
## 输出量控制
|
|
29
|
-
|
|
30
|
-
| 手段 | 效果 |
|
|
31
|
-
|------|------|
|
|
32
|
-
| `--max 20` | 截断结果数,防止刷屏 |
|
|
33
|
-
| `--count` | 只报分布,不报内容 |
|
|
34
|
-
| `--type py,ts` | 只扫目标类型 |
|
|
35
|
-
| `--context 0`(默认) | 不输出上下文行 |
|
|
36
|
-
| `-l` 手动模式 | 只列文件名 |
|
|
37
|
-
|
|
38
|
-
## 常见失败与换词策略
|
|
39
|
-
|
|
40
|
-
| 现象 | 处理 |
|
|
41
|
-
|------|------|
|
|
42
|
-
| 无匹配 | 换同义词/拆词/去掉修饰词,重试 1 次后换工具 |
|
|
43
|
-
| 命中过多 | 加 `--type` / `--max` / 更具体的关键词(加引号做短语匹配) |
|
|
44
|
-
| 结果太泛 | 指定目录缩小范围 |
|
|
45
|
-
| 搜代码但命中注释/文档 | 换更精确的符号名或结构模式 |
|
|
46
|
-
| Spotlight 搜不到 | 确认目录已索引;退回 rg + 明确 --path |
|
|
47
|
-
|
|
48
|
-
## 与 Argo 的分工
|
|
49
|
-
|
|
50
|
-
- 用户要「网上查」→ argo(联网)
|
|
51
|
-
- 用户要「本地找/搜我的文件」→ local-seek
|
|
52
|
-
- 混合需求(如「查网上的同时翻本地笔记」)→ 并行调用,互不干扰
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
# 结构搜索手册(--structural)
|
|
2
|
-
|
|
3
|
-
按「语义」而非「字符串」检索代码模式:找裸 except、空 catch、装饰函数这类
|
|
4
|
-
「看着就知道有问题/有特征」的结构。零安装实现:rg -U 多行匹配 + 语言感知
|
|
5
|
-
pattern,本机装 ast-grep 后可升级为 AST 精确匹配(见文末)。
|
|
6
|
-
|
|
7
|
-
## 用法
|
|
8
|
-
|
|
9
|
-
```bash
|
|
10
|
-
# 按语义名或中文别名检索,输出同普通搜索(路径:行号:片段)
|
|
11
|
-
python3 ~/.agents/skills/argo/sub-skills/local-seek/scripts/seek.py "裸except" --structural
|
|
12
|
-
python3 ~/.agents/skills/argo/sub-skills/local-seek/scripts/seek.py "empty-catch" --structural --path ~/repo
|
|
13
|
-
python3 ~/.agents/skills/argo/sub-skills/local-seek/scripts/seek.py "函数定义" --structural --path ~/repo --type py
|
|
14
|
-
python3 ~/.agents/skills/argo/sub-skills/local-seek/scripts/seek.py "不存在语义" --structural # 报可用列表
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
查询词可写语义名(empty-catch)或任意中文别名(空catch、裸异常),大小写不敏感。
|
|
18
|
-
|
|
19
|
-
## 内置规则
|
|
20
|
-
|
|
21
|
-
| 语义名 | 中文别名 | 查什么 | 覆盖语言 |
|
|
22
|
-
|--------|---------|--------|---------|
|
|
23
|
-
| empty-catch | 空catch、空捕获、空异常处理 | `catch (...) {}` 空体 | js/jsx/ts/tsx |
|
|
24
|
-
| bare-except | 裸except、无类型except | `except:` 无异常类型 | py |
|
|
25
|
-
| unwrapped-error | 错误未包装、裸return err | `return err` 直接返回错误 | go |
|
|
26
|
-
| decorated-fn | 装饰函数、装饰器函数 | 带 `@decorator` 的函数定义 | py |
|
|
27
|
-
| function-def | 函数定义、找函数 | 函数定义行 | py/js/ts/go/rs |
|
|
28
|
-
| class-def | 类定义、找类 | 类/结构体定义行 | py/js/ts/go/java |
|
|
29
|
-
|
|
30
|
-
## 实现说明
|
|
31
|
-
|
|
32
|
-
- 每条规则 = 若干 (扩展名集合, 正则) 对,逐语言跑 `rg -U -i --line-number`。
|
|
33
|
-
- `-U` 启用多行模式,decorated-fn 才能跨行匹配 `@装饰器\n def`。
|
|
34
|
-
- 语言无命中(rg 退出码 1)静默跳过,不报错。
|
|
35
|
-
- 与正文搜索共用排除规则(domains.yaml + --exclude)。
|
|
36
|
-
- 局限:正则近似,非真实 AST。缩进风格怪异的代码、嵌套场景可能漏报;
|
|
37
|
-
`catch {}` 内只有注释也算空体(正则按字面空体判断)。
|
|
38
|
-
|
|
39
|
-
## 扩展新规则
|
|
40
|
-
|
|
41
|
-
在 seek.py 的 `STRUCTURAL_RULES` 字典追加一条:
|
|
42
|
-
|
|
43
|
-
```python
|
|
44
|
-
"todo-count": {
|
|
45
|
-
"aliases": ("待办统计", "todo盘点"),
|
|
46
|
-
"patterns": [
|
|
47
|
-
(("py", "js", "ts"), r"TODO|FIXME|HACK"),
|
|
48
|
-
],
|
|
49
|
-
},
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
规则键即语义名,aliases 提供中文入口,patterns 按语言给正则。
|
|
53
|
-
加完跑 `python3 scripts/eval_seek.py` 确认无回归,再补一条结构用例。
|
|
54
|
-
|
|
55
|
-
## 升级路径(装 ast-grep 后)
|
|
56
|
-
|
|
57
|
-
ast-grep 能精确匹配 AST 节点(真·空 catch 块、未捕获的裸 except),
|
|
58
|
-
消除正则的漏报误报。届时在 structural_search 里检测 `sg` 命令存在则优先
|
|
59
|
-
AST,缺失时回落当前 rg -U 实现,行为对调用方透明。
|