Skip to content

fix(plugin): support installing from .zip URL#2126

Merged
tempurai merged 3 commits intomainfrom
fix-plugin-install-zip-url
Apr 30, 2026
Merged

fix(plugin): support installing from .zip URL#2126
tempurai merged 3 commits intomainfrom
fix-plugin-install-zip-url

Conversation

@tempurai
Copy link
Copy Markdown
Collaborator

@tempurai tempurai commented Apr 30, 2026

Summary

  • kimi plugin install now accepts http(s) URLs that point to a .zip archive — the file is streamed to a temp dir via httpx and then runs through the existing extraction path.
  • The zip URL branch is checked before the git-URL heuristic, so GitHub/GitLab archive links such as https://github.com/owner/repo/archive/refs/heads/main.zip no longer get misrouted into git clone.
  • Zip extraction (path-traversal guard + plugin.json discovery) is factored into a shared helper so local .zip files and remote .zip URLs go through the same code.
  • Help text and the en/zh plugin docs updated with the new usage.

Test plan

  • uv run pytest tests/core/test_plugin.py — 47 passed (4 new cases: happy path, query string, GitHub archive URL skips git clone, download failure cleans up tmp).
  • End-to-end: kimi plugin install https://cdn.kimi.com/kimi-code-plugins/kimi-datasource.zip on a clean ~/.kimi/plugins/ installs kimi-datasource v2.0.0.

Open in Devin Review

Copilot AI review requested due to automatic review settings April 30, 2026 08:16
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds support for installing Kimi CLI plugins directly from remote .zip URLs, routing those URLs through the existing zip-extraction/install flow (instead of the git-clone heuristic), and updates docs/tests accordingly.

Changes:

  • Extend kimi plugin install to accept http(s) .zip URLs (download via httpx, extract into temp dir, then install).
  • Factor zip extraction + plugin.json discovery into a shared helper used by both local zip files and remote zip URLs.
  • Add pytest coverage for zip URL cases and update en/zh plugin documentation.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

File Description
src/kimi_cli/cli/plugin.py Adds zip URL download path, shared zip extraction helper, and updates CLI help/error text.
tests/core/test_plugin.py Adds new tests covering zip URL success/failure and GitHub archive .zip routing.
docs/zh/customization/plugins.md Documents remote zip URL installation examples.
docs/en/customization/plugins.md Documents remote zip URL installation examples.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/kimi_cli/cli/plugin.py Outdated
Comment on lines +69 to +76
with zipfile.ZipFile(zip_path, "r") as zf:
for member in zf.namelist():
member_path = (tmp / member).resolve()
if not member_path.is_relative_to(tmp.resolve()):
shutil.rmtree(tmp, ignore_errors=True)
typer.echo(f"Error: zip contains unsafe path: {member}", err=True)
raise typer.Exit(1)
zf.extractall(tmp)
Comment on lines +78 to +83
for candidate in [tmp] + sorted(tmp.iterdir()):
if candidate.is_dir() and (candidate / "plugin.json").exists():
return candidate, tmp
dirs = [d for d in tmp.iterdir() if d.is_dir() and not d.name.startswith("_")]
if len(dirs) == 1 and (dirs[0] / "plugin.json").exists():
return dirs[0], tmp
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 11bf9e2845

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

typer.echo(f"Error: download failed: {exc}", err=True)
raise typer.Exit(1) from exc

return _extract_zip_to_plugin(zip_path, tmp)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Handle invalid downloaded ZIP archives gracefully

When a .zip URL returns non-ZIP content (for example, an HTML error page with status 200), _extract_zip_to_plugin raises zipfile.BadZipFile and this propagates out of _resolve_source unhandled. In this path, users get a Python traceback instead of a CLI error, and the temp directory created for the download is not cleaned up because install_cmd never reaches its cleanup finally. Please catch ZIP parsing/extraction errors around the remote ZIP path and convert them to typer.Exit after removing the temp dir.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 4 additional findings.

Open in Devin Review

@tempurai tempurai merged commit 7640535 into main Apr 30, 2026
14 checks passed
@tempurai tempurai deleted the fix-plugin-install-zip-url branch April 30, 2026 08:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants