@jesdi/skills 0.0.3 → 0.0.4

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jesdi/skills",
3
- "version": "0.0.3",
3
+ "version": "0.0.4",
4
4
  "description": "jesdi's agent skills (content package consumed by @jesdi/skills-cli)",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -139,16 +139,25 @@ def render(result):
139
139
  return "\n".join(lines)
140
140
 
141
141
 
142
- def _gh_json(args):
143
- completed = subprocess.run(args, capture_output=True, text=True, check=True)
142
+ def _gh_json(args, env=None):
143
+ completed = subprocess.run(args, capture_output=True, text=True, check=True,
144
+ env=env)
144
145
  return json.loads(completed.stdout)
145
146
 
146
147
 
148
+ def _project_env():
149
+ """User-owned Projects v2 are invisible to fine-grained PATs, so when
150
+ GH_PROJECT_TOKEN is set, `gh project` calls run with GH_TOKEN swapped to
151
+ it; every other gh call keeps the stored auth (which can read the repo)."""
152
+ token = os.environ.get("GH_PROJECT_TOKEN")
153
+ return {**os.environ, "GH_TOKEN": token} if token else None
154
+
155
+
147
156
  def main(owner, project_number, repo):
148
157
  payload = _gh_json([
149
158
  "gh", "project", "item-list", str(project_number),
150
159
  "--owner", owner, "--format", "json", "--limit", "200",
151
- ])
160
+ ], env=_project_env())
152
161
  project_items = payload.get("items", [])
153
162
  issue_rows = _gh_json([
154
163
  "gh", "issue", "list", "--repo", repo, "--state", "all",
@@ -206,6 +206,38 @@ def test_find_project_meta_nearest_ancestor_wins(tmp_path, monkeypatch):
206
206
  assert rank.find_project_meta() == str(inner_meta)
207
207
 
208
208
 
209
+ def test_project_env_absent_without_token(monkeypatch):
210
+ monkeypatch.delenv("GH_PROJECT_TOKEN", raising=False)
211
+ assert rank._project_env() is None
212
+
213
+
214
+ def test_project_env_swaps_gh_token(monkeypatch):
215
+ monkeypatch.setenv("GH_PROJECT_TOKEN", "classic-tok")
216
+ env = rank._project_env()
217
+ assert env["GH_TOKEN"] == "classic-tok"
218
+
219
+
220
+ def test_main_uses_project_token_only_for_project_call(monkeypatch):
221
+ monkeypatch.setenv("GH_PROJECT_TOKEN", "classic-tok")
222
+ calls = []
223
+
224
+ def fake_run(args, capture_output, text, check, env=None):
225
+ calls.append((args, env))
226
+
227
+ class R:
228
+ stdout = "{\"items\": []}" if args[1] == "project" else "[]"
229
+
230
+ return R()
231
+
232
+ monkeypatch.setattr(rank.subprocess, "run", fake_run)
233
+ rank.main("acme", 1, "acme/private-repo")
234
+ project_call, issue_call = calls
235
+ assert project_call[0][1] == "project"
236
+ assert project_call[1]["GH_TOKEN"] == "classic-tok"
237
+ assert issue_call[0][1] == "issue"
238
+ assert issue_call[1] is None # stored gh auth (repo PAT) stays active
239
+
240
+
209
241
  def test_find_project_meta_errors_clearly_when_absent(tmp_path, monkeypatch):
210
242
  monkeypatch.chdir(tmp_path)
211
243
  with pytest.raises(FileNotFoundError) as exc:
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
- "generatedAt": "2026-07-16T10:07:19.685Z",
3
+ "generatedAt": "2026-07-23T11:12:36.101Z",
4
4
  "skills": [
5
5
  {
6
6
  "name": "backlog",
7
- "version": "0.1.0",
8
- "hash": "sha256-ac26c0313981666dfc143bb6eabbf603e0b02111c13ea543e1c86c2900e40559",
7
+ "version": "0.1.1",
8
+ "hash": "sha256-2a594bc97cd045b92b5771f6c462b861b8adcfaee0135c59820af092bdf02a2f",
9
9
  "description": "Manage a GitHub-Issues-backed backlog and a Projects-v2 work graph via five verbs. Use when the user wants to CAPTURE an idea/research thread (\"add to backlog\", \"capture this\", \"note this idea\", \"log a task\"), TRIAGE the inbox (\"triage the backlog\", \"score the inbox\"), see what to work on NEXT (\"what's next\", \"what should I work on\", \"ranked backlog\", \"next actionable task\"), LAND a finished item (\"mark done\", \"close out #N\"), or SETUP the board the first time. Ranks open issues by impact÷effort, respecting `Blocked by:` edges, so only actionable work surfaces."
10
10
  },
11
11
  {