claude-dev-env 1.93.0 → 1.94.0
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/_shared/pr-loop/CLAUDE.md +1 -0
- package/_shared/pr-loop/audit-contract.md +1 -1
- package/_shared/pr-loop/gh-payloads.md +3 -3
- package/_shared/pr-loop/post-audit-thread-contract.md +51 -0
- package/_shared/pr-loop/scripts/README.md +2 -2
- package/_shared/pr-loop/scripts/code_rules_gate.py +127 -13
- package/_shared/pr-loop/scripts/fix_hookspath.py +47 -12
- package/_shared/pr-loop/scripts/pr_loop_shared_constants/code_rules_gate_constants.py +4 -0
- package/_shared/pr-loop/scripts/tests/test_code_rules_gate.py +146 -69
- package/_shared/pr-loop/scripts/tests/test_fix_hookspath.py +497 -374
- package/_shared/pr-loop/state-schema.md +3 -22
- package/bin/CLAUDE.md +1 -1
- package/bin/install.mjs +2 -7
- package/bin/install.test.mjs +10 -4
- package/hooks/blocking/CLAUDE.md +2 -0
- package/hooks/blocking/pii_commit_command.py +398 -0
- package/hooks/blocking/pii_payload_scan.py +133 -0
- package/hooks/blocking/pii_prevention_blocker.py +151 -449
- package/hooks/blocking/pii_scanner.py +26 -1
- package/hooks/blocking/test_code_rules_enforcer_dead_config_field.py +2 -2
- package/hooks/blocking/test_pii_prevention_blocker.py +299 -0
- package/hooks/blocking/test_pii_scanner.py +27 -2
- package/hooks/blocking/test_verdict_directory_write_blocker.py +42 -7
- package/hooks/hooks_constants/CLAUDE.md +2 -2
- package/hooks/hooks_constants/code_rules_path_utils_constants.py +0 -2
- package/hooks/hooks_constants/local_identity.py +65 -15
- package/hooks/hooks_constants/pii_prevention_constants.py +20 -8
- package/hooks/hooks_constants/pr_description_enforcer_constants.py +1 -1
- package/hooks/hooks_constants/test_local_identity.py +68 -0
- package/package.json +1 -1
- package/scripts/CLAUDE.md +10 -1
- package/scripts/Get-SessionAccount.ps1 +210 -0
- package/scripts/tests/CLAUDE.md +15 -1
- package/scripts/tests/Get-SessionAccount.Tests.ps1 +350 -0
- package/skills/CLAUDE.md +3 -25
- package/skills/anthropic-plan/SKILL.md +1 -13
- package/skills/autoconverge/CLAUDE.md +5 -2
- package/skills/autoconverge/SKILL.md +112 -387
- package/skills/autoconverge/reference/CLAUDE.md +4 -1
- package/skills/autoconverge/reference/closing-report.md +9 -2
- package/skills/autoconverge/reference/convergence.md +26 -22
- package/skills/autoconverge/reference/headless-safety.md +44 -0
- package/skills/autoconverge/reference/multi-pr.md +88 -0
- package/skills/autoconverge/reference/self-closing-loop.md +84 -0
- package/skills/autoconverge/reference/stop-conditions.md +21 -13
- package/skills/autoconverge/workflow/converge.clean-audit.test.mjs +87 -27
- package/skills/autoconverge/workflow/converge.contract.test.mjs +40 -10
- package/skills/autoconverge/workflow/converge.copilot-gate.test.mjs +179 -47
- package/skills/autoconverge/workflow/converge.fix-progress.test.mjs +1 -1
- package/skills/autoconverge/workflow/converge.mjs +284 -94
- package/skills/bugteam/CLAUDE.md +1 -1
- package/skills/bugteam/CONSTRAINTS.md +3 -3
- package/skills/bugteam/PROMPTS.md +8 -19
- package/skills/bugteam/SKILL.md +13 -14
- package/skills/bugteam/reference/CLAUDE.md +1 -1
- package/skills/bugteam/reference/audit-and-teammates.md +2 -2
- package/skills/bugteam/reference/copilot-gap-analysis.md +2 -0
- package/skills/bugteam/reference/github-pr-reviews.md +56 -38
- package/skills/bugteam/reference/team-setup.md +11 -11
- package/skills/bugteam/scripts/CLAUDE.md +6 -6
- package/skills/bugteam/scripts/README.md +20 -8
- package/skills/bugteam/scripts/bugteam_code_rules_gate.py +13 -1463
- package/skills/bugteam/scripts/bugteam_fix_hookspath.py +23 -358
- package/skills/bugteam/scripts/bugteam_preflight.py +13 -315
- package/skills/bugteam/scripts/bugteam_scripts_constants/CLAUDE.md +2 -3
- package/skills/bugteam/scripts/test_bugteam_code_rules_gate.py +34 -1053
- package/skills/bugteam/scripts/test_bugteam_fix_hookspath.py +30 -347
- package/skills/bugteam/scripts/test_bugteam_preflight.py +30 -305
- package/skills/copilot-finding-triage/SKILL.md +80 -28
- package/skills/copilot-finding-triage/reference/tier-rubric.md +70 -11
- package/skills/copilot-finding-triage/templates/notification.md +8 -3
- package/skills/everything-search/SKILL.md +1 -2
- package/skills/grokify/SKILL.md +58 -0
- package/skills/grokify/templates/handoff-template.md +92 -0
- package/skills/orchestrator/SKILL.md +12 -8
- package/skills/orchestrator-refresh/SKILL.md +3 -3
- package/skills/pr-converge/SKILL.md +132 -233
- package/skills/pr-converge/reference/convergence-gates.md +102 -66
- package/skills/pr-converge/reference/examples.md +37 -25
- package/skills/pr-converge/reference/fix-protocol.md +7 -7
- package/skills/pr-converge/reference/multi-pr-orchestration.md +10 -4
- package/skills/pr-converge/reference/per-tick.md +64 -41
- package/skills/pr-converge/reference/state-schema.md +27 -2
- package/skills/pr-converge/scripts/CLAUDE.md +8 -0
- package/skills/pr-converge/scripts/README.md +4 -3
- package/skills/pr-converge/scripts/_pr_converge_path_setup.py +23 -0
- package/skills/pr-converge/scripts/check_convergence.py +189 -645
- package/skills/pr-converge/scripts/check_convergence_gates.py +235 -0
- package/skills/pr-converge/scripts/check_convergence_thread_gates.py +219 -0
- package/skills/pr-converge/scripts/conftest.py +8 -0
- package/skills/pr-converge/scripts/pr_converge_scripts_constants/CLAUDE.md +1 -0
- package/skills/pr-converge/scripts/pr_converge_scripts_constants/convergence_gate_constants.py +36 -0
- package/skills/pr-converge/scripts/test__pr_converge_path_setup.py +26 -0
- package/skills/pr-converge/scripts/test_check_convergence.py +73 -228
- package/skills/pr-converge/scripts/test_check_convergence_contract.py +321 -0
- package/skills/pr-converge/scripts/test_check_convergence_gates.py +68 -0
- package/skills/pr-converge/scripts/test_check_convergence_thread_gates.py +75 -0
- package/skills/privacy-hygiene/SKILL.md +8 -7
- package/skills/reviewer-gates/SKILL.md +26 -8
- package/skills/session-log/SKILL.md +11 -12
- package/skills/session-tidy/SKILL.md +40 -30
- package/skills/skill-builder/CLAUDE.md +13 -10
- package/skills/skill-builder/SKILL.md +31 -31
- package/skills/skill-builder/references/CLAUDE.md +10 -6
- package/skills/skill-builder/references/delegation-map.md +13 -4
- package/skills/skill-builder/references/description-field.md +113 -0
- package/skills/skill-builder/references/self-audit-checklist.md +21 -4
- package/skills/skill-builder/references/skill-modularity.md +113 -0
- package/skills/skill-builder/references/skill-types.md +4 -0
- package/skills/skill-builder/templates/CLAUDE.md +4 -4
- package/skills/skill-builder/templates/gap-analysis.md +25 -1
- package/skills/skill-builder/workflows/CLAUDE.md +6 -4
- package/skills/skill-builder/workflows/improve-skill.md +17 -16
- package/skills/skill-builder/workflows/new-skill.md +34 -10
- package/skills/skill-builder/workflows/polish-skill.md +59 -43
- package/skills/usage-pause/SKILL.md +10 -14
- package/skills/bdd-protocol/CLAUDE.md +0 -26
- package/skills/bdd-protocol/SKILL.md +0 -30
- package/skills/bdd-protocol/references/CLAUDE.md +0 -10
- package/skills/bdd-protocol/references/anti-patterns.md +0 -26
- package/skills/bdd-protocol/references/example-mapping.md +0 -23
- package/skills/bg-agent/CLAUDE.md +0 -17
- package/skills/bg-agent/SKILL.md +0 -69
- package/skills/bugteam/scripts/bugteam_scripts_constants/bugteam_code_rules_gate_constants.py +0 -55
- package/skills/bugteam/scripts/bugteam_scripts_constants/bugteam_fix_hookspath_constants.py +0 -26
- package/skills/bugteam/scripts/bugteam_scripts_constants/bugteam_preflight_constants.py +0 -35
- package/skills/caveman/CLAUDE.md +0 -15
- package/skills/caveman/SKILL.md +0 -38
- package/skills/code/CLAUDE.md +0 -17
- package/skills/code/SKILL.md +0 -178
- package/skills/deep-research/CLAUDE.md +0 -17
- package/skills/deep-research/SKILL.md +0 -80
- package/skills/findbugs/CLAUDE.md +0 -20
- package/skills/findbugs/SKILL.md +0 -241
- package/skills/fixbugs/CLAUDE.md +0 -19
- package/skills/fixbugs/SKILL.md +0 -142
- package/skills/gh-paginate/CLAUDE.md +0 -18
- package/skills/gh-paginate/SKILL.md +0 -84
- package/skills/gotcha/CLAUDE.md +0 -33
- package/skills/gotcha/SKILL.md +0 -73
- package/skills/implement/CLAUDE.md +0 -27
- package/skills/implement/SKILL.md +0 -66
- package/skills/implement/scripts/CLAUDE.md +0 -22
- package/skills/implement/scripts/append_note.py +0 -133
- package/skills/implement/scripts/implement_scripts_constants/CLAUDE.md +0 -22
- package/skills/implement/scripts/implement_scripts_constants/__init__.py +0 -0
- package/skills/implement/scripts/implement_scripts_constants/notes_constants.py +0 -12
- package/skills/implement/scripts/test_append_note.py +0 -191
- package/skills/log-audit/CLAUDE.md +0 -20
- package/skills/log-audit/SKILL.md +0 -66
- package/skills/log-audit/reference/CLAUDE.md +0 -9
- package/skills/log-audit/reference/charter.md +0 -52
- package/skills/log-audit/scripts/CLAUDE.md +0 -27
- package/skills/log-audit/scripts/cluster_recurrences.py +0 -261
- package/skills/log-audit/scripts/collect_log_window.py +0 -199
- package/skills/log-audit/scripts/log_audit_constants/CLAUDE.md +0 -12
- package/skills/log-audit/scripts/log_audit_constants/__init__.py +0 -0
- package/skills/log-audit/scripts/log_audit_constants/cluster_recurrences_constants.py +0 -23
- package/skills/log-audit/scripts/log_audit_constants/collect_log_window_constants.py +0 -24
- package/skills/log-audit/scripts/log_audit_constants/mine_copilot_findings_constants.py +0 -49
- package/skills/log-audit/scripts/mine_copilot_findings.py +0 -302
- package/skills/log-audit/scripts/test_cluster_recurrences.py +0 -160
- package/skills/log-audit/scripts/test_collect_log_window.py +0 -111
- package/skills/log-audit/scripts/test_mine_copilot_findings.py +0 -126
- package/skills/logifix/CLAUDE.md +0 -36
- package/skills/logifix/SKILL.md +0 -69
- package/skills/logifix/scripts/CLAUDE.md +0 -16
- package/skills/logifix/scripts/logifix.ps1 +0 -205
- package/skills/monitor-open-prs/CLAUDE.md +0 -34
- package/skills/monitor-open-prs/SKILL.md +0 -88
- package/skills/monitor-open-prs/scripts/CLAUDE.md +0 -17
- package/skills/monitor-open-prs/scripts/discover_open_prs.py +0 -69
- package/skills/monitor-open-prs/scripts/test_discover_open_prs.py +0 -149
- package/skills/monitor-open-prs/test_skill_contract.py +0 -27
- package/skills/post-audit-findings/SKILL.md +0 -80
- package/skills/pr-consistency-audit/CLAUDE.md +0 -34
- package/skills/pr-consistency-audit/SKILL.md +0 -116
- package/skills/pr-consistency-audit/reference/CLAUDE.md +0 -16
- package/skills/pr-consistency-audit/reference/detection-rules.md +0 -96
- package/skills/pr-consistency-audit/reference/illustrations.md +0 -78
- package/skills/pr-fix-protocol/SKILL.md +0 -65
- package/skills/pr-review-responder/CLAUDE.md +0 -35
- package/skills/pr-review-responder/EXAMPLES.md +0 -590
- package/skills/pr-review-responder/PRINCIPLES.md +0 -533
- package/skills/pr-review-responder/README.md +0 -168
- package/skills/pr-review-responder/SKILL.md +0 -203
- package/skills/pr-review-responder/TESTING.md +0 -350
- package/skills/pr-scope-resolve/SKILL.md +0 -45
- package/skills/pre-compact/CLAUDE.md +0 -24
- package/skills/pre-compact/SKILL.md +0 -134
- package/skills/qbug/CLAUDE.md +0 -40
- package/skills/qbug/SKILL.md +0 -387
- package/skills/qbug/test_qbug_skill_audit_schema.py +0 -152
- package/skills/qbug/test_qbug_skill_post_fix_audit.py +0 -103
- package/skills/refine/CLAUDE.md +0 -44
- package/skills/refine/SKILL.md +0 -262
- package/skills/refine/templates/CLAUDE.md +0 -17
- package/skills/refine/templates/implementation-notes-template.html +0 -56
- package/skills/refine/templates/plan-template.md +0 -60
- package/skills/research-mode/CLAUDE.md +0 -35
- package/skills/research-mode/SKILL.md +0 -53
- package/skills/structure-prompt/CLAUDE.md +0 -42
- package/skills/structure-prompt/SKILL.md +0 -44
- package/skills/structure-prompt/reference/CLAUDE.md +0 -28
- package/skills/structure-prompt/reference/adversarial-tuning.md +0 -62
- package/skills/structure-prompt/reference/block-classification.md +0 -27
- package/skills/structure-prompt/reference/canonical-case.md +0 -48
- package/skills/structure-prompt/reference/citation-depth.md +0 -70
- package/skills/structure-prompt/reference/cleanup.md +0 -33
- package/skills/structure-prompt/reference/constraints.md +0 -33
- package/skills/structure-prompt/reference/directives.md +0 -37
- package/skills/structure-prompt/reference/examples.md +0 -72
- package/skills/structure-prompt/reference/instantiation.md +0 -51
- package/skills/structure-prompt/reference/output-contract.md +0 -72
- package/skills/structure-prompt/reference/per-category.md +0 -23
- package/skills/structure-prompt/reference/persona.md +0 -38
- package/skills/structure-prompt/reference/research.md +0 -33
- package/skills/structure-prompt/reference/structure.md +0 -28
- package/skills/verified-build/CLAUDE.md +0 -33
- package/skills/verified-build/SKILL.md +0 -33
package/skills/logifix/CLAUDE.md
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
# logifix skill
|
|
2
|
-
|
|
3
|
-
Restores the Logitech Gaming Software (LCore) tray icon when it disappears on Windows. Runs a PowerShell script that reproduces the verified recovery procedure.
|
|
4
|
-
|
|
5
|
-
**Trigger:** `/logifix`, "logitech tray icon missing", "LCore tray gone", "logitech is not loaded".
|
|
6
|
-
|
|
7
|
-
## Key files
|
|
8
|
-
|
|
9
|
-
| File | Purpose |
|
|
10
|
-
|---|---|
|
|
11
|
-
| `SKILL.md` | Full procedure description, invocation options, fallback steps |
|
|
12
|
-
| `scripts/logifix.ps1` | PowerShell script that runs the recovery procedure |
|
|
13
|
-
|
|
14
|
-
## Subdirectories
|
|
15
|
-
|
|
16
|
-
| Directory | Role |
|
|
17
|
-
|---|---|
|
|
18
|
-
| `scripts/` | The PowerShell recovery script |
|
|
19
|
-
|
|
20
|
-
## What the script does
|
|
21
|
-
|
|
22
|
-
1. Takes a state snapshot (Explorer instances, Logitech services, LCore process).
|
|
23
|
-
2. Stops LCore in user context.
|
|
24
|
-
3. Runs one elevated UAC step: starts `LogiRegistryService`, stops `explorer.exe`, and lets Windows shell auto-respawn rebuild it (does **not** call `Start-Process explorer` from the elevated block).
|
|
25
|
-
4. Waits for shell auto-respawn (default 5 seconds).
|
|
26
|
-
5. Confirms exactly one Explorer in the user's session.
|
|
27
|
-
6. Runs `LCoreRelaunchAttemptCount` full stop-then-launch cycles of `LCore.exe /minimized` (default 2). Always runs the full count.
|
|
28
|
-
7. Takes a final state snapshot.
|
|
29
|
-
|
|
30
|
-
## Invocation
|
|
31
|
-
|
|
32
|
-
```
|
|
33
|
-
/logifix
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
Optional parameters: `-ExplorerAutoRespawnWaitSeconds`, `-LCoreInitializationWaitSeconds`, `-LCoreRelaunchAttemptCount`.
|
package/skills/logifix/SKILL.md
DELETED
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: logifix
|
|
3
|
-
description: Restore the Logitech Gaming Software (LCore) tray icon when it disappears on Windows. Calls a PowerShell script that reproduces the verified Session 2 recovery procedure from 2026-04-25. Triggers on "logifix", "/logifix", "logitech tray icon missing", "LCore tray gone", "logitech is not loaded".
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# logifix
|
|
7
|
-
|
|
8
|
-
## Overview
|
|
9
|
-
|
|
10
|
-
Restore the Logitech Gaming Software (LCore) tray icon by reproducing the verified recovery procedure documented in `sessions/System Support/2. Logitech Tray Icon Fix Recurrence.md`.
|
|
11
|
-
|
|
12
|
-
**Announce at start:** "Running /logifix to restore the LCore tray icon."
|
|
13
|
-
|
|
14
|
-
## What the script does
|
|
15
|
-
|
|
16
|
-
`scripts/logifix.ps1` runs this sequence (verified during Session 2 on 2026-04-25):
|
|
17
|
-
|
|
18
|
-
1. **State snapshot.** Explorer instances per session, Logitech services state, LCore process state.
|
|
19
|
-
2. **Stop LCore in user context.** `Stop-Process -Name LCore -Force`.
|
|
20
|
-
3. **Single elevated UAC step:**
|
|
21
|
-
- `Start-Service -Name LogiRegistryService` (handles the recurrence case where the service is Stopped).
|
|
22
|
-
- `Stop-Process -Name explorer -Force`.
|
|
23
|
-
- **Does NOT** call `Start-Process explorer` from inside the elevated block. Windows shell auto-respawn handles the user-session explorer cleanly. Skipping this line is the operative fix discovered in Session 2 — including it created a duplicate admin-context `explorer.exe` (no resolvable owner, parent = the admin pwsh) that blocked LCore tray registration.
|
|
24
|
-
4. **Wait for Windows shell auto-respawn** (default 5 seconds).
|
|
25
|
-
5. **Verify exactly one explorer in the user's session.**
|
|
26
|
-
6. **Perform `LCoreRelaunchAttemptCount` full stop-then-launch cycles of `LCore.exe /minimized`** (default 2). The full count always runs — a responsive LCore on the first attempt does NOT imply the tray icon registered. Per Session 2 gotcha #2, the first relaunch can leave LCore responsive with no tray icon; only a second stop+launch reliably triggers `Shell_NotifyIcon` registration.
|
|
27
|
-
7. **Final state snapshot.**
|
|
28
|
-
|
|
29
|
-
## Invocation
|
|
30
|
-
|
|
31
|
-
From Claude Code:
|
|
32
|
-
|
|
33
|
-
```
|
|
34
|
-
/logifix
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
Direct PowerShell:
|
|
38
|
-
|
|
39
|
-
```
|
|
40
|
-
pwsh -File "$HOME\.claude\skills\logifix\scripts\logifix.ps1"
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
Optional parameters (all have safe defaults):
|
|
44
|
-
|
|
45
|
-
- `-ExplorerAutoRespawnWaitSeconds <int>` — wait after the elevated kill (default 5).
|
|
46
|
-
- `-LCoreInitializationWaitSeconds <int>` — wait after each LCore relaunch before checking responsiveness (default 5).
|
|
47
|
-
- `-LCoreRelaunchAttemptCount <int>` — number of LCore stop+launch cycles to perform (default 2). Always runs the full count.
|
|
48
|
-
|
|
49
|
-
## When to use
|
|
50
|
-
|
|
51
|
-
- LCore tray icon missing (also confirmed absent from the overflow `^` chevron).
|
|
52
|
-
- LCore process is running but the tray icon never appears.
|
|
53
|
-
- After resume from sleep, system restart, or a Logitech service crash that leaves LCore in a half-loaded state.
|
|
54
|
-
|
|
55
|
-
## Fallback (if the script does not restore the icon)
|
|
56
|
-
|
|
57
|
-
If `/logifix` reports that UAC was canceled, or LCore is still not responding after both relaunch cycles:
|
|
58
|
-
|
|
59
|
-
1. **Ctrl+Shift+Esc** → Task Manager.
|
|
60
|
-
2. Find **Windows Explorer** → right-click → **Restart**.
|
|
61
|
-
3. Re-run `/logifix`.
|
|
62
|
-
|
|
63
|
-
The Task Manager restart path is guaranteed to hit the correct interactive session and elevation context regardless of how the calling shell was launched. In Session 2, elevated calls from Claude Code's PowerShell tool could not be confirmed to reach the user's interactive Session 1 — Task Manager bypasses that ambiguity.
|
|
64
|
-
|
|
65
|
-
## Source
|
|
66
|
-
|
|
67
|
-
Procedure verified during Session 2 (Logitech Tray Icon Fix Recurrence), 2026-04-25. The session log lists the verified command set, the gotcha catalog, and the final process/service state.
|
|
68
|
-
|
|
69
|
-
The "always run the full relaunch count" behavior was added on 2026-04-26 after `/logifix` reported success on the first responsive attempt but the tray icon never appeared — the original early-break optimization conflicted with documented Session 2 gotcha #2 (responsive LCore, no tray icon).
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
# logifix/scripts
|
|
2
|
-
|
|
3
|
-
PowerShell recovery script for the `logifix` skill.
|
|
4
|
-
|
|
5
|
-
## Key files
|
|
6
|
-
|
|
7
|
-
| File | Purpose |
|
|
8
|
-
|---|---|
|
|
9
|
-
| `logifix.ps1` | Restores the LCore tray icon: stops LCore, runs one elevated UAC step (starts `LogiRegistryService`, stops explorer, lets Windows auto-respawn), then re-launches LCore a configurable number of times |
|
|
10
|
-
|
|
11
|
-
## Conventions
|
|
12
|
-
|
|
13
|
-
- The script accepts three optional parameters: `-ExplorerAutoRespawnWaitSeconds` (default 5), `-LCoreInitializationWaitSeconds` (default 5), `-LCoreRelaunchAttemptCount` (default 2).
|
|
14
|
-
- The full relaunch count always runs — an early-exit on a responsive LCore is intentional behavior per the recovery procedure.
|
|
15
|
-
- The elevated block does **not** call `Start-Process explorer`; Windows shell auto-respawn handles that to avoid a duplicate admin-context Explorer.
|
|
16
|
-
- Run directly as: `pwsh -File "$HOME\.claude\skills\logifix\scripts\logifix.ps1"`.
|
|
@@ -1,205 +0,0 @@
|
|
|
1
|
-
<#
|
|
2
|
-
.SYNOPSIS
|
|
3
|
-
Restores the Logitech Gaming Software (LCore) tray icon when it is missing on Windows.
|
|
4
|
-
|
|
5
|
-
.DESCRIPTION
|
|
6
|
-
Reproduces the verified recovery procedure from
|
|
7
|
-
sessions/System Support/2. Logitech Tray Icon Fix Recurrence.md (2026-04-25):
|
|
8
|
-
1. Stops LCore in user context.
|
|
9
|
-
2. Single elevated UAC step:
|
|
10
|
-
- Starts LogiRegistryService (handles the case where it is Stopped).
|
|
11
|
-
- Stops explorer.exe and lets Windows shell auto-respawn rebuild it.
|
|
12
|
-
Deliberately omits Start-Process explorer from the elevated block to
|
|
13
|
-
avoid the duplicate admin-context explorer that blocked tray registration
|
|
14
|
-
during Session 2.
|
|
15
|
-
3. Waits for shell auto-respawn.
|
|
16
|
-
4. Verifies a single user-session explorer.
|
|
17
|
-
5. Performs LCoreRelaunchAttemptCount full stop-then-launch cycles of
|
|
18
|
-
LCore /minimized. Always runs the full count: a responsive LCore on the
|
|
19
|
-
first attempt does NOT imply Shell_NotifyIcon registered, per Session 2
|
|
20
|
-
gotcha #2 (responsive process, no tray icon).
|
|
21
|
-
|
|
22
|
-
.PARAMETER ExplorerAutoRespawnWaitSeconds
|
|
23
|
-
Seconds to wait after the elevated explorer kill before verifying respawn.
|
|
24
|
-
|
|
25
|
-
.PARAMETER LCoreInitializationWaitSeconds
|
|
26
|
-
Seconds to wait after each LCore relaunch before checking responsiveness.
|
|
27
|
-
|
|
28
|
-
.PARAMETER LCoreRelaunchAttemptCount
|
|
29
|
-
Total number of LCore relaunch cycles to perform (default 2). The full count
|
|
30
|
-
always runs, because the documented failure mode is a responsive LCore that
|
|
31
|
-
never registered a tray icon -- only a second stop+launch reliably triggers
|
|
32
|
-
Shell_NotifyIcon registration.
|
|
33
|
-
#>
|
|
34
|
-
|
|
35
|
-
[CmdletBinding()]
|
|
36
|
-
param(
|
|
37
|
-
[int] $ExplorerAutoRespawnWaitSeconds = 5,
|
|
38
|
-
[int] $LCoreInitializationWaitSeconds = 5,
|
|
39
|
-
[int] $LCoreRelaunchAttemptCount = 2
|
|
40
|
-
)
|
|
41
|
-
|
|
42
|
-
Set-StrictMode -Version Latest
|
|
43
|
-
$ErrorActionPreference = 'Stop'
|
|
44
|
-
|
|
45
|
-
$script:LCoreExecutablePath = 'C:\Program Files\Logitech Gaming Software\LCore.exe'
|
|
46
|
-
$script:LCoreProcessName = 'LCore'
|
|
47
|
-
|
|
48
|
-
function Get-CurrentInteractiveSessionId {
|
|
49
|
-
[OutputType([int])]
|
|
50
|
-
param()
|
|
51
|
-
return (Get-CimInstance Win32_Process -Filter "ProcessId=$PID").SessionId
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
function Get-ExplorerProcessesInSession {
|
|
55
|
-
[OutputType([object[]])]
|
|
56
|
-
param([Parameter(Mandatory)] [int] $TargetSessionId)
|
|
57
|
-
$allExplorers = Get-CimInstance Win32_Process -Filter "Name='explorer.exe'"
|
|
58
|
-
$matchingExplorers = @()
|
|
59
|
-
foreach ($eachExplorer in $allExplorers) {
|
|
60
|
-
if ($eachExplorer.SessionId -ne $TargetSessionId) { continue }
|
|
61
|
-
$ownerInfo = Invoke-CimMethod -InputObject $eachExplorer -MethodName GetOwner -ErrorAction SilentlyContinue
|
|
62
|
-
$matchingExplorers += [PSCustomObject]@{
|
|
63
|
-
ProcessId = $eachExplorer.ProcessId
|
|
64
|
-
SessionId = $eachExplorer.SessionId
|
|
65
|
-
OwnerUser = if ($ownerInfo) { $ownerInfo.User } else { $null }
|
|
66
|
-
CreationDate = $eachExplorer.CreationDate
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
return ,$matchingExplorers
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
function Stop-LCoreIfRunning {
|
|
73
|
-
[OutputType([void])]
|
|
74
|
-
param()
|
|
75
|
-
$stopSettleMilliseconds = 500
|
|
76
|
-
Stop-Process -Name $script:LCoreProcessName -Force -ErrorAction SilentlyContinue
|
|
77
|
-
Start-Sleep -Milliseconds $stopSettleMilliseconds
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
function Invoke-ElevatedExplorerRebuild {
|
|
81
|
-
[OutputType([bool])]
|
|
82
|
-
param()
|
|
83
|
-
$elevatedScriptBlockText = @'
|
|
84
|
-
Start-Service -Name LogiRegistryService -ErrorAction SilentlyContinue
|
|
85
|
-
Stop-Process -Name explorer -Force -ErrorAction SilentlyContinue
|
|
86
|
-
'@
|
|
87
|
-
$encodedElevatedCommand = [Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($elevatedScriptBlockText))
|
|
88
|
-
try {
|
|
89
|
-
Start-Process -FilePath 'pwsh' `
|
|
90
|
-
-ArgumentList '-NoProfile', '-EncodedCommand', $encodedElevatedCommand `
|
|
91
|
-
-Verb RunAs `
|
|
92
|
-
-Wait `
|
|
93
|
-
-ErrorAction Stop
|
|
94
|
-
return $true
|
|
95
|
-
} catch {
|
|
96
|
-
Write-Warning "Elevated step did not run: $($_.Exception.Message)"
|
|
97
|
-
return $false
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
function Start-LCoreMinimized {
|
|
102
|
-
[OutputType([void])]
|
|
103
|
-
param()
|
|
104
|
-
$launchArguments = '/minimized'
|
|
105
|
-
Start-Process -FilePath $script:LCoreExecutablePath -ArgumentList $launchArguments
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
function Test-LCoreIsResponding {
|
|
109
|
-
[OutputType([bool])]
|
|
110
|
-
param([Parameter(Mandatory)] [int] $WaitSeconds)
|
|
111
|
-
Start-Sleep -Seconds $WaitSeconds
|
|
112
|
-
$lcoreProcesses = Get-Process -Name $script:LCoreProcessName -ErrorAction SilentlyContinue
|
|
113
|
-
if (-not $lcoreProcesses) { return $false }
|
|
114
|
-
foreach ($eachLCore in @($lcoreProcesses)) {
|
|
115
|
-
if (-not $eachLCore.Responding) { return $false }
|
|
116
|
-
}
|
|
117
|
-
return $true
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
function Write-StateSnapshot {
|
|
121
|
-
[OutputType([void])]
|
|
122
|
-
param([Parameter(Mandatory)] [string] $Label)
|
|
123
|
-
$logitechServiceNamesToVerify = @('LogiRegistryService', 'logi_lamparray_service')
|
|
124
|
-
Write-Host ""
|
|
125
|
-
Write-Host "=== $Label ==="
|
|
126
|
-
$sessionId = Get-CurrentInteractiveSessionId
|
|
127
|
-
$explorersInSession = Get-ExplorerProcessesInSession -TargetSessionId $sessionId
|
|
128
|
-
Write-Host "Explorer instances in session ${sessionId}: $($explorersInSession.Count)"
|
|
129
|
-
if ($explorersInSession.Count -gt 0) {
|
|
130
|
-
$explorersInSession | Format-Table ProcessId, OwnerUser, CreationDate -AutoSize | Out-String | Write-Host
|
|
131
|
-
}
|
|
132
|
-
$servicesObserved = Get-Service -Name $logitechServiceNamesToVerify -ErrorAction SilentlyContinue
|
|
133
|
-
if ($servicesObserved) {
|
|
134
|
-
$servicesObserved | Format-Table Name, Status -AutoSize | Out-String | Write-Host
|
|
135
|
-
}
|
|
136
|
-
$lcoreProcessesObserved = Get-Process -Name $script:LCoreProcessName -ErrorAction SilentlyContinue
|
|
137
|
-
if ($lcoreProcessesObserved) {
|
|
138
|
-
$lcoreProcessesObserved | Select-Object Id, Responding | Format-Table -AutoSize | Out-String | Write-Host
|
|
139
|
-
} else {
|
|
140
|
-
Write-Host "LCore not running."
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
function Invoke-LogifixRecovery {
|
|
145
|
-
[OutputType([void])]
|
|
146
|
-
param()
|
|
147
|
-
|
|
148
|
-
Write-StateSnapshot -Label 'Before'
|
|
149
|
-
|
|
150
|
-
if (-not (Test-Path -Path $script:LCoreExecutablePath)) {
|
|
151
|
-
Write-Error "LCore.exe not found at expected path: $script:LCoreExecutablePath"
|
|
152
|
-
return
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
Stop-LCoreIfRunning
|
|
156
|
-
|
|
157
|
-
$elevatedSucceeded = Invoke-ElevatedExplorerRebuild
|
|
158
|
-
if (-not $elevatedSucceeded) {
|
|
159
|
-
Write-Warning "UAC was canceled or the elevated step failed."
|
|
160
|
-
Write-Warning "Fallback: open Task Manager (Ctrl+Shift+Esc), find 'Windows Explorer', right-click, Restart. Then re-run /logifix."
|
|
161
|
-
return
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
Start-Sleep -Seconds $ExplorerAutoRespawnWaitSeconds
|
|
165
|
-
|
|
166
|
-
$sessionId = Get-CurrentInteractiveSessionId
|
|
167
|
-
$explorersAfterRespawn = Get-ExplorerProcessesInSession -TargetSessionId $sessionId
|
|
168
|
-
$explorerCountAfterRespawn = @($explorersAfterRespawn).Count
|
|
169
|
-
if ($explorerCountAfterRespawn -ne 1) {
|
|
170
|
-
if ($explorerCountAfterRespawn -eq 0) {
|
|
171
|
-
Write-Warning "No explorer.exe found in session $sessionId after $ExplorerAutoRespawnWaitSeconds-second wait."
|
|
172
|
-
} else {
|
|
173
|
-
Write-Warning "Expected exactly 1 explorer.exe in session $sessionId after shell auto-respawn, but found $explorerCountAfterRespawn."
|
|
174
|
-
Write-Warning "Multiple explorer.exe processes in the same session reproduce the Session 2 duplicate-explorer failure mode that blocks tray icon registration."
|
|
175
|
-
$explorersAfterRespawn | Format-Table ProcessId, OwnerUser, CreationDate -AutoSize | Out-String | Write-Host
|
|
176
|
-
}
|
|
177
|
-
Write-Warning "Restart Explorer manually via Task Manager (Ctrl+Shift+Esc, Windows Explorer, Restart), then re-run /logifix."
|
|
178
|
-
return
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
$lastAttemptResponded = $false
|
|
182
|
-
for ($attemptIndex = 1; $attemptIndex -le $LCoreRelaunchAttemptCount; $attemptIndex++) {
|
|
183
|
-
Stop-LCoreIfRunning
|
|
184
|
-
Start-LCoreMinimized
|
|
185
|
-
$lastAttemptResponded = Test-LCoreIsResponding -WaitSeconds $LCoreInitializationWaitSeconds
|
|
186
|
-
if ($lastAttemptResponded) {
|
|
187
|
-
Write-Host "LCore relaunch attempt ${attemptIndex}: process is responding."
|
|
188
|
-
} else {
|
|
189
|
-
Write-Warning "LCore relaunch attempt ${attemptIndex}: process not responding."
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
Write-StateSnapshot -Label 'After'
|
|
194
|
-
|
|
195
|
-
if (-not $lastAttemptResponded) {
|
|
196
|
-
Write-Warning "LCore did not respond after $LCoreRelaunchAttemptCount attempts."
|
|
197
|
-
Write-Warning "Use Task Manager to Restart Windows Explorer, then re-run /logifix."
|
|
198
|
-
return
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
Write-Host ""
|
|
202
|
-
Write-Host "Recovery complete ($LCoreRelaunchAttemptCount stop+launch cycles performed). If the tray icon is still not visible, use Task Manager to Restart Windows Explorer (guaranteed correct session/elevation), then re-run /logifix."
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
Invoke-LogifixRecovery
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
# monitor-open-prs skill
|
|
2
|
-
|
|
3
|
-
Discovers every open pull request across the `jl-cmd/*` and `JonEcho/*` owner scopes, dispatches `/bugteam` on each with the `--bugbot-retrigger` flag, and polls for new Cursor bugbot replies after each bugteam run.
|
|
4
|
-
|
|
5
|
-
**Trigger:** `/monitor-open-prs`, "sweep the open PRs", "audit the open PR backlog".
|
|
6
|
-
|
|
7
|
-
## Key files
|
|
8
|
-
|
|
9
|
-
| File | Purpose |
|
|
10
|
-
|---|---|
|
|
11
|
-
| `SKILL.md` | Full workflow: refusal cases, discovery, dispatch, post-convergence polling, final report |
|
|
12
|
-
| `test_skill_contract.py` | Contract tests for the skill |
|
|
13
|
-
| `packages/claude-dev-env/skills/monitor-open-prs/scripts/discover_open_prs.py` | Shells out to `gh search prs` per owner scope and flattens results to a uniform dict shape |
|
|
14
|
-
| `packages/claude-dev-env/skills/monitor-open-prs/scripts/test_discover_open_prs.py` | Tests for the discovery helper |
|
|
15
|
-
|
|
16
|
-
## Subdirectories
|
|
17
|
-
|
|
18
|
-
| Directory | Role |
|
|
19
|
-
|---|---|
|
|
20
|
-
| `scripts/` | Discovery helper and its tests |
|
|
21
|
-
|
|
22
|
-
## Workflow summary
|
|
23
|
-
|
|
24
|
-
1. Call `discover_open_prs.discover_open_prs(all_owners=["jl-cmd", "JonEcho"])` to get the full open-PR list.
|
|
25
|
-
2. For each PR, invoke `/bugteam <pr_number>`; include `--bugbot-retrigger` only when bugbot is enabled (`reviews_disabled.py --reviewer bugbot` exits 1).
|
|
26
|
-
3. After each bugteam run, poll for new bugbot comments on a 60s → 120s → 240s → 480s → 960s backoff. Re-invoke bugteam if new findings appear.
|
|
27
|
-
4. Emit a sweep summary when all PRs exit polling.
|
|
28
|
-
|
|
29
|
-
## Refusals (checked first)
|
|
30
|
-
|
|
31
|
-
- `CLAUDE_REVIEWS_DISABLED` has `bugteam` → stop with a message.
|
|
32
|
-
- GitHub API not accessible → stop.
|
|
33
|
-
- Uncommitted changes in the caller's repo → stop.
|
|
34
|
-
- Required subagent types missing (`code-quality-agent`, `clean-coder`) → stop.
|
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: monitor-open-prs
|
|
3
|
-
description: >-
|
|
4
|
-
Discover every open pull request across the jl-cmd/* and JonEcho/*
|
|
5
|
-
owner scopes, spawn /bugteam on each in parallel with the bugbot
|
|
6
|
-
re-trigger flag (--bugbot-retrigger), and poll Cursor's bugbot replies
|
|
7
|
-
after convergence so any post-bugteam findings loop back through
|
|
8
|
-
/bugteam. Triggers: '/monitor-open-prs', 'sweep the open PRs',
|
|
9
|
-
'audit the open PR backlog'.
|
|
10
|
-
---
|
|
11
|
-
|
|
12
|
-
# Monitor Open PRs
|
|
13
|
-
|
|
14
|
-
**Core principle:** One sweep covers every open PR across both owner scopes. Claude discovers PRs live via `scripts/discover_open_prs.py` which shells out to `gh search prs --owner <owner> --state open --json ...`, dispatches `/bugteam --bugbot-retrigger` per PR, then polls Cursor's bugbot replies until each PR is quiet for a full backoff cycle.
|
|
15
|
-
|
|
16
|
-
## Contents
|
|
17
|
-
|
|
18
|
-
- Transport check — gh presence and auth route the sweep local or through the cloud transport
|
|
19
|
-
- When this skill applies — refusal cases and trigger conditions
|
|
20
|
-
- Discovery — `scripts/discover_open_prs.py` queries via `gh search prs` across both owner scopes
|
|
21
|
-
- Dispatch — `/bugteam --bugbot-retrigger <pr_numbers...>`
|
|
22
|
-
- Post-convergence polling — bugbot replies and re-invocation
|
|
23
|
-
- `scripts/discover_open_prs.py` — the discovery helper
|
|
24
|
-
|
|
25
|
-
## Transport check (before any GitHub step)
|
|
26
|
-
|
|
27
|
-
Run `command -v gh`; when it succeeds, run `gh auth status`; for each PR the sweep dispatches, `gh api repos/<owner>/<repo> --jq .permissions.push` must print `true`. When any check fails, run the `pr-loop-cloud-transport` skill first and route every `gh` operation in this skill through its substitution matrix, including the discovery query (`mcp__github__search_pull_requests` with `perPage` in place of `gh search prs`).
|
|
28
|
-
|
|
29
|
-
## When this skill applies
|
|
30
|
-
|
|
31
|
-
`/monitor-open-prs` authorizes one full sweep over all open PRs in both owner scopes.
|
|
32
|
-
|
|
33
|
-
Refusals — first match wins; respond with the quoted line exactly and stop:
|
|
34
|
-
|
|
35
|
-
- **Disabled via environment.** When `CLAUDE_REVIEWS_DISABLED` (comma-separated, case-insensitive, whitespace-tolerant) has the token `bugteam`: `/monitor-open-prs is a /bugteam dispatcher and /bugteam is disabled via CLAUDE_REVIEWS_DISABLED.` Gate semantics live in the `reviewer-gates` skill ([../reviewer-gates/SKILL.md](../reviewer-gates/SKILL.md)).
|
|
36
|
-
- **GitHub API not accessible.** `get_me failed. /monitor-open-prs needs active GitHub MCP credentials.`
|
|
37
|
-
- **Dirty tree on the caller's repo.** `Uncommitted changes detected. Stash, commit, or revert before /monitor-open-prs.`
|
|
38
|
-
- **Required subagents missing.** Confirm `code-quality-agent` and `clean-coder` exist. Else: `Required subagent type <name> not installed.`
|
|
39
|
-
|
|
40
|
-
## Discovery
|
|
41
|
-
|
|
42
|
-
Call `scripts/discover_open_prs.discover_open_prs(all_owners=["jl-cmd", "JonEcho"])` to merge the live open-PR list across both scopes. The helper shells out to `gh search prs --owner <owner> --state open --json number,repository,url,headRefName,baseRefName` for each owner scope and flattens the result to a uniform dict shape with keys `number`, `owner`, `repo`, `head_ref`, `base_ref`, `url`. Empty scopes contribute empty lists; an entirely empty sweep returns `[]` and exits cleanly.
|
|
43
|
-
|
|
44
|
-
## Dispatch
|
|
45
|
-
|
|
46
|
-
For each discovered PR:
|
|
47
|
-
|
|
48
|
-
1. Resolve the PR's repo checkout (existing worktree or fresh `git clone`).
|
|
49
|
-
2. From that checkout, invoke `/bugteam <pr_number>`. Include `--bugbot-retrigger` only when bugbot is enabled for the run — when `python "$HOME/.claude/_shared/pr-loop/scripts/reviews_disabled.py" --reviewer bugbot` exits 1. On exit 0 (bugbot disabled — the default) omit `--bugbot-retrigger` so the bugbot leg sits out the run.
|
|
50
|
-
3. The `--bugbot-retrigger` flag tells bugteam to post `bugbot run` as an issue comment after every successful FIX push so Cursor's bugbot re-evaluates the new commit.
|
|
51
|
-
4. Bugteam runs its own 20-loop audit/fix cycle per PR; this skill waits for each bugteam invocation to return before dispatching the next (or fanning out — see below).
|
|
52
|
-
|
|
53
|
-
**Fan-out (optional):** when the discovered list has more than one PR, the skill may spawn `/bugteam` dispatches in parallel by issuing multiple `Agent` calls in a single assistant message. Each dispatch operates in its own per-PR worktree (bugteam Step 1.1). Serialize when the caller sets an explicit `--serial` flag.
|
|
54
|
-
|
|
55
|
-
## Post-Convergence Polling
|
|
56
|
-
|
|
57
|
-
After a `/bugteam` invocation returns (converged, cap reached, stuck, or error), the PR may accumulate new Cursor bugbot comments within minutes. Poll for them:
|
|
58
|
-
|
|
59
|
-
1. Baseline: capture `since_timestamp` as the PR's last commit timestamp.
|
|
60
|
-
2. Every 60 seconds, call `pull_request_read(method="get", pullNumber=<pr_number>, owner=<owner>, repo=<repo>)` and filter the response's `comments` array for entries whose `.author.login` matches `"bugbot"` or `"cursor"` and `.createdAt` is after `<since_timestamp>`.
|
|
61
|
-
3. Back off: 60s → 120s → 240s → 480s → 960s. If five successive polls return empty, exit polling for this PR.
|
|
62
|
-
4. If bugbot posts a new finding in any poll, re-invoke `/bugteam <pr_number>` with the bugbot finding text seeded into the invocation's `bugs_to_fix` preamble. Reset the backoff.
|
|
63
|
-
|
|
64
|
-
### Polling Cost and Cadence
|
|
65
|
-
|
|
66
|
-
The five-step backoff sums to `60 + 120 + 240 + 480 + 960 = 1860` seconds (~31 minutes) of idle polling per PR before the skill declares bugbot quiet. A sweep over ten open PRs therefore retains up to ~5 wall-clock hours of bugbot-watch time beyond the active `/bugteam` work. Callers who need faster turnaround should pass `--serial` to disable fan-out (so polling starts only after the previous PR finishes) or accept the tradeoff: the backoff exists specifically to catch late bugbot analyses that can take several minutes to appear after a push.
|
|
67
|
-
|
|
68
|
-
## Final Report
|
|
69
|
-
|
|
70
|
-
After every PR has exited polling, emit:
|
|
71
|
-
|
|
72
|
-
```
|
|
73
|
-
/monitor-open-prs sweep summary
|
|
74
|
-
PRs discovered: <N>
|
|
75
|
-
jl-cmd/*: <count>
|
|
76
|
-
JonEcho/*: <count>
|
|
77
|
-
PRs converged clean: <count>
|
|
78
|
-
PRs hit 20-loop cap: <count>
|
|
79
|
-
PRs stuck: <count>
|
|
80
|
-
PRs errored: <count>
|
|
81
|
-
Bugbot re-triggers fired: <count>
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
## Non-Negotiable Guardrails
|
|
85
|
-
|
|
86
|
-
- Never pass `--no-verify` or `--no-gpg-sign` to git in any dispatched bugteam run.
|
|
87
|
-
- Never open a PR from this skill; only comment on existing ones.
|
|
88
|
-
- Never merge or close PRs; the skill is read + audit + patch only.
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
# monitor-open-prs/scripts
|
|
2
|
-
|
|
3
|
-
Discovery helper for the `monitor-open-prs` skill.
|
|
4
|
-
|
|
5
|
-
## Key files
|
|
6
|
-
|
|
7
|
-
| File | Purpose |
|
|
8
|
-
|---|---|
|
|
9
|
-
| `discover_open_prs.py` | Queries `gh search prs` for each owner scope and flattens results to a uniform list of dicts |
|
|
10
|
-
| `test_discover_open_prs.py` | Tests for the discovery helper |
|
|
11
|
-
|
|
12
|
-
## Conventions
|
|
13
|
-
|
|
14
|
-
- `discover_open_prs(all_owners: list[str]) -> list[dict]` is the single entry point. It shells out to `gh search prs --owner <owner> --state open --json number,repository,url,headRefName,baseRefName` once per owner and merges the results.
|
|
15
|
-
- Each returned dict has keys: `number`, `owner`, `repo`, `head_ref`, `base_ref`, `url`.
|
|
16
|
-
- An empty scope or an empty sweep returns an empty list and exits cleanly with no errors.
|
|
17
|
-
- The module is stateless and has no filesystem side effects.
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
"""Discover every open pull request across a list of owner scopes.
|
|
2
|
-
|
|
3
|
-
Shells out to ``gh search prs --owner <owner> --state open --json ...`` once per
|
|
4
|
-
owner, parses the JSON output, and flattens each entry to a uniform dict shape.
|
|
5
|
-
The module is stateless, takes no filesystem side effects, and exposes a single
|
|
6
|
-
``discover_open_prs`` entry point consumed by the monitor-open-prs skill.
|
|
7
|
-
"""
|
|
8
|
-
|
|
9
|
-
from __future__ import annotations
|
|
10
|
-
|
|
11
|
-
import json
|
|
12
|
-
import subprocess
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
def build_gh_search_argv(owner: str) -> list[str]:
|
|
16
|
-
gh_command_name = "gh"
|
|
17
|
-
search_subcommand = ("search", "prs")
|
|
18
|
-
owner_flag = "--owner"
|
|
19
|
-
state_flag = "--state"
|
|
20
|
-
state_open_value = "open"
|
|
21
|
-
json_fields_flag = "--json"
|
|
22
|
-
json_fields_value = "number,repository,url,headRefName,baseRefName"
|
|
23
|
-
return [
|
|
24
|
-
gh_command_name,
|
|
25
|
-
*search_subcommand,
|
|
26
|
-
owner_flag,
|
|
27
|
-
owner,
|
|
28
|
-
state_flag,
|
|
29
|
-
state_open_value,
|
|
30
|
-
json_fields_flag,
|
|
31
|
-
json_fields_value,
|
|
32
|
-
]
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
def split_repository_name(name_with_owner: str) -> tuple[str, str]:
|
|
36
|
-
repo_separator = "/"
|
|
37
|
-
if repo_separator not in name_with_owner:
|
|
38
|
-
return "", name_with_owner
|
|
39
|
-
owner_segment, repository_segment = name_with_owner.split(repo_separator, 1)
|
|
40
|
-
return owner_segment, repository_segment
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
def flatten_pr_entry(raw_pr_entry: dict) -> dict:
|
|
44
|
-
name_with_owner = raw_pr_entry.get("repository", {}).get("nameWithOwner", "")
|
|
45
|
-
owner_segment, repository_segment = split_repository_name(name_with_owner)
|
|
46
|
-
return {
|
|
47
|
-
"number": raw_pr_entry.get("number"),
|
|
48
|
-
"owner": owner_segment,
|
|
49
|
-
"repo": repository_segment,
|
|
50
|
-
"head_ref": raw_pr_entry.get("headRefName", ""),
|
|
51
|
-
"base_ref": raw_pr_entry.get("baseRefName", ""),
|
|
52
|
-
"url": raw_pr_entry.get("url", ""),
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
def fetch_open_prs_for_owner(owner: str) -> list[dict]:
|
|
57
|
-
search_argv = build_gh_search_argv(owner)
|
|
58
|
-
completed_process = subprocess.run(
|
|
59
|
-
search_argv, check=True, capture_output=True, text=True
|
|
60
|
-
)
|
|
61
|
-
raw_pr_entries = json.loads(completed_process.stdout)
|
|
62
|
-
return [flatten_pr_entry(each_entry) for each_entry in raw_pr_entries]
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
def discover_open_prs(all_owners: list[str]) -> list[dict]:
|
|
66
|
-
all_discovered: list[dict] = []
|
|
67
|
-
for each_owner in all_owners:
|
|
68
|
-
all_discovered.extend(fetch_open_prs_for_owner(each_owner))
|
|
69
|
-
return all_discovered
|