grga 0.2.0__tar.gz
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.
- grga-0.2.0/CHANGELOG.md +416 -0
- grga-0.2.0/LICENSE +21 -0
- grga-0.2.0/MANIFEST.in +9 -0
- grga-0.2.0/PKG-INFO +192 -0
- grga-0.2.0/README.md +129 -0
- grga-0.2.0/pyproject.toml +65 -0
- grga-0.2.0/setup.cfg +4 -0
- grga-0.2.0/src/grga/__init__.py +1 -0
- grga-0.2.0/src/grga/__main__.py +5 -0
- grga-0.2.0/src/grga/cli.py +1759 -0
- grga-0.2.0/src/grga/deep_search.py +2157 -0
- grga-0.2.0/src/grga/env_loader.py +243 -0
- grga-0.2.0/src/grga/exit_codes.py +88 -0
- grga-0.2.0/src/grga/expand.py +145 -0
- grga-0.2.0/src/grga/file_read.py +339 -0
- grga-0.2.0/src/grga/graph/__init__.py +30 -0
- grga-0.2.0/src/grga/graph/build.py +2606 -0
- grga-0.2.0/src/grga/graph/ids.py +314 -0
- grga-0.2.0/src/grga/graph/inspect.py +579 -0
- grga-0.2.0/src/grga/graph/promote.py +242 -0
- grga-0.2.0/src/grga/graph/schema.py +1511 -0
- grga-0.2.0/src/grga/graph/votes.py +278 -0
- grga-0.2.0/src/grga/gui.py +1187 -0
- grga-0.2.0/src/grga/meta.py +236 -0
- grga-0.2.0/src/grga/models.py +114 -0
- grga-0.2.0/src/grga/paths.py +92 -0
- grga-0.2.0/src/grga/probe.py +390 -0
- grga-0.2.0/src/grga/prompts/__init__.py +32 -0
- grga-0.2.0/src/grga/prompts/suggest_expand.txt +25 -0
- grga-0.2.0/src/grga/prompts/suggest_reformulate.txt +24 -0
- grga-0.2.0/src/grga/prompts/suggest_rerank.txt +23 -0
- grga-0.2.0/src/grga/related.py +704 -0
- grga-0.2.0/src/grga/runtime_env.py +69 -0
- grga-0.2.0/src/grga/search.py +1036 -0
- grga-0.2.0/src/grga/skill_install.py +82 -0
- grga-0.2.0/src/grga/skills/grga/SKILL.md +311 -0
- grga-0.2.0/src/grga/skills/grga/examples/probe-search-reflect.md +107 -0
- grga-0.2.0/src/grga/skills/grga/examples/search-expand-chapter.md +79 -0
- grga-0.2.0/src/grga/skills/grga/examples/search-related-graph.md +134 -0
- grga-0.2.0/src/grga/skills/grga/examples/search-suggest.md +98 -0
- grga-0.2.0/src/grga/skills/grga/references/anti-patterns.md +105 -0
- grga-0.2.0/src/grga/skills/grga/references/reflection-loop.md +307 -0
- grga-0.2.0/src/grga/skills/grga/references/storage-model.md +99 -0
- grga-0.2.0/src/grga/skills/grga/references/troubleshooting.md +57 -0
- grga-0.2.0/src/grga/skills/grga/references/verbs.md +181 -0
- grga-0.2.0/src/grga/structure/__init__.py +0 -0
- grga-0.2.0/src/grga/structure/md.py +262 -0
- grga-0.2.0/src/grga/structure/sidecar.py +84 -0
- grga-0.2.0/src/grga/suggest.py +424 -0
- grga-0.2.0/src/grga/toolchain.py +1119 -0
- grga-0.2.0/src/grga.egg-info/PKG-INFO +192 -0
- grga-0.2.0/src/grga.egg-info/SOURCES.txt +84 -0
- grga-0.2.0/src/grga.egg-info/dependency_links.txt +1 -0
- grga-0.2.0/src/grga.egg-info/entry_points.txt +3 -0
- grga-0.2.0/src/grga.egg-info/requires.txt +10 -0
- grga-0.2.0/src/grga.egg-info/top_level.txt +2 -0
- grga-0.2.0/tests/test_cli_expand.py +74 -0
- grga-0.2.0/tests/test_cli_json.py +192 -0
- grga-0.2.0/tests/test_cli_smoke.py +109 -0
- grga-0.2.0/tests/test_ensure_tools.py +91 -0
- grga-0.2.0/tests/test_env_loader.py +116 -0
- grga-0.2.0/tests/test_exit_codes.py +79 -0
- grga-0.2.0/tests/test_expand.py +154 -0
- grga-0.2.0/tests/test_graph_build.py +955 -0
- grga-0.2.0/tests/test_graph_schema.py +497 -0
- grga-0.2.0/tests/test_incremental_build.py +578 -0
- grga-0.2.0/tests/test_md_parser_eval.py +49 -0
- grga-0.2.0/tests/test_meta.py +211 -0
- grga-0.2.0/tests/test_models.py +89 -0
- grga-0.2.0/tests/test_paths.py +124 -0
- grga-0.2.0/tests/test_promote.py +183 -0
- grga-0.2.0/tests/test_related.py +164 -0
- grga-0.2.0/tests/test_related_keywords.py +283 -0
- grga-0.2.0/tests/test_related_signals.py +334 -0
- grga-0.2.0/tests/test_scaffold.py +28 -0
- grga-0.2.0/tests/test_schema_v5_migration.py +399 -0
- grga-0.2.0/tests/test_schema_v8_migration.py +511 -0
- grga-0.2.0/tests/test_scope_stopwords.py +351 -0
- grga-0.2.0/tests/test_search_cap.py +221 -0
- grga-0.2.0/tests/test_sidecar.py +101 -0
- grga-0.2.0/tests/test_skill_install_cli.py +76 -0
- grga-0.2.0/tests/test_structure_md.py +142 -0
- grga-0.2.0/tests/test_suggest.py +221 -0
- grga-0.2.0/tests/test_toolchain_dependencies.py +66 -0
- grga-0.2.0/tests/test_toolchain_sha256_verify.py +540 -0
- grga-0.2.0/tests/test_votes.py +174 -0
grga-0.2.0/CHANGELOG.md
ADDED
|
@@ -0,0 +1,416 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to `grga` are recorded here.
|
|
4
|
+
|
|
5
|
+
## [Unreleased]
|
|
6
|
+
|
|
7
|
+
### 依赖清理 · 删除已死的 `perf` extra + `markdown-it-py` 提升为核心依赖
|
|
8
|
+
|
|
9
|
+
- **删除** `pyproject.toml` 的 `[project.optional-dependencies].perf =
|
|
10
|
+
["numpy>=1.20"]`。这个 extra 是 v8 时代给 PPR 幂迭代的 numpy CSR +
|
|
11
|
+
bincount SpMV 后端准备的(详见 `docs/design/plan-2026-07-12-related-perf.md`
|
|
12
|
+
§2.3 / §P3)。v9 keyword-primary 已整体移除 PPR(`graph/ppr.py` /
|
|
13
|
+
`graph/adjacency_cache.py` 都删了,`related_keywords` 走 index-only 早
|
|
14
|
+
停查 `keyword_pairs`,无矩阵运算)。运行时代码里没有任何 `import numpy`,
|
|
15
|
+
`perf` extra 装了也没有加速目标。用户端 `pip install grga[perf]` 现在
|
|
16
|
+
会安装失败 —— 一次性砍掉,避免 pyproject 里保留死符号误导。
|
|
17
|
+
- **合并** `[project.optional-dependencies].v2 = ["markdown-it-py>=3.0"]`
|
|
18
|
+
→ 核心 `dependencies`。`markdown-it-py` 是 `structure/md.py` 的主
|
|
19
|
+
Markdown 解析器(ADR-0001),`expand --level chapter` 与 `heading_path`
|
|
20
|
+
元数据必需。v2 分组当初是为了"v1 打包不污染"而设的临时缓冲,v2 早已
|
|
21
|
+
是默认路径,分组抽象无实际意义。核心 install 直接带上,避免 caller
|
|
22
|
+
忘记 `pip install grga[v2]` 后 heading 静默降级为空。
|
|
23
|
+
- **不变**:`scripts/build-onefile.py` 的 `EXCLUDED_MODULES` 里仍列了
|
|
24
|
+
`numpy`(防御性排除,避免任何传递依赖把 numpy 拖进单文件),无需改动。
|
|
25
|
+
|
|
26
|
+
### build 期写入门槛自适应 · Gate 1 独立性 + Gate 2 阶梯(docs/design/decisions.md §2026-07-13)
|
|
27
|
+
|
|
28
|
+
`min_pair_count` 固定为 5 对小语料过严:一本中篇(几百 chunk)的真实
|
|
29
|
+
概念对常只共现 2-3 次,全被砍空,`related --mode graph` 频繁空结果。
|
|
30
|
+
但直接降门槛会放进 npmi 虚高的噪声(两个词各出现 1 次恰好同现 → npmi
|
|
31
|
+
满分 1.0)。改为两条正交门槛:
|
|
32
|
+
|
|
33
|
+
- **新增**:写入期 **Gate 1 · 独立性判据**(无参、恒开、严格三元相等)——
|
|
34
|
+
`chunk_df_a == chunk_df_b == cooccur_count`。挡掉"两个词完全绑定"
|
|
35
|
+
(npmi=1.0 artefact);保留"单向依附"(rare 词只跟 common 词同现)
|
|
36
|
+
的真信号。用严格三元相等(不用 `co >= max`)是因为 `mode='build'`
|
|
37
|
+
下 `cooccur_count` 是 grow-only(D6),可以出现 `co > min(df_a, df_b)`
|
|
38
|
+
的合法单向依附——`co >= max` 会误杀,三元相等不会。
|
|
39
|
+
`_finalize_pairs_from_temp` 与 `_prune_low_score_pairs` 同步实现。
|
|
40
|
+
- **变更**:`min_pair_count` 默认从固定 `5` 改为 **scope 自适应阶梯**
|
|
41
|
+
`resolve_min_pair_count(n_chunks)`:`≤200→2` / `≤2000→3` / `≤20000→4`
|
|
42
|
+
/ `>20000→5`。`grga index build/rebuild --min-pair-count` 默认值
|
|
43
|
+
`5` → 未设置(哨兵 `None` = 自适应);显式传 int 覆盖阶梯。
|
|
44
|
+
- **变更**:`grga.graph.build.build_graph_index` 的 `min_pair_count`
|
|
45
|
+
形参类型 `int` → `Optional[int]`(`None` = 自适应)。
|
|
46
|
+
- **变更**:`_prune_low_score_pairs`(v7→v8 迁移的存储契约执行者)改为
|
|
47
|
+
per-scope 查 `scope_stats.n_chunks` 求 floor + Gate 1;无 scope_stats
|
|
48
|
+
时回退固定 5。
|
|
49
|
+
- **不变**:Gate 3(`min_npmi=0.2`)、大语料(>20000 chunks)行为、
|
|
50
|
+
`related --json` 契约、BuildStats / CLI JSON 形状。
|
|
51
|
+
- 小语料 `related` 覆盖率显著提升;大语料零回归。
|
|
52
|
+
|
|
53
|
+
## [Unreleased] · related 信号契约 v3.1 · `resolved_seeds` 多 seed 探针(docs/design/related-signals-v3.md)
|
|
54
|
+
|
|
55
|
+
多 seed `related --mode graph` 的空结果原本二义——分不清"seed 未索引"
|
|
56
|
+
和"seed 已索引但孤立(边被写入期/读侧 npmi 门槛滤空)"。这两种情况
|
|
57
|
+
caller 从 `results` 派生不出来(信息天然重合),下一步动作却相反。新增
|
|
58
|
+
唯一一个 envelope 级探针补这一 bit。
|
|
59
|
+
|
|
60
|
+
- **新增**:`grga related --json --mode graph` envelope 加
|
|
61
|
+
`resolved_seeds: [{seed, in_index}]` — 每个去重(casefold + 保序)输入
|
|
62
|
+
seed 一条,`in_index` 报告是否命中 `keywords` 词表(与 scope 无关)。
|
|
63
|
+
- **变更**:`grga.related.related_keywords()` 返回类型 `List[RelatedKeyword]`
|
|
64
|
+
→ `RelatedKeywordsResult{results, resolved_seeds}`。新增 `SeedResolution`
|
|
65
|
+
dataclass。
|
|
66
|
+
- **变更**:graph 模式非 JSON 输出把 dead seed 以 stderr 两行提示呈现
|
|
67
|
+
(`unknown seeds ...` / `indexed but no candidates ...`),不再在空结果时
|
|
68
|
+
提前 `Exit`;exit code 仍为 0,stdout 候选流不受影响。
|
|
69
|
+
- **不变**:`RelatedKeyword` 六字段、排序 `(via_seed, -npmi, kw)`、多 seed
|
|
70
|
+
不融合(D4)、heading 模式、热路径动词 `--json`。
|
|
71
|
+
- caller 一段 5 行即可分派:`in_index=false` → 换词 / `suggest reformulate`;
|
|
72
|
+
`in_index=true` 但缺席于 `{results[].via_seed}` → 换更具体 seed 或松
|
|
73
|
+
`--min-npmi`。免去逐 seed 的 `grga graph inspect` round-trip。
|
|
74
|
+
- schema:`schemas/related-signals-v3.json` graph 分支加 `resolved_seeds`
|
|
75
|
+
(required)+ `seed_resolution` $def。
|
|
76
|
+
|
|
77
|
+
## [Unreleased] · 历史条目
|
|
78
|
+
|
|
79
|
+
### BREAKING · related 信号契约 v2 / v2.1 / v2.2(docs/design/related-signals-v2.md)
|
|
80
|
+
|
|
81
|
+
同日三步落地:v2.0 撤 trace-signals v1("图游走可视化"),v2.1 把
|
|
82
|
+
`graph_signals` 折叠进顶层 `expansion`(去 `neighbor_edges` 里 `a=seed`
|
|
83
|
+
重复),v2.2 进一步扁平化 `edges_to_seeds` 列表包装(单 seed 查询里
|
|
84
|
+
"数组包一个字典包一个 seed 回显" 的三层嵌套 → 顶层内联 `npmi` /
|
|
85
|
+
`cooccur_count`)。动机:生产实测稀有种子经 PPR 扩展会拉入通用词命中
|
|
86
|
+
的假阳性文档(`苍坤` seed 拉进《三体》),旧 `graph_actions` op log
|
|
87
|
+
无法帮 caller 识别;同时每一次 caller 反馈都指向"信号一处收,去嵌套
|
|
88
|
+
去回显"。
|
|
89
|
+
|
|
90
|
+
- **移除**:`trace_signals_version` + `graph_actions` 从
|
|
91
|
+
`grga related --json` 与 `grga suggest --json` 撤除。
|
|
92
|
+
- **移除(v2.1)**:`Related.graph_signals` 整块(含 `seed_chunk_df` /
|
|
93
|
+
`neighbor_edges` / 里面的 `total_chunks_in_scope`),`--graph-signals-limit`
|
|
94
|
+
CLI 参数。
|
|
95
|
+
- **移除**:`src/grga/trace.py`、`schemas/trace-signals-v1.json`、
|
|
96
|
+
`schemas/trace-viz-session-v1.json`,以及依赖 `graph_actions` 的两个内置
|
|
97
|
+
skill 工件(`skills/grga-trace-viz/`、`skills/grga/workflows/trace-viewer/`)。
|
|
98
|
+
- **新增(v2.1)**:`grga related --json --mode graph` 顶层 `expansion` 一体化承载:
|
|
99
|
+
* `seeds: List[{kw, chunk_df?}]` — 每个 seed 附加 in-scope chunk df。
|
|
100
|
+
* `expanded_keywords: List[{kw, ppr_score, hops_from_seed?, chunk_df?,
|
|
101
|
+
...}]` — 每个 PPR 邻居一处出现,无跨数组 join。
|
|
102
|
+
* `total_chunks_in_scope: int` — `chunk_df` 的分母。
|
|
103
|
+
- **变更(v2.2)**:`expanded_keywords[i]` 里最强直接边扁平化,dropping
|
|
104
|
+
`edges_to_seeds` 列表包装:
|
|
105
|
+
* `npmi` / `cooccur_count`:内联在 entry 自身(两字段一起出现或一起
|
|
106
|
+
缺席)。存在条件:该邻居在 `keyword_pairs` 有直接 seed 边(与
|
|
107
|
+
`hops_from_seed` 解耦,允许"低 npmi 直接边被 PPR 绕开"的信号透过)。
|
|
108
|
+
* `source`:只在 != `"chunk_cooccur"` 时 emit(即 `llm_promoted`)。
|
|
109
|
+
* `via_seeds`:只在**多 seed 查询里 + 邻居有 >=2 条直接边**时出现,
|
|
110
|
+
按 npmi desc 列出被桥接的 seed 名。
|
|
111
|
+
- **新增**:graph 模式每条 `results[]` 内嵌 `keyword_contributions`
|
|
112
|
+
(`[{kw, occurrences}]`,按 `(-occurrences, kw)` 排序)。
|
|
113
|
+
- **变更**:`related --mode dir|heading` 与 `suggest --json` 去 envelope,
|
|
114
|
+
现返回 `{"results": [...]}` 对象。
|
|
115
|
+
- **不变**:`search` / `probe` / `expand` / `deep-search` 的 `--json` 输出。
|
|
116
|
+
- caller 用 `expansion.seeds` + `keyword_contributions` 即可 ~5 行过滤
|
|
117
|
+
"仅由 PPR 扩展词命中" 的假阳性;加 `expanded_keywords[].chunk_df` 阈值
|
|
118
|
+
可再叠一层 hub-word 剪枝。契约 schema:`schemas/related-signals-v2.json`。
|
|
119
|
+
旧规范归档于 `docs/design/deprecated/trace-signals.md`。
|
|
120
|
+
|
|
121
|
+
### 性能 · `related --mode graph` 优化 (docs/design/plan-2026-07-12-related-perf.md)
|
|
122
|
+
|
|
123
|
+
7 项独立优化叠加,把冷启动从 ~110s 压到 ~3s、生产热启动预期 ~200ms。
|
|
124
|
+
top-20 结果 top-20 doc Jaccard=1.0(vs 旧行为),numpy 后端与纯 Python
|
|
125
|
+
逐位一致。实验证据:`experiments/related_perf_2026_07_12/`。
|
|
126
|
+
|
|
127
|
+
- **P2.3 doc 聚合 id-native**:`aggregate_docs` 用 `kw_id IN (int)` 替换
|
|
128
|
+
`k.kw IN (text)`,直接命中 `keyword_chunks` 复合主键
|
|
129
|
+
`(kw_id, doc_id, chunk_id)`。doc 聚合 SQL 从 ~11s → ~53ms(-99.5%)。
|
|
130
|
+
设 `GRGA_DOC_AGG_LEGACY=1` 走旧路径。
|
|
131
|
+
- **P3 numpy CSR + `np.bincount` backend**:`_ppr_numpy` SpMV 幂迭代,PPR
|
|
132
|
+
从 ~35s → ~96ms(-99.7%)。numpy 是**可选依赖**:`pip install grga[perf]`
|
|
133
|
+
安装;缺失时自动退回纯 Python `_ppr_python`。`GRGA_PPR_BACKEND=py|numpy|auto`
|
|
134
|
+
可强制选后端,`GRGA_PPR_NUMPY_MIN_EDGES`(默认 50000)控制 auto 切换阈值。
|
|
135
|
+
- **P2.2 id-native 图构建**:新增 `load_edges_indexed` 跳过 JOIN + casefold,
|
|
136
|
+
`IndexedGraph.node_ids` 仍填字符串(契约兼容)。
|
|
137
|
+
- **P2.1 删热路径 `build_adjacency`**:`adjacency_cache` 不再构建从不使用的
|
|
138
|
+
dict adjacency;`get_adjacency` 返回 3-tuple 兼容语法但 `adj` 位恒为 `None`。
|
|
139
|
+
`build_adjacency` / `personalized_pagerank`(dict 版)函数本身保留供 legacy
|
|
140
|
+
caller / 单元测试使用。
|
|
141
|
+
- **P1.2 `min_npmi` 默认 0.2**:`related --min-npmi FLOAT` 参数化;
|
|
142
|
+
`GRGA_PPR_MIN_NPMI` env 覆盖。SQL WHERE 过滤 `chunk_cooccur` 边使 npmi <
|
|
143
|
+
阈值的边不参与 PPR。`neighbor_edges` schema 不变但**门槛语义微变**(详见
|
|
144
|
+
`docs/design/trace-signals.md` §7.1)。
|
|
145
|
+
- **P1.4a `--edge-quantile` 便捷入口**:`grga related --edge-quantile 0.1`
|
|
146
|
+
保留 top 10% 边(按 npmi 采样),内部换算为等效 `min_npmi`;与
|
|
147
|
+
`--min-npmi` 互斥(同给报 exit 2)。
|
|
148
|
+
- **P1.1 stopword ∪ core_boundaries**:建图层 `_INDEX_STOPWORDS` 复用已有
|
|
149
|
+
的 26 字 `_CORE_STOP_BOUNDARIES` 结构虚词集,索引层不再放行 `在/是/也/就/但/
|
|
150
|
+
这/有/都/后/上/…` 等高频功能词。需要 `grga index build --rebuild` 生效;detect
|
|
151
|
+
层的 `_CORE_STOP_BOUNDARIES` 语义分层不变(构词后缀如 面壁**者** 仍安全)。
|
|
152
|
+
|
|
153
|
+
### Changed
|
|
154
|
+
|
|
155
|
+
- `adjacency_cache` 的缓存键增加 `min_npmi` 维度,不同阈值不串扰。
|
|
156
|
+
- `edge_weight` 中 `chunk_cooccur` 边的 `0.01 * log1p(count)` 小地板**保留**
|
|
157
|
+
作为小语料下 npmi=0 的防御性 fallback(与 P1.2 的 SQL WHERE 过滤解耦,
|
|
158
|
+
见 `src/grga/graph/ppr.py::edge_weight` docstring)。
|
|
159
|
+
|
|
160
|
+
### Added
|
|
161
|
+
|
|
162
|
+
- `pyproject.toml [project.optional-dependencies].perf = ["numpy>=1.20"]`
|
|
163
|
+
—— 一体化开关 `pip install grga[perf]` 启用 numpy 加速后端。
|
|
164
|
+
|
|
165
|
+
## [0.2.0] - 2026-07-09
|
|
166
|
+
|
|
167
|
+
### BREAKING
|
|
168
|
+
|
|
169
|
+
- **Wheel no longer bundles binaries.** `rg`, `rga`, `pandoc`, `fzf`, and
|
|
170
|
+
`pdftotext` are downloaded at first use (or on demand via
|
|
171
|
+
`grga tools install`). This trims the wheel from ~187 MB to under 1 MB
|
|
172
|
+
and makes distribution license-compliant (upstream AGPL/GPL binaries
|
|
173
|
+
are fetched at runtime, not redistributed).
|
|
174
|
+
- **Managed tools cache moved out of `site-packages`.** New default:
|
|
175
|
+
`$XDG_DATA_HOME/grga/tools/<platform>` on Linux/macOS,
|
|
176
|
+
`%LOCALAPPDATA%\grga\tools\<platform>` on Windows. Override with
|
|
177
|
+
`$GRGA_TOOLS_DIR`. Legacy `site-packages/grga/data/tools/` is still
|
|
178
|
+
discovered as a fallback; run `grga tools migrate` to copy it into the
|
|
179
|
+
new location.
|
|
180
|
+
- **Stable exit-code contract frozen.** See `docs/exit-codes.md`. Codes
|
|
181
|
+
may only be *added* in future releases, never removed or renumbered.
|
|
182
|
+
`--json` errors now use a fixed schema on stdout so agents can pipe
|
|
183
|
+
results reliably.
|
|
184
|
+
|
|
185
|
+
### Added
|
|
186
|
+
|
|
187
|
+
- `grga tools migrate` — copy legacy site-packages binaries into the
|
|
188
|
+
XDG cache with `--dry-run` support.
|
|
189
|
+
- `grga tools install --from <dir>` — install from a local mirror
|
|
190
|
+
directory (offline / air-gapped installs). Optional `--fallback-online`
|
|
191
|
+
falls back to GitHub when a local asset is missing.
|
|
192
|
+
- `grga tools install --no-verify` and `GRGA_INSECURE=1` — bypass sha256
|
|
193
|
+
verification (with a loud warning) for mirror scenarios.
|
|
194
|
+
- `tools.json` now supports optional `sha256` per tool; `install_tool`
|
|
195
|
+
verifies the downloaded archive when present.
|
|
196
|
+
- `grga skill install --to <dir>` (+ `list` / `path`) — copy bundled
|
|
197
|
+
agent skills into any workspace.
|
|
198
|
+
- `--offline` / `GRGA_OFFLINE=1` — fail fast instead of prompting to
|
|
199
|
+
download missing tools.
|
|
200
|
+
- `MIN_VERSIONS` map (empty by default) lets future releases pin minimum
|
|
201
|
+
versions per tool without more code.
|
|
202
|
+
- `GRGA_PREFER_SYSTEM=1` — invert tool resolution to prefer system-PATH
|
|
203
|
+
binaries over managed ones.
|
|
204
|
+
|
|
205
|
+
### Changed
|
|
206
|
+
|
|
207
|
+
- `find_tool` now honors `GRGA_PREFER_SYSTEM` and applies `MIN_VERSIONS`.
|
|
208
|
+
- `check_tools` recognizes bundled binaries in both the XDG cache and
|
|
209
|
+
the legacy site-packages location.
|
|
210
|
+
- `scripts/download-tools.py` extended with `--platform`, `--out`,
|
|
211
|
+
`--write-hashes`, `--yes`. It is a *developer* tool only; wheel
|
|
212
|
+
builds no longer invoke it.
|
|
213
|
+
- Project metadata (license, urls, classifiers, `Development Status`)
|
|
214
|
+
hardened for PyPI publishing.
|
|
215
|
+
|
|
216
|
+
### Fixed
|
|
217
|
+
|
|
218
|
+
- Downloads write to a `.part` file then atomically rename on success,
|
|
219
|
+
so aborted downloads no longer leave half-installed tools.
|
|
220
|
+
|
|
221
|
+
## Unreleased
|
|
222
|
+
|
|
223
|
+
### Breaking changes (chunk-level graph migration, schema v4)
|
|
224
|
+
|
|
225
|
+
- **The L2 graph moved from document-level to segment (chunk) level.**
|
|
226
|
+
`related --mode graph` now runs Personalized PageRank over segment
|
|
227
|
+
co-occurrence instead of whole-document co-occurrence. The doc-level graph
|
|
228
|
+
was structurally unable to produce signal on large single-file corpora
|
|
229
|
+
(a 22 MB novel collapsed every keyword into one `doc_path`, giving PPR no
|
|
230
|
+
real edges). See `docs/design/plan-2026-07-11-chunk-migration.md`.
|
|
231
|
+
|
|
232
|
+
The CLI surface is unchanged: `related --mode graph|dir|heading` keeps its
|
|
233
|
+
name and parameters, so existing caller skills need no edits.
|
|
234
|
+
|
|
235
|
+
- **`keyword_docs` table dropped.** The doc-level inverted index is gone.
|
|
236
|
+
`related` / `graph inspect` now read the new `keyword_chunks` table.
|
|
237
|
+
|
|
238
|
+
- **`keyword_pairs` schema rebuilt.** Primary key is now
|
|
239
|
+
`(directory, keyword_a, keyword_b, source)`. New columns: `source`
|
|
240
|
+
(`'chunk_cooccur'` | `'llm_promoted'`), `cooccur_count`, `npmi`. The old
|
|
241
|
+
`(scope, directory, keyword_a, keyword_b)` / `count` shape is gone.
|
|
242
|
+
|
|
243
|
+
- **One-shot v3 → v4 migration.** `ensure_schema` detects a legacy database
|
|
244
|
+
and, in a single atomic transaction: drops `keyword_docs`; rebuilds
|
|
245
|
+
`keyword_pairs`; salvages old promotion rows (`scope='llm_promoted'`) as
|
|
246
|
+
`source='llm_promoted'`; clears every other legacy (doc-level) pair — the
|
|
247
|
+
segment build recomputes it. `PRAGMA user_version` bumps 3 → 4. Failure
|
|
248
|
+
rolls back; no half-migrated state is left on disk.
|
|
249
|
+
|
|
250
|
+
- **`grga index build` gains chunk knobs.** `--chunk-mode {line,chars}`
|
|
251
|
+
(default `line`), `--chunk-max-chars` (600), `--chunk-min-chars` (300),
|
|
252
|
+
`--min-pair-count` (3). The old `--min-count` / `--max-terms` flags are
|
|
253
|
+
removed. `chars` mode splits on `heading > blank line > hard char cut`.
|
|
254
|
+
|
|
255
|
+
- **`deep_search` LLM pairs route through votes.** `KeywordLibrary` no
|
|
256
|
+
longer writes `keyword_pairs` directly; deep-search co-mentions accumulate
|
|
257
|
+
in `llm_extension_votes` and graduate via `grga index promote` — the same
|
|
258
|
+
anti-pollution gate the `suggest` flow already used. `keyword_counts`
|
|
259
|
+
(self-evolving heat table) is unchanged.
|
|
260
|
+
|
|
261
|
+
### Added (chunk migration)
|
|
262
|
+
|
|
263
|
+
- **`graph_signals` metadata on `related --mode graph --json`.** Each result
|
|
264
|
+
carries `seed_chunk_df` (per-seed segment df), `total_chunks_in_scope`, and
|
|
265
|
+
`neighbor_edges` (PPR neighbour edges with `npmi` / `cooccur_count` /
|
|
266
|
+
`source`). Callers can classify seeds (hub / domain / rare) and re-rank
|
|
267
|
+
neighbours themselves — grga does no filtering / rerank / warning on top.
|
|
268
|
+
`--graph-signals-limit N` caps `neighbor_edges` (default 30). The block is
|
|
269
|
+
emitted only under `--json`; human-readable output stays terse.
|
|
270
|
+
|
|
271
|
+
- **`chunks` / `keyword_chunks` tables.** `chunks` records each chunk's line
|
|
272
|
+
range + char count; `keyword_chunks` is the keyword → chunk inverted index
|
|
273
|
+
(segment df is derivable via `COUNT(*) GROUP BY keyword`, no extra column).
|
|
274
|
+
|
|
275
|
+
### Performance
|
|
276
|
+
|
|
277
|
+
- **`related --mode graph` is 2–5× faster across every corpus size.** Five
|
|
278
|
+
stacked optimisations (PERF plan §P0-1 through §P1-2), each with bench
|
|
279
|
+
data in its own commit:
|
|
280
|
+
- **P0-1** LRU cache of ``(edges, adjacency, indexed_graph)`` keyed on
|
|
281
|
+
``(db_path, mtime, scope)`` (cap 8, mtime-invalidated by `index build`
|
|
282
|
+
/ `suggest` / `promote`).
|
|
283
|
+
- **P0-2** Preview reuses the main PPR result — a single unrestricted
|
|
284
|
+
PPR now feeds both the scope-limited result list and the cross-scope
|
|
285
|
+
`crossed_scopes_preview` annotation. `--preview` no longer costs a
|
|
286
|
+
second full PPR.
|
|
287
|
+
- **P0-3** PPR internals: hoisted ``sum(neighbours.values())`` into an
|
|
288
|
+
``out_degree`` map computed once per graph, and switched
|
|
289
|
+
``seed_in_graph`` to a set for O(1) exclusion. Semantics pinned by a
|
|
290
|
+
reference-implementation diff test (score drift < 1e-9).
|
|
291
|
+
- **P1-1** `IndexedGraph` — integer-indexed adjacency (``list[list[(int,
|
|
292
|
+
float)]]``) with `personalized_pagerank_indexed`. The legacy dict API
|
|
293
|
+
now delegates. Eliminates the 2.33M `dict.get` calls that dominated
|
|
294
|
+
the profile.
|
|
295
|
+
- **P1-2** ``keyword_docs.keyword`` stored casefolded (schema v3, one-
|
|
296
|
+
shot migration bumps ``PRAGMA user_version`` 2→3, merging any
|
|
297
|
+
same-fold collisions in place). Every read path drops the non-
|
|
298
|
+
sargable ``LOWER(keyword)`` wrapper. The self-join in ``load_edges``
|
|
299
|
+
keeps a ``+column`` optimiser barrier so SQLite still joins on
|
|
300
|
+
``(directory, doc_path)`` instead of range-scanning ``(directory,
|
|
301
|
+
keyword > ?)``.
|
|
302
|
+
|
|
303
|
+
Bench (600 docs / 3 scopes / 7414 keyword_docs rows, 5-call avg):
|
|
304
|
+
|
|
305
|
+
| | v2.2 baseline | v2.3 target |
|
|
306
|
+
| ------------- | ------------- | ----------- |
|
|
307
|
+
| scoped | 151 ms | **42 ms** |
|
|
308
|
+
| global | 350 ms | **94 ms** |
|
|
309
|
+
| cross-scope | 354 ms | **72 ms** |
|
|
310
|
+
| preview=True | 527 ms (3.8×) | **96 ms** |
|
|
311
|
+
| PPR own time (3 calls) | 1.83 s | **0.18 s** |
|
|
312
|
+
|
|
313
|
+
Numpy fallback is intentionally not shipped (PERF plan §P2-1); the pure-
|
|
314
|
+
Python indexed path lands well inside the 100 ms perception threshold
|
|
315
|
+
for personal-corpus graphs.
|
|
316
|
+
|
|
317
|
+
### Changed
|
|
318
|
+
|
|
319
|
+
- **Storage model reframed as user-scoped.** grga's DB is a single per-user
|
|
320
|
+
knowledge graph (`~/.config/grga/deep_keywords.db`). All `index build`
|
|
321
|
+
scopes write into it; `--directory` is a query-time filter, not a
|
|
322
|
+
partition key. See "Storage model (user-scoped)" in SKILL.md.
|
|
323
|
+
|
|
324
|
+
### Breaking changes
|
|
325
|
+
|
|
326
|
+
- **`related --mode heading` now searches across scopes by default.** Pass
|
|
327
|
+
`--same-scope` to restore the old scope-limited behaviour. Heading paths
|
|
328
|
+
are structural filters (`Install > macOS` means the same thing across
|
|
329
|
+
corpora), so cross-scope is the more useful default.
|
|
330
|
+
|
|
331
|
+
- **`grga search` multi-word semantics: space now means AND, not OR.**
|
|
332
|
+
Adjacent terms with no explicit operator (e.g. `grga search "韩立 师傅"`)
|
|
333
|
+
used to compile to `韩立 || 师傅` (union of matches). They now compile to
|
|
334
|
+
`韩立 && 师傅` (both terms on the same line), matching the Google / ripgrep
|
|
335
|
+
intuition and the existing skill docs. When implicit AND fires, grga prints
|
|
336
|
+
a one-line notice to stderr:
|
|
337
|
+
|
|
338
|
+
```
|
|
339
|
+
[grga] multi-term query treated as AND: "韩立 师傅" → "韩立" AND "师傅"
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
Explicit `||` / `OR` and `&&` / `AND` are unchanged. Pass `--implicit-or`
|
|
343
|
+
to restore the v1 space-is-OR behaviour, or `--implicit-and` to force the
|
|
344
|
+
new default and suppress the notice. Python callers can pass
|
|
345
|
+
`search_directory(..., implicit_operator="or")` for the same effect.
|
|
346
|
+
|
|
347
|
+
Deep-search subprocess invocations of `grga search` continue to use
|
|
348
|
+
`--implicit-or` internally so the deep-search planner's expressions keep
|
|
349
|
+
their previous semantics.
|
|
350
|
+
|
|
351
|
+
### Added
|
|
352
|
+
|
|
353
|
+
- **`related --cross-scope` flag** (`mode=graph` only): keep seeds in
|
|
354
|
+
`--directory` but let PPR expansion cross into every other scope in the
|
|
355
|
+
shared DB. Off by default — cross-corpus association is an *escalation*,
|
|
356
|
+
not the default retrieval path.
|
|
357
|
+
|
|
358
|
+
- **`related --same-scope` flag** (`mode=heading` only): force heading
|
|
359
|
+
matches to stay within `--directory` (the previous default).
|
|
360
|
+
|
|
361
|
+
- **`crossed_scopes_preview` metadata on `related --mode graph --json`.**
|
|
362
|
+
Opt-in via `--preview`: the graph JSON envelope then carries a
|
|
363
|
+
`crossed_scopes_preview` object (`would_add`, `top_other_scopes`,
|
|
364
|
+
`top_bridge_keywords`) so a caller can see what opening cross-scope would
|
|
365
|
+
pull in *before* committing to it. It is opt-in because the preview runs
|
|
366
|
+
a full-graph PPR whose cost scales with every other scope in the shared
|
|
367
|
+
DB. The graph `--json` output is now an envelope
|
|
368
|
+
`{results, crossed_scopes_preview}` rather than a bare array (`dir` /
|
|
369
|
+
`heading` modes still return arrays).
|
|
370
|
+
|
|
371
|
+
- **`Related` objects now carry `directory` and `qualified_path`.** Every
|
|
372
|
+
related result records the indexed scope root it came from, so
|
|
373
|
+
cross-scope / global queries no longer conflate identically-named files
|
|
374
|
+
(`README.md`, `docs/install.md`) from different scopes.
|
|
375
|
+
|
|
376
|
+
- **`grga graph inspect <keyword>` command.** Reports a keyword's
|
|
377
|
+
`docs_by_scope` distribution, `top_cooccurring_keywords`, and a
|
|
378
|
+
`suspected_polysemy` heuristic (per-scope neighbour sets with pairwise
|
|
379
|
+
Jaccard < 0.2) so callers can spot same-name-different-meaning collisions
|
|
380
|
+
before enabling `--cross-scope`.
|
|
381
|
+
|
|
382
|
+
- **`--max-total / -N` global result cap on `grga search`.** Defaults to
|
|
383
|
+
`1000` (`0` disables). grga now streams rga's JSON output, and once the
|
|
384
|
+
cap is hit it stops reading, kills the rga subprocess, and returns a
|
|
385
|
+
partial result with `truncated: true` in the envelope. Layer 2 metadata
|
|
386
|
+
(`occurrence_index` / `total_occurrences` / `line_ratio` / `nearby_hits`)
|
|
387
|
+
is computed *after* truncation, so the counts reflect the returned slice
|
|
388
|
+
rather than the untrimmed rga output.
|
|
389
|
+
|
|
390
|
+
This closes the "22 MB single novel + two-word query returned 111 525 hits
|
|
391
|
+
in 40 s" pathology that previously wedged caller agents against their
|
|
392
|
+
default 60 s tool timeout.
|
|
393
|
+
|
|
394
|
+
Deep-search runs its own generous cap (`DEEP_SEARCH_MAX_TOTAL = 20000` per
|
|
395
|
+
iteration, exposed as the `max_total` parameter on
|
|
396
|
+
`_run_grga_search`) because its planner needs many raw hits per query for
|
|
397
|
+
keyword ranking. Set `max_total=None`/`0` on that helper to disable.
|
|
398
|
+
|
|
399
|
+
- **`--strict-cap` on `grga search`.** Instead of truncating, run a cheap
|
|
400
|
+
`rga --count-matches` pre-check and return
|
|
401
|
+
`{"ok": false, "error": "too_many_matches", "total_hits": N, "message": …}`
|
|
402
|
+
when the cap is exceeded. Useful when callers would rather fail loudly
|
|
403
|
+
than reason about partial data.
|
|
404
|
+
|
|
405
|
+
- `search_directory(...)` gains `max_total`, `strict_cap`, and
|
|
406
|
+
`implicit_operator` keyword arguments. `build_rga_command_preview(...)`
|
|
407
|
+
gains `implicit_operator`.
|
|
408
|
+
|
|
409
|
+
- `grga search --json` output now always includes a `truncated: bool` field
|
|
410
|
+
and, when adjacency was treated as implicit AND, an `implicit_notice`
|
|
411
|
+
string. See `docs/api.md`.
|
|
412
|
+
|
|
413
|
+
### Fixed
|
|
414
|
+
|
|
415
|
+
- Very large rga result sets no longer force grga to buffer the entire
|
|
416
|
+
stdout (24 MB in the pathology case) before parsing.
|
grga-0.2.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024-2026 grga maintainers
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
grga-0.2.0/MANIFEST.in
ADDED
grga-0.2.0/PKG-INFO
ADDED
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: grga
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: A CLI and Tkinter GUI for ripgrep-all search with L2 graph index and LLM-assisted deep search
|
|
5
|
+
Author: grga maintainers
|
|
6
|
+
License: MIT License
|
|
7
|
+
|
|
8
|
+
Copyright (c) 2024-2026 grga maintainers
|
|
9
|
+
|
|
10
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
11
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
12
|
+
in the Software without restriction, including without limitation the rights
|
|
13
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
14
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
15
|
+
furnished to do so, subject to the following conditions:
|
|
16
|
+
|
|
17
|
+
The above copyright notice and this permission notice shall be included in all
|
|
18
|
+
copies or substantial portions of the Software.
|
|
19
|
+
|
|
20
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
21
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
22
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
23
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
24
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
25
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
26
|
+
SOFTWARE.
|
|
27
|
+
|
|
28
|
+
Project-URL: Homepage, https://github.com/grga-tools/grga
|
|
29
|
+
Project-URL: Repository, https://github.com/grga-tools/grga
|
|
30
|
+
Project-URL: Documentation, https://github.com/grga-tools/grga#readme
|
|
31
|
+
Project-URL: Changelog, https://github.com/grga-tools/grga/blob/main/CHANGELOG.md
|
|
32
|
+
Project-URL: Issues, https://github.com/grga-tools/grga/issues
|
|
33
|
+
Keywords: ripgrep,rga,search,gui,cli,llm,graph
|
|
34
|
+
Classifier: Development Status :: 4 - Beta
|
|
35
|
+
Classifier: Environment :: Console
|
|
36
|
+
Classifier: Environment :: X11 Applications
|
|
37
|
+
Classifier: Intended Audience :: Developers
|
|
38
|
+
Classifier: Intended Audience :: End Users/Desktop
|
|
39
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
40
|
+
Classifier: Operating System :: OS Independent
|
|
41
|
+
Classifier: Programming Language :: Python :: 3
|
|
42
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
43
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
44
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
45
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
46
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
47
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
48
|
+
Classifier: Topic :: Desktop Environment
|
|
49
|
+
Classifier: Topic :: Text Processing :: Indexing
|
|
50
|
+
Classifier: Topic :: Utilities
|
|
51
|
+
Requires-Python: >=3.8
|
|
52
|
+
Description-Content-Type: text/markdown
|
|
53
|
+
License-File: LICENSE
|
|
54
|
+
Requires-Dist: typer>=0.9
|
|
55
|
+
Requires-Dist: openai>=1.0
|
|
56
|
+
Requires-Dist: jieba>=0.42
|
|
57
|
+
Requires-Dist: markdown-it-py>=3.0
|
|
58
|
+
Provides-Extra: standalone
|
|
59
|
+
Requires-Dist: pyinstaller>=6.0; extra == "standalone"
|
|
60
|
+
Provides-Extra: test
|
|
61
|
+
Requires-Dist: pytest>=7.0; extra == "test"
|
|
62
|
+
Dynamic: license-file
|
|
63
|
+
|
|
64
|
+
# grga
|
|
65
|
+
|
|
66
|
+
> **一款向文档学习、却不依赖文档,可迁移的0成本检索器。** — 从你的文档中自动发现概念连接,学习到的知识可直接用于同领域文档的检索。完全本地运行,不依赖 Embedding 和 LLM。
|
|
67
|
+
|
|
68
|
+
`grga` 是一个基于 `ripgrep-all` 的 Agent 友好全文搜索工具,提供命令行入口和 Tkinter 图形界面。它封装 `rga`、`rg` 等底层工具,支持在普通文本、Markdown、PDF、Office 文档等文件中搜索内容,也支持只按文件路径搜索。
|
|
69
|
+
|
|
70
|
+
项目目标是把常用搜索能力、工具链检查和内置工具管理集成到一个 Python 包中,并支持打包成 standalone 可执行文件,尽量减少用户手动配置系统命令的成本。
|
|
71
|
+
|
|
72
|
+
### 与普通 grep 有什么不同?
|
|
73
|
+
|
|
74
|
+
grga 是"grep 家族的最外层封装":底层复用 `ripgrep` 的速度和 `ripgrep-all`
|
|
75
|
+
的文档适配器,再往上叠**上下文扩展**、**共现关系图**、**LLM 深度搜索**几层能力。下表按"从 grep 一路加码到 grga"的顺序对比各工具的支持程度,并给出
|
|
76
|
+
grga 侧的具体命令与依赖:
|
|
77
|
+
|
|
78
|
+
| 能力 | grep | `rg` | `rga` | grga 命令 / 用法 | 依赖 / 配置 |
|
|
79
|
+
|---|:---:|:---:|:---:|---|---|
|
|
80
|
+
| 纯文本 / 源码搜索 | ✅ | ✅ | ✅ | `grga search 关键词` | 无 |
|
|
81
|
+
| 大仓库速度(并发 + `.gitignore`) | ❌ 单线程 | ✅ 多线程 | ✅ 继承 rg | 同上,自动透传 `rg` | `rg`(首次 `grga tools install` 自动下载) |
|
|
82
|
+
| PDF / Office / EPUB / 归档 / sqlite | ❌ | ❌ | ✅ 内建适配器 | 同上,自动透传 `rga` | `rga` + `rga-preproc` + `pandoc` + `pdftotext`(自动下载) |
|
|
83
|
+
| 查询表达式(短语 / 正则 / glob / `\|\|` / `&&` / 括号) | ⚠️ 仅正则 | ⚠️ 仅正则 | ⚠️ 仅正则 | 默认多词 **AND**,`--implicit-or` 恢复 v1 OR 语义 | 无 |
|
|
84
|
+
| 路径搜索(只匹配文件名,不读内容) | ⚠️ 需配合 `find` | ⚠️ 需 `--files \| rg` | ⚠️ 同 rg | `grga search --path-only` | 无 |
|
|
85
|
+
| 命令预览与试探(先看规模再决定读不读) | ❌ | ❌ | ❌ | `grga preview` / `grga probe` | 无 |
|
|
86
|
+
| Markdown / PDF 的段落 / 章节上下文扩展 | ❌ | ❌ | ❌ | `grga expand`(按行 / 段落 / 章节逐级) | |
|
|
87
|
+
| 关键词共现关系图(离线索引 + 亚毫秒查询) | ❌ | ❌ | ❌ | `grga index build` → `grga related` / `grga graph inspect` | |
|
|
88
|
+
| LLM 深度搜索、查询改写、结果重排 | ❌ | ❌ | ❌ | `grga deep-search` / `grga suggest` | OpenAI 兼容 API;至少 `GRGA_OPENAI_API_KEY` + `GRGA_OPENAI_MODEL`(详见 [docs/env-vars.md](docs/env-vars.md)) |
|
|
89
|
+
| Tk 图形界面 | ❌ | ❌ | ❌ | `grga gui` 或 `grga-gui` | 系统自带 Tk |
|
|
90
|
+
| Agent 友好(`--json` + 稳定退出码契约) | ❌ | ⚠️ 部分 | ⚠️ 部分 | `grga skill install` 分发内置 agent 技能包 | 错误契约见 [docs/exit-codes.md](docs/exit-codes.md) |
|
|
91
|
+
|
|
92
|
+
所有环境变量都可以写进 `$XDG_CONFIG_HOME/grga/.env`(首次运行会自动生成
|
|
93
|
+
一份注释模板),完整清单见 [docs/env-vars.md](docs/env-vars.md)。更多 CLI
|
|
94
|
+
参数细节见 [docs/CLI.md](docs/CLI.md)。
|
|
95
|
+
|
|
96
|
+
> **外部工具运行时下载**:自 0.2.0 起,wheel 不再内嵌 `rg` / `rga` / `pandoc` / `fzf` / `pdftotext` 等二进制文件。首次使用时会按需下载到用户缓存目录(见下文),也可提前运行 `grga tools install`。
|
|
97
|
+
>
|
|
98
|
+
> **许可证**:`grga` 本身以 **MIT** 许可证发布(见 [LICENSE](LICENSE))。它调用的外部工具各自遵循其上游许可证(`rg`:MIT/Unlicense;`rga`:AGPL;`pandoc`:GPL;`fzf`:MIT),请分别遵守。
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
### 与其它 GraphRAG 有什么不同
|
|
102
|
+
- 不依赖 LLM 抽实体
|
|
103
|
+
- 不依赖 Embedding 和向量库
|
|
104
|
+
- 仅依赖统计学从语料中学习短语以及进行短语的自连接,学习到的内容存入 Sqlite,与原始语料库解绑。
|
|
105
|
+
- 一方面可以只选取部分代表性语料进行学习;另一方面可以直接应用于其它同领域文档库。代价是理论上的精度漂移,实践中完全可接受。如果漂移到不可接受,在新语料上再增量学习一遍即可。
|
|
106
|
+
- 不过分追求 Recall 的准确度,提供5类原语动词,依赖 Agent 进行多轮循环检索补齐证据。
|
|
107
|
+
|
|
108
|
+
## 快速上手
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
# 安装 grga
|
|
112
|
+
pip install grga
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
安装后即可**直接搜索纯文本类文件**(`.txt` / `.md` / 源码 / 日志 / JSON / CSV
|
|
116
|
+
等),无需额外配置:
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
cd /path/to/your/documents
|
|
120
|
+
grga search "面壁计划" # 全文搜索
|
|
121
|
+
grga search "面壁计划" --path-only # 只按文件名搜
|
|
122
|
+
grga gui # 图形界面(或 grga-gui)
|
|
123
|
+
grga --help # 查看命令帮助
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
**给你的 AI Agent 装 skill**(可选,一行搞定,让 Kilo / Claude Code / QwenPaw 等直接学会用 grga):
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
grga skill install --to ~/.kilocode/skills # 换成你的 agent skill 目录即可
|
|
130
|
+
|
|
131
|
+
# 预学习(可选,视语料规模需要花费一定时间,但可以提供图扩展能力)
|
|
132
|
+
cd /path/to/your/documents
|
|
133
|
+
grga index build
|
|
134
|
+
```
|
|
135
|
+
`docs/search-demo`下提供了“纯LLM回答”、“简单文本检索回答”、“图扩展回答”三种搜索结果,可以看到明显的差别。
|
|
136
|
+
|
|
137
|
+
### 按场景选用
|
|
138
|
+
|
|
139
|
+
**搜索 PDF / Office / 电子书** —— 首次需装一次工具链(`rga` / `pandoc` /
|
|
140
|
+
`pdftotext` 等,之后自动复用):
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
grga tools install
|
|
144
|
+
grga search "面壁计划" -g "*.pdf"
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
**上下文扩展** —— 把命中扩展成段落 / 章节:
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
grga expand ... # 按行 / 段落 / 章节逐级扩展
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
**关键词共现关系图**(不依赖 LLM,先建索引再查):
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
cd /path/to/your/documents
|
|
157
|
+
grga index build
|
|
158
|
+
grga related 面壁计划
|
|
159
|
+
grga graph inspect 面壁计划
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
**LLM 深度搜索**(需配置 OpenAI 兼容凭据,见 [docs/env-vars.md](docs/env-vars.md)):
|
|
163
|
+
|
|
164
|
+
```bash
|
|
165
|
+
export GRGA_OPENAI_API_KEY=sk-...
|
|
166
|
+
export GRGA_OPENAI_MODEL=gpt-4o-mini
|
|
167
|
+
# or write them to $HOME/.config/grga/.env
|
|
168
|
+
|
|
169
|
+
grga deep-search "面壁计划"
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
> 注:作者到现在还没用过深度搜索功能,基本靠文本检索+图扩展就解决问题了。
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
**打包成可执行文件 / 离线部署 / 作为 agent 原语接入** —— 见
|
|
176
|
+
[docs/install-and-usage.md](docs/install-and-usage.md):
|
|
177
|
+
|
|
178
|
+
```bash
|
|
179
|
+
python -m build # 构建 wheel
|
|
180
|
+
python scripts/build-onefile.py --clean # 构建单文件可执行程序
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
> 完整安装、工具下载、镜像/打包构建、面向 AI Agent 的进阶说明都在
|
|
184
|
+
> **[docs/install-and-usage.md](docs/install-and-usage.md)**;环境变量清单见
|
|
185
|
+
> [docs/env-vars.md](docs/env-vars.md),CLI 参数见 [docs/CLI.md](docs/CLI.md)。
|
|
186
|
+
|
|
187
|
+
## 致谢
|
|
188
|
+
|
|
189
|
+
`grga` 的诞生离不开这两个工具在日常开发中的持续加成:
|
|
190
|
+
|
|
191
|
+
- **[QwenPaw](https://github.com/liunux4odoo/qwenpaw)** —— 本地多智能体框架。`grga` 从"检索能力"演进到"Agent-Native 检索契约",很多设计决策(skill 分发、退出码契约、`--json` schema、caller 反思循环)都是先在 QwenPaw 的 agent 场景里被反复打磨,才沉淀成规格的。
|
|
192
|
+
- **[Kilo Code](https://kilocode.ai)** —— IDE 里的 AI 编程助手。`grga` 的大部分实装、测试、重构都由它落地;作者只写"目标 / 约束 / 边界",实现细节交给它——这套"规格给约束,实现给自由"的分工正是这个项目能小而快演进的关键。
|