chore: 1.1.3 release
This commit is contained in:
@@ -4,6 +4,23 @@
|
||||
|
||||
本项目遵循 [语义化版本](https://semver.org/lang/zh-CN/)。
|
||||
|
||||
## [1.1.3] - 2026-08-06
|
||||
|
||||
### 新增
|
||||
|
||||
- `install` 在交互终端下列出 `.agents` / `.codex` / `.claude` / `.cursor` / `.workbuddy` 技能目录,支持空格多选
|
||||
- 支持 `-y/--yes`(非交互默认目录)、可重复的 `--target`
|
||||
- `--all` 仅装到已检测到的 Agent 目录;对应目录不存在的 Agent 会跳过并提示,不会新建目录
|
||||
- Windows 导出自动启动一个常驻调试浏览器(Chrome,未安装时回退 Edge),规避 agent-browser 无法自行拉起 Chrome 导致的导出失败;实例导出后常驻、后续导出复用同一个,也可用 `AGENT_BROWSER_CDP` 指定自己启动的调试浏览器
|
||||
|
||||
### 修复
|
||||
|
||||
- 修复 `find_download` 在 Downloads 目录扫描时因 `.crdownload` 被 Chrome 重命名而触发 `FileNotFoundError` 导致导出中断(Related to #4)
|
||||
|
||||
### 变更
|
||||
|
||||
- README 默认指引 AI 通过 `npx open-kimi-ppt-skills@latest install -y` 安装,不再建议 clone 仓库
|
||||
|
||||
## [1.1.2] - 2026-08-06
|
||||
|
||||
### 修复
|
||||
|
||||
@@ -4,6 +4,23 @@
|
||||
|
||||
This project follows [Semantic Versioning](https://semver.org/).
|
||||
|
||||
## [1.1.3] - 2026-08-06
|
||||
|
||||
### Added
|
||||
|
||||
- Interactive `install` checklist for `.agents` / `.codex` / `.claude` / `.cursor` / `.workbuddy` skill directories (space to multi-select)
|
||||
- `-y/--yes` (non-interactive default) and repeatable `--target`
|
||||
- `--all` installs only into detected agent directories; missing agents are skipped with a notice instead of being created
|
||||
- Windows export auto-starts a persistent debug browser (Chrome, falling back to Edge) to work around agent-browser failing to launch Chrome itself; the instance stays resident and is reused across exports, and `AGENT_BROWSER_CDP` can point to a debug browser you started yourself
|
||||
|
||||
### Fixed
|
||||
|
||||
- Tolerate files vanishing mid-scan in `find_download` when Chrome renames `.crdownload` entries in Downloads, avoiding `FileNotFoundError` aborting export (Related to #4)
|
||||
|
||||
### Changed
|
||||
|
||||
- README now steers agents to `npx open-kimi-ppt-skills@latest install -y` instead of cloning the repo
|
||||
|
||||
## [1.1.2] - 2026-08-06
|
||||
|
||||
### Fixed
|
||||
|
||||
@@ -5,78 +5,64 @@
|
||||
[](https://www.npmjs.com/package/open-kimi-ppt-skills)
|
||||
[](https://nodejs.org)
|
||||
|
||||
逆向 Kimi Slides 实现的非官方演示文稿 Skill:让 AI Coding Agent 能够创建、编辑、复刻、读取并导出 PPT/PPTX。**每次生成默认同时交付两份成果:可继续编辑的 PPTD 项目和开箱即用的 PPTX 成品**(自动嵌入字体、写入淡入淡出翻页切换),支持页内元素动画与[预设主题](theme.md),并提供本地在线 PPTD 编辑器随时手动导出。支持 Codex、Claude Code、Cursor、WorkBuddy 等任何兼容 SKILL.md 规范的 Agent。
|
||||
逆向 Kimi Slides 实现的非官方演示文稿 Skill,让 AI Coding Agent 可以创建、编辑、复刻、读取并导出 PPT/PPTX。每次生成默认产出两份文件:可继续编辑的 PPTD 项目,以及嵌入字体、带淡入淡出翻页切换的 PPTX。支持页内元素动画和[预设主题](theme.md),附带本地浏览器编辑器,可随时手动导出 PPTX。支持 Codex、Claude Code、Cursor、WorkBuddy 等任何兼容 SKILL.md 规范的 Agent。
|
||||
|
||||
> [!IMPORTANT]
|
||||
> 本项目通过逆向分析 Kimi Slides Skill、PPTD 格式以及公开网页编辑器的前端行为与通信协议实现,并非 Kimi 或 Moonshot AI 的官方项目,也未获得其认可或支持。项目依赖的公开前端资源和兼容协议可能随 Kimi 更新而失效,仅供学习与研究使用。
|
||||
|
||||
## 安装
|
||||
|
||||
需要 Node.js 18 或更高版本。
|
||||
需要 Node.js 18 或更高版本。**请用 `npx` 安装,不要 clone 仓库**:仓库图片多、体积大,`npx` 只取打包后的 Skill 文件。默认装到共享目录 `~/.agents/skills/open-kimi-ppt`(Windows 为 `%USERPROFILE%\.agents\skills\open-kimi-ppt`),多数 Agent 装一次即可发现。
|
||||
|
||||
**二选一即可,不要两种都做**,否则容易装到多个目录、反复安装。默认会装到跨 Agent 通用目录 `~/.agents/skills/open-kimi-ppt`(Windows 为 `%USERPROFILE%\.agents\skills\open-kimi-ppt`);多数支持该目录的 Agent 装一次就能用。
|
||||
### 方式一:让 AI 安装(推荐)
|
||||
|
||||
### 方式一:自动安装(推荐)
|
||||
|
||||
直接对 AI 说下面任意一句,让 Agent 帮你装:
|
||||
|
||||
```text
|
||||
帮我从 github 安装 open-kimi-ppt skills
|
||||
```
|
||||
|
||||
```text
|
||||
帮我安装 https://github.com/Binaryify/open-kimi-ppt-skill
|
||||
```
|
||||
|
||||
装完后一般无需再手动执行 `npx ... install`。
|
||||
|
||||
### 方式二:手动安装
|
||||
|
||||
自己在终端执行:
|
||||
对 AI 说「帮我用 npx 安装 open-kimi-ppt skill」,或直接让它执行:
|
||||
|
||||
```bash
|
||||
npx open-kimi-ppt-skills@latest install -y
|
||||
```
|
||||
|
||||
**WorkBuddy 用户**:它发现不了共享目录,对 AI 说「帮我用 npx 安装 open-kimi-ppt skill 到 WorkBuddy」,或让它执行:
|
||||
|
||||
```bash
|
||||
# macOS / Linux
|
||||
npx open-kimi-ppt-skills@latest install --target ~/.workbuddy/skills
|
||||
# Windows
|
||||
npx open-kimi-ppt-skills@latest install --target %USERPROFILE%\.workbuddy\skills
|
||||
```
|
||||
|
||||
### 方式二:终端手动安装
|
||||
|
||||
```bash
|
||||
# 交互多选目录(空格选择、回车确认)
|
||||
npx open-kimi-ppt-skills install
|
||||
|
||||
# 非交互:只装共享目录
|
||||
npx open-kimi-ppt-skills install -y
|
||||
|
||||
# 装到全部已检测到的 Agent 目录(不存在的会跳过)
|
||||
npx open-kimi-ppt-skills install --all
|
||||
```
|
||||
|
||||
仅当你的 Agent **不识别** `~/.agents/skills`、必须装到专属目录时,才加 `--target`(以下为 macOS / Linux;Windows 将 `~` 换成 `%USERPROFILE%`,例如 `%USERPROFILE%\.codex\skills`):
|
||||
`--all` 与交互多选会检测以下目录:`~/.agents/skills`、`~/.codex/skills`、`~/.claude/skills`、`~/.cursor/skills`、`~/.workbuddy/skills`。
|
||||
|
||||
### Agent 发现不了 Skill 时
|
||||
|
||||
先用共享目录,不要默认对每个 Agent 各装一遍;确认某个 Agent 发现不了时,再为它单独指定目录(`--target` 可重复,Windows 下用 `%USERPROFILE%` 代替 `~`):
|
||||
|
||||
```bash
|
||||
# Codex
|
||||
npx open-kimi-ppt-skills install --target ~/.codex/skills
|
||||
|
||||
# Claude Code
|
||||
npx open-kimi-ppt-skills install --target ~/.claude/skills
|
||||
|
||||
# Cursor
|
||||
npx open-kimi-ppt-skills install --target ~/.cursor/skills
|
||||
|
||||
# WorkBuddy
|
||||
npx open-kimi-ppt-skills install --target ~/.workbuddy/skills
|
||||
npx open-kimi-ppt-skills@latest install --target ~/.codex/skills --target ~/.claude/skills
|
||||
```
|
||||
|
||||
> 不要默认对每个 Agent 各装一遍。先用默认目录;确认某个 Agent 发现不了 Skill 时,再对该 Agent 使用 `--target`。
|
||||
|
||||
### 更新
|
||||
|
||||
Skill 有更新时,再执行一次安装即可(会直接覆盖本地已安装版本):
|
||||
|
||||
```bash
|
||||
npx open-kimi-ppt-skills@latest install
|
||||
```
|
||||
|
||||
若当初用过 `--target`,更新时带上相同路径:
|
||||
|
||||
```bash
|
||||
npx open-kimi-ppt-skills@latest install --target ~/.claude/skills
|
||||
```
|
||||
|
||||
也可以对 AI 说:`帮我更新 open-kimi-ppt skill`。更新只替换 Skill 文件,不会影响已生成的 PPTD / PPTX 项目。
|
||||
再执行一次 `npx open-kimi-ppt-skills@latest install -y` 即可覆盖更新;当初用过 `--target` / `--all` 就带上相同参数。更新只替换 Skill 文件,不影响已生成的 PPTD / PPTX 项目。
|
||||
|
||||
## 使用
|
||||
|
||||
### 让 Agent 生成 PPT
|
||||
|
||||
安装完成后,直接向 Agent 描述需求即可。**默认交付物始终是两份**:完整的 PPTD 项目目录(可继续编辑)和对应的 PPTX 成品文件;只有明确要求只输出 PPTD 时才会跳过 PPTX 生成。
|
||||
安装完成后,直接向 Agent 描述需求即可。默认会同时生成完整的 PPTD 项目目录(可继续编辑)和对应的 PPTX 文件;只有明确要求只输出 PPTD 时才会跳过 PPTX 生成。
|
||||
|
||||
为了更稳定的出品,Prompt 里最好带上风格(如「深色产品发布风」),或附上参考 PPT 模板;只写主题、不给风格时效果更容易波动。
|
||||
|
||||
@@ -147,21 +133,32 @@ npx open-kimi-ppt-skills serve --port 56000
|
||||
|
||||
可写目录需要使用支持 File System Access API 的 Chromium 系浏览器;其他浏览器会回退为只读文件夹上传。按 `Ctrl+C` 停止服务。
|
||||
|
||||
### Windows:常驻调试浏览器说明
|
||||
|
||||
在 Windows 上导出 PPTX 时,脚本会自动启动一个**常驻的调试浏览器**。这是有意设计,不是异常进程:
|
||||
|
||||
- **为什么需要**:agent-browser 在 Windows 下无法自行启动 Chrome(Chrome 启动器把进程交接给子进程后立即退出,被误判为崩溃),导出只能改为驱动一个外部启动的浏览器。
|
||||
- **它是什么**:优先使用本机 Chrome,未安装时回退到 Edge;以 `--remote-debugging-port`(默认 `9337`)和独立配置目录 `%TEMP%\okp-cdp-profile` 启动,窗口定位在屏幕外,不影响日常使用。
|
||||
- **为什么常驻**:导出完成后实例保持运行,下次导出会复用同一个实例,而不是每导一次就多一个浏览器进程——设计目标是「最多一个,反复复用」。若想关掉,直接结束该浏览器进程即可,下次导出会自动重新拉起。
|
||||
- **想完全自控**:自行以 `--remote-debugging-port=<端口>` 启动浏览器,并把环境变量 `AGENT_BROWSER_CDP` 设为该端口,脚本会优先使用你自己的实例。
|
||||
|
||||
macOS / Linux 无此行为,不受影响。
|
||||
|
||||
## 功能特性
|
||||
|
||||
- **PPTD 生成**:让 Agent 生成完整、可继续编辑的 PPTD 项目,支持从零创作、风格迁移、模板复用、图片/PDF 复刻。
|
||||
- **预设主题**:内置约 30 套官方同款 design system,点名即可套用;完整列表与预览图见 [theme.md](theme.md)。
|
||||
- **元素动画**:默认不加。提示词加上「要求带元素入场动画」即可,由 AI 按页编排合适的入场效果。
|
||||
- **PPTX 生成**:默认同步生成 PPTX 成品,自动嵌入字体并写入淡入淡出**翻页**切换(与页内元素动画是两回事)。
|
||||
- **视觉质检**:多模态模型在导出 PPTX 前自动导出整份页面图片、拼接总览图逐项核查(变形、遮挡、出界、对比度、排版、文字溢出),问题页面修复后复检,直至全部通过。
|
||||
- **在线编辑**:通过浏览器查看和编辑本地 PPTD 项目,自动保存,可配置页面切换动画。
|
||||
- **手动导出**:在编辑器中随时手动导出 PPTX。
|
||||
- **格式互转**:将现有 PPTX 转换为 PPTD 后继续修改。
|
||||
- **安全可控**:本地编辑仅在用户明确授权的项目目录内读写文件。
|
||||
- PPTD 生成:让 Agent 生成完整、可继续编辑的 PPTD 项目,支持从零创作、风格迁移、模板复用、图片/PDF 复刻。
|
||||
- 预设主题:内置约 30 套官方同款 design system,点名即可套用;完整列表与预览图见 [theme.md](theme.md)。
|
||||
- 元素动画:默认不加。提示词加上「要求带元素入场动画」即可,由 AI 按页编排合适的入场效果。
|
||||
- PPTX 生成:默认同步生成 PPTX,自动嵌入字体并写入淡入淡出翻页切换(与页内元素动画是两回事)。
|
||||
- 视觉质检:多模态模型在导出 PPTX 前自动导出整份页面图片、拼接总览图逐项核查(变形、遮挡、出界、对比度、排版、文字溢出),问题页面修复后复检,直至全部通过。
|
||||
- 在线编辑:通过浏览器查看和编辑本地 PPTD 项目,自动保存,可配置页面切换动画。
|
||||
- 手动导出:在编辑器中随时手动导出 PPTX。
|
||||
- 格式互转:将现有 PPTX 转换为 PPTD 后继续修改。
|
||||
- 安全可控:本地编辑仅在用户明确授权的项目目录内读写文件。
|
||||
|
||||
## 为什么选 open-kimi-ppt
|
||||
|
||||
常见 PPT Skill 大致分三类:用代码库直接拼 OOXML / pptxgenjs、整页生成图片再塞进 PPTX、或输出网页 HTML 翻页。open-kimi-ppt 走的是 **PPTD 中间层 + 真实可编辑 PPTX** 路线,兼顾 Agent 好写、人好看、PowerPoint 能改。
|
||||
常见 PPT Skill 大致分三类:用代码库直接拼 OOXML / pptxgenjs、整页生成图片再塞进 PPTX、或输出网页 HTML 翻页。open-kimi-ppt 走的是 PPTD 中间层 + 真实可编辑 PPTX 这条路线,想让 Agent 好写、人好看、PowerPoint 能改。
|
||||
|
||||
| | open-kimi-ppt | 代码拼 PPTX(如 pptxgenjs) | 整页图片 PPT | 网页 HTML PPT |
|
||||
| --- | --- | --- | --- | --- |
|
||||
@@ -172,19 +169,19 @@ npx open-kimi-ppt-skills serve --port 56000
|
||||
| 二次编辑 | 浏览器可视化编辑 + 自动保存 | 主要靠改代码重导出 | 基本需重新出图 | 改 HTML 源码 |
|
||||
| 适用场景 | 要交可改的正式 PPTX,又要好看 | 结构化汇报、模板填充 | 视觉统一的海报风讲稿 | 浏览器内演讲 / 发布会 |
|
||||
|
||||
更具体地说,相对其他方案的优势是:
|
||||
具体来说:
|
||||
|
||||
1. **中间格式为 Agent 设计**:PPTD 用 YAML 描述主题、布局与元素,比直接写 OOXML / pptxgenjs 更稳,也比「整页渲一张图」更可局部修改。
|
||||
2. **默认同交两份成果**:可继续迭代的 PPTD 项目 + 开箱即用的 PPTX(嵌字体、淡入淡出翻页),不是只给半成品。
|
||||
3. **支持元素动画**:提示词写「要求带元素入场动画」即可启用;具体效果与节奏由 AI 处理,无需用户点名动画类型。
|
||||
4. **PPTX 真能改**:导出后文本框、形状仍可在 PowerPoint / WPS 里编辑,不像图片型 PPT 只能当海报。
|
||||
5. **有本地可视化编辑器**:浏览器里预览、微调、配切换动画并手动再导出,不需要每次都让 Agent 重跑全流程。
|
||||
6. **导出前强制视觉质检**:整页截图 + 总览图检查遮挡、出界、对比度、溢出等问题,修完再出 PPTX。
|
||||
7. **不绑官方模型,成本更低**:相对官方 Kimi Slides,你可以在任意兼容 Agent 里使用 DeepSeek 等低成本模型;即便模型不支持多模态,只要按 PPTD 规范生成,也能做出不错的成品(有多模态时再做视觉质检会更稳)。
|
||||
- PPTD 用 YAML 描述主题、布局与元素,比直接写 OOXML / pptxgenjs 更稳,也比整页渲一张图更方便局部修改。
|
||||
- 默认同时交付两份文件:可继续迭代的 PPTD 项目,加上嵌字体、带淡入淡出翻页的 PPTX,不是只给半成品。
|
||||
- 提示词写「要求带元素入场动画」即可启用元素动画,具体效果与节奏由 AI 处理,不用自己点名动画类型。
|
||||
- 导出的 PPTX 里,文本框、形状仍可在 PowerPoint / WPS 中编辑,不像图片型 PPT 只能当海报。
|
||||
- 浏览器里可以预览、微调、配置切换动画并再次导出,不用每次都让 Agent 重跑全流程。
|
||||
- 导出前会做视觉质检:整页截图加总览图,检查遮挡、出界、对比度、溢出等问题,修完再出 PPTX。
|
||||
- 不绑定官方模型,成本更低。相对官方 Kimi Slides,可以在任意兼容 Agent 里使用 DeepSeek 等低成本模型;模型不支持多模态时,按 PPTD 规范生成也能做出像样的成品,有多模态时再做一遍视觉质检会更稳。
|
||||
|
||||
[](docs/images/example-deepseek-liquid-glass.png)
|
||||
|
||||
*上图:在 WorkBuddy 中使用 DeepSeek-V4-Flash 生成 Apple Liquid Glass 风格 PPT 的实际效果。*
|
||||
*上图:在 WorkBuddy 中用 DeepSeek-V4-Flash 生成的 Apple Liquid Glass 风格 PPT。*
|
||||
|
||||
[](docs/images/example-reasonix-deepseek.png)
|
||||
|
||||
@@ -192,7 +189,7 @@ npx open-kimi-ppt-skills serve --port 56000
|
||||
|
||||
[](docs/images/example-codex-iphone17pro.png)
|
||||
|
||||
*上图:在 ChatGPT / Codex 中使用 5.6 Luna 模型生成 iPhone 17 Pro PPT,又快又好。*
|
||||
*上图:在 ChatGPT / Codex 中使用 5.6 Luna 模型生成的 iPhone 17 Pro PPT。*
|
||||
|
||||
### 关于风格与主题
|
||||
|
||||
@@ -201,7 +198,7 @@ npx open-kimi-ppt-skills serve --port 56000
|
||||
完整主题名、风格说明与预览图见 **[theme.md](theme.md)**。
|
||||
|
||||
> [!TIP]
|
||||
> **强烈建议在 Prompt 里写明 PPT 风格、点名一套 preset,或直接附上参考 PPT / PPTX 模板。** 有风格约束或模板参照时,出品会明显更好、更稳定;只给主题不给风格时,Agent 会自行发挥,效果容易波动。
|
||||
> 建议在 Prompt 里写明 PPT 风格、点名一套 preset,或直接附上参考 PPT / PPTX 模板。有风格约束或模板参照时,效果会稳定不少;只给主题不给风格时,Agent 只能自行发挥,容易波动。
|
||||
|
||||
常见用法:
|
||||
|
||||
|
||||
+59
-62
@@ -5,78 +5,64 @@
|
||||
[](https://www.npmjs.com/package/open-kimi-ppt-skills)
|
||||
[](https://nodejs.org)
|
||||
|
||||
An unofficial presentation skill for AI coding agents, reverse-engineered from Kimi Slides. It lets your agent create, edit, replicate, read, and export PPT/PPTX files. **Every run delivers two outputs by default: an editable PPTD project and a ready-to-use PPTX** — fonts embedded and fade page transitions included — with optional on-slide element animations and [preset themes](theme_EN.md), plus a local in-browser PPTD editor with manual PPTX export. Works with Codex, Claude Code, Cursor, WorkBuddy, and any agent that supports the SKILL.md format.
|
||||
An unofficial presentation skill for AI coding agents, reverse-engineered from Kimi Slides. It lets your agent create, edit, replicate, read, and export PPT/PPTX files. Each run produces two outputs by default: an editable PPTD project, and a PPTX with embedded fonts and fade page transitions. On-slide element animations and [preset themes](theme_EN.md) are supported, and a local in-browser PPTD editor is included for manual export. Works with Codex, Claude Code, Cursor, WorkBuddy, and any agent that supports the SKILL.md format.
|
||||
|
||||
> [!IMPORTANT]
|
||||
> This project is implemented by reverse-engineering the Kimi Slides skill, the PPTD format, and the frontend behavior and communication protocol of the publicly accessible web editor. It is not an official Kimi or Moonshot AI project and is not endorsed or supported by them. Public frontend resources and compatibility contracts used by this project may change without notice. Provided for learning and research purposes only.
|
||||
|
||||
## Install
|
||||
|
||||
Node.js 18 or later is required.
|
||||
Node.js 18 or later is required. **Install with `npx` — do not clone the repository**: the repo ships many images and is heavy, while `npx` only fetches the packaged skill files. The default location is the shared directory `~/.agents/skills/open-kimi-ppt` (Windows: `%USERPROFILE%\.agents\skills\open-kimi-ppt`), which most agents discover with a single install.
|
||||
|
||||
**Pick one method — do not run both**, or you may end up with duplicate installs across directories. By default the skill lands in the shared directory `~/.agents/skills/open-kimi-ppt` (Windows: `%USERPROFILE%\.agents\skills\open-kimi-ppt`). For most agents that discover that path, a single install is enough.
|
||||
### Option 1: Ask your agent (recommended)
|
||||
|
||||
### Option 1: Automatic install (recommended)
|
||||
Say "Install the open-kimi-ppt skill for me with npx", or have it run:
|
||||
|
||||
Ask your agent with either of these prompts and let it install for you:
|
||||
|
||||
```text
|
||||
Install the open-kimi-ppt skills from GitHub for me.
|
||||
```bash
|
||||
npx open-kimi-ppt-skills@latest install -y
|
||||
```
|
||||
|
||||
```text
|
||||
Install https://github.com/Binaryify/open-kimi-ppt-skill for me.
|
||||
```
|
||||
**WorkBuddy users**: WorkBuddy can't discover the shared directory. Say "Install the open-kimi-ppt skill for me with npx into WorkBuddy", or have it run:
|
||||
|
||||
After that, you usually do **not** need to run `npx ... install` yourself.
|
||||
```bash
|
||||
# macOS / Linux
|
||||
npx open-kimi-ppt-skills@latest install --target ~/.workbuddy/skills
|
||||
# Windows
|
||||
npx open-kimi-ppt-skills@latest install --target %USERPROFILE%\.workbuddy\skills
|
||||
```
|
||||
|
||||
### Option 2: Manual install
|
||||
|
||||
Run this in your terminal:
|
||||
|
||||
```bash
|
||||
# Interactive checklist (space to select, Enter to confirm)
|
||||
npx open-kimi-ppt-skills install
|
||||
|
||||
# Non-interactive: shared directory only
|
||||
npx open-kimi-ppt-skills install -y
|
||||
|
||||
# All detected agent skill directories (missing ones are skipped)
|
||||
npx open-kimi-ppt-skills install --all
|
||||
```
|
||||
|
||||
Only add `--target` if your agent **does not** pick up `~/.agents/skills` and must use its own skills directory (paths below are for macOS / Linux; on Windows replace `~` with `%USERPROFILE%`, e.g. `%USERPROFILE%\.codex\skills`):
|
||||
Directories detected by `--all` and the interactive checklist: `~/.agents/skills`, `~/.codex/skills`, `~/.claude/skills`, `~/.cursor/skills`, `~/.workbuddy/skills`.
|
||||
|
||||
### When an agent can't discover the skill
|
||||
|
||||
Start with the shared directory instead of installing once per agent. If a specific agent can't discover the skill there, pass its directory explicitly (`--target` may be repeated; on Windows use `%USERPROFILE%` instead of `~`):
|
||||
|
||||
```bash
|
||||
# Codex
|
||||
npx open-kimi-ppt-skills install --target ~/.codex/skills
|
||||
|
||||
# Claude Code
|
||||
npx open-kimi-ppt-skills install --target ~/.claude/skills
|
||||
|
||||
# Cursor
|
||||
npx open-kimi-ppt-skills install --target ~/.cursor/skills
|
||||
|
||||
# WorkBuddy
|
||||
npx open-kimi-ppt-skills install --target ~/.workbuddy/skills
|
||||
npx open-kimi-ppt-skills@latest install --target ~/.codex/skills --target ~/.claude/skills
|
||||
```
|
||||
|
||||
> Do not install once per agent by default. Start with the shared directory; only use `--target` for an agent that cannot discover the skill there.
|
||||
|
||||
### Update
|
||||
|
||||
When the skill is updated, run install again — it overwrites the local installation:
|
||||
|
||||
```bash
|
||||
npx open-kimi-ppt-skills@latest install
|
||||
```
|
||||
|
||||
If you originally installed with `--target`, pass the same path again:
|
||||
|
||||
```bash
|
||||
npx open-kimi-ppt-skills@latest install --target ~/.claude/skills
|
||||
```
|
||||
|
||||
You can also ask your agent: `Update the open-kimi-ppt skill for me.` Updating only replaces the skill files; it does not touch PPTD / PPTX projects you already generated.
|
||||
Run `npx open-kimi-ppt-skills@latest install -y` again to overwrite the local installation; if you originally used `--target` / `--all`, pass the same flags. Updating only replaces the skill files and does not touch PPTD / PPTX projects you already generated.
|
||||
|
||||
## Usage
|
||||
|
||||
### Generate a presentation with your agent
|
||||
|
||||
Once installed, just describe what you need. **You always get two deliverables by default**: the complete, editable PPTD project directory and the matching PPTX file. PPTX generation is skipped only when you explicitly ask for PPTD-only output.
|
||||
Once installed, just describe what you need. By default you get both the complete, editable PPTD project directory and the matching PPTX file. PPTX generation is skipped only when you explicitly ask for PPTD-only output.
|
||||
|
||||
For more stable quality, put a style in the prompt (e.g. “dark product-launch look”) or attach a reference PPT template; topic-only prompts without style guidance tend to vary more.
|
||||
|
||||
@@ -135,21 +121,32 @@ npx open-kimi-ppt-skills serve --port 56000
|
||||
|
||||
Writable folder access requires a Chromium-based browser with the File System Access API. Other browsers fall back to read-only folder upload. Press `Ctrl+C` to stop the server.
|
||||
|
||||
### Windows: a persistent debug browser
|
||||
|
||||
On Windows, exporting PPTX automatically starts a **persistent debug browser**. This is by design, not a stray process:
|
||||
|
||||
- **Why it's needed**: agent-browser cannot launch Chrome by itself on Windows (the Chrome launcher hands off to a child process and exits immediately, which is misread as a crash), so the export drives an externally started browser instead.
|
||||
- **What it is**: your installed Chrome (falling back to Edge), launched with `--remote-debugging-port` (default `9337`) and a dedicated profile at `%TEMP%\okp-cdp-profile`, with the window positioned off-screen so it stays out of the way.
|
||||
- **Why it persists**: the instance intentionally keeps running after the export. Relaunching with the same profile joins the existing browser, so repeated exports reuse one instance instead of piling up processes — the design goal is "at most one, reused forever". To get rid of it, just kill the browser process; the next export starts a fresh one.
|
||||
- **Take full control**: start your own browser with `--remote-debugging-port=<port>` and set the `AGENT_BROWSER_CDP` environment variable to that port; the script prefers your instance.
|
||||
|
||||
macOS and Linux are unaffected.
|
||||
|
||||
## Features
|
||||
|
||||
- **PPTD generation**: let your agent generate complete, editable PPTD projects — from scratch, with style transfer, template reuse, or replication from images/PDFs.
|
||||
- **Preset themes**: ~30 official-style design systems you can name to apply; full list with previews in [theme_EN.md](theme_EN.md).
|
||||
- **Element animations**: Off by default. Add `Require element entrance animations` to the prompt; the agent picks suitable on-slide effects per page.
|
||||
- **PPTX generation**: produce a matching PPTX by default, with fonts embedded and fade **page** transitions written automatically (separate from on-slide element animations).
|
||||
- **Visual QA**: with a multimodal model, the skill exports every page as an image, stitches them into an overview sheet, and checks each page (distortion, occlusion, out-of-bounds elements, contrast, layout consistency, text overflow) before PPTX export — fixing and re-checking until every page passes.
|
||||
- **Online editing**: view and edit local PPTD projects in a browser, with autosave and configurable slide transitions.
|
||||
- **Manual export**: export PPTX manually from the editor at any time.
|
||||
- **Format conversion**: convert existing PPTX files to PPTD for further editing.
|
||||
- **Secure by design**: local editing only reads and writes project directories explicitly authorized by the user.
|
||||
- PPTD generation: let your agent generate complete, editable PPTD projects, from scratch, with style transfer, template reuse, or replication from images/PDFs.
|
||||
- Preset themes: ~30 official-style design systems you can name to apply; full list with previews in [theme_EN.md](theme_EN.md).
|
||||
- Element animations: off by default. Add `Require element entrance animations` to the prompt and the agent picks suitable on-slide effects per page.
|
||||
- PPTX generation: a matching PPTX is produced by default, with fonts embedded and fade page transitions written automatically (separate from on-slide element animations).
|
||||
- Visual QA: with a multimodal model, the skill exports every page as an image, stitches them into an overview sheet, and checks each page (distortion, occlusion, out-of-bounds elements, contrast, layout consistency, text overflow) before PPTX export, fixing and re-checking until every page passes.
|
||||
- Online editing: view and edit local PPTD projects in a browser, with autosave and configurable slide transitions.
|
||||
- Manual export: export PPTX manually from the editor at any time.
|
||||
- Format conversion: convert existing PPTX files to PPTD for further editing.
|
||||
- Secure by design: local editing only reads and writes project directories explicitly authorized by the user.
|
||||
|
||||
## Why open-kimi-ppt
|
||||
|
||||
Most PPT skills fall into three buckets: assemble OOXML / pptxgenjs in code, render each slide as a full-bleed image, or ship a swipeable HTML deck. open-kimi-ppt takes a **PPTD intermediate layer + real editable PPTX** path — easy for agents to write, good to look at, and still editable in PowerPoint.
|
||||
Most PPT skills fall into three buckets: assemble OOXML / pptxgenjs in code, render each slide as a full-bleed image, or ship a swipeable HTML deck. open-kimi-ppt takes a different path: a PPTD intermediate layer plus real editable PPTX output, meant to be easy for agents to write and still editable in PowerPoint.
|
||||
|
||||
| | open-kimi-ppt | Code-built PPTX (e.g. pptxgenjs) | Full-slide image PPT | Web HTML PPT |
|
||||
| --- | --- | --- | --- | --- |
|
||||
@@ -160,15 +157,15 @@ Most PPT skills fall into three buckets: assemble OOXML / pptxgenjs in code, ren
|
||||
| Re-editing | Browser visual editor + autosave | Mostly re-run code | Usually regenerate images | Edit HTML source |
|
||||
| Best for | Formal PPTX you still need to tweak | Structured reports / template fills | Visually unified poster decks | In-browser talks / launches |
|
||||
|
||||
In short:
|
||||
Specifically:
|
||||
|
||||
1. **DSL built for agents** — PPTD describes theme, layout, and elements in YAML, more stable than raw OOXML / pptxgenjs, and more locally editable than full-slide images.
|
||||
2. **Two deliverables by default** — an iterable PPTD project plus a ready-to-open PPTX (embedded fonts, fade page transitions).
|
||||
3. **Element animations** — add `Require element entrance animations` to the prompt; the agent chooses effects and timing for you.
|
||||
4. **Truly editable PPTX** — text boxes and shapes remain editable in PowerPoint / WPS, unlike image-only decks.
|
||||
5. **Local visual editor** — preview, tweak, set transitions, and re-export in the browser without rerunning the whole agent flow.
|
||||
6. **Visual QA before export** — full-page screenshots plus an overview sheet catch occlusion, overflow, contrast, and layout issues before PPTX is written.
|
||||
7. **Not locked to the official model — lower cost** — unlike official Kimi Slides, you can run this in any compatible agent with cheaper models such as DeepSeek. Even without multimodal vision, a model that follows the PPTD spec can still produce strong decks (multimodal helps more with the visual QA pass).
|
||||
- PPTD describes theme, layout, and elements in YAML, which is more stable than raw OOXML / pptxgenjs and easier to edit locally than full-slide images.
|
||||
- You get both deliverables by default: an iterable PPTD project plus a ready-to-open PPTX with embedded fonts and fade page transitions.
|
||||
- Add `Require element entrance animations` to the prompt and the agent chooses effects and timing for you.
|
||||
- Text boxes and shapes in the exported PPTX remain editable in PowerPoint / WPS, unlike image-only decks.
|
||||
- You can preview, tweak, set transitions, and re-export in the browser without rerunning the whole agent flow.
|
||||
- Before export, full-page screenshots plus an overview sheet are used to catch occlusion, overflow, contrast, and layout issues.
|
||||
- It is not locked to the official model, so it costs less. Unlike official Kimi Slides, you can run this in any compatible agent with cheaper models such as DeepSeek. Even without multimodal vision, a model that follows the PPTD spec can still produce decent decks; with a multimodal model you additionally get the visual QA pass.
|
||||
|
||||
[](docs/images/example-deepseek-liquid-glass.png)
|
||||
|
||||
@@ -180,7 +177,7 @@ In short:
|
||||
|
||||
[](docs/images/example-codex-iphone17pro.png)
|
||||
|
||||
*Above: an iPhone 17 Pro deck generated with the 5.6 Luna model in ChatGPT / Codex — fast and strong.*
|
||||
*Above: an iPhone 17 Pro deck generated with the 5.6 Luna model in ChatGPT / Codex.*
|
||||
|
||||
### Style and themes
|
||||
|
||||
@@ -189,7 +186,7 @@ By default the agent **does not** auto-apply a fixed theme: without a style cue
|
||||
Browse theme IDs, descriptions, and preview images in **[theme_EN.md](theme_EN.md)**.
|
||||
|
||||
> [!TIP]
|
||||
> **Best results come from stating a PPT style in the prompt, naming a preset, or attaching a reference PPT / PPTX template.** With a style constraint or template to follow, output quality is clearly better and more stable. Topic-only prompts leave the agent free to invent a look, so results vary more.
|
||||
> It helps to state a PPT style in the prompt, name a preset, or attach a reference PPT / PPTX template. With a style constraint or template to follow, output is noticeably more consistent. Topic-only prompts leave the agent to invent a look, so results vary more.
|
||||
|
||||
Common approaches:
|
||||
|
||||
|
||||
+201
-7
@@ -2,8 +2,9 @@
|
||||
|
||||
import { cpSync, existsSync, mkdtempSync, mkdirSync, renameSync, rmSync } from "node:fs";
|
||||
import { homedir } from "node:os";
|
||||
import { basename, dirname, join, resolve } from "node:path";
|
||||
import { basename, dirname, join, resolve, sep } from "node:path";
|
||||
import { spawn } from "node:child_process";
|
||||
import { stdin as input, stdout as output } from "node:process";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { startEditorServer } from "../lib/editor-server.js";
|
||||
|
||||
@@ -12,6 +13,14 @@ const MIN_NODE_MAJOR = 18;
|
||||
const packageRoot = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
||||
const sourceDirectory = join(packageRoot, "skills", SKILL_NAME);
|
||||
|
||||
const KNOWN_TARGETS = [
|
||||
{ id: "agents", label: "Shared / default", relative: [".agents", "skills"] },
|
||||
{ id: "codex", label: "Codex", relative: [".codex", "skills"] },
|
||||
{ id: "claude", label: "Claude Code", relative: [".claude", "skills"] },
|
||||
{ id: "cursor", label: "Cursor", relative: [".cursor", "skills"] },
|
||||
{ id: "workbuddy", label: "WorkBuddy", relative: [".workbuddy", "skills"] },
|
||||
];
|
||||
|
||||
function assertNodeVersion() {
|
||||
const major = Number.parseInt(process.versions.node.split(".")[0], 10);
|
||||
if (!Number.isInteger(major) || major < MIN_NODE_MAJOR) {
|
||||
@@ -43,7 +52,17 @@ Usage:
|
||||
open-kimi-ppt-skills serve [options]
|
||||
|
||||
Install options:
|
||||
--target <directory> Skills directory (default: ~/.agents/skills)
|
||||
--target <directory> Skills directory (repeatable)
|
||||
-y, --yes Non-interactive; install to ~/.agents/skills when no --target
|
||||
--all Install to all detected agent skill directories
|
||||
(agents whose home directory is missing are skipped)
|
||||
-h, --help Show this help
|
||||
|
||||
In an interactive terminal (no --target / --yes / --all), a checklist is shown:
|
||||
↑/↓ move space select a all enter confirm
|
||||
|
||||
For agents / CI, prefer:
|
||||
npx open-kimi-ppt-skills@latest install -y
|
||||
|
||||
Re-running install replaces an existing open-kimi-ppt installation.
|
||||
Run "open-kimi-ppt-skills serve --help" for server options.
|
||||
@@ -55,7 +74,7 @@ function parseArguments(arguments_) {
|
||||
const command = args[0] === "install" || args[0] === "serve" ? args.shift() : "install";
|
||||
const options = command === "serve"
|
||||
? { command, open: false, port: 55173 }
|
||||
: { command, target: undefined };
|
||||
: { command, targets: [], yes: false, all: false };
|
||||
|
||||
while (args.length > 0) {
|
||||
const argument = args.shift();
|
||||
@@ -65,12 +84,22 @@ function parseArguments(arguments_) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (command === "install" && (argument === "-y" || argument === "--yes")) {
|
||||
options.yes = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (command === "install" && argument === "--all") {
|
||||
options.all = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (command === "install" && argument === "--target") {
|
||||
const target = args.shift();
|
||||
if (!target || target.startsWith("-")) {
|
||||
throw new Error("--target requires a directory");
|
||||
}
|
||||
options.target = resolve(target);
|
||||
options.targets.push(resolve(target));
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -111,12 +140,170 @@ function defaultSkillsDirectory() {
|
||||
return join(homedir(), ".agents", "skills");
|
||||
}
|
||||
|
||||
function installSkill({ target }) {
|
||||
function knownTargetDirectories() {
|
||||
const home = homedir();
|
||||
return KNOWN_TARGETS.map((entry) => ({
|
||||
...entry,
|
||||
directory: join(home, ...entry.relative),
|
||||
}));
|
||||
}
|
||||
|
||||
function displayPath(absolutePath) {
|
||||
const home = homedir();
|
||||
const normalized = absolutePath.split(sep).join("/");
|
||||
const homeNormalized = home.split(sep).join("/");
|
||||
if (normalized === homeNormalized || normalized.startsWith(`${homeNormalized}/`)) {
|
||||
return `~${normalized.slice(homeNormalized.length)}`;
|
||||
}
|
||||
return absolutePath;
|
||||
}
|
||||
|
||||
function isInteractiveInstall() {
|
||||
return Boolean(input.isTTY && output.isTTY);
|
||||
}
|
||||
|
||||
function uniqueDirectories(directories) {
|
||||
const seen = new Set();
|
||||
const unique = [];
|
||||
for (const directory of directories) {
|
||||
const key = resolve(directory);
|
||||
if (seen.has(key)) continue;
|
||||
seen.add(key);
|
||||
unique.push(key);
|
||||
}
|
||||
return unique;
|
||||
}
|
||||
|
||||
async function promptInstallTargets() {
|
||||
const choices = knownTargetDirectories();
|
||||
const selected = new Set([0]);
|
||||
let cursor = 0;
|
||||
const lines = choices.length + 3;
|
||||
|
||||
const render = (initial = false) => {
|
||||
if (!initial) {
|
||||
output.write(`\u001b[${lines}A`);
|
||||
}
|
||||
output.write("Install open-kimi-ppt to which skills directories?\n");
|
||||
output.write("↑/↓ move · space select · a all · enter confirm · ctrl+c cancel\n");
|
||||
for (const [index, choice] of choices.entries()) {
|
||||
const pointer = index === cursor ? "❯" : " ";
|
||||
const mark = selected.has(index) ? "◉" : "◯";
|
||||
const installed = existsSync(join(choice.directory, SKILL_NAME, "SKILL.md"))
|
||||
? " (installed)"
|
||||
: "";
|
||||
const line = `${pointer}${mark} ${displayPath(choice.directory).padEnd(28)} ${choice.label}${installed}`;
|
||||
output.write(`\u001b[2K${line}\n`);
|
||||
}
|
||||
};
|
||||
|
||||
return new Promise((resolvePromise, reject) => {
|
||||
if (typeof input.setRawMode !== "function") {
|
||||
resolvePromise([defaultSkillsDirectory()]);
|
||||
return;
|
||||
}
|
||||
|
||||
render(true);
|
||||
input.setRawMode(true);
|
||||
input.resume();
|
||||
input.setEncoding("utf8");
|
||||
|
||||
const cleanup = () => {
|
||||
input.off("data", onData);
|
||||
input.setRawMode(false);
|
||||
input.pause();
|
||||
};
|
||||
|
||||
const onData = (key) => {
|
||||
if (key === "\u0003") {
|
||||
cleanup();
|
||||
output.write("\n");
|
||||
reject(new Error("install cancelled"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (key === "\u001b[A" || key === "k") {
|
||||
cursor = (cursor - 1 + choices.length) % choices.length;
|
||||
render();
|
||||
return;
|
||||
}
|
||||
|
||||
if (key === "\u001b[B" || key === "j") {
|
||||
cursor = (cursor + 1) % choices.length;
|
||||
render();
|
||||
return;
|
||||
}
|
||||
|
||||
if (key === " ") {
|
||||
if (selected.has(cursor)) selected.delete(cursor);
|
||||
else selected.add(cursor);
|
||||
render();
|
||||
return;
|
||||
}
|
||||
|
||||
if (key === "a" || key === "A") {
|
||||
if (selected.size === choices.length) selected.clear();
|
||||
else for (let index = 0; index < choices.length; index += 1) selected.add(index);
|
||||
render();
|
||||
return;
|
||||
}
|
||||
|
||||
if (key === "\r" || key === "\n") {
|
||||
if (selected.size === 0) {
|
||||
output.write("\u0007");
|
||||
return;
|
||||
}
|
||||
cleanup();
|
||||
output.write("\n");
|
||||
resolvePromise([...selected].sort((a, b) => a - b).map((index) => choices[index].directory));
|
||||
}
|
||||
};
|
||||
|
||||
input.on("data", onData);
|
||||
});
|
||||
}
|
||||
|
||||
function detectedTargetDirectories() {
|
||||
const home = homedir();
|
||||
const detected = [];
|
||||
const skipped = [];
|
||||
for (const entry of knownTargetDirectories()) {
|
||||
if (existsSync(join(home, entry.relative[0]))) detected.push(entry);
|
||||
else skipped.push(entry);
|
||||
}
|
||||
return { detected, skipped };
|
||||
}
|
||||
|
||||
async function resolveInstallTargets(options) {
|
||||
if (options.targets.length > 0) {
|
||||
return uniqueDirectories(options.targets);
|
||||
}
|
||||
|
||||
if (options.all) {
|
||||
const { detected, skipped } = detectedTargetDirectories();
|
||||
for (const entry of skipped) {
|
||||
console.log(`Skipped ${entry.directory} (${entry.label} not found)`);
|
||||
}
|
||||
if (detected.length === 0) {
|
||||
console.warn(
|
||||
"No known agent directories found; nothing installed. Use -y for ~/.agents/skills or --target <directory>.",
|
||||
);
|
||||
}
|
||||
return uniqueDirectories(detected.map((entry) => entry.directory));
|
||||
}
|
||||
|
||||
if (options.yes || !isInteractiveInstall()) {
|
||||
return [defaultSkillsDirectory()];
|
||||
}
|
||||
|
||||
return promptInstallTargets();
|
||||
}
|
||||
|
||||
function installSkillTo(skillsDirectory) {
|
||||
if (!existsSync(join(sourceDirectory, "SKILL.md"))) {
|
||||
throw new Error(`packaged skill is incomplete: ${sourceDirectory}`);
|
||||
}
|
||||
|
||||
const skillsDirectory = target ?? defaultSkillsDirectory();
|
||||
const destination = join(skillsDirectory, SKILL_NAME);
|
||||
const replaced = existsSync(destination);
|
||||
|
||||
@@ -143,6 +330,13 @@ function installSkill({ target }) {
|
||||
);
|
||||
}
|
||||
|
||||
async function installSkill(options) {
|
||||
const targets = await resolveInstallTargets(options);
|
||||
for (const target of targets) {
|
||||
installSkillTo(target);
|
||||
}
|
||||
}
|
||||
|
||||
async function main() {
|
||||
assertNodeVersion();
|
||||
const options = parseArguments(process.argv.slice(2));
|
||||
@@ -152,7 +346,7 @@ async function main() {
|
||||
}
|
||||
|
||||
if (options.command === "install") {
|
||||
installSkill(options);
|
||||
await installSkill(options);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "open-kimi-ppt-skills",
|
||||
"version": "1.1.2",
|
||||
"version": "1.1.3",
|
||||
"description": "Unofficial reverse-engineered Kimi Slides skill for AI coding agents with local PPTD editing and PPTX export.",
|
||||
"license": "MIT",
|
||||
"author": "binaryify",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import assert from "node:assert/strict";
|
||||
import { existsSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
||||
import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
||||
import { tmpdir } from "node:os";
|
||||
import { dirname, join, resolve } from "node:path";
|
||||
import { spawnSync } from "node:child_process";
|
||||
@@ -31,7 +31,7 @@ test("installs the packaged skill into a custom skills directory", () => {
|
||||
}
|
||||
});
|
||||
|
||||
test("installs into ~/.agents/skills when no target is provided", () => {
|
||||
test("installs into ~/.agents/skills when no target is provided (non-interactive)", () => {
|
||||
const root = mkdtempSync(join(tmpdir(), "open-kimi-ppt-test-"));
|
||||
|
||||
try {
|
||||
@@ -43,6 +43,89 @@ test("installs into ~/.agents/skills when no target is provided", () => {
|
||||
}
|
||||
});
|
||||
|
||||
test("supports -y for non-interactive default install", () => {
|
||||
const root = mkdtempSync(join(tmpdir(), "open-kimi-ppt-test-"));
|
||||
|
||||
try {
|
||||
const result = runCli(["install", "-y"], {
|
||||
...process.env,
|
||||
HOME: root,
|
||||
USERPROFILE: root,
|
||||
CODEX_HOME: undefined,
|
||||
});
|
||||
assert.equal(result.status, 0, result.stderr);
|
||||
assert.equal(existsSync(join(root, ".agents", "skills", "open-kimi-ppt", "SKILL.md")), true);
|
||||
} finally {
|
||||
rmSync(root, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
test("installs into multiple --target directories", () => {
|
||||
const root = mkdtempSync(join(tmpdir(), "open-kimi-ppt-test-"));
|
||||
const first = join(root, "codex", "skills");
|
||||
const second = join(root, "claude", "skills");
|
||||
|
||||
try {
|
||||
const result = runCli(["install", "--target", first, "--target", second]);
|
||||
assert.equal(result.status, 0, result.stderr);
|
||||
assert.equal(existsSync(join(first, "open-kimi-ppt", "SKILL.md")), true);
|
||||
assert.equal(existsSync(join(second, "open-kimi-ppt", "SKILL.md")), true);
|
||||
} finally {
|
||||
rmSync(root, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
test("--all installs into detected agent directories and skips missing ones", () => {
|
||||
const root = mkdtempSync(join(tmpdir(), "open-kimi-ppt-test-"));
|
||||
|
||||
try {
|
||||
mkdirSync(join(root, ".agents"), { recursive: true });
|
||||
mkdirSync(join(root, ".codex"), { recursive: true });
|
||||
mkdirSync(join(root, ".claude"), { recursive: true });
|
||||
|
||||
const result = runCli(["install", "--all"], {
|
||||
...process.env,
|
||||
HOME: root,
|
||||
USERPROFILE: root,
|
||||
CODEX_HOME: undefined,
|
||||
});
|
||||
assert.equal(result.status, 0, result.stderr);
|
||||
|
||||
for (const relative of [[".agents", "skills"], [".codex", "skills"], [".claude", "skills"]]) {
|
||||
assert.equal(
|
||||
existsSync(join(root, ...relative, "open-kimi-ppt", "SKILL.md")),
|
||||
true,
|
||||
relative.join("/"),
|
||||
);
|
||||
}
|
||||
for (const missing of [".cursor", ".workbuddy"]) {
|
||||
assert.equal(existsSync(join(root, missing)), false, missing);
|
||||
}
|
||||
assert.match(result.stdout, /Skipped .*\.cursor/);
|
||||
assert.match(result.stdout, /Skipped .*\.workbuddy/);
|
||||
} finally {
|
||||
rmSync(root, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
test("--all warns and installs nothing when no agent directory exists", () => {
|
||||
const root = mkdtempSync(join(tmpdir(), "open-kimi-ppt-test-"));
|
||||
|
||||
try {
|
||||
const result = runCli(["install", "--all"], {
|
||||
...process.env,
|
||||
HOME: root,
|
||||
USERPROFILE: root,
|
||||
CODEX_HOME: undefined,
|
||||
});
|
||||
assert.equal(result.status, 0, result.stderr);
|
||||
assert.equal(existsSync(join(root, ".agents")), false);
|
||||
assert.match(result.stderr, /No known agent directories found/);
|
||||
} finally {
|
||||
rmSync(root, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
test("overwrites an existing installation by default", () => {
|
||||
const root = mkdtempSync(join(tmpdir(), "open-kimi-ppt-test-"));
|
||||
const target = join(root, "skills");
|
||||
@@ -74,3 +157,12 @@ test("accepts legacy --force without changing overwrite behavior", () => {
|
||||
rmSync(root, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
test("help documents interactive install and -y for agents", () => {
|
||||
const result = runCli(["install", "--help"]);
|
||||
assert.equal(result.status, 0, result.stderr);
|
||||
assert.match(result.stdout, /space select/);
|
||||
assert.match(result.stdout, /-y, --yes/);
|
||||
assert.match(result.stdout, /--all/);
|
||||
assert.match(result.stdout, /npx open-kimi-ppt-skills@latest install -y/);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user