forked from arechen/EapilSkillMarket
Sync third-party and MCP marketplace plugins
Constraint: Public skills are published only by explicit administrator action unless they are tracked third-party market sources. Confidence: high Scope-risk: narrow Directive: Keep private/internal skills out of the public marketplace and preserve normal incremental market Git history. Tested: Marketplace validation passed.
This commit is contained in:
1 parent
ed52dd300b
commit
e224150d81
15 files changed
+215
-43
No files matched your search
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "artemis-automation",
|
||||
"version": "2.0.1",
|
||||
"version": "2.1.0",
|
||||
"description": "使用 ARTEMIS MCP 完成 Android 自动化测试、批量执行、失败诊断、历史检索和报告交付。",
|
||||
"author": {
|
||||
"name": "chenmingxuan",
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
{
|
||||
"sourceId": "artemis-automation",
|
||||
"repo": "https://git.playones.com/chenmingxuan/Artemis-Eapil.git",
|
||||
"ref": "v2.0.1",
|
||||
"commit": "b584dae80aaae66607d6335bf1efa4b847f1955b",
|
||||
"ref": "v2.1.0",
|
||||
"commit": "83bcfd54d578a76aaea73e059a8547e3dc07ddbd",
|
||||
"adapter": "claude-skill",
|
||||
"sourcePath": "skills/artemis-use",
|
||||
"syncedAt": "2026-10-22T16:00:00Z"
|
||||
"syncedAt": "2026-10-23T16:00:00Z"
|
||||
}
|
||||
@@ -22,7 +22,7 @@ ARTEMIS 自己编排手机和已授权插件,共用网页的任务队列、历
|
||||
|
||||
## 三种模式
|
||||
|
||||
- **Flash**:路径明确的快速执行,单个执行模型观察并操作;适合冒烟、稳定流程与探索后复跑。可以接受中途指导,也有结束验收。任务长不自动等于需要 Pro。
|
||||
- **Flash**:路径明确的快速执行,单个执行模型观察并操作;适合冒烟、稳定流程与探索后复跑。可以接受中途指导;最终 AI 判定与分析默认关闭,可在全局功能配置开启。关闭时显示“未做 AI 判定”,不能当作验收通过。任务长不自动等于需要 Pro。
|
||||
- **Pro**:需要持久计划、多个分支、检查点、ADB/日志诊断或详细报告;按计划执行并验证。`explorer_mode` 是 Pro 的视觉定位深度,不是探索任务模式。
|
||||
- **探索**:用户只有大概流程,需要与模型交流、纠正方向或人工示范;以 Pro 的执行能力推进,最终提炼一个可复用用例。超时保存并暂停,可继续。探索成功、生成用例和 Flash/Pro 复跑成功是三个不同结果。
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
| --- | --- | --- | --- |
|
||||
| 适合 | 目标清楚、路径明确、低分支流程;冒烟和已提炼用例复跑 | 复杂分支、持久计划、检查点、长程监控、ADB/日志、详细记录 | 流程尚未定型,用户参与纠正或示范的一个复杂用例 |
|
||||
| 执行方式 | 单执行模型观察→动作;需要时使用定位等辅助工具 | Planner 制订计划;Operator 执行;Checker 验收;按需生成报告 | 复用 Pro 工具和计划,加持续对话、提问等待、示范分析和用例提炼 |
|
||||
| 验收 | 默认结束时只读验收 | 默认结束验收,可配置检查点/strict | 先处理用户指导,再验收探索目标;不把示范当独立复跑通过 |
|
||||
| 验收 | 最终 AI 判定与分析默认关闭,可在全局功能配置开启 | 默认结束验收,可配置检查点/strict | 先处理用户指导,再验收探索目标;不把示范当独立复跑通过 |
|
||||
| 中途输入 | `inject_instruction` 指导当前任务 | 同 Flash,还能记录计划及诊断信息 | `message` 持续交流;结束后消息仅讨论,再操作需 `continue` |
|
||||
| 入口 | `mobile_run_task(model="Flash")` | `mobile_run_task(model="Pro")` | `mobile_exploration(create/start/...)` |
|
||||
| 产物 | 步骤、证据、测试结果,按需导出报告 | 以上加计划、笔记和可选详细报告 | 对话、各轮执行和示范证据、一个用例的不可变版本 |
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
"sourceId": "caveman",
|
||||
"repo": "https://github.com/JuliusBrussee/caveman.git",
|
||||
"ref": "main",
|
||||
"commit": "bad48a0e1df55e05e3f52249afa35ecc1909ee76",
|
||||
"commit": "b4531dfc05a3ef0ba93b57e8bfa5f48564a4b4d6",
|
||||
"adapter": "codex-plugin",
|
||||
"sourcePath": "plugins/caveman",
|
||||
"syncedAt": "2026-10-21T06:48:34Z"
|
||||
"syncedAt": "2026-10-23T16:00:00Z"
|
||||
}
|
||||
@@ -3,5 +3,5 @@
|
||||
"name": "playwright浏览器自动化操作",
|
||||
"version": "20260605",
|
||||
"keySource": "none",
|
||||
"syncedAt": "2026-10-22T16:02:41Z"
|
||||
"syncedAt": "2026-10-23T16:02:55Z"
|
||||
}
|
||||
@@ -2,8 +2,8 @@
|
||||
"sourceId": "next-skills",
|
||||
"repo": "https://github.com/vercel/next.js.git",
|
||||
"ref": "canary",
|
||||
"commit": "443a9e7abf105be7b9e4bfe77200aebb2d46645f",
|
||||
"commit": "3dd7baa502a13a96836680fa4d84cb5020ae94fc",
|
||||
"adapter": "skill-collection",
|
||||
"sourcePath": "skills",
|
||||
"syncedAt": "2026-10-22T16:00:00Z"
|
||||
"syncedAt": "2026-10-23T16:00:00Z"
|
||||
}
|
||||
@@ -2,8 +2,8 @@
|
||||
"sourceId": "ppt-master",
|
||||
"repo": "https://github.com/hugohe3/ppt-master.git",
|
||||
"ref": "main",
|
||||
"commit": "622bf0148bca4f697b0184322c7e2aa2a04520a2",
|
||||
"commit": "523e5bd972f94c3cac8742fec0d54d43824a17bb",
|
||||
"adapter": "claude-skill",
|
||||
"sourcePath": "skills/ppt-master",
|
||||
"syncedAt": "2026-10-22T16:00:00Z"
|
||||
"syncedAt": "2026-10-23T16:00:00Z"
|
||||
}
|
||||
@@ -421,7 +421,9 @@ eligible visual layer may be a direct full-canvas `<rect>` or one inside a
|
||||
simple single-child group. Its fill must have a registered native mapping
|
||||
(solid, linear/radial gradient, or preset pattern), and it must have no
|
||||
transform, filter, clip, rounding, or visible stroke. Export writes the fill as
|
||||
Slide `p:bg`; image elements remain pictures. Structured routes use the
|
||||
Slide `p:bg`; image elements remain pictures. A rebuilt round-trip slide keeps
|
||||
its source `p:bg`, so a new full-canvas `<rect>` there stays a shape at its SVG
|
||||
paint position. Structured routes use the
|
||||
narrower explicit solid-background ownership contract in
|
||||
[`pptx-structure-interface.md`](../../references/pptx-structure-interface.md).
|
||||
|
||||
|
||||
+31
-11
@@ -1823,15 +1823,22 @@ def _apply_roundtrip_slide_overlay(
|
||||
)
|
||||
else:
|
||||
selected_by_id[shape_id] = (source_shapes[shape_id], False)
|
||||
extra_generated = [
|
||||
generated_shapes[shape_id]
|
||||
for shape_id in generated_order
|
||||
if shape_id not in source_id_by_generated_top_id
|
||||
]
|
||||
# New objects keep their SVG paint position: each one follows the nearest
|
||||
# preceding authored object, and leading ones precede the first slot.
|
||||
extra_generated: dict[str | None, list[ET.Element]] = {}
|
||||
preceding_authored_id: str | None = None
|
||||
for shape_id in generated_order:
|
||||
if shape_id in source_id_by_generated_top_id:
|
||||
preceding_authored_id = source_id_by_generated_top_id[shape_id]
|
||||
else:
|
||||
extra_generated.setdefault(preceding_authored_id, []).append(
|
||||
generated_shapes[shape_id]
|
||||
)
|
||||
|
||||
authored_iterator = iter(authored_order)
|
||||
merged_children: list[tuple[ET.Element, bool]] = []
|
||||
final_authored_slot = 0
|
||||
anchor_slots: dict[str | None, int] = {}
|
||||
for child in list(source_tree):
|
||||
shape_id = (
|
||||
source_key_by_element.get(id(child))
|
||||
@@ -1841,16 +1848,18 @@ def _apply_roundtrip_slide_overlay(
|
||||
if shape_id not in authored_top_ids:
|
||||
merged_children.append((child, False))
|
||||
continue
|
||||
anchor_slots.setdefault(None, len(merged_children))
|
||||
next_shape_id = next(authored_iterator, None)
|
||||
if next_shape_id is not None:
|
||||
merged_children.append(selected_by_id[next_shape_id])
|
||||
anchor_slots[next_shape_id] = len(merged_children)
|
||||
final_authored_slot = len(merged_children)
|
||||
if next(authored_iterator, None) is not None:
|
||||
raise TemplateStructureError(
|
||||
"Generated authored shape roster exceeds the source overlay slots"
|
||||
)
|
||||
if not authored_top_ids:
|
||||
final_authored_slot = next(
|
||||
anchor_slots[None] = next(
|
||||
(
|
||||
index
|
||||
for index, (element, _generated) in enumerate(merged_children)
|
||||
@@ -1858,10 +1867,16 @@ def _apply_roundtrip_slide_overlay(
|
||||
),
|
||||
len(merged_children),
|
||||
)
|
||||
merged_children[final_authored_slot:final_authored_slot] = [
|
||||
(element, True)
|
||||
for element in extra_generated
|
||||
]
|
||||
if authored_order:
|
||||
# Trailing additions stay after every source authored slot, so unlisted
|
||||
# source shapes past the last filled slot keep painting below them.
|
||||
anchor_slots[authored_order[-1]] = final_authored_slot
|
||||
# Anchors ascend in authored order; splice from the back to keep indexes valid.
|
||||
for anchor, elements in reversed(list(extra_generated.items())):
|
||||
insert_at = anchor_slots[anchor]
|
||||
merged_children[insert_at:insert_at] = [
|
||||
(element, True) for element in elements
|
||||
]
|
||||
|
||||
generated_nodes = [
|
||||
element for element, generated in merged_children if generated
|
||||
@@ -7706,7 +7721,12 @@ def create_pptx_with_native_svg(
|
||||
theme_font_spec=active_theme_font_spec,
|
||||
theme_color_spec=active_theme_color_spec,
|
||||
primary_language=primary_language,
|
||||
promote_background=pptx_structure != "structured",
|
||||
# A round-trip overlay keeps the source p:bg, so a
|
||||
# new full-canvas rect must stay a shape to survive.
|
||||
promote_background=(
|
||||
pptx_structure != "structured"
|
||||
and slide_patch is None
|
||||
),
|
||||
dangerous_nonconforming_export=(
|
||||
dangerous_nonconforming_export
|
||||
),
|
||||
|
||||
+148
@@ -0,0 +1,148 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Regress Edit Native paint order for new objects on rebuilt round-trip slides.
|
||||
|
||||
Usage: python3 -m unittest tests.test_edit_native_batch_d
|
||||
Dependencies: python-pptx and the converter's normal dependencies.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import io
|
||||
import re
|
||||
import sys
|
||||
import tempfile
|
||||
import unittest
|
||||
import zipfile
|
||||
from contextlib import redirect_stderr, redirect_stdout
|
||||
from pathlib import Path
|
||||
from xml.etree import ElementTree as ET
|
||||
|
||||
SCRIPTS_DIR = Path(__file__).resolve().parents[1]
|
||||
if str(SCRIPTS_DIR) not in sys.path:
|
||||
sys.path.insert(0, str(SCRIPTS_DIR))
|
||||
|
||||
from pptx import Presentation # noqa: E402
|
||||
from pptx.enum.shapes import MSO_SHAPE # noqa: E402
|
||||
from pptx.util import Inches # noqa: E402
|
||||
|
||||
from pptx_to_svg.converter import ConvertOptions, convert_pptx_to_svg # noqa: E402
|
||||
from svg_to_pptx.pptx_package import cli # noqa: E402
|
||||
|
||||
NS = {
|
||||
'p': 'http://schemas.openxmlformats.org/presentationml/2006/main',
|
||||
'a': 'http://schemas.openxmlformats.org/drawingml/2006/main',
|
||||
}
|
||||
SOURCE_NAMES = ('base', 'tab', 'callout')
|
||||
SOURCE_GROUP_IDS = {'base': 'shape-2', 'tab': 'shape-3', 'callout': 'shape-4'}
|
||||
|
||||
|
||||
def _rect(name: str, *, full: bool = False) -> str:
|
||||
frame = 'x="0" y="0" width="960" height="720"' if full else 'x="8" y="8" width="100" height="80"'
|
||||
return f'<rect id="{name}" {frame} fill="#F12345" />'
|
||||
|
||||
|
||||
class EditNativeBatchDTests(unittest.TestCase):
|
||||
def setUp(self) -> None:
|
||||
self.temporary = tempfile.TemporaryDirectory()
|
||||
self.addCleanup(self.temporary.cleanup)
|
||||
self.root = Path(self.temporary.name)
|
||||
|
||||
def _workspace(self, *, hidden: tuple[str, ...] = ()) -> Path:
|
||||
prs = Presentation()
|
||||
slide = prs.slides.add_slide(prs.slide_layouts[6])
|
||||
for index, name in enumerate(SOURCE_NAMES):
|
||||
shape = slide.shapes.add_shape(
|
||||
MSO_SHAPE.RECTANGLE, Inches(index + 0.5), Inches(1), Inches(2), Inches(2),
|
||||
)
|
||||
shape.name = name
|
||||
if name in hidden:
|
||||
shape._element.find('.//p:cNvPr', NS).set('hidden', '1')
|
||||
source = self.root / 'source.pptx'
|
||||
prs.save(source)
|
||||
project = self.root / 'workspace'
|
||||
with redirect_stdout(io.StringIO()), redirect_stderr(io.StringIO()):
|
||||
convert_pptx_to_svg(source, project, ConvertOptions(inheritance_mode='both', roundtrip=True))
|
||||
return project
|
||||
|
||||
def _groups(self, project: Path) -> tuple[Path, str, dict[str, str]]:
|
||||
path = project / 'authoring-svg-flat' / 'slide_01.svg'
|
||||
text = path.read_text(encoding='utf-8')
|
||||
groups = {
|
||||
name: re.search(rf'<g id="{group_id}".*?</g>', text, re.S).group(0)
|
||||
for name, group_id in SOURCE_GROUP_IDS.items()
|
||||
if f'<g id="{group_id}"' in text
|
||||
}
|
||||
return path, text, groups
|
||||
|
||||
def _author(self, project: Path, *order: str) -> None:
|
||||
"""Rewrite slide 1 so its top-level objects follow ``order``.
|
||||
|
||||
Source names reuse their imported groups; any other name is a new rect,
|
||||
and a ``full:`` prefix makes it full-canvas.
|
||||
"""
|
||||
path, text, groups = self._groups(project)
|
||||
first = min(text.index(group) for group in groups.values())
|
||||
last = max(text.index(group) + len(group) for group in groups.values())
|
||||
body = []
|
||||
for name in order:
|
||||
if name in groups:
|
||||
body.append(groups[name])
|
||||
elif name.startswith('full:'):
|
||||
body.append(_rect(name.removeprefix('full:'), full=True))
|
||||
else:
|
||||
body.append(_rect(name))
|
||||
path.write_text(text[:first] + '\n'.join(body) + text[last:], encoding='utf-8')
|
||||
|
||||
def _export_roster(self, project: Path) -> tuple[list[str], ET.Element]:
|
||||
output = project / 'result.pptx'
|
||||
stdout, stderr = io.StringIO(), io.StringIO()
|
||||
with redirect_stdout(stdout), redirect_stderr(stderr):
|
||||
result = cli.main([str(project), '--roundtrip', '-o', str(output)])
|
||||
self.assertEqual(result, 0, stdout.getvalue() + stderr.getvalue())
|
||||
self.assertIn('rebuilt=1', stdout.getvalue())
|
||||
with zipfile.ZipFile(output) as archive:
|
||||
slide = ET.fromstring(archive.read('ppt/slides/slide1.xml'))
|
||||
tree = slide.find('p:cSld/p:spTree', NS)
|
||||
names = [
|
||||
child.find('./*/p:cNvPr', NS).get('name')
|
||||
for child in tree
|
||||
if child.find('./*/p:cNvPr', NS) is not None
|
||||
]
|
||||
return names, slide
|
||||
|
||||
def test_replaced_first_object_stays_below_source_objects(self) -> None:
|
||||
project = self._workspace()
|
||||
self._author(project, 'hr-base-map', 'tab', 'callout')
|
||||
names, _slide = self._export_roster(project)
|
||||
self.assertEqual(names, ['hr-base-map', 'tab', 'callout'])
|
||||
|
||||
def test_new_objects_keep_leading_middle_and_trailing_positions(self) -> None:
|
||||
project = self._workspace()
|
||||
self._author(project, 'lead', 'base', 'mid-1', 'mid-2', 'tab', 'callout', 'tail')
|
||||
names, _slide = self._export_roster(project)
|
||||
self.assertEqual(names, ['lead', 'base', 'mid-1', 'mid-2', 'tab', 'callout', 'tail'])
|
||||
|
||||
def test_reused_slots_anchor_to_the_object_actually_placed(self) -> None:
|
||||
project = self._workspace()
|
||||
self._author(project, 'callout', 'new', 'tab')
|
||||
names, _slide = self._export_roster(project)
|
||||
self.assertEqual(names, ['callout', 'new', 'tab'])
|
||||
|
||||
def test_trailing_object_stays_above_unlisted_source_shape(self) -> None:
|
||||
project = self._workspace(hidden=('tab',))
|
||||
self._author(project, 'base', 'tail')
|
||||
names, _slide = self._export_roster(project)
|
||||
self.assertEqual(names, ['base', 'tab', 'tail'])
|
||||
|
||||
def test_middle_object_follows_its_authored_predecessor(self) -> None:
|
||||
project = self._workspace(hidden=('tab',))
|
||||
self._author(project, 'base', 'mid', 'callout')
|
||||
names, _slide = self._export_roster(project)
|
||||
self.assertEqual(names, ['base', 'mid', 'tab', 'callout'])
|
||||
|
||||
def test_new_full_canvas_rect_stays_a_shape_under_the_source_background(self) -> None:
|
||||
project = self._workspace()
|
||||
self._author(project, 'full:new-under', 'base', 'tab', 'callout')
|
||||
names, slide = self._export_roster(project)
|
||||
self.assertEqual(names, ['new-under', 'base', 'tab', 'callout'])
|
||||
self.assertIsNone(slide.find('p:cSld/p:bg', NS))
|
||||
@@ -2,8 +2,8 @@
|
||||
"sourceId": "shadcn",
|
||||
"repo": "https://github.com/shadcn-ui/ui.git",
|
||||
"ref": "main",
|
||||
"commit": "25af02b1b467fcd53b63e0c6d6d324c57c16ef18",
|
||||
"commit": "3d98900e9b73c45f035f8109e9d41ba6a51685e7",
|
||||
"adapter": "claude-skill",
|
||||
"sourcePath": "skills/shadcn",
|
||||
"syncedAt": "2026-10-22T16:00:00Z"
|
||||
"syncedAt": "2026-10-23T16:00:00Z"
|
||||
}
|
||||
@@ -290,6 +290,7 @@ uipro init --ai warp # Warp
|
||||
uipro init --ai augment # Augment
|
||||
uipro init --ai codewhale # CodeWhale
|
||||
uipro init --ai zcode # ZCode
|
||||
uipro init --ai kimi # Kimi Code
|
||||
uipro init --ai amazonq # Amazon Q Developer
|
||||
uipro init --ai openclaw # OpenClaw (.agents/skills/)
|
||||
uipro init --ai universal # Universal / Agent Standard (.agents/skills/)
|
||||
@@ -304,6 +305,7 @@ The npm package is `ui-ux-pro-max-cli`; it still installs the `uipro` command. O
|
||||
uipro init --ai claude --global # Install to ~/.claude/skills/
|
||||
uipro init --ai cursor --global # Install to ~/.cursor/skills/
|
||||
uipro init --ai zcode --global # Install to ~/.zcode/skills/
|
||||
uipro init --ai kimi --global # Install to ~/.kimi-code/skills/
|
||||
uipro init --ai universal --global # Install to ~/.agents/skills/
|
||||
```
|
||||
|
||||
@@ -336,7 +338,7 @@ If it is missing, install it yourself from [python.org](https://www.python.org/d
|
||||
|
||||
### Skill Mode (Auto-activate)
|
||||
|
||||
**Supported:** Claude Code, Cursor, Windsurf, Antigravity, Codex CLI, Continue, Gemini CLI, OpenCode, Qoder, CodeBuddy, Droid (Factory), KiloCode, Warp, Augment, CodeWhale, ZCode, Amazon Q Developer, OpenClaw, GitHub Copilot
|
||||
**Supported:** Claude Code, Cursor, Windsurf, Antigravity, Codex CLI, Continue, Gemini CLI, OpenCode, Qoder, CodeBuddy, Droid (Factory), KiloCode, Warp, Augment, CodeWhale, ZCode, Kimi Code, Amazon Q Developer, OpenClaw, GitHub Copilot
|
||||
|
||||
The skill activates automatically when you request UI/UX work. Just chat naturally:
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
"sourceId": "ui-ux-pro-max",
|
||||
"repo": "https://github.com/nextlevelbuilder/ui-ux-pro-max-skill.git",
|
||||
"ref": "main",
|
||||
"commit": "623a9a9037d006ea727f8213f084d02a6b6f11b5",
|
||||
"commit": "d14efff8ed1faa4187f004f79926f428c8074ec7",
|
||||
"adapter": "claude-skill",
|
||||
"sourcePath": ".claude/skills/ui-ux-pro-max",
|
||||
"syncedAt": "2026-10-22T16:00:00Z"
|
||||
"syncedAt": "2026-10-23T16:00:00Z"
|
||||
}
|
||||
Reference in new issue
Block a user