feat: publish curated marketplace artifacts#35
Conversation
Signed-off-by: Michael Kantor <6068672+kantorcodes@users.noreply.github.com>
Code Review SummaryStatus: 2 Issues Found | Recommendation: Address before merge Overview
Issue Details (click to expand)WARNING
Other Observations (not in diff)Issues found in unchanged code that cannot receive inline comments:
Files Reviewed (4 files)
The PR introduces a solid foundation for publishing curated marketplace artifacts. The main concerns are around error handling in the sync script — network and parsing failures should be handled gracefully to prevent the workflow from failing completely when a single plugin has issues. Reviewed by minimax-m2.5-20260211 · 848,800 tokens |
There was a problem hiding this comment.
Code Review
This pull request introduces a plugin marketplace for Codex and adds several new plugins for persistent memory, task scheduling, and electronics design. The review feedback identifies several technical issues in the KiCad design scripts, specifically pointing out incomplete token expiry handling and redundant authentication logic in the DigiKey synchronization process. Additionally, the feedback highlights fragile CLI argument parsing for backwards compatibility and provides a code suggestion to handle potential errors when reading from standard input.
| if result.get("status") == "not_found" and "No DigiKey results" in result.get("error", ""): | ||
| pass | ||
|
|
There was a problem hiding this comment.
The token expiry handling logic is incomplete and currently does nothing. Since the DigiKey OAuth token has a short lifetime (10 minutes) and the sync process can take much longer due to the 1-second delay between calls, the script will fail for projects with many components. The "refresh once and retry" logic should be implemented, and it should also be applied to the parallel execution path (line 617).
| # Read updates | ||
| if args.updates: | ||
| updates = json.loads(args.updates.read_text()) | ||
| elif not sys.stdin.isatty(): |
There was a problem hiding this comment.
json.load(sys.stdin) will raise a JSONDecodeError if the redirected input is empty. It's safer to check if the input is empty or wrap the call in a try-except block to provide a cleaner error message.
| elif not sys.stdin.isatty(): | |
| try: | |
| updates = json.load(sys.stdin) | |
| except json.JSONDecodeError: | |
| print("Error: stdin is empty or not valid JSON", file=sys.stderr) | |
| sys.exit(1) |
| def get_oauth_token() -> tuple[str, str] | None: | ||
| """Get DigiKey OAuth token. Returns (token, client_id) or None.""" | ||
| client_id = os.environ.get("DIGIKEY_CLIENT_ID", "") | ||
| client_secret = os.environ.get("DIGIKEY_CLIENT_SECRET", "") | ||
| if not client_id or not client_secret: | ||
| print("Error: DIGIKEY_CLIENT_ID and DIGIKEY_CLIENT_SECRET environment variables required.", | ||
| file=sys.stderr) | ||
| print(" Get credentials at developer.digikey.com → My Apps → Create App", | ||
| file=sys.stderr) | ||
| return None | ||
|
|
||
| try: | ||
| token_data = urllib.parse.urlencode({ | ||
| "client_id": client_id, | ||
| "client_secret": client_secret, | ||
| "grant_type": "client_credentials", | ||
| }).encode() | ||
| req = urllib.request.Request( | ||
| "https://api.digikey.com/v1/oauth2/token", | ||
| data=token_data, | ||
| headers={"Content-Type": "application/x-www-form-urlencoded"}, | ||
| ) | ||
| with urllib.request.urlopen(req, timeout=15) as resp: | ||
| token_resp = json.loads(resp.read()) | ||
| token = token_resp.get("access_token", "") | ||
| if not token: | ||
| print("Error: Failed to get OAuth token", file=sys.stderr) | ||
| return None | ||
| return token, client_id | ||
| except Exception as e: | ||
| print(f"Error: OAuth failed: {e}", file=sys.stderr) | ||
| return None |
There was a problem hiding this comment.
This file defines its own get_oauth_token which does not implement caching, while the sibling script fetch_datasheet_digikey.py (which is already imported) has a more robust implementation with temp-file caching. Reusing the cached version would avoid redundant authentication calls and help manage the 10-minute token lifetime more effectively across multiple script invocations.
| if len(sys.argv) > 1 and sys.argv[1].endswith(".kicad_sch"): | ||
| sys.argv.insert(1, "analyze") |
There was a problem hiding this comment.
This backwards compatibility logic is fragile because it only works if the .kicad_sch file is the first argument. If a user provides global flags before the filename (e.g., python3 bom_manager.py --recursive schematic.kicad_sch), the check will fail and argparse will raise an error because --recursive is not a valid subcommand.
Purpose
Publish a real Codex repo marketplace for the curated awesome list so private consumers can ingest
.agents/plugins/marketplace.jsoninstead of scraping the legacy compatibility JSON.Changes
.agents/plugins/marketplace.jsonfrom the README listplugins/<owner>/<repo>/plugins.jsonas a compatibility export during migrationVerification
python3 scripts/generate_plugins_json.pypython3 -m py_compile scripts/generate_plugins_json.py