gaia-cli 4.2.1__tar.gz → 4.3.6__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.
- {gaia_cli-4.2.1/src/gaia_cli.egg-info → gaia_cli-4.3.6}/PKG-INFO +18 -24
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/README.md +17 -23
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/pyproject.toml +1 -1
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/src/gaia_cli/cardRenderer.py +14 -0
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/src/gaia_cli/commands/stats.py +3 -1
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/src/gaia_cli/graph.py +1 -1
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/src/gaia_cli/main.py +32 -20
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/src/gaia_cli/pathEngine.py +6 -1
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/src/gaia_cli/prWriter.py +5 -0
- {gaia_cli-4.2.1 → gaia_cli-4.3.6/src/gaia_cli.egg-info}/PKG-INFO +18 -24
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/tests/test_card_renderer.py +27 -0
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/tests/test_dx.py +22 -0
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/tests/test_intake.py +2 -1
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/tests/test_path_command.py +8 -8
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/tests/test_push.py +2 -2
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/tests/test_stats.py +20 -0
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/tests/test_validate.py +41 -1
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/LICENSE +0 -0
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/setup.cfg +0 -0
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/src/gaia_cli/__init__.py +0 -0
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/src/gaia_cli/__main__.py +0 -0
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/src/gaia_cli/authz.py +0 -0
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/src/gaia_cli/combinator.py +0 -0
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/src/gaia_cli/commands/__init__.py +0 -0
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/src/gaia_cli/commands/dev.py +0 -0
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/src/gaia_cli/data/registry/gaia.json +0 -0
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/src/gaia_cli/data/registry/named/devin-ai/autonomous-swe.md +0 -0
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/src/gaia_cli/data/registry/named/karpathy/autoresearch.md +0 -0
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/src/gaia_cli/data/registry/named-skills.json +0 -0
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/src/gaia_cli/data/registry/schema/combination.schema.json +0 -0
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/src/gaia_cli/data/registry/schema/meta.json +0 -0
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/src/gaia_cli/data/registry/schema/namedSkill.schema.json +0 -0
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/src/gaia_cli/data/registry/schema/pluginConfig.schema.json +0 -0
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/src/gaia_cli/data/registry/schema/realSkillCatalog.schema.json +0 -0
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/src/gaia_cli/data/registry/schema/skill.schema.json +0 -0
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/src/gaia_cli/data/registry/schema/skillBatch.schema.json +0 -0
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/src/gaia_cli/data/registry/schema/skillSuite.schema.json +0 -0
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/src/gaia_cli/data/registry/schema/skillTree.schema.json +0 -0
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/src/gaia_cli/embeddings.py +0 -0
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/src/gaia_cli/evidence.py +0 -0
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/src/gaia_cli/formatting.py +0 -0
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/src/gaia_cli/hook.py +0 -0
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/src/gaia_cli/install.py +0 -0
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/src/gaia_cli/interactive.py +0 -0
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/src/gaia_cli/leveling.py +0 -0
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/src/gaia_cli/localContext.py +0 -0
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/src/gaia_cli/name.py +0 -0
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/src/gaia_cli/promotion.py +0 -0
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/src/gaia_cli/push.py +0 -0
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/src/gaia_cli/redaction.py +0 -0
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/src/gaia_cli/registry.py +0 -0
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/src/gaia_cli/resolver.py +0 -0
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/src/gaia_cli/scanner.py +0 -0
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/src/gaia_cli/semantic_search.py +0 -0
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/src/gaia_cli/timeline.py +0 -0
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/src/gaia_cli/treeManager.py +0 -0
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/src/gaia_cli/tui/__init__.py +0 -0
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/src/gaia_cli/tui/app.py +0 -0
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/src/gaia_cli/tui/screens/__init__.py +0 -0
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/src/gaia_cli/tui/screens/agent.py +0 -0
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/src/gaia_cli/tui/screens/hero.py +0 -0
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/src/gaia_cli/tui/screens/levelup.py +0 -0
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/src/gaia_cli/tui/screens/scan.py +0 -0
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/src/gaia_cli/tui/screens/tree.py +0 -0
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/src/gaia_cli/tui/theme.tcss +0 -0
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/src/gaia_cli/tui/tokens.py +0 -0
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/src/gaia_cli/versioning.py +0 -0
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/src/gaia_cli.egg-info/SOURCES.txt +0 -0
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/src/gaia_cli.egg-info/dependency_links.txt +0 -0
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/src/gaia_cli.egg-info/entry_points.txt +0 -0
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/src/gaia_cli.egg-info/requires.txt +0 -0
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/src/gaia_cli.egg-info/top_level.txt +0 -0
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/tests/test_authz.py +0 -0
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/tests/test_crawlers.py +0 -0
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/tests/test_docs_site.py +0 -0
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/tests/test_docs_skill_explorer.py +0 -0
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/tests/test_embeddings.py +0 -0
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/tests/test_evidence_inheritance.py +0 -0
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/tests/test_formatting.py +0 -0
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/tests/test_graph.py +0 -0
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/tests/test_install.py +0 -0
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/tests/test_interactive.py +0 -0
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/tests/test_leveling.py +0 -0
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/tests/test_lifecycle.py +0 -0
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/tests/test_local_context.py +0 -0
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/tests/test_meta_ops.py +0 -0
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/tests/test_named_skills.py +0 -0
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/tests/test_packaging.py +0 -0
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/tests/test_path_engine.py +0 -0
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/tests/test_pr540_review.py +0 -0
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/tests/test_pr_writer.py +0 -0
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/tests/test_promotion.py +0 -0
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/tests/test_real_skill_catalog.py +0 -0
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/tests/test_redaction.py +0 -0
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/tests/test_registry_layout.py +0 -0
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/tests/test_scanner.py +0 -0
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/tests/test_suite_install.py +0 -0
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/tests/test_timelines.py +0 -0
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/tests/test_treeManager.py +0 -0
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/tests/test_tui_tokens.py +0 -0
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/tests/test_unlocked_at_datetime.py +0 -0
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/tests/test_verify_evidence.py +0 -0
- {gaia_cli-4.2.1 → gaia_cli-4.3.6}/tests/test_workflows.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: gaia-cli
|
|
3
|
-
Version: 4.
|
|
3
|
+
Version: 4.3.6
|
|
4
4
|
Summary: Gaia AI Agent Skill Registry CLI
|
|
5
5
|
Author: Gaia contributors
|
|
6
6
|
License: MIT
|
|
@@ -54,20 +54,18 @@ Dynamic: license-file
|
|
|
54
54
|
</picture>
|
|
55
55
|
</div>
|
|
56
56
|
|
|
57
|
-
# Gaia -
|
|
57
|
+
# Gaia - This is not a skill marketplace
|
|
58
58
|
|
|
59
|
-
>
|
|
59
|
+
> This is an open, evidence-backed skill graph. The game is to name a skill to your repository--the best skill takes "origin".
|
|
60
60
|
> Success means becoming the public record AI agent developers cite when making capability claims — the pkg.go.dev for agent skills.
|
|
61
61
|
|
|
62
|
-
###
|
|
62
|
+
### How does ranking work? Read [META.md](META.md) for a comprehensive list
|
|
63
63
|
|
|
64
64
|
[](https://github.com/mbtiongson1/gaia-skill-tree/actions/workflows/validate.yml)
|
|
65
65
|
[](LICENSE)
|
|
66
66
|
[](https://gaia.tiongson.co/)
|
|
67
67
|
|
|
68
|
-
#
|
|
69
|
-
|
|
70
|
-
Have a named skill? Get yours now! Should look like this:
|
|
68
|
+
# Name a skill, get a badge.
|
|
71
69
|
|
|
72
70
|
[](https://gaia.tiongson.co/u/mbtiongson1/)<br>
|
|
73
71
|
[](https://gaia.tiongson.co/u/mbtiongson1/)<br>
|
|
@@ -81,9 +79,15 @@ Generate yours at **[gaia.tiongson.co/badges/](https://gaia.tiongson.co/badges/)
|
|
|
81
79
|
|
|
82
80
|
---
|
|
83
81
|
|
|
84
|
-
|
|
82
|
+
# Who maintains this?
|
|
83
|
+
|
|
84
|
+
Truth is, Gaia will exist even without anyone sending their skills.
|
|
85
|
+
|
|
86
|
+
I built this because skills should be attributed to the people who proved them. Permanently, not just until the repo goes private.
|
|
85
87
|
|
|
86
|
-
|
|
88
|
+
So that means, its the developers who make skills maintaining this. I have a thorough curation process, and the dev community is evidence on why this works. As long as developers making skills exists, this registry will exist. This is open-source, so feel free to contribute!
|
|
89
|
+
|
|
90
|
+
# The Skill Tree
|
|
87
91
|
|
|
88
92
|
<!-- gaia:registry-start -->
|
|
89
93
|
```text
|
|
@@ -163,7 +167,7 @@ Skills rank up through **verifiable evidence** (Class A/B/C) and can be demoted
|
|
|
163
167
|
**1. Install the CLI**
|
|
164
168
|
|
|
165
169
|
<!-- gaia:version-start -->
|
|
166
|
-
Current Gaia CLI version: `4.
|
|
170
|
+
Current Gaia CLI version: `4.3.6`.
|
|
167
171
|
|
|
168
172
|
```bash
|
|
169
173
|
curl -fsSL https://gaia.tiongson.co/install.sh | sh
|
|
@@ -179,17 +183,7 @@ npm install -g @gaia-registry/cli
|
|
|
179
183
|
Requires Python 3.8+. The script prefers `pipx` if available, otherwise falls back to `pip install --user` and prints a PATH hint if needed.
|
|
180
184
|
|
|
181
185
|
<details>
|
|
182
|
-
<summary>
|
|
183
|
-
|
|
184
|
-
**pip (Python):**
|
|
185
|
-
```bash
|
|
186
|
-
pip install gaia-cli
|
|
187
|
-
```
|
|
188
|
-
|
|
189
|
-
**npm wrapper:**
|
|
190
|
-
```bash
|
|
191
|
-
npm install -g @gaia-registry/cli
|
|
192
|
-
```
|
|
186
|
+
<summary>pipx / Windows alternatives</summary>
|
|
193
187
|
|
|
194
188
|
**pipx:**
|
|
195
189
|
```bash
|
|
@@ -207,7 +201,7 @@ $env:PATH += ";" + (python -c "import sysconfig; print(sysconfig.get_path('scrip
|
|
|
207
201
|
```bash
|
|
208
202
|
git clone https://github.com/mbtiongson1/gaia-skill-tree.git
|
|
209
203
|
cd gaia-skill-tree
|
|
210
|
-
pip install -e ".[embeddings,dev]"
|
|
204
|
+
pip install -e ".[embeddings,dev,docs]"
|
|
211
205
|
```
|
|
212
206
|
|
|
213
207
|
The `dev` extra installs packaging/test tools such as `build` and `pytest`; without it,
|
|
@@ -426,9 +420,9 @@ Thank you to everyone who has expanded the Gaia registry.
|
|
|
426
420
|
| [@rico-tiongson](https://github.com/rico-tiongson) | Collaborator: early feature contributions and ongoing pair programming |
|
|
427
421
|
| [@Juno](https://github.com/Juno) | Key contributor: graph browser expansion, function-calling skill, RAG pipeline evidence, and CLI DX improvements |
|
|
428
422
|
|
|
429
|
-
### Named
|
|
423
|
+
### Named Skills
|
|
430
424
|
|
|
431
|
-
|
|
|
425
|
+
| Developers | Skills |
|
|
432
426
|
|---|---|
|
|
433
427
|
| [@ruvnet](https://github.com/ruvnet) | 48 — agentdb, flow-nexus, hive-mind-coordination, browser, and 44 others |
|
|
434
428
|
| [@garrytan](https://github.com/garrytan) | 47 — gstack ecosystem: browse, qa, ship, review, benchmark, learn, and 41 others |
|
|
@@ -5,20 +5,18 @@
|
|
|
5
5
|
</picture>
|
|
6
6
|
</div>
|
|
7
7
|
|
|
8
|
-
# Gaia -
|
|
8
|
+
# Gaia - This is not a skill marketplace
|
|
9
9
|
|
|
10
|
-
>
|
|
10
|
+
> This is an open, evidence-backed skill graph. The game is to name a skill to your repository--the best skill takes "origin".
|
|
11
11
|
> Success means becoming the public record AI agent developers cite when making capability claims — the pkg.go.dev for agent skills.
|
|
12
12
|
|
|
13
|
-
###
|
|
13
|
+
### How does ranking work? Read [META.md](META.md) for a comprehensive list
|
|
14
14
|
|
|
15
15
|
[](https://github.com/mbtiongson1/gaia-skill-tree/actions/workflows/validate.yml)
|
|
16
16
|
[](LICENSE)
|
|
17
17
|
[](https://gaia.tiongson.co/)
|
|
18
18
|
|
|
19
|
-
#
|
|
20
|
-
|
|
21
|
-
Have a named skill? Get yours now! Should look like this:
|
|
19
|
+
# Name a skill, get a badge.
|
|
22
20
|
|
|
23
21
|
[](https://gaia.tiongson.co/u/mbtiongson1/)<br>
|
|
24
22
|
[](https://gaia.tiongson.co/u/mbtiongson1/)<br>
|
|
@@ -32,9 +30,15 @@ Generate yours at **[gaia.tiongson.co/badges/](https://gaia.tiongson.co/badges/)
|
|
|
32
30
|
|
|
33
31
|
---
|
|
34
32
|
|
|
35
|
-
|
|
33
|
+
# Who maintains this?
|
|
34
|
+
|
|
35
|
+
Truth is, Gaia will exist even without anyone sending their skills.
|
|
36
|
+
|
|
37
|
+
I built this because skills should be attributed to the people who proved them. Permanently, not just until the repo goes private.
|
|
36
38
|
|
|
37
|
-
|
|
39
|
+
So that means, its the developers who make skills maintaining this. I have a thorough curation process, and the dev community is evidence on why this works. As long as developers making skills exists, this registry will exist. This is open-source, so feel free to contribute!
|
|
40
|
+
|
|
41
|
+
# The Skill Tree
|
|
38
42
|
|
|
39
43
|
<!-- gaia:registry-start -->
|
|
40
44
|
```text
|
|
@@ -114,7 +118,7 @@ Skills rank up through **verifiable evidence** (Class A/B/C) and can be demoted
|
|
|
114
118
|
**1. Install the CLI**
|
|
115
119
|
|
|
116
120
|
<!-- gaia:version-start -->
|
|
117
|
-
Current Gaia CLI version: `4.
|
|
121
|
+
Current Gaia CLI version: `4.3.6`.
|
|
118
122
|
|
|
119
123
|
```bash
|
|
120
124
|
curl -fsSL https://gaia.tiongson.co/install.sh | sh
|
|
@@ -130,17 +134,7 @@ npm install -g @gaia-registry/cli
|
|
|
130
134
|
Requires Python 3.8+. The script prefers `pipx` if available, otherwise falls back to `pip install --user` and prints a PATH hint if needed.
|
|
131
135
|
|
|
132
136
|
<details>
|
|
133
|
-
<summary>
|
|
134
|
-
|
|
135
|
-
**pip (Python):**
|
|
136
|
-
```bash
|
|
137
|
-
pip install gaia-cli
|
|
138
|
-
```
|
|
139
|
-
|
|
140
|
-
**npm wrapper:**
|
|
141
|
-
```bash
|
|
142
|
-
npm install -g @gaia-registry/cli
|
|
143
|
-
```
|
|
137
|
+
<summary>pipx / Windows alternatives</summary>
|
|
144
138
|
|
|
145
139
|
**pipx:**
|
|
146
140
|
```bash
|
|
@@ -158,7 +152,7 @@ $env:PATH += ";" + (python -c "import sysconfig; print(sysconfig.get_path('scrip
|
|
|
158
152
|
```bash
|
|
159
153
|
git clone https://github.com/mbtiongson1/gaia-skill-tree.git
|
|
160
154
|
cd gaia-skill-tree
|
|
161
|
-
pip install -e ".[embeddings,dev]"
|
|
155
|
+
pip install -e ".[embeddings,dev,docs]"
|
|
162
156
|
```
|
|
163
157
|
|
|
164
158
|
The `dev` extra installs packaging/test tools such as `build` and `pytest`; without it,
|
|
@@ -377,9 +371,9 @@ Thank you to everyone who has expanded the Gaia registry.
|
|
|
377
371
|
| [@rico-tiongson](https://github.com/rico-tiongson) | Collaborator: early feature contributions and ongoing pair programming |
|
|
378
372
|
| [@Juno](https://github.com/Juno) | Key contributor: graph browser expansion, function-calling skill, RAG pipeline evidence, and CLI DX improvements |
|
|
379
373
|
|
|
380
|
-
### Named
|
|
374
|
+
### Named Skills
|
|
381
375
|
|
|
382
|
-
|
|
|
376
|
+
| Developers | Skills |
|
|
383
377
|
|---|---|
|
|
384
378
|
| [@ruvnet](https://github.com/ruvnet) | 48 — agentdb, flow-nexus, hive-mind-coordination, browser, and 44 others |
|
|
385
379
|
| [@garrytan](https://github.com/garrytan) | 47 — gstack ecosystem: browse, qa, ship, review, benchmark, learn, and 41 others |
|
|
@@ -561,6 +561,20 @@ def render_appraise_card(
|
|
|
561
561
|
deriv_line = prefix + ", ".join(deriv_items)
|
|
562
562
|
if len(derivatives) > 4:
|
|
563
563
|
deriv_line += f" +{len(derivatives) - 4} more"
|
|
564
|
+
# Truncate at comma boundary instead of mid-word
|
|
565
|
+
if len(deriv_line) > inner:
|
|
566
|
+
truncated = prefix
|
|
567
|
+
for i, item in enumerate(deriv_items):
|
|
568
|
+
candidate = truncated + (", " if i > 0 else "") + item
|
|
569
|
+
if len(candidate) > inner - 2: # leave room for " …"
|
|
570
|
+
remaining = len(deriv_items) - i + (len(derivatives) - 4 if len(derivatives) > 4 else 0)
|
|
571
|
+
truncated += f" +{remaining} more" if remaining > 0 else ""
|
|
572
|
+
break
|
|
573
|
+
truncated = candidate
|
|
574
|
+
else:
|
|
575
|
+
if len(derivatives) > 4:
|
|
576
|
+
truncated += f" +{len(derivatives) - 4} more"
|
|
577
|
+
deriv_line = truncated
|
|
564
578
|
lines.append(f"{bc}{V}{r} {fg(*COLOR_MUTED)}{_pad(deriv_line, inner)}{r} {bc}{V}{r}")
|
|
565
579
|
else:
|
|
566
580
|
lines.append(f"{bc}{V}{r} {fg(*COLOR_MUTED)}{_pad('Unlocks: (terminal skill)', inner)}{r} {bc}{V}{r}")
|
|
@@ -133,7 +133,9 @@ def collect_stats(registry_path: str | Path) -> dict:
|
|
|
133
133
|
]
|
|
134
134
|
|
|
135
135
|
type_counts = Counter(skill.get("type", "unknown") for skill in skills)
|
|
136
|
-
level_counts = Counter(
|
|
136
|
+
level_counts = Counter(
|
|
137
|
+
skill["level"] for skill in skills if "level" in skill
|
|
138
|
+
)
|
|
137
139
|
effective_level_counts = Counter()
|
|
138
140
|
demerit_counts: Counter[str] = Counter()
|
|
139
141
|
skills_with_demerits = 0
|
|
@@ -1205,7 +1205,7 @@ def graph_command(args: Any) -> None:
|
|
|
1205
1205
|
pass # Degrade gracefully to canon mode
|
|
1206
1206
|
|
|
1207
1207
|
out_path = write_graph_artifact(registry_path, output=output, fmt=fmt, user_ctx=user_ctx)
|
|
1208
|
-
print(f" saved {
|
|
1208
|
+
print(f" saved {out_path}")
|
|
1209
1209
|
|
|
1210
1210
|
# Regenerate the GEXF from current node data
|
|
1211
1211
|
if fmt == "html":
|
|
@@ -294,8 +294,8 @@ def init_command(args):
|
|
|
294
294
|
config_dir = '.gaia'
|
|
295
295
|
os.makedirs(config_dir, exist_ok=True)
|
|
296
296
|
config_path = os.path.join(config_dir, 'config.toml')
|
|
297
|
-
if os.path.exists(config_path):
|
|
298
|
-
print("Gaia is already initialized in this repository.")
|
|
297
|
+
if os.path.exists(config_path) and not getattr(args, "force", False):
|
|
298
|
+
print("Gaia is already initialized in this repository. Use --force to overwrite.")
|
|
299
299
|
return
|
|
300
300
|
|
|
301
301
|
username = args.user or _detect_github_username()
|
|
@@ -472,16 +472,20 @@ def scan_command(args):
|
|
|
472
472
|
skill_map = {s['id']: s for s in graph_data.get('skills', [])}
|
|
473
473
|
unlocked = [s.get('skillId') for s in tree.get('unlockedSkills', [])]
|
|
474
474
|
combos = get_combinations(graph_data, unlocked, resolved)
|
|
475
|
-
if combos
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
print(
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
475
|
+
if combos:
|
|
476
|
+
# Persist fusion candidates so `gaia fuse` can find them
|
|
477
|
+
tree['pendingCombinations'] = combos
|
|
478
|
+
save_tree(username, tree, registry_path=args.registry)
|
|
479
|
+
if not quiet:
|
|
480
|
+
print("\nNew fusion candidates:")
|
|
481
|
+
for c in combos:
|
|
482
|
+
result_skill = skill_map.get(c['candidateResult'], {})
|
|
483
|
+
result_type = result_skill.get('type', 'extra')
|
|
484
|
+
print(render_fusion_diagram(
|
|
485
|
+
c['detectedSkills'], c['candidateResult'], result_type,
|
|
486
|
+
canon=canon, ctx=ctx
|
|
487
|
+
))
|
|
488
|
+
print("Run `gaia fuse <skill>` to confirm.")
|
|
485
489
|
|
|
486
490
|
# Path engine integration
|
|
487
491
|
old_paths = load_paths()
|
|
@@ -537,7 +541,7 @@ def render_user_tree_outputs(username: str, tree: dict | None, graph_data: dict
|
|
|
537
541
|
with open(html_path, "w", encoding="utf-8") as f:
|
|
538
542
|
f.write(html)
|
|
539
543
|
if not quiet:
|
|
540
|
-
print(f" saved {
|
|
544
|
+
print(f" saved {html_path} & {md_path}")
|
|
541
545
|
return html_path, md_path
|
|
542
546
|
|
|
543
547
|
|
|
@@ -599,7 +603,8 @@ def lookup_command(args):
|
|
|
599
603
|
display = skill.get("name") or f"/{skill_id}"
|
|
600
604
|
print(f"{display}")
|
|
601
605
|
|
|
602
|
-
|
|
606
|
+
user_level = ctx.skill_level(skill_id) if ctx else skill.get('level', '?')
|
|
607
|
+
print(f"Type: {skill.get('type', 'unknown')} Level: {user_level}")
|
|
603
608
|
if skill.get("description"):
|
|
604
609
|
print(skill["description"])
|
|
605
610
|
|
|
@@ -792,7 +797,7 @@ def promote_command(args):
|
|
|
792
797
|
return
|
|
793
798
|
if not skill_id:
|
|
794
799
|
# Try interactive picker
|
|
795
|
-
candidates = promotable_candidates(
|
|
800
|
+
candidates = promotable_candidates(args.registry, username)
|
|
796
801
|
if candidates:
|
|
797
802
|
picked = select_promotion_candidate(candidates, "Select skill to promote:")
|
|
798
803
|
if picked:
|
|
@@ -1284,9 +1289,9 @@ def install_command(args):
|
|
|
1284
1289
|
interactive_install(args.registry, location=location)
|
|
1285
1290
|
return
|
|
1286
1291
|
if not args.skill_id:
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1292
|
+
print("Usage: gaia install <skill_id>", file=sys.stderr)
|
|
1293
|
+
print(" To update all installed skills, use: gaia update", file=sys.stderr)
|
|
1294
|
+
sys.exit(2)
|
|
1290
1295
|
|
|
1291
1296
|
# Use suite logic if flagged or implicitly requested
|
|
1292
1297
|
if getattr(args, 'ultimate', False) or getattr(args, 'suite', False):
|
|
@@ -1300,7 +1305,7 @@ def install_command(args):
|
|
|
1300
1305
|
|
|
1301
1306
|
def uninstall_command(args):
|
|
1302
1307
|
from gaia_cli.install import uninstall_skill
|
|
1303
|
-
success = uninstall_skill(args.skill_id)
|
|
1308
|
+
success = uninstall_skill(args.skill_id.lstrip("/"))
|
|
1304
1309
|
if not success:
|
|
1305
1310
|
sys.exit(1)
|
|
1306
1311
|
|
|
@@ -1362,7 +1367,7 @@ def skills_command(args):
|
|
|
1362
1367
|
|
|
1363
1368
|
|
|
1364
1369
|
available = [
|
|
1365
|
-
{"id": sid, "name": meta.get("name") or sid, "level": meta.get("level", "?"), "description": meta.get("description", "")}
|
|
1370
|
+
{"id": sid, "name": meta.get("name") or sid, "level": meta.get("level", "?"), "type": meta.get("type", "basic"), "description": meta.get("description", "")}
|
|
1366
1371
|
for sid, meta in list_available(args.registry)
|
|
1367
1372
|
]
|
|
1368
1373
|
items = available + pending
|
|
@@ -1459,6 +1464,12 @@ def pull_command(args):
|
|
|
1459
1464
|
print("Note: Registry could not be updated via git (no upstream configured). Local registry unchanged.", file=sys.stderr)
|
|
1460
1465
|
else:
|
|
1461
1466
|
print(f"Warning: git pull failed. Local registry unchanged.\n {stderr}", file=sys.stderr)
|
|
1467
|
+
else:
|
|
1468
|
+
stdout = res.stdout.strip()
|
|
1469
|
+
if "Already up to date" in stdout:
|
|
1470
|
+
print("Registry is already up to date.")
|
|
1471
|
+
else:
|
|
1472
|
+
print("Registry updated successfully.")
|
|
1462
1473
|
|
|
1463
1474
|
|
|
1464
1475
|
def update_command(args):
|
|
@@ -1647,6 +1658,7 @@ def get_parser():
|
|
|
1647
1658
|
init_parser.add_argument('--registry-ref', help='Gaia registry URL to write into .gaia/config.toml')
|
|
1648
1659
|
init_parser.add_argument('--scan', action='append', help='Path to scan; repeat for multiple paths')
|
|
1649
1660
|
init_parser.add_argument('--yes', action='store_true', help='Use non-interactive defaults')
|
|
1661
|
+
init_parser.add_argument('--force', action='store_true', help='Overwrite existing .gaia/config.toml')
|
|
1650
1662
|
init_parser.add_argument(
|
|
1651
1663
|
'--auto-prompt-combinations',
|
|
1652
1664
|
action='store_true',
|
|
@@ -144,7 +144,12 @@ def render_unlock_path(
|
|
|
144
144
|
total += c_total
|
|
145
145
|
return owned, total
|
|
146
146
|
|
|
147
|
-
|
|
147
|
+
# Count prerequisites only (children of root — root is the target, not a prereq).
|
|
148
|
+
owned_count, total_count = 0, 0
|
|
149
|
+
for child in tree.get('children', []):
|
|
150
|
+
c_owned, c_total = _count(child)
|
|
151
|
+
owned_count += c_owned
|
|
152
|
+
total_count += c_total
|
|
148
153
|
|
|
149
154
|
# Render root line manually.
|
|
150
155
|
root_sid = tree['id']
|
|
@@ -203,6 +203,11 @@ def open_intake_issue(username, batch_data, batch_path=None, repo_root="."):
|
|
|
203
203
|
|
|
204
204
|
issue_url = issue.stdout.strip().splitlines()[-1] if issue.stdout.strip() else ""
|
|
205
205
|
print(f"Success: intake issue opened ({issue_url}).")
|
|
206
|
+
# Clean up temp body file
|
|
207
|
+
try:
|
|
208
|
+
os.remove(body_path)
|
|
209
|
+
except OSError:
|
|
210
|
+
pass
|
|
206
211
|
return issue_url or None
|
|
207
212
|
|
|
208
213
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: gaia-cli
|
|
3
|
-
Version: 4.
|
|
3
|
+
Version: 4.3.6
|
|
4
4
|
Summary: Gaia AI Agent Skill Registry CLI
|
|
5
5
|
Author: Gaia contributors
|
|
6
6
|
License: MIT
|
|
@@ -54,20 +54,18 @@ Dynamic: license-file
|
|
|
54
54
|
</picture>
|
|
55
55
|
</div>
|
|
56
56
|
|
|
57
|
-
# Gaia -
|
|
57
|
+
# Gaia - This is not a skill marketplace
|
|
58
58
|
|
|
59
|
-
>
|
|
59
|
+
> This is an open, evidence-backed skill graph. The game is to name a skill to your repository--the best skill takes "origin".
|
|
60
60
|
> Success means becoming the public record AI agent developers cite when making capability claims — the pkg.go.dev for agent skills.
|
|
61
61
|
|
|
62
|
-
###
|
|
62
|
+
### How does ranking work? Read [META.md](META.md) for a comprehensive list
|
|
63
63
|
|
|
64
64
|
[](https://github.com/mbtiongson1/gaia-skill-tree/actions/workflows/validate.yml)
|
|
65
65
|
[](LICENSE)
|
|
66
66
|
[](https://gaia.tiongson.co/)
|
|
67
67
|
|
|
68
|
-
#
|
|
69
|
-
|
|
70
|
-
Have a named skill? Get yours now! Should look like this:
|
|
68
|
+
# Name a skill, get a badge.
|
|
71
69
|
|
|
72
70
|
[](https://gaia.tiongson.co/u/mbtiongson1/)<br>
|
|
73
71
|
[](https://gaia.tiongson.co/u/mbtiongson1/)<br>
|
|
@@ -81,9 +79,15 @@ Generate yours at **[gaia.tiongson.co/badges/](https://gaia.tiongson.co/badges/)
|
|
|
81
79
|
|
|
82
80
|
---
|
|
83
81
|
|
|
84
|
-
|
|
82
|
+
# Who maintains this?
|
|
83
|
+
|
|
84
|
+
Truth is, Gaia will exist even without anyone sending their skills.
|
|
85
|
+
|
|
86
|
+
I built this because skills should be attributed to the people who proved them. Permanently, not just until the repo goes private.
|
|
85
87
|
|
|
86
|
-
|
|
88
|
+
So that means, its the developers who make skills maintaining this. I have a thorough curation process, and the dev community is evidence on why this works. As long as developers making skills exists, this registry will exist. This is open-source, so feel free to contribute!
|
|
89
|
+
|
|
90
|
+
# The Skill Tree
|
|
87
91
|
|
|
88
92
|
<!-- gaia:registry-start -->
|
|
89
93
|
```text
|
|
@@ -163,7 +167,7 @@ Skills rank up through **verifiable evidence** (Class A/B/C) and can be demoted
|
|
|
163
167
|
**1. Install the CLI**
|
|
164
168
|
|
|
165
169
|
<!-- gaia:version-start -->
|
|
166
|
-
Current Gaia CLI version: `4.
|
|
170
|
+
Current Gaia CLI version: `4.3.6`.
|
|
167
171
|
|
|
168
172
|
```bash
|
|
169
173
|
curl -fsSL https://gaia.tiongson.co/install.sh | sh
|
|
@@ -179,17 +183,7 @@ npm install -g @gaia-registry/cli
|
|
|
179
183
|
Requires Python 3.8+. The script prefers `pipx` if available, otherwise falls back to `pip install --user` and prints a PATH hint if needed.
|
|
180
184
|
|
|
181
185
|
<details>
|
|
182
|
-
<summary>
|
|
183
|
-
|
|
184
|
-
**pip (Python):**
|
|
185
|
-
```bash
|
|
186
|
-
pip install gaia-cli
|
|
187
|
-
```
|
|
188
|
-
|
|
189
|
-
**npm wrapper:**
|
|
190
|
-
```bash
|
|
191
|
-
npm install -g @gaia-registry/cli
|
|
192
|
-
```
|
|
186
|
+
<summary>pipx / Windows alternatives</summary>
|
|
193
187
|
|
|
194
188
|
**pipx:**
|
|
195
189
|
```bash
|
|
@@ -207,7 +201,7 @@ $env:PATH += ";" + (python -c "import sysconfig; print(sysconfig.get_path('scrip
|
|
|
207
201
|
```bash
|
|
208
202
|
git clone https://github.com/mbtiongson1/gaia-skill-tree.git
|
|
209
203
|
cd gaia-skill-tree
|
|
210
|
-
pip install -e ".[embeddings,dev]"
|
|
204
|
+
pip install -e ".[embeddings,dev,docs]"
|
|
211
205
|
```
|
|
212
206
|
|
|
213
207
|
The `dev` extra installs packaging/test tools such as `build` and `pytest`; without it,
|
|
@@ -426,9 +420,9 @@ Thank you to everyone who has expanded the Gaia registry.
|
|
|
426
420
|
| [@rico-tiongson](https://github.com/rico-tiongson) | Collaborator: early feature contributions and ongoing pair programming |
|
|
427
421
|
| [@Juno](https://github.com/Juno) | Key contributor: graph browser expansion, function-calling skill, RAG pipeline evidence, and CLI DX improvements |
|
|
428
422
|
|
|
429
|
-
### Named
|
|
423
|
+
### Named Skills
|
|
430
424
|
|
|
431
|
-
|
|
|
425
|
+
| Developers | Skills |
|
|
432
426
|
|---|---|
|
|
433
427
|
| [@ruvnet](https://github.com/ruvnet) | 48 — agentdb, flow-nexus, hive-mind-coordination, browser, and 44 others |
|
|
434
428
|
| [@garrytan](https://github.com/garrytan) | 47 — gstack ecosystem: browse, qa, ship, review, benchmark, learn, and 41 others |
|
|
@@ -18,6 +18,7 @@ from gaia_cli.cardRenderer import (
|
|
|
18
18
|
load_and_render,
|
|
19
19
|
_pad,
|
|
20
20
|
_wrap_lines,
|
|
21
|
+
render_appraise_card,
|
|
21
22
|
)
|
|
22
23
|
|
|
23
24
|
|
|
@@ -520,3 +521,29 @@ class TestRenderFusionDiagram:
|
|
|
520
521
|
# First line (shorter name) should be padded
|
|
521
522
|
assert "/ab" in lines[0]
|
|
522
523
|
assert "/longername" in lines[2]
|
|
524
|
+
|
|
525
|
+
|
|
526
|
+
def test_render_appraise_card_truncation():
|
|
527
|
+
skill_data = {
|
|
528
|
+
"id": "test-skill",
|
|
529
|
+
"name": "Test Skill",
|
|
530
|
+
"type": "basic",
|
|
531
|
+
"level": "0★",
|
|
532
|
+
"rarity": "common",
|
|
533
|
+
"description": "Short description.",
|
|
534
|
+
}
|
|
535
|
+
derivatives = [
|
|
536
|
+
{"id": "d1", "name": "First Derivative Skill Name"},
|
|
537
|
+
{"id": "d2", "name": "Second Derivative Skill Name"},
|
|
538
|
+
{"id": "d3", "name": "Third Derivative Skill Name"},
|
|
539
|
+
]
|
|
540
|
+
output = render_appraise_card(
|
|
541
|
+
skill_data=skill_data,
|
|
542
|
+
prereq_status={},
|
|
543
|
+
derivatives=derivatives,
|
|
544
|
+
actions=[],
|
|
545
|
+
)
|
|
546
|
+
assert "First Derivative Skill Name" in output
|
|
547
|
+
assert "+2 more" in output
|
|
548
|
+
assert "Second Derivative" not in output
|
|
549
|
+
|
|
@@ -445,3 +445,25 @@ def test_gaia_uninstall_command_removes_skill(tmp_path, monkeypatch):
|
|
|
445
445
|
from gaia_cli.install import load_manifest
|
|
446
446
|
manifest = load_manifest()
|
|
447
447
|
assert not any(e["id"] == "testuser/test-skill" for e in manifest["installed"])
|
|
448
|
+
|
|
449
|
+
|
|
450
|
+
def test_init_force_overwrite(tmp_path, monkeypatch, capsys):
|
|
451
|
+
monkeypatch.chdir(tmp_path)
|
|
452
|
+
|
|
453
|
+
# First init
|
|
454
|
+
run_cli(monkeypatch, ["init", "--user", "firstuser", "--yes"])
|
|
455
|
+
config = parse_config(tmp_path / ".gaia" / "config.toml")
|
|
456
|
+
assert config["username"] == "firstuser"
|
|
457
|
+
|
|
458
|
+
# Second init without --force (should print message and not overwrite)
|
|
459
|
+
run_cli(monkeypatch, ["init", "--user", "seconduser", "--yes"])
|
|
460
|
+
output = capsys.readouterr().out
|
|
461
|
+
assert "Gaia is already initialized in this repository. Use --force to overwrite." in output
|
|
462
|
+
config = parse_config(tmp_path / ".gaia" / "config.toml")
|
|
463
|
+
assert config["username"] == "firstuser" # unchanged
|
|
464
|
+
|
|
465
|
+
# Third init with --force (should overwrite)
|
|
466
|
+
run_cli(monkeypatch, ["init", "--user", "seconduser", "--yes", "--force"])
|
|
467
|
+
config = parse_config(tmp_path / ".gaia" / "config.toml")
|
|
468
|
+
assert config["username"] == "seconduser" # overwritten
|
|
469
|
+
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import json
|
|
2
2
|
import os
|
|
3
3
|
import subprocess
|
|
4
|
+
import sys
|
|
4
5
|
import tempfile
|
|
5
6
|
import unittest
|
|
6
7
|
|
|
@@ -15,7 +16,7 @@ def run_validate_intake(intake_dir, *extra_args):
|
|
|
15
16
|
env["PYTHONIOENCODING"] = "utf-8"
|
|
16
17
|
result = subprocess.run(
|
|
17
18
|
[
|
|
18
|
-
|
|
19
|
+
sys.executable,
|
|
19
20
|
VALIDATE_INTAKE_SCRIPT,
|
|
20
21
|
"--intake-dir",
|
|
21
22
|
intake_dir,
|
|
@@ -236,23 +236,23 @@ class TestRenderUnlockPath:
|
|
|
236
236
|
def test_basic_leaf_renders(self, linear_graph):
|
|
237
237
|
text = render_unlock_path(linear_graph, "a", set())
|
|
238
238
|
assert "a" in text
|
|
239
|
-
# leaf has no children, summary should say 0 owned out of
|
|
240
|
-
assert "0 /
|
|
239
|
+
# leaf has no children, summary should say 0 owned out of 0
|
|
240
|
+
assert "0 / 0" in text
|
|
241
241
|
|
|
242
242
|
def test_footer_counts_correct(self, linear_graph):
|
|
243
243
|
text = render_unlock_path(linear_graph, "c", set())
|
|
244
|
-
#
|
|
245
|
-
assert "0 /
|
|
246
|
-
assert "
|
|
244
|
+
# 2 prerequisites total (a, b), 0 owned
|
|
245
|
+
assert "0 / 2" in text
|
|
246
|
+
assert "2 skill(s) needed" in text
|
|
247
247
|
|
|
248
248
|
def test_footer_with_owned(self, linear_graph):
|
|
249
249
|
# unlock_path stops recursing into owned nodes, so the visible tree
|
|
250
250
|
# for 'c' with owned={'a','b'} is: c(missing) + b(owned, no children).
|
|
251
251
|
# 'a' is not in the tree because b is already owned → recursion stops.
|
|
252
|
-
# Count:
|
|
252
|
+
# Count: 1 prerequisite total (b), 1 owned (b).
|
|
253
253
|
text = render_unlock_path(linear_graph, "c", {"a", "b"})
|
|
254
|
-
assert "1 /
|
|
255
|
-
assert "
|
|
254
|
+
assert "1 / 1" in text
|
|
255
|
+
assert "0 skill(s) needed" in text
|
|
256
256
|
|
|
257
257
|
def test_owned_only_prunes_owned_branches(self, linear_graph):
|
|
258
258
|
"""--owned-only prunes the display of owned 'b' from the output."""
|
|
@@ -37,7 +37,7 @@ class TestGaiaPush(unittest.TestCase):
|
|
|
37
37
|
env["PYTHONIOENCODING"] = "utf-8"
|
|
38
38
|
result = subprocess.run(
|
|
39
39
|
[
|
|
40
|
-
|
|
40
|
+
sys.executable,
|
|
41
41
|
CLI_PATH,
|
|
42
42
|
"--registry",
|
|
43
43
|
REPO_ROOT,
|
|
@@ -83,7 +83,7 @@ class TestGaiaPush(unittest.TestCase):
|
|
|
83
83
|
env["PYTHONIOENCODING"] = "utf-8"
|
|
84
84
|
result = subprocess.run(
|
|
85
85
|
[
|
|
86
|
-
|
|
86
|
+
sys.executable,
|
|
87
87
|
CLI_PATH,
|
|
88
88
|
"--registry",
|
|
89
89
|
registry,
|
|
@@ -114,3 +114,23 @@ def test_stats_cli_prints_summary(tmp_path, monkeypatch, capsys):
|
|
|
114
114
|
assert "Gaia Registry — 4 skills 1 edges" in output
|
|
115
115
|
assert "Class A" in output
|
|
116
116
|
assert "Effective level breakdown" in output
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def test_collect_stats_missing_level(tmp_path):
|
|
120
|
+
registry = tmp_path / "registry"
|
|
121
|
+
registry.mkdir(parents=True, exist_ok=True)
|
|
122
|
+
(registry / "gaia.json").write_text(
|
|
123
|
+
json.dumps(
|
|
124
|
+
{
|
|
125
|
+
"skills": [
|
|
126
|
+
{"id": "tokenize", "type": "basic", "evidence": []}, # No 'level' key
|
|
127
|
+
],
|
|
128
|
+
"edges": [],
|
|
129
|
+
}
|
|
130
|
+
),
|
|
131
|
+
encoding="utf-8",
|
|
132
|
+
)
|
|
133
|
+
stats = collect_stats(tmp_path)
|
|
134
|
+
assert "?" not in stats["level_counts"]
|
|
135
|
+
assert "level_counts" in stats
|
|
136
|
+
|
|
@@ -17,7 +17,7 @@ def run_validate(graph_path):
|
|
|
17
17
|
env = os.environ.copy()
|
|
18
18
|
env["PYTHONIOENCODING"] = "utf-8"
|
|
19
19
|
result = subprocess.run(
|
|
20
|
-
[
|
|
20
|
+
[sys.executable, VALIDATE_SCRIPT, "--graph", graph_path],
|
|
21
21
|
capture_output=True,
|
|
22
22
|
text=True,
|
|
23
23
|
encoding="utf-8",
|
|
@@ -210,6 +210,46 @@ class TestNamedSkillValidation(unittest.TestCase):
|
|
|
210
210
|
f"Expected unresolved-ref error, got: {errors}",
|
|
211
211
|
)
|
|
212
212
|
|
|
213
|
+
def test_invalid_github_url_casing_fails_validation(self):
|
|
214
|
+
"""validate_named_skills reports an error when links.github URL has invalid casing (e.g. skill.md)."""
|
|
215
|
+
import tempfile
|
|
216
|
+
import shutil
|
|
217
|
+
from scripts.validate import validate_named_skills
|
|
218
|
+
|
|
219
|
+
temp_named_dir = tempfile.mkdtemp()
|
|
220
|
+
try:
|
|
221
|
+
fake_author_dir = os.path.join(temp_named_dir, "fake_author")
|
|
222
|
+
os.makedirs(fake_author_dir)
|
|
223
|
+
|
|
224
|
+
fake_skill_file = os.path.join(fake_author_dir, "skill_with_bad_casing.md")
|
|
225
|
+
frontmatter = (
|
|
226
|
+
"---\n"
|
|
227
|
+
"id: fake_author/skill_with_bad_casing\n"
|
|
228
|
+
"name: Bad Casing Skill\n"
|
|
229
|
+
"contributor: fake_author\n"
|
|
230
|
+
"origin: true\n"
|
|
231
|
+
"genericSkillRef: web-search\n"
|
|
232
|
+
"status: named\n"
|
|
233
|
+
"level: 2★\n"
|
|
234
|
+
"description: A skill that references lowercase skill.md in links.github.\n"
|
|
235
|
+
"links:\n"
|
|
236
|
+
" github: https://github.com/fake_author/skills/blob/main/skills/skill.md\n"
|
|
237
|
+
"createdAt: '2026-06-07'\n"
|
|
238
|
+
"updatedAt: '2026-06-07'\n"
|
|
239
|
+
"---\n"
|
|
240
|
+
)
|
|
241
|
+
with open(fake_skill_file, "w", encoding="utf-8") as f:
|
|
242
|
+
f.write(frontmatter)
|
|
243
|
+
|
|
244
|
+
graph = {"skills": [{"id": "web-search"}]}
|
|
245
|
+
errors = validate_named_skills(graph, named_dir=temp_named_dir)
|
|
246
|
+
self.assertTrue(
|
|
247
|
+
any("invalid casing" in e and "SKILL.md" in e for e in errors),
|
|
248
|
+
f"Expected casing error, got: {errors}"
|
|
249
|
+
)
|
|
250
|
+
finally:
|
|
251
|
+
shutil.rmtree(temp_named_dir)
|
|
252
|
+
|
|
213
253
|
|
|
214
254
|
if __name__ == "__main__":
|
|
215
255
|
unittest.main()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{gaia_cli-4.2.1 → gaia_cli-4.3.6}/src/gaia_cli/data/registry/named/devin-ai/autonomous-swe.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{gaia_cli-4.2.1 → gaia_cli-4.3.6}/src/gaia_cli/data/registry/schema/pluginConfig.schema.json
RENAMED
|
File without changes
|
{gaia_cli-4.2.1 → gaia_cli-4.3.6}/src/gaia_cli/data/registry/schema/realSkillCatalog.schema.json
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|