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:
KeyInfo Bot
2026-08-13 16:40:27 +08:00
parent 7a846d93c6
commit 5e6f30c141
48 changed files with 1282 additions and 130 deletions
@@ -40,6 +40,18 @@
},
"category": "Productivity"
},
{
"name": "grill-me",
"source": {
"source": "local",
"path": "./plugins/grill-me"
},
"policy": {
"installation": "AVAILABLE",
"authentication": "ON_INSTALL"
},
"category": "Productivity"
},
{
"name": "guizang-ppt-skill",
"source": {
@@ -2,8 +2,8 @@
"sourceId": "caveman",
"repo": "https://github.com/JuliusBrussee/caveman.git",
"ref": "main",
"commit": "b2ca50b8809d4dbc9f664b398938fddede320001",
"commit": "613d7f0402fb51bdde0edb6b01853b391a06b765",
"adapter": "codex-plugin",
"sourcePath": "plugins/caveman",
"syncedAt": "2026-08-11T16:00:01Z"
"syncedAt": "2026-08-13T08:38:10Z"
}
@@ -0,0 +1,40 @@
{
"name": "grill-me",
"version": "0.1.0",
"description": "通过持续追问和分轮决策树访谈,帮助用户检验并澄清计划、设计、决策或想法。",
"author": {
"name": "Matt Pocock",
"url": "https://github.com/mattpocock"
},
"homepage": "https://github.com/mattpocock/skills/tree/main/skills/productivity/grill-me",
"repository": "https://github.com/mattpocock/skills",
"license": "MIT",
"keywords": [
"grill-me",
"grilling",
"interview",
"planning",
"decision-making"
],
"skills": "./skills/",
"interface": {
"displayName": "Grill Me",
"shortDescription": "用分轮追问检验并澄清计划、设计和决策。",
"longDescription": "Grill Me 通过 grilling 基础 skill 构建设计树,按决策依赖分轮提出问题和推荐答案,持续检验计划、设计、决策或想法,直到双方确认没有未说明的假设。插件同时包含 grill-me 和其必需依赖 grilling。",
"developerName": "Matt Pocock",
"category": "Productivity",
"capabilities": [
"Interactive",
"Read"
],
"defaultPrompt": [
"使用 Grill Me 帮我彻底检验这个想法。",
"使用 Grill Me 通过分轮提问帮我澄清这个计划。"
],
"websiteURL": "https://github.com/mattpocock/skills/tree/main/skills/productivity/grill-me",
"privacyPolicyURL": "https://github.com/mattpocock/skills",
"termsOfServiceURL": "https://github.com/mattpocock/skills",
"brandColor": "#DC2626",
"screenshots": []
}
}
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2026 Matt Pocock
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
@@ -0,0 +1,9 @@
{
"sourceId": "grill-me",
"repo": "https://github.com/mattpocock/skills.git",
"ref": "main",
"commit": "84fdeffd12f2ee307994d1eb6feb48173b6e0502",
"adapter": "skill-collection",
"sourcePath": "skills/productivity",
"syncedAt": "2026-08-13T08:38:10Z"
}
@@ -0,0 +1,7 @@
---
name: grill-me
description: "在用户明确要求严格追问、压力测试或彻底澄清计划、设计、决策或想法时使用。"
disable-model-invocation: true
---
Run a `/grilling` session.
@@ -0,0 +1,5 @@
interface:
display_name: "Grill Me"
short_description: "Sharpen a plan through interview"
policy:
allow_implicit_invocation: false
@@ -0,0 +1,22 @@
---
name: grilling
description: "在用户希望通过分轮问题压力测试计划、决策或想法,或使用 grill 相关触发语时使用。"
---
Interview the user relentlessly until you reach a shared understanding. Map this as a **design tree**: every decision branches into the decisions that hang off it.
Work the tree in **rounds**. The **frontier** is every decision whose prerequisites are already settled — the questions you can ask _now_ without guessing at answers you haven't heard yet. Ask the whole frontier in one round: number each question and give your recommended answer. Then wait for the user's answers before the next round.
Each question should be formatted like so:
```
❓ **Q1** - **<question title>**: <question body, might be multiple paragraphs, including multiple choices>
➡️ <your recommended answer>
```
Each round the user answers reshapes the tree — settled decisions push the frontier outward and unblock questions that depended on them. Recompute the frontier and ask the next round. A question whose answer depends on another question still open in this round belongs to a _later_ round, not this one.
Finding _facts_ is your job, never the user's. When a frontier question needs a fact from the environment (filesystem, tools, etc.), dispatch a sub-agent to find it — don't ask the user for anything you could look up yourself. Don't block on it: a running exploration is an unsettled prerequisite, so only the questions downstream of it wait for the sub-agent to report — ask the rest of the frontier now. The _decisions_ are the user's — put each to them and wait.
The session is done when the frontier is empty: every branch of the design tree visited, nothing left silently assumed. Do not act on it until the user confirms you have reached a shared understanding.
@@ -0,0 +1,3 @@
interface:
display_name: "Grilling"
short_description: "Stress-test thinking a round of questions at a time"
@@ -3,5 +3,5 @@
"name": "playwright浏览器自动化操作",
"version": "20260605",
"keySource": "none",
"syncedAt": "2026-08-11T16:02:06Z"
"syncedAt": "2026-08-13T08:40:25Z"
}
@@ -2,8 +2,8 @@
"sourceId": "next-skills",
"repo": "https://github.com/vercel/next.js.git",
"ref": "canary",
"commit": "bbec4fe2bd7222aaa9b4de58269d821ab128fab8",
"commit": "fef4c28bba9f080fce9687a7a8ee7ac3784de57e",
"adapter": "skill-collection",
"sourcePath": "skills",
"syncedAt": "2026-08-11T16:00:01Z"
"syncedAt": "2026-08-13T08:38:10Z"
}
@@ -2,8 +2,8 @@
"sourceId": "ppt-master",
"repo": "https://github.com/hugohe3/ppt-master.git",
"ref": "main",
"commit": "4e6ecbcb0dc079efebd3c79b775c0f02581509fe",
"commit": "bcc5762d6c770025f37ca459f5d9ea96f1783fc1",
"adapter": "claude-skill",
"sourcePath": "skills/ppt-master",
"syncedAt": "2026-08-11T16:00:01Z"
"syncedAt": "2026-08-13T08:38:10Z"
}
@@ -233,7 +233,7 @@ If motion is enabled, [`animations.md`](./animations.md) owns its implementation
| Scene-backed evidence or metrics | `#P2-01` / `#P2-05` + `#M2-01` or `#M2-03`; let the image carry context and native SVG carry information |
| One selected region needs explanation | Use `#P2-03` for an outline and caption on one picture; use `#P2-04` when a second same-source picture must magnify the region |
| Several sources should read as one object | `#P3-21` + restrained `#M3-01`, or `#P3-20` + a native text/color cell |
| One continuous scene should span detached shapes | `#M1-10` + optional `#M3-05`; keep one-picture topology |
| One continuous scene should span detached shapes | `#M1-10` + optional `#M3-05`; combine `#P1-08` for a triangular image-and-copy split, and keep one-picture topology |
| Same-source windows must remain independent | `#M1-11`; add `#C2-01` or `#C2-02` only when consecutive pages use the relationship |
| A prepared subject should re-layer over its source | `#A2-03`; keep the base and cutout registered, and insert a native middle layer only when it has a distinct job |
| A busy visual needs one focal region | `#M2-05`, or prepared `#A3-01` / `#A3-03` when a native contrast treatment is insufficient |
@@ -669,6 +669,18 @@ least two.
[`paths.py`](../scripts/svg_to_pptx/drawingml/paths.py); native-object fallback
bounds reuse its normalized commands rather than a second path grammar.
**Reference — not a constraint**: use the fewest curve segments and control
points that preserve the intended silhouette. Set endpoints and tangent
directions first; use `S` after `C` or `T` after `Q` when reflected controls
preserve deliberate tangent continuity.
```xml
<path d="M80 300 C180 180 300 180 400 300 S620 420 720 300"
fill="none" stroke="#2563EB" stroke-width="4" stroke-linecap="round"/>
<path d="M80 520 Q240 400 400 520 T720 520"
fill="none" stroke="#0F766E" stroke-width="4" stroke-linecap="round"/>
```
Command identity, relative coordinates, shorthand, arc parameters, and original
handles are not retained. Geometry needs non-zero bounds. Before authoring a
freeform, apply [`native-shape-authoring.md`](./native-shape-authoring.md):
@@ -130,9 +130,9 @@ _ICON_PREVIEW_SAMPLES = {
'phosphor-duotone': ('house', 'chart-line', 'users', 'target'),
}
# Prefer the same memorable entry port as live preview. Normal single-project
# execution releases it between Step 4 and Step 6; concurrent projects advance
# from this base while explicit ``--port`` remains exact.
# Keep the long-standing Confirm UI entry port. Live preview uses a separate
# base range so stale preview tabs cannot address a later Confirm UI process.
# Concurrent Confirm UI sessions advance while explicit ``--port`` remains exact.
DEFAULT_PORT = 5050
PUBLIC_HOST = '127.0.0.1'
STARTUP_TIMEOUT = 10
@@ -1258,7 +1258,7 @@ def _localized_text_present(candidate: dict, field: str) -> bool:
"""Return whether a candidate carries non-empty localized prose."""
return any(
isinstance(candidate.get(key), str) and bool(candidate[key].strip())
for key in (field, f'{field}_zh', f'{field}_en', f'{field}_ja')
for key in (field, f'{field}_zh', f'{field}_zh_tw', f'{field}_en', f'{field}_ja')
)
@@ -2270,8 +2270,8 @@ def _build_catalogs() -> dict:
"""Return the static catalog set with the canvas list synced live from
``config.CANVAS_FORMATS`` — the single source of truth for canvas formats —
so the confirm page can never drift from the pipeline's real formats. The
set of formats and their dimensions come from config; trilingual labels and
use text are kept from catalogs.json (with a plain fallback for any new id).
set of formats and their dimensions come from config; four-language labels
and use text are kept from catalogs.json (with a plain fallback for new ids).
"""
data = json.loads(_CATALOGS_PATH.read_text(encoding='utf-8'))
try:
@@ -560,16 +560,204 @@
on: "开",
option_prefix: "方案",
error_retry: "出错,请重试"
},
"zh-TW": {
page_title: "確認設計方案",
topbar_hint: "回答開放問題,或選擇並調整推薦項,然後繼續。",
stage_anchors: "第一階段 · 溝通契約",
stage_final_plan: "第二階段 · 最終方案與製作",
loading: "載入中…",
load_error: "無法載入推薦檔案,需在啟動前寫入。",
btn_confirm: "確認",
btn_confirm_contract: "確認溝通契約並繼續 →",
btn_confirm_final_plan: "確認最終方案 →",
deriving: "正在根據你的選擇生成下游選項…",
template_selection_required: "請選擇自由設計或使用範本;選擇使用範本時,至少選擇一個工作區。",
connection_lost: "確認頁服務連線中斷,正在重試;如果持續失敗,請回到聊天視窗走聊天確認。",
confirmed_title: "✓ 已確認",
confirmed_hint: "選擇已儲存,可關閉此頁並回到聊天視窗。",
lang_toggle_title: "切換語言",
sec_template_choice: "設計基礎",
template_choice_hint: "選擇這份簡報如何建立設計系統。",
template_free_title: "根據目前內容從零設計",
template_free_desc: "不使用可重複使用的範本工作區,由 Strategist 根據目前專案推導視覺系統。",
template_use_title: "使用範本",
template_use_desc: "選擇一個或多個 Brand、Style、Layout、Deck 或指定工作區。",
sec_template_library: "範本組合",
template_library_hint: "每種已註冊範本最多選擇一個;Brand、Style、Layout、Deck 可以組合使用。",
sec_template_explicit: "指定範本",
template_explicit_hint: "本次執行明確提供的精確工作區最多選擇一個;顯示來源路徑供你核對。",
template_kind_brand: "Brand",
template_kind_style: "Style",
template_kind_layout: "Layout",
template_kind_deck: "Deck",
template_source_library: "範本庫",
template_source_explicit: "指定地址",
template_source_path: "來源路徑",
template_select_none: "無",
template_none_registered: "尚無已註冊範本",
template_none_explicit: "本次執行沒有指定範本",
sec_canvas: "畫布格式",
sec_pages: "頁數",
sec_audience: "目標受眾",
sec_communication: "這份簡報要完成什麼",
sec_delivery: "如何使用、之後留下什麼",
sec_narrative: "敘事方向",
sec_visual: "視覺方向",
sec_color: "色彩方案",
sec_icons: "圖示使用",
sec_type: "字型方案",
sec_images: "圖片使用",
sec_image_production: "圖片產製",
sec_proactive_execution: "主動執行",
sec_mode: "生成模式",
sec_refine: "先審閱設計規範",
sec_design_directions: "成套設計方向",
design_directions_hint: "AI 最傾向的成套方案已預設套用;你可以改選其他方案,或在下方微調各項。調整後可用「還原原始方案」還原整套預設。",
direction_active: "已套用",
direction_adjusted: "已調整",
direction_apply_hint: "按一下即可套用這套完整方案。",
direction_restore: "還原原始方案",
scheme_component_options: "專案專屬自訂方案 · 選取卡片後可編輯",
sec_template_application: "範本套用方式",
template_application_hint: "AI 會根據目前內容推薦如何使用已安裝範本;你可以直接用自然語言修改。",
placeholder_template_application: "說明使用、跳過、重複或重排哪些範本頁面/原型,哪些內容必須保留,哪些可以替換或重組。",
sub_mode: "敘事模式",
sub_visual: "視覺風格",
sub_divergence: "材料發散度(多大程度重塑,還是貼近源材料)",
placeholder_divergence: "用你自己的話寫,例如「嚴格貼著文件來」/「在源材料範圍內自由重組並展開」。留空則按平衡處理。",
communication_intent: "這份簡報需要完成什麼?",
communication_intent_hint: "開放回答,可按需組合:告知、解釋、說服、決策、對齊、教學、報告與問責、動員、留檔與交接。必要時說明主次或先後,不需要選擇標籤。",
placeholder_communication_intent: "例如:先報告進展並暴露風險,再推動管理階層決定下一階段投入。",
audience_outcome: "期望的受眾變化 / 成功條件",
placeholder_audience_outcome: "結束後,受眾應該知道、理解、相信、決定或採取什麼行動?",
core_message: "核心資訊 / 決策請求 / 行動",
placeholder_core_message: "即使其他內容沒有被記住,受眾至少需要接住哪些主張、請求或行動?",
delivery_context: "傳遞場景(明確主要模式)",
delivery_context_hint: "區分演講者主導、讀者主導、混合、錄製/自動播放;混合場景要說明哪一種主導,以及還要兼顧什麼次要用途。",
placeholder_delivery_context: "例如:主要為有主講的 20 分鐘管理階層現場評審;次要為會後獨立閱讀的簽核文件。",
artifact_afterlife: "簡報後的成果用途",
placeholder_artifact_afterlife: "例如:簽核、評審、稽核、留檔、交接或重複使用;沒有後續用途時可留空。",
stage1_current_value_hint: "可編輯欄位中是推薦內容。你可以保留、修改或清空;確認時會按目前內容原樣儲存,空白也會保持為空。",
content_divergence_locked_hint: "目前流程要求原文和頁面結構保持不變,因此該欄位已鎖定。",
custom: "自訂",
custom_placeholder: "輸入自訂內容…",
ai_custom_candidate: "AI 自訂方案",
ai_custom_candidate_hint: "始終展示完整內容用於比較;預設不選取,選擇後可編輯。",
custom_behavior_required: "已選擇的 AI 自訂方案不能為空。",
custom_color_required: "請先填寫自訂配色說明,再繼續確認。",
design_system_required: "請先選擇完整的配色與字型方案,再繼續確認。",
mode_behavior_placeholder: "描述敘事階段、標題語氣、頁面節奏和表達姿態。",
visual_style_behavior_placeholder: "描述形狀語言、構圖、裝飾密度、留白、字型氣質和紋理。",
recommended: "推薦",
placeholder_audience: "這份簡報面向誰?",
placeholder_pages: "如:12-15",
hex_override: "自訂色值覆蓋:",
formula_policy: "公式渲染策略",
image_ai_path: "生成配圖來源",
image_strategy: "生成圖風格",
image_strategy_empty: "目前沒有可用的預設風格參考,仍可使用自訂風格。",
image_strategy_required: "請選擇一種生成圖預設,或填寫自訂風格。",
image_strategy_invalid: "所選生成圖預設目前不可用。",
image_strategy_select_placeholder: "選擇生成圖預設…",
image_strategy_recommended_group: "本專案推薦",
image_strategy_all_group: "全部預設風格",
image_strategy_rendering: "渲染風格",
image_strategy_visual: "視覺",
image_strategy_mood: "情緒",
image_strategy_ai_custom: "AI 自訂方案",
image_strategy_ai_custom_desc: "一套全新或綜合多個已有風格的渲染方案;選擇後可以編輯。",
image_strategy_custom_placeholder: "描述生成圖的具體方向、主體、構圖、風格關鍵字或需要避免的內容。",
image_strategy_reference_hint: "參考圖只展示渲染風格;最終 AI 圖片直接繼承上方已選的整套 PPT 配色。",
image_strategy_no_reference: "自訂選擇沒有參考圖。",
image_source_summary: "已選圖片來源",
image_production_hint: "圖片來源和渲染方向已在上方選擇;這裡僅決定實際產製路徑。",
image_usage_notes: "圖片補充要求",
image_usage_notes_placeholder: "例如:優先真實洗手場景;不要卡通病菌;產品照片保持原樣。",
image_usage_required: "請至少選擇一種圖片使用方式。",
image_usage_none_exclusive: "「不使用圖片」不能和其他圖片選項同時選擇。",
proactive_execution_hint: "這些預設開關只在你沒有明確要求時生效;你最新的明確指令始終優先。",
proactive_speaker_notes: "主動生成演講者備註",
proactive_speaker_notes_desc: "預設開啟。無需另行要求,Agent 也會生成演講者備註。",
proactive_custom_animations: "主動生成自訂動畫",
proactive_custom_animations_desc: "預設關閉。策略師的動畫建議仍會保留;開啟後,Agent 可在沒有另行要求時實際製作自訂動畫。",
proactive_narration_audio: "主動生成旁白音訊",
proactive_narration_audio_desc: "預設關閉。這裡保留原始選擇,不改寫演講者備註開關;策略師會在設計規範中解析旁白所需的最終備註狀態。",
font_heading: "標題",
font_body: "正文",
font_selection: "字型選擇",
primary_language_font: "主要語言字型",
english_font: "英文字型",
font_picker_hint: "選擇推薦方案會同步下方字型;修改任一下拉或手動字型後會標記為已自訂。",
other_installed_font: "其他已安裝字型…",
other_font_placeholder: "輸入精確的已安裝字型名稱",
customized: "已自訂",
font_body_size: "正文基準字級",
font_body_size_hint: "所有字級按這個正文基準推導。",
body_size_unit_relation: "SVG px 與 PPT pt 的換算:1px = 0.75pt。",
body_size_pt_hint: "約 {pt} pt(按 1px = 0.75pt 換算;提交仍儲存 px)。",
role_size_pt_hint: "約 {pt} pt",
body_size_hint_canvas: "目前畫布建議 ~{lo}–{hi}px(依有效畫布跨距計算)。",
body_size_hint_purpose: "該閱讀模式推薦 {def}px(單一固定值,非區間)。",
body_size_hint_oor: "(目前數值超出該畫布的常用範圍——請確認單位無誤、是否合適。)",
delivery_purpose: "閱讀模式",
delivery_purpose_hint: "決定資訊主要由頁面還是講者承擔:近讀型用完整句、短段落和細節自洽;演講型一頁一意,以簡短主張和視覺證據為主。",
size_override: "逐角色字級覆蓋:",
size_role_title: "標題",
size_role_subtitle: "副標題",
size_role_annotation: "註解",
custom_typography: "自訂字型方案",
custom_color: "自訂配色",
custom_color_placeholder: "用文字描述配色,如:深藍主色、暖橙強調、白色背景——或直接貼上 HEX 值…",
role_background: "背景",
role_secondary_bg: "次級背景",
role_primary: "主色",
role_accent: "強調",
role_secondary_accent: "次強調",
role_body_text: "正文文字",
cjk: "中文",
latin: "西文",
sample_heading_cjk: "主題方案標題",
sample_heading_latin: "Presentation Title",
sample_body_cjk: "關鍵資訊摘要",
sample_body_latin: "Key message summary",
style_preview_label: "整體形象(配色 + 字型 + 圖示)",
style_preview_body: "· 僅大致形象,非實際版式",
no_icons: "無圖示",
preview_big_title: "大標題",
preview_section_title: "章節標題",
preview_latin_title: "Section Title",
preview_body_intro: "正文內容用於判斷基礎字級、行距和顏色對比。",
preview_latin_body: "Body text sample for checking Latin typography.",
preview_point_1_title: "正文內容",
preview_point_1_text: "這裡展示普通段落的密度和閱讀節奏。",
preview_point_2_title: "要點說明",
preview_point_2_text: "圖示和文字放在一起,判斷真實使用效果。",
preview_point_3_title: "結論建議",
preview_point_3_text: "組合效果需要在簡報場景下保持清晰可讀。",
mode_continuous_desc: "一次性連續生成整份簡報。",
mode_split_desc: "寫完設計規範後停止,另開視窗繼續生成頁面。",
refine_off_desc: "依次生成設計規範和執行鎖,然後自動繼續。",
refine_on_desc: "生成設計規範後暫停;你可在聊天中修改任何部分,明確確認後再生成執行鎖並繼續製作。",
off_default: "關",
on: "開",
option_prefix: "方案",
error_retry: "出錯,請重試"
}
};
var LANG = (function () {
try {
var stored = window.localStorage.getItem("ppt_lang");
if (stored === "zh" || stored === "en" || stored === "ja") return stored;
if (stored === "zh" || stored === "en" || stored === "ja" ||
stored === "zh-TW") return stored;
} catch (e) { /* ignore */ }
var nav = (navigator.language || navigator.userLanguage || "en").toLowerCase();
if (nav.indexOf("zh") === 0) return "zh";
if (nav.indexOf("zh") === 0) {
if (/\bhans\b/.test(nav)) return "zh";
if (/\bhant\b/.test(nav) || /\b(tw|hk|mo)\b/.test(nav)) return "zh-TW";
return "zh";
}
if (nav.indexOf("ja") === 0) return "ja";
return "en";
})();
@@ -579,37 +767,50 @@
return dict[key] != null ? dict[key] : key;
}
// Fallback stays LANG-relative: zh/en users never see Japanese labels,
// ja pages fall back ja → en → zh.
var LANG_FALLBACK = { zh: ["zh", "en", "ja"], en: ["en", "zh", "ja"], ja: ["ja", "en", "zh"] };
// Preserve the existing locale order, then accept zh_tw-only candidate
// prose from any persisted UI language so browser and server validation agree.
// Entries are FIELD SUFFIXES, not BCP-47 tags: "zh-TW" data lives in
// `<base>_zh_tw` keys, so a hyphenless suffix is used here and in langField().
var LANG_FALLBACK = {
zh: ["zh", "en", "ja", "zh_tw"],
en: ["en", "zh", "ja", "zh_tw"],
ja: ["ja", "en", "zh", "zh_tw"],
"zh-TW": ["zh_tw", "zh", "en", "ja"]
};
// Suffix used to look up localized catalog/recommendation fields.
var LANG_FIELD = { "zh-TW": "zh_tw" };
function langField(lang) {
return LANG_FIELD[lang] || lang;
}
var IMAGE_COMPARISON_LABELS = {
rendering: {
"vector-illustration": { zh: "矢量插画", en: "Vector illustration", ja: "ベクターイラスト" },
flat: { zh: "扁平插画", en: "Flat illustration", ja: "フラットイラスト" },
"3d-isometric": { zh: "3D 等距", en: "3D isometric", ja: "3Dアイソメトリック" },
"digital-dashboard": { zh: "数字仪表盘", en: "Digital dashboard", ja: "デジタルダッシュボード" },
"corporate-photo": { zh: "企业摄影", en: "Corporate photo", ja: "企業写真" },
blueprint: { zh: "蓝图线稿", en: "Blueprint", ja: "ブループリント" },
editorial: { zh: "编辑杂志", en: "Editorial", ja: "エディトリアル" },
"sketch-notes": { zh: "手绘笔记", en: "Sketch notes", ja: "スケッチノート" },
"ink-notes": { zh: "墨线笔记", en: "Ink notes", ja: "インクノート" },
chalkboard: { zh: "粉笔黑板", en: "Chalkboard", ja: "チョークボード" },
watercolor: { zh: "水彩", en: "Watercolor", ja: "水彩" },
"warm-scene": { zh: "暖调场景", en: "Warm scene", ja: "暖色シーン" },
"screen-print": { zh: "丝网印刷", en: "Screen print", ja: "スクリーンプリント" },
"fantasy-animation": { zh: "幻想动画", en: "Fantasy animation", ja: "ファンタジーアニメ" },
"pixel-art": { zh: "像素艺术", en: "Pixel art", ja: "ピクセルアート" },
nature: { zh: "自然有机", en: "Nature", ja: "自然・オーガニック" },
"minimalist-swiss": { zh: "瑞士极简", en: "Minimalist Swiss", ja: "スイスミニマル" },
glassmorphism: { zh: "玻璃拟态", en: "Glassmorphism", ja: "グラスモーフィズム" },
"vintage-poster": { zh: "复古海报", en: "Vintage poster", ja: "ヴィンテージポスター" },
"paper-cut": { zh: "剪纸拼贴", en: "Paper cut", ja: "ペーパーカット" }
"vector-illustration": { zh: "矢量插画", zh_tw: "向量插畫", en: "Vector illustration", ja: "ベクターイラスト" },
flat: { zh: "扁平插画", zh_tw: "扁平插畫", en: "Flat illustration", ja: "フラットイラスト" },
"3d-isometric": { zh: "3D 等距", zh_tw: "3D 等距", en: "3D isometric", ja: "3Dアイソメトリック" },
"digital-dashboard": { zh: "数字仪表盘", zh_tw: "數位儀表板", en: "Digital dashboard", ja: "デジタルダッシュボード" },
"corporate-photo": { zh: "企业摄影", zh_tw: "企業攝影", en: "Corporate photo", ja: "企業写真" },
blueprint: { zh: "蓝图线稿", zh_tw: "藍圖線稿", en: "Blueprint", ja: "ブループリント" },
editorial: { zh: "编辑杂志", zh_tw: "編輯雜誌", en: "Editorial", ja: "エディトリアル" },
"sketch-notes": { zh: "手绘笔记", zh_tw: "手繪筆記", en: "Sketch notes", ja: "スケッチノート" },
"ink-notes": { zh: "墨线笔记", zh_tw: "墨線筆記", en: "Ink notes", ja: "インクノート" },
chalkboard: { zh: "粉笔黑板", zh_tw: "粉筆黑板", en: "Chalkboard", ja: "チョークボード" },
watercolor: { zh: "水彩", zh_tw: "水彩", en: "Watercolor", ja: "水彩" },
"warm-scene": { zh: "暖调场景", zh_tw: "暖調場景", en: "Warm scene", ja: "暖色シーン" },
"screen-print": { zh: "丝网印刷", zh_tw: "絲網印刷", en: "Screen print", ja: "スクリーンプリント" },
"fantasy-animation": { zh: "幻想动画", zh_tw: "幻想動畫", en: "Fantasy animation", ja: "ファンタジーアニメ" },
"pixel-art": { zh: "像素艺术", zh_tw: "像素藝術", en: "Pixel art", ja: "ピクセルアート" },
nature: { zh: "自然有机", zh_tw: "自然有機", en: "Nature", ja: "自然・オーガニック" },
"minimalist-swiss": { zh: "瑞士极简", zh_tw: "瑞士極簡", en: "Minimalist Swiss", ja: "スイスミニマル" },
glassmorphism: { zh: "玻璃拟态", zh_tw: "玻璃擬態", en: "Glassmorphism", ja: "グラスモーフィズム" },
"vintage-poster": { zh: "复古海报", zh_tw: "復古海報", en: "Vintage poster", ja: "ヴィンテージポスター" },
"paper-cut": { zh: "剪纸拼贴", zh_tw: "剪紙拼貼", en: "Paper cut", ja: "ペーパーカット" }
}
};
function localized(obj, base) {
if (!obj) return "";
var langKey = base + "_" + LANG;
var langKey = base + "_" + langField(LANG);
if (obj[langKey] != null) return obj[langKey];
var order = LANG_FALLBACK[LANG] || LANG_FALLBACK.en;
var i;
@@ -663,13 +864,13 @@
}
function applyStaticTranslations() {
document.documentElement.setAttribute("lang", LANG === "zh" ? "zh-CN" : (LANG === "ja" ? "ja" : "en"));
document.documentElement.setAttribute("lang", LANG === "zh" ? "zh-CN" : (LANG === "zh-TW" ? "zh-TW" : (LANG === "ja" ? "ja" : "en")));
document.querySelectorAll("[data-i18n]").forEach(function (node) {
node.textContent = t(node.getAttribute("data-i18n"));
});
}
var LANG_NAMES = { zh: "中文", en: "English", ja: "日本語" };
var LANG_NAMES = { zh: "中文", en: "English", ja: "日本語", "zh-TW": "繁體中文" };
function refreshLangToggle(toggleBtn) {
// Custom dropdown (OS-independent): button shows the CURRENT language.
@@ -1447,7 +1648,7 @@
}
function setUiLanguageAttributes(node) {
node.lang = LANG === "zh" ? "zh-CN" : (LANG === "ja" ? "ja-JP" : "en-US");
node.lang = LANG === "zh" ? "zh-CN" : (LANG === "zh-TW" ? "zh-TW" : (LANG === "ja" ? "ja-JP" : "en-US"));
node.dir = "ltr";
}
@@ -3117,7 +3318,7 @@
var signatureMatch = -1;
var stateSignature = typographySignature(STATE.typography || {});
if (STATE.typography && STATE.typography.name !== "custom") cands.forEach(function (c, i) {
var sameName = [localized(c, "name"), c.name_zh, c.name_en, c.name_ja]
var sameName = [localized(c, "name"), c.name_zh, c.name_zh_tw, c.name_en, c.name_ja]
.some(function (name) { return name === STATE.typography.name; });
if (!sameName && c.name && typeof c.name === "object") {
sameName = Object.keys(c.name).some(function (key) {
@@ -4187,7 +4388,8 @@
function applyServerLanguage(data) {
var requested = data && data.lang;
if (requested !== "zh" && requested !== "en" && requested !== "ja") return;
if (requested !== "zh" && requested !== "en" && requested !== "ja" &&
requested !== "zh-TW") return;
var hasStored = false;
try { hasStored = !!window.localStorage.getItem("ppt_lang"); } catch (e) { /* ignore */ }
if (hasStored) return;
@@ -4239,7 +4441,7 @@
var chooseLang = function (v) {
setMenuOpen(false);
toggleBtn.focus();
if (v !== "ja" && v !== "en" && v !== "zh") return;
if (v !== "ja" && v !== "en" && v !== "zh" && v !== "zh-TW") return;
if (v === LANG) return;
LANG = v;
try { window.localStorage.setItem("ppt_lang", LANG); } catch (e2) { /* ignore */ }
@@ -30,6 +30,7 @@
<button id="btn-lang-toggle" class="lang-select-btn" type="button" title="Switch language" aria-haspopup="listbox" aria-expanded="false"><span id="lang-current"></span><span class="lang-caret" aria-hidden="true"></span></button>
<ul id="lang-menu" class="lang-menu" role="listbox" hidden>
<li role="option" tabindex="0" aria-selected="false" data-lang="zh">中文</li>
<li role="option" tabindex="0" aria-selected="false" data-lang="zh-TW">繁體中文</li>
<li role="option" tabindex="0" aria-selected="false" data-lang="en">English</li>
<li role="option" tabindex="0" aria-selected="false" data-lang="ja">日本語</li>
</ul>
@@ -325,7 +325,7 @@ Direction-local custom projections apply to mode, visual style, and generated-im
## Catalogs — `static/catalogs.json` (the finite option universe)
The front-end loads `/api/catalogs` (served by the confirm server) and falls back to the static `/static/catalogs.json` if that route is unavailable. `/api/catalogs` returns the static file **with the `canvas` list synced live from `config.py CANVAS_FORMATS`** — the set of formats and their `dim` come from config (single source of truth, zero drift), while trilingual labels / use text stay in catalogs.json (a plain fallback label is synthesized for any new id config adds). Keys: `canvas`, `modes`, `visual_styles` (grouped), `icons`, `image_usage`, `image_ai_path`, `formula_policy`, `generation_mode`, `delivery_purpose`. Each entry is `{ "id", "label", "label_zh", "label_en", "label_ja", ... }`; descriptions use `desc_zh` / `desc_en` / `desc_ja`, and `visual_styles` groups use `group_zh` / `group_en` / `group_ja`. The front-end falls back to legacy `label` / `desc` / `group`, so old catalogs still load, but new user-facing catalog text must cover all three languages (zh / en / ja). English labels should mirror canonical reference names (`pyramid`, `swiss-minimal`, `Path A`, `mixed`, etc.); Chinese and Japanese labels should be translated for users. Descriptions render inline after the option title, not as a separate selected-option line. `visual_styles` is `[{ "group", "group_zh", "group_en", "group_ja", "items": [...] }]`. For `canvas` you only need to maintain the trilingual labels in catalogs.json; the format set and dimensions are authoritative in `config.py CANVAS_FORMATS`.
The front-end loads `/api/catalogs` (served by the confirm server) and falls back to the static `/static/catalogs.json` if that route is unavailable. `/api/catalogs` returns the static file **with the `canvas` list synced live from `config.py CANVAS_FORMATS`** — the set of formats and their `dim` come from config (single source of truth, zero drift), while four-language labels / use text stay in catalogs.json (a plain fallback label is synthesized for any new id config adds). Keys: `canvas`, `modes`, `visual_styles` (grouped), `icons`, `image_usage`, `image_ai_path`, `formula_policy`, `generation_mode`, `delivery_purpose`. Each entry is `{ "id", "label", "label_zh", "label_zh_tw", "label_en", "label_ja", ... }`; descriptions use `desc_zh` / `desc_zh_tw` / `desc_en` / `desc_ja`, and `visual_styles` groups use `group_zh` / `group_zh_tw` / `group_en` / `group_ja`. The front-end falls back to legacy `label` / `desc` / `group`, so old catalogs still load, but new user-facing catalog text must cover all four languages (zh / zh-TW / en / ja). English labels should mirror canonical reference names (`pyramid`, `swiss-minimal`, `Path A`, `mixed`, etc.); Simplified Chinese, Traditional Chinese, and Japanese labels should be translated for users. Descriptions render inline after the option title, not as a separate selected-option line. `visual_styles` is `[{ "group", "group_zh", "group_zh_tw", "group_en", "group_ja", "items": [...] }]`. For `canvas` you only need to maintain the four-language labels in catalogs.json; the format set and dimensions are authoritative in `config.py CANVAS_FORMATS`.
## Round-trip data contract
@@ -521,7 +521,7 @@ Template-mode-only Stage-2 fragment:
- `image_notes` is the initial strategy note shown under the image source chips. Use it for page-role guidance and constraints: which source applies where, what to avoid, which user assets are authoritative, how realistic / abstract the imagery should be, and what can remain as placeholders. It is intent guidance, not a separate finite option.
- Final Stage 2 shows and submits `recommend.image_ai_path` as one of `auto` / `api` / `host-native` / `manual` only while its current `image_usage` includes `ai`; changing sources refreshes that production control on the same page.
- **Color candidates carry the user-facing core `palette`**: `background`, `secondary_bg`, `primary`, `accent`, `secondary_accent`, and `body_text`. The page renders every role as a labelled swatch with its HEX value visible, and offers per-role override inputs for precise single-role edits, plus a **Custom color card with a free-text box** — the user can describe the palette in words or paste HEX values instead of filling each role; this writes `color: { "name": "custom", "custom": "<text>" }` to `result.json` for the AI to interpret. Legacy `text` is accepted as an alias for `body_text`, but new files should write `body_text`. Strategist derives secondary text, borders, state colors, and visual-style neutral tiers while writing `design_spec.md`, then projects the machine values to `spec_lock.md`; those are not user-facing confirmation choices.
- **Candidate display text may be multilingual**: color / typography candidates can provide `name_zh` / `name_en` / `name_ja` and `note_zh` / `note_en` / `note_ja`; the page falls back to legacy `name` / `note`. Labels resolve in the page language first, then fall back across the others (a `ja` page: ja → en → zh; zh/en pages keep their zh↔en fallback and try `_ja` last), so when `lang` is `ja` always include the `_ja` variants — otherwise the candidate labels render in English.
- **Candidate display text may be multilingual**: color / typography candidates can provide `name_zh` / `name_zh_tw` / `name_en` / `name_ja` and `note_zh` / `note_zh_tw` / `note_en` / `note_ja`; the page falls back to legacy `name` / `note` when present. Otherwise localized fields resolve in the page language first, then by the locale's fallback order: zh → en → ja → zh_tw, en → zh → ja → zh_tw, ja → en → zh → zh_tw, or zh_tw → zh → en → ja. Include all four variants in newly authored multilingual candidates so a persisted UI-language choice never hides recommendation text.
- **Typography candidates** use concrete heading/body `primary`; non-English decks also use `english`, while English-primary decks omit it. `cjk` / `latin` remain legacy aliases. Localized `name` labels the pair and `css` only previews. Bundles differ overall; font pairs may repeat without blocking. Fixed pairs require `fixed: true`. Catalog `fonts` supplies language-filtered dropdowns plus Other without limiting recommendations; edits mark Custom and refresh the preview. Include topic samples. [`canvas-formats.md`](../../references/canvas-formats.md) § "Typography Scale Start" is the single owner of initial body anchors and sanity bands; the browser mirrors that rule, and submitted values remain px.
- **Per-role size override** (parallel to color's per-role HEX override): besides `body_size`, the page exposes editable inputs for `title` / `subtitle` / `annotation`. The browser applies one documented deterministic dependency chain: PPT uses `reading mode → body baseline`, non-PPT uses `canvas → body baseline`, then every canvas uses `body baseline → unpinned role sizes` (role ramp: `body ×` the §g ratios). Changing reading mode updates a PPT body and all unpinned roles locally; changing body updates unpinned roles locally. Editing body or a role pins that value, so later reading-mode changes do not overwrite it. A font-only selection preserves current sizes; applying a different complete direction, or using the active card's explicit restore action, restores that direction's typography baseline and derived unpinned sizes. This is a browser-only state update: it performs no fetch and asks the backend to author no new recommendations. Each role input is labelled as px and shows an approximate pt equivalent (`1px = 0.75pt`) for orientation. The final values are written to `result.json` as `typography.sizes: { "title", "subtitle", "annotation" }` in **px** — every canvas, no pt and no `sizes_pt` provenance. These confirmed values are Strategist input anchors: the completed page plan may add recurring roles, and downstream execution owns bounded per-occurrence treatment. Candidate `sizes` remain accepted for compatibility; fresh Stage 2 preserves a candidate `body_size` as its baseline and derives only missing or unpinned role sizes from the same local ramp before first render.
- **`delivery_purpose` compatibility key / Reading mode** (enumerable, PPT only) decides where meaning is carried, not merely how large type is: `text` makes pages self-contained with complete sentences, short prose, captions, tables, and necessary detail; `balanced` shares explanation between page and presenter; `presentation` uses one idea, concise claims, and visual evidence while speech / notes carry the detail. It therefore governs page grammar, granularity, density / rhythm, and note burden. Reading-mode cards intentionally show **no px value**; the typography section owns the separately visible body / role sizes and applies any local default. It is surfaced in Stage 2 beside the visual system, separate from communication intent. `recommend.delivery_purpose` pre-selects one; `result.json` retains the key, while `spec_lock.md` uses canonical `consumption_mode`. Non-PPT canvases omit it.
@@ -530,7 +530,7 @@ Template-mode-only Stage-2 fragment:
- **`design_directions`** is the canonical Stage-2 starting set: exactly three top-down, project-fit bundles with stable ids, localized copy, custom mode/style/rendering, icons, complete language-aware typography, and HEX `background`, `secondary_bg`, `primary`, `accent`, `secondary_accent`, `body_text`. The `selected` card carries the persistent Recommended marker and is applied first. A custom direction card uses its localized style-summary note—or the required behavior fallback—instead of requesting a preset-style preview. Newly authored notes may borrow localized catalog display labels where useful or use concise natural language freely; they never force an approximate label or expose internal catalog ids. Clicking an inactive card applies every field it owns; projected custom fields can then be edited in place and all lower controls may diverge. The active card shows an adjusted state and exposes an explicit restore action for its immutable authored bundle. `result.json` stores the edited current components, never a direction id.
- `recommend.generation_mode` and `refine_spec` mirror [`generate-pptx`](../../workflows/generate-pptx.md) Step 4. `split` / `true` are explicit opt-ins. Refinement adds no UI stage: after Gate 1 it stops before the lock for unrestricted chat revision until approval.
- `content_divergence` is a **free-text** Stage-1 source-treatment field. Blank means a balanced default; facts stay sourced at every level. Strategist consumes it while authoring §IX and records it in `design_spec.md §I`; it is not written to `spec_lock.md`. Beautify sends `{ "value": "keep source wording and page structure verbatim", "locked": true }`, so the UI displays it read-only and the server restores it on every staged submit. Template-fill does not use this confirmation flow and does not surface it.
- `lang` is the soft UI-language default (`zh` / `en` / `ja`); the persisted user choice wins. It never sets `primary_language`.
- `lang` is the soft UI-language default (`zh` / `zh-TW` / `en` / `ja`); the persisted user choice wins. It never sets `primary_language`.
### Output — `result.json` (written on submit, read by the AI)
@@ -110,7 +110,9 @@ _SLIDE_CACHE: dict = {} # path -> (mtime, (content, warnings))
_LIST_CACHE_LOCK = threading.Lock()
_LIST_CACHE: dict = {} # path -> (mtime, annotation_count_on_disk)
DEFAULT_PORT = 5050
# Keep live preview on a separate range from Confirm UI so a stale preview tab
# cannot send ``/api/shutdown`` to a later Confirm UI process.
DEFAULT_PORT = 6060
PUBLIC_HOST = '127.0.0.1'
STARTUP_TIMEOUT = 15
@@ -231,16 +231,96 @@
nav_last: "末页 (End)",
nav_counter: "{current} / {total}",
nav_empty: "— / —"
},
"zh-TW": {
page_title: "PPT Master - 即時預覽",
panel_slides: "投影片",
panel_annotations: "標註",
panel_edit_annotate: "編輯 / 標註",
placeholder_select_slide: "在左側選擇一張投影片開始",
label_selected_element: "已選元素",
empty_selected_element: "點選投影片中的元素進行選擇",
btn_select_group: "選擇父群組",
label_batch_edit: "批次編輯",
label_group_edit: "群組編輯",
section_geometry: "幾何",
section_style: "樣式",
section_text_style: "文字",
section_raw_attrs: "原始屬性",
label_edit_instruction: "修改說明",
pending_none: "沒有待套用修改",
pending_summary: "{edits} 筆直接修改、{annotations} 個頁面有 AI 標註待套用",
pending_pages: "頁面:{pages}",
quick_align: "對齊/移動",
quick_resize: "調整大小",
quick_replace_image: "換圖",
quick_copy: "改文案",
quick_relayout: "重排此區域",
placeholder_annotation: "描述希望 AI 如何修改該元素……",
placeholder_annotation_multi: "描述希望如何修改所選 {count} 個元素……",
btn_add_annotation: "新增標註",
label_annotations_on_slide: "本頁標註",
btn_submit_annotations: "套用修改",
btn_exit_preview: "結束預覽",
modal_submit: "提交",
modal_cancel: "取消",
empty_waiting_slides: "正在等待生成投影片……",
empty_no_slides: "未找到投影片",
placeholder_live_ready: "即時預覽已就緒,生成的投影片會在這裡出現。",
placeholder_slide_writing: "投影片仍在寫入,等待下次重新整理……",
empty_annotations: "尚無標註",
tooltip_remove_annotation: "刪除標註",
multi_selected: "已選 {count} 個元素",
multi_mixed: "混合",
err_load_slides: "載入投影片失敗:",
err_load_slide: "載入投影片失敗:",
err_add_annotation: "新增標註失敗:",
err_remove_annotation: "刪除標註失敗:",
err_save: "儲存失敗:",
err_edit: "編輯失敗:",
label_direct_edit: "物件屬性(點選套用修改後寫入)",
prop_multiline_hint: "多行文字——選取單行(tspan)編輯文字",
edit_saved_hint: "修改已暫存。點選「套用修改」後寫入 svg_output。",
btn_undo: "復原",
undo_done: "已復原上一筆暫存修改",
undo_empty: "沒有可復原的暫存修改",
overlap_caption: "此處元素重疊——請點選其中一個",
err_empty_svg: "投影片已載入但畫布為空。SVG 可能損壞或缺少根 <svg> 元素。",
warn_icon_inline: "{count} 個圖示渲染失敗:{names}",
warn_matrix_transform: "本次幾何修改會以 transform matrix 儲存。預覽是準確的;PPTX 匯出需要使用支援 matrix 的目前匯出器。",
modal_matrix_transform_note: "\n\n提示:至少有一筆暫存幾何修改使用了 transform matrix。請用目前 PPTX 匯出器重新匯出,確保 matrix 被套用。",
slide_error_tooltip: "該投影片解析失敗:",
reload_banner: "目前頁已在磁碟上更新,點此重新載入。",
modal_confirm_submit: "確認將暫存的直接修改和 AI 標註寫入磁碟?\n\n預覽服務會繼續執行。需要關閉時請點選結束預覽。",
modal_success_submit: "修改已儲存到 svg_output。\n\n預覽服務仍在執行。",
modal_success_direct_only: "修改已儲存到 svg_output。\n\n直接修改已經寫入 SVG 原始檔;需要重新整理 PPTX 時,請回到對話視窗要求重新匯出。預覽服務仍在執行。",
modal_success_annotations_only: "標註已儲存到 svg_output。\n\n需要 AI 理解並執行這些標註時,請回到對話視窗要求套用標註。預覽服務仍在執行。",
modal_success_mixed: "直接修改和標註已儲存到 svg_output。\n\n請回到對話視窗先套用需要 AI 判斷的標註,確認後再重新匯出 PPTX。預覽服務仍在執行。",
modal_confirm_exit: "結束預覽並停止本機服務?\n\n未套用的屬性修改和標註將被丟棄。",
modal_success_exit: "預覽已停止。\n\n可以關閉本分頁並回到對話視窗。",
modal_stopping: "正在停止預覽服務……",
lang_toggle_title: "切換語言",
nav_first: "第一頁 (Home)",
nav_prev: "上一頁 (←)",
nav_next: "下一頁 (→)",
nav_last: "末頁 (End)",
nav_counter: "{current} / {total}",
nav_empty: "— / —"
}
};
var LANG = (function () {
try {
var stored = window.localStorage.getItem("ppt_lang");
if (stored === "zh" || stored === "en" || stored === "ja") return stored;
if (stored === "zh" || stored === "en" || stored === "ja" ||
stored === "zh-TW") return stored;
} catch (e) { /* ignore */ }
var nav = (navigator.language || navigator.userLanguage || "en").toLowerCase();
if (nav.indexOf("zh") === 0) return "zh";
if (nav.indexOf("zh") === 0) {
if (/\bhans\b/.test(nav)) return "zh";
if (/\bhant\b/.test(nav) || /\b(tw|hk|mo)\b/.test(nav)) return "zh-TW";
return "zh";
}
if (nav.indexOf("ja") === 0) return "ja";
return "en";
})();
@@ -259,7 +339,7 @@
}
function applyI18n() {
document.documentElement.setAttribute("lang", LANG === "zh" ? "zh-CN" : (LANG === "ja" ? "ja" : "en"));
document.documentElement.setAttribute("lang", LANG === "zh" ? "zh-CN" : (LANG === "zh-TW" ? "zh-TW" : (LANG === "ja" ? "ja" : "en")));
document.title = t("page_title");
document.querySelectorAll("[data-i18n]").forEach(function (el) {
el.textContent = t(el.getAttribute("data-i18n"));
@@ -273,7 +353,7 @@
updateNavLabel();
}
var LANG_NAMES = { zh: "中文", en: "English", ja: "日本語" };
var LANG_NAMES = { zh: "中文", en: "English", ja: "日本語", "zh-TW": "繁體中文" };
function refreshLangUI(lang) {
// Custom dropdown (OS-independent): button shows the CURRENT language.
@@ -289,7 +369,7 @@
}
function setLang(lang) {
if (lang !== "zh" && lang !== "en" && lang !== "ja") return;
if (lang !== "zh" && lang !== "en" && lang !== "ja" && lang !== "zh-TW") return;
LANG = lang;
try { window.localStorage.setItem("ppt_lang", lang); } catch (e) { /* ignore */ }
applyI18n();
@@ -34,6 +34,7 @@
<button id="btn-lang-toggle" class="lang-select-btn" type="button" title="Switch language" aria-haspopup="listbox" aria-expanded="false"><span id="lang-current"></span><span class="lang-caret" aria-hidden="true"></span></button>
<ul id="lang-menu" class="lang-menu" role="listbox" hidden>
<li role="option" tabindex="0" aria-selected="false" data-lang="zh">中文</li>
<li role="option" tabindex="0" aria-selected="false" data-lang="zh-TW">繁體中文</li>
<li role="option" tabindex="0" aria-selected="false" data-lang="en">English</li>
<li role="option" tabindex="0" aria-selected="false" data-lang="ja">日本語</li>
</ul>
@@ -240,7 +240,7 @@ the inherited / source-derived default so the user sees the recommendation and
keeps the place to change it. Schema →
[`scripts/docs/confirm_ui.md`](../../scripts/docs/confirm_ui.md).
The typography rows below show the non-English shape; omit `english` for an English source.
Rows are abbreviated; follow Confirm UI's four-locale contract and omit `english` for English sources.
```json
{
@@ -69,7 +69,7 @@ Triggered by the user signals listed in "When to Run".
## Notes (editor invariants — referenced from Generate Step 6)
- **UI**: trilingual (中文 / English / 日本語); auto-detects from `navigator.language`, persists in `localStorage`, switched via the language dropdown on the right panel. The right panel is an **Edit / Annotate** surface: direct SVG edits and AI-needed annotations are visually separated, with a pending-status strip showing staged direct edits and pages with unsaved annotations. Slide navigation: first/prev/next/last buttons at the top of the center panel, plus `←` / `→` / `Home` / `End` (suppressed while typing in the annotation textarea).
- **UI**: four-language (中文 / 繁體中文 / English / 日本語); auto-detects from `navigator.language`, persists in `localStorage`, switched via the language dropdown on the right panel. The right panel is an **Edit / Annotate** surface: direct SVG edits and AI-needed annotations are visually separated, with a pending-status strip showing staged direct edits and pages with unsaved annotations. Slide navigation: first/prev/next/last buttons at the top of the center panel, plus `←` / `→` / `Home` / `End` (suppressed while typing in the annotation textarea).
- **Buttons**: `Add annotation` stages annotation text in memory; `Apply changes` writes staged direct edits plus annotation markers to disk and keeps the service running; `Exit preview` is the only UI action that stops Flask.
- **Direct edit (no AI)**: selection mode determines the right-panel surface. Single element = full object inspector (geometry, safe text content, computed text styles for the selected text node or descendant text inside a selected textbox/group, raw SVG attributes except protected fields like `id`, UI `class`, event handlers, and hrefs). SVG `<g>` group = group-level edit surface; select via `Alt/Option` + click or **Select parent group** from a child element. Multi-select = limited batch editor over top-level selected objects only: shared x/y plus `fill` / `stroke` / `opacity`; text style fields (`font-size` / `font-family` / `font-weight` / `text-anchor`) appear only when every selected object is `text`/`tspan`. Preview updates immediately; disk writes wait for **Apply changes**.
- **Drag to move**: press and drag an already-selected element on the canvas to reposition it (selection stays a separate click, so the background is never dragged by accident); the whole selection moves together under multi-select. The pointer delta is mapped through each element's own CTM, so moves track the cursor regardless of viewport scale or group transforms. Each release stages one direct edit per moved element (the same `x`/`y`-or-`transform` write the geometry inputs produce), previewed live and written only on **Apply changes**; dragging on empty canvas is still rubber-band selection. A failed stage rolls the canvas back to the pre-drag position.
@@ -2,8 +2,8 @@
"sourceId": "shadcn",
"repo": "https://github.com/shadcn-ui/ui.git",
"ref": "main",
"commit": "41bbc12cfd39ed8d9cb8da04275479ee7ecc0612",
"commit": "a85299a9edd2a961e32f01ced86963a852652bd2",
"adapter": "claude-skill",
"sourcePath": "skills/shadcn",
"syncedAt": "2026-08-11T16:00:01Z"
"syncedAt": "2026-08-13T08:38:10Z"
}
@@ -1,6 +1,6 @@
{
"name": "superpowers",
"version": "6.2.0",
"version": "6.3.0",
"description": "面向编码 Agent 的规划、TDD、调试、代码评审和交付工作流集合。",
"author": {
"name": "Jesse Vincent",
+76 -11
View File
@@ -2,10 +2,33 @@
Superpowers is a complete software development methodology for your coding agents, built on top of a set of composable skills and some initial instructions that make sure your agent uses them.
## Table of Contents
## Quickstart
Give your agent Superpowers: [Claude Code](#claude-code), [Antigravity](#antigravity), [Codex App](#codex-app), [Codex CLI](#codex-cli), [Cursor](#cursor), [Factory Droid](#factory-droid), [Gemini CLI](#gemini-cli), [GitHub Copilot CLI](#github-copilot-cli), [Kimi Code](#kimi-code), [OpenCode](#opencode), [Pi](#pi).
- [How it works](#how-it-works)
- [Commercial Services](#commercial-services)
- [Getting Started](#installation)
- [Claude Code](#claude-code)
- [Antigravity](#antigravity)
- [Codex App](#codex-app)
- [Codex CLI](#codex-cli)
- [Cursor](#cursor)
- [Devin CLI](#devin-cli)
- [Factory Droid](#factory-droid)
- [Gemini CLI](#gemini-cli)
- [GitHub Copilot CLI](#github-copilot-cli)
- [Grok Build CLI](#grok-build-cli)
- [Kimi Code](#kimi-code)
- [OpenCode](#opencode)
- [Pi](#pi)
- [Hermes Agent](#hermes-agent)
- [The Basic Workflow](#the-basic-workflow)
- [Community](#community)
- [What's Inside](#whats-inside)
- [Philosophy](#philosophy)
- [Contributing](#contributing)
- [Updating](#updating)
- [License](#license)
- [Visual companion telemetry](#visual-companion-telemetry)
## How it works
@@ -102,6 +125,20 @@ Superpowers is available via the [official Codex plugin marketplace](https://git
- Or search for "superpowers" in the plugin marketplace.
### Devin CLI
- Install the plugin from this repository:
```bash
devin plugins install obra/superpowers
```
- Update to the latest version with:
```bash
devin plugins update superpowers
```
### Factory Droid
- Register the marketplace:
@@ -144,6 +181,22 @@ Superpowers is available via the [official Codex plugin marketplace](https://git
copilot plugin install superpowers@superpowers-marketplace
```
### Grok Build CLI
Superpowers is available via the [official Grok plugin marketplace](https://github.com/xai-org/plugin-marketplace).
- Install the plugin from xAI's official marketplace:
```bash
grok plugin install superpowers@xai-official --trust
```
- Or open the marketplace in the TUI, search for Superpowers, and install it:
```text
/marketplace
```
### Kimi Code
Superpowers is available in Kimi Code's plugin marketplace.
@@ -193,6 +246,18 @@ pi -e /path/to/superpowers
The Pi package loads the Superpowers skills and a small extension that injects the `using-superpowers` bootstrap at session startup and again after compaction. Pi has native skills, so no compatibility `Skill` tool is required. Subagent and task-list tools remain optional Pi companion packages.
### Hermes Agent
Install Superpowers as a Hermes plugin from this repository:
```bash
hermes plugins install obra/superpowers --enable
```
Restart any active Hermes sessions after installing. Note: Hermes has no
post-compaction hook, so a very long session that compacts over its first
turn loses the bootstrap — start a fresh session if skills stop triggering.
## The Basic Workflow
1. **brainstorming** - Activates before writing code. Refines rough ideas through questions, explores alternatives, presents design in sections for validation. Saves design document.
@@ -211,6 +276,14 @@ The Pi package loads the Superpowers skills and a small extension that injects t
**The agent checks for relevant skills before any task.** Mandatory workflows, not suggestions.
## Community
Superpowers is built by [Jesse Vincent](https://blog.fsck.com) and the rest of the folks at [Prime Radiant](https://primeradiant.com).
- **Discord**: [Join us](https://discord.gg/35wsABTejz) for community support, questions, and sharing what you're building with Superpowers
- **Issues**: https://github.com/obra/superpowers/issues
- **Release announcements**: [Sign up](https://primeradiant.com/superpowers/) to get notified about new versions
## What's Inside
### Skills Library
@@ -271,11 +344,3 @@ MIT License - see LICENSE file for details
## Visual companion telemetry
Because skills and plugins don't provide any feedback to creators, we have no idea how many of you are using Superpowers. By default, the Prime Radiant logo on brainstorming's optional visual companion feature is loaded from our website. It includes the version of Superpowers in use. It does not include any details about your project, prompt, or coding agent. We don't see your clicks or anything about what you're building. This helps us have a rough idea of how many folks are using Superpowers and which version of Superpowers they're using. It's 100% optional. To disable this, set the environment variable `SUPERPOWERS_DISABLE_TELEMETRY` to any true value. Superpowers also honors Claude Code's `DISABLE_TELEMETRY` and `CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC` opt-outs.
## Community
Superpowers is built by [Jesse Vincent](https://blog.fsck.com) and the rest of the folks at [Prime Radiant](https://primeradiant.com).
- **Discord**: [Join us](https://discord.gg/35wsABTejz) for community support, questions, and sharing what you're building with Superpowers
- **Issues**: https://github.com/obra/superpowers/issues
- **Release announcements**: [Sign up](https://primeradiant.com/superpowers/) to get notified about new versions
@@ -2,8 +2,8 @@
"sourceId": "superpowers",
"repo": "https://github.com/obra/superpowers.git",
"ref": "main",
"commit": "44c9b2d6e889982ac18c27d05a19fefe335194e1",
"commit": "b36e0829c6d0140e93cfef2ca599b1b07d4a7797",
"adapter": "codex-plugin",
"sourcePath": ".",
"syncedAt": "2026-07-29T16:00:04Z"
"syncedAt": "2026-08-13T08:38:10Z"
}
@@ -7,20 +7,91 @@ description: "在开始创造性工作前澄清意图、约束和可行方向;
Help turn ideas into fully formed designs and specs through natural collaborative dialogue.
Start by understanding the current project context, then ask questions one at a time to refine the idea. Once you understand what you're building, present the design and get user approval.
Start by classifying how much process the request needs, then work
through your path: understand the context, refine the idea, present a
design, and get your human partner's approval.
<HARD-GATE>
Do NOT invoke any implementation skill, write any code, scaffold any project, or take any implementation action until you have presented a design and the user has approved it. This applies to EVERY project regardless of perceived simplicity.
Do NOT invoke any implementation skill, write any code, scaffold any
project, or take any implementation action until you have told your
human partner what you intend and they have approved it. This applies
to EVERY task on EVERY path below — the ceremony scales with the task;
the approval gate never does.
</HARD-GATE>
## Anti-Pattern: "This Is Too Simple To Need A Design"
## Three Paths
Every project goes through this process. A todo list, a single-function utility, a config change — all of them. "Simple" projects are where unexamined assumptions cause the most wasted work. The design can be short (a few sentences for truly simple projects), but you MUST present it and get approval.
Before your first question, classify the request and say the
classification out loud — "this looks bounded, so I'll present a short
design here rather than write a spec" — so your human partner can
override it:
- **Spike** — a feasibility question ("can we...", "is it possible...",
"quick and dirty is fine") whose output is an answer, not code you
keep. Present the question and what you'll try in 2-3 sentences, get
a nod, then find out as cheaply as correctness allows. No design
doc, no spec file. Report findings as a recommendation; anything you
built stays labeled throwaway.
- **Bounded** — a well-scoped change to code that already exists in
this repo: a new flag, a small endpoint, a one-file fix.
Understanding the kind of app is not enough — bounded means the flow
you are changing is already here to read. If there is no existing
flow to change, the task is not bounded. Ask the clarifying
questions that matter, present a short design IN CHAT (a few
sentences to a few short paragraphs), and STOP. Implementation
starts only after your human partner says yes to that design — a
bounded task's approval is as hard a gate as an architectural
one. No spec file, no implementation plan document.
- **Architectural** — new projects, new subsystems, changes that
restructure how components fit together or alter interfaces others
depend on. Follow the full process: questions, approaches, sectioned
design, written spec, then the writing-plans skill.
When in doubt between two paths, take the heavier one. The ratchet is
one-way: hidden complexity discovered mid-task upgrades the path —
stop, say so, and step up. Nothing downgrades mid-task.
## Anti-Pattern: "Too Simple To Need Approval"
Every path ends with your human partner approving your intent before
implementation. A todo list, a single-function utility, a config
change — the design may be two sentences in chat, but you MUST present
it and get approval. "Simple" tasks are where unexamined assumptions
cause the most wasted work. What scales with simplicity is the
artifact, never the approval.
## Red Flags
| Thought | Reality |
|---------|---------|
| "This is too simple to need a design" | Simple means a short design, not no design. Two sentences in chat, then approval. |
| "I'll call it bounded and skip the spec" | Reaching for a label to skip work IS the doubt — take the heavier path. |
| "It's bounded and the design is obvious — I'll start while they read it" | The gate is the approval, not the design's length. Present, then stop until you hear yes. |
| "I understand this kind of app, so it's bounded" | Bounded measures the repo, not your familiarity. A new project has no existing flow — it is architectural. |
| "The spike works, so I'll keep the code" | A spike's output is an answer. Keeping the code is a new request — classify it. |
| "It grew, but I'm almost done — no need to re-classify" | Hidden complexity upgrades the path mid-task. Stop and say so. |
| "They approved the spike, so the follow-up change is approved too" | Each task gets its own classification and its own approval. |
## Checklist
You MUST create a task for each of these items and complete them in order:
Classify first, announce the path, then create a task for each item on
your path and complete them in order.
**Spike:**
1. **Explore project context** — enough to frame the probe
2. **Present question + probe plan** — 2-3 sentences
3. **Get approval** — a nod is enough
4. **Investigate** — as cheaply as correctness allows
5. **Report findings** — a recommendation; label anything built as throwaway
**Bounded:**
1. **Explore project context** — check files, docs, recent commits
2. **Ask clarifying questions** — one at a time, the ones that matter
3. **Present short design in chat** — approach, files touched, testing
4. **Get approval** — STOP and wait for an explicit yes; presenting the design and starting in the same breath is skipping the gate
5. **Implement** — proceed with the normal development workflow (TDD applies); no plan document
**Architectural:**
1. **Explore project context** — check files, docs, recent commits
2. **Offer the visual companion just-in-time** — NOT upfront. The first time a question would genuinely be clearer shown than described, offer it then (its own message); on approval its browser tab opens for you. If no visual question ever arises, never offer it. See the Visual Companion section below.
3. **Ask clarifying questions** — one at a time, understand purpose/constraints/success criteria
@@ -35,6 +106,13 @@ You MUST create a task for each of these items and complete them in order:
```dot
digraph brainstorming {
"Classify: spike / bounded / architectural" [shape=diamond];
"Present question + probe (2-3 sentences)" [shape=box];
"Ask clarifying questions (bounded)" [shape=box];
"Present short design in chat" [shape=box];
"Human approves?" [shape=diamond];
"Investigate; report recommendation" [shape=doublecircle];
"Implement via normal workflow (no plan doc)" [shape=doublecircle];
"Explore project context" [shape=box];
"Ask clarifying questions" [shape=box];
"Propose 2-3 approaches" [shape=box];
@@ -44,7 +122,17 @@ digraph brainstorming {
"Spec self-review\n(fix inline)" [shape=box];
"User reviews spec?" [shape=diamond];
"Invoke writing-plans skill" [shape=doublecircle];
"Hidden complexity? Upgrade path" [shape=box];
"Classify: spike / bounded / architectural" -> "Present question + probe (2-3 sentences)" [label="spike"];
"Classify: spike / bounded / architectural" -> "Ask clarifying questions (bounded)" [label="bounded"];
"Classify: spike / bounded / architectural" -> "Explore project context" [label="architectural"];
"Present question + probe (2-3 sentences)" -> "Human approves?";
"Ask clarifying questions (bounded)" -> "Present short design in chat";
"Present short design in chat" -> "Human approves?";
"Human approves?" -> "Investigate; report recommendation" [label="spike: yes"];
"Human approves?" -> "Implement via normal workflow (no plan doc)" [label="bounded: yes"];
"Hidden complexity? Upgrade path" -> "Classify: spike / bounded / architectural";
"Explore project context" -> "Ask clarifying questions";
"Ask clarifying questions" -> "Propose 2-3 approaches";
"Propose 2-3 approaches" -> "Present design sections";
@@ -58,10 +146,21 @@ digraph brainstorming {
}
```
**The terminal state is invoking writing-plans.** Do NOT invoke frontend-design, mcp-builder, or any other implementation skill. The ONLY skill you invoke after brainstorming is writing-plans.
**Terminal states are path-bound.** Architectural: the ONLY skill you
invoke after brainstorming is writing-plans — never frontend-design,
mcp-builder, or any other implementation skill. Bounded: after
approval, implementation proceeds directly through the normal
development workflow; no plan document. Spike: the terminal state is a
reported recommendation.
## The Process
The subsections below serve the bounded and architectural paths (a
spike stops at "present the probe, get a nod"). Sections from
**Exploring approaches** onward are architectural-path depth — for
bounded work, context plus a few questions plus a short in-chat design
is the whole process.
**Understanding the idea:**
- Check out the current project state first (files, docs, recent commits)
@@ -100,7 +199,7 @@ digraph brainstorming {
- Where existing code has problems that affect the work (e.g., a file that's grown too large, unclear boundaries, tangled responsibilities), include targeted improvements as part of the design - the way a good developer improves code they're working in.
- Don't propose unrelated refactoring. Stay focused on what serves the current goal.
## After the Design
## After the Design (architectural path)
**Documentation:**
@@ -83,10 +83,11 @@ scripts/start-server.sh --project-dir /path/to/project --open --foreground
**Copilot CLI:**
```bash
# Use --foreground and start the server via the bash tool with mode: "async"
# so the process survives across turns. Capture the returned shellId for
# read_bash / stop_bash if you need to interact with it later.
scripts/start-server.sh --project-dir /path/to/project --open --foreground
# Start it with Copilot CLI's non-blocking/background shell mechanism so the
# server survives across turns. Keep --foreground so the harness, not the
# script, owns backgrounding. The launcher is a .sh, so invoke it via bash
# (on Windows, call Git Bash's bash.exe from the PowerShell tool).
bash scripts/start-server.sh --project-dir /path/to/project --open --foreground
```
**Other environments:** The server must keep running in the background across conversation turns. If your environment reaps detached processes, use `--foreground` and launch the command with your platform's background execution mechanism.
@@ -174,6 +174,29 @@ git worktree remove "$WORKTREE_PATH"
git worktree prune # Self-healing: clean up any stale registrations
```
**If removal is refused** (`contains modified or untracked files`): the
worktree holds files that exist nowhere else — uncommitted plans, notes,
or scratch work. Never `--force` on your own initiative. Show your human
partner what is at stake and ask:
```bash
git -C "$WORKTREE_PATH" status --porcelain -uall
```
```
Worktree removal refused — these files were never committed:
<file list>
1. Commit them to <branch> before cleanup
2. Move them into <main repo root>
3. Delete them (unrecoverable)
Which?
```
Carry out the choice, then remove the worktree.
**Otherwise:** The host environment owns this workspace — leave it in
place. If your platform provides a workspace-exit tool, use it.
@@ -196,6 +219,7 @@ place. If your platform provides a workspace-exit tool, use it.
| "'Yeah, get rid of it' counts as confirmation" | Only the typed word `discard` authorizes deletion. |
| "The PR is up, so the worktree is clutter now" | PR feedback gets fixed in that worktree. It stays until the work lands. |
| "This other worktree looks stale — I'll clean it too" | Clean up only worktrees under `.worktrees/` or `worktrees/`. Everything else belongs to the host. |
| "Removal refused — `--force` is just finishing the cleanup" | The refusal means files exist only in that worktree. `--force` destroys them permanently. Show your human partner and ask. |
| "The merged-result failure is probably flaky" | A failing merged result stops everything. Branch and worktree stay put while you investigate. |
| "The base branch is obviously main" | Confirm the fork point or ask. Merging into the wrong base is expensive to undo. |
| "The push was rejected — force-push will fix it" | A rejected push means the remote moved. Investigate; force-push only on your human partner's explicit request. |
@@ -34,6 +34,15 @@ Subagent (general-purpose):
Your review is read-only on this checkout. Do not mutate the working tree, the index, HEAD, or branch state in any way. Use tools like `git show`, `git diff`, and `git log` to inspect history. If you need a working copy of a different revision, check it out into a separate temporary directory (e.g. `git worktree add /tmp/review-[SHA] [SHA]`) — never move HEAD on this checkout.
## You Do Not Dispatch Subagents
Do all of this review yourself. Never spawn a subagent to review part
of the diff, and never spawn another reviewer for a second opinion.
This process already provides every review seat the work gets; a
reviewer you spawn duplicates one of them at full cost, and its
verdict counts for nothing. If the diff feels too large for one
pass, review it in passes yourself and say so in your report.
## What to Check
**Plan alignment:**
@@ -14,7 +14,21 @@ Execute plan by dispatching a fresh implementer subagent per task, a task review
**Narration:** between tool calls, narrate at most one short line — the
ledger and the tool results carry the record.
**Continuous execution:** Do not pause to check in with your human partner between tasks. Execute all tasks from the plan without stopping. The only reasons to stop are: BLOCKED status you cannot resolve, ambiguity that genuinely prevents progress, or all tasks complete. "Should I continue?" prompts and progress summaries waste their time — they asked you to execute the plan, so execute it.
**Continuous execution:** Do not pause to check in with your human partner between tasks. Execute all tasks from the plan without stopping. The only reasons to stop are the four named below, or all tasks complete. "Should I continue?" prompts and progress summaries waste their time — they asked you to execute the plan, so execute it.
**Rulings, not stalls.** A running plan does not wait on a human. Conflicts,
ambiguities, plan defects, a cap you would have asked to exceed — decide
them. The spec is the binding authority, the plan is its argument, and your
judgment settles what neither answers. Record every decision in the ledger as
`Ruling: <what you decided> — <why> — <what it costs if wrong>`, and keep
going. A wrong ruling costs rework your human partner can see and undo; a
session parked on a question costs their whole day and buys nothing.
Four things stop you, and only these: an irreversible or destructive
operation; a security-sensitive action; a side effect outside this worktree
that norms say you ask about first (a merge, a push to a shared branch, a
publish); and a plan so broken that every path forward is a guess. For those,
stop and ask.
## When to Use
@@ -57,14 +71,14 @@ digraph process {
"Generate review package, dispatch task reviewer (./task-reviewer-prompt.md)" [shape=box];
"Spec ✅ and quality approved?" [shape=diamond];
"Finding conflicts with plan text?" [shape=diamond];
"Ask human partner which governs" [shape=box];
"Rule on the conflict, ledger the ruling" [shape=box];
"Fix round R of 5: R≤3 resume implementer; R≥4 fresh implementer, more capable model" [shape=box];
"Dispatch scoped re-review (./re-review-prompt.md)" [shape=box];
"All findings addressed?" [shape=diamond];
"R = 5?" [shape=diamond];
"Adjudicate each open finding" [shape=box];
"Any load-bearing finding?" [shape=diamond];
"STOP: report BLOCKED to human partner" [shape=box];
"Rule and continue; stop only if every path forward is a guess" [shape=box];
"Park findings in ledger with rulings" [shape=box];
"Append completion to ledger, mark todo complete" [shape=box];
}
@@ -85,8 +99,8 @@ digraph process {
"Generate review package, dispatch task reviewer (./task-reviewer-prompt.md)" -> "Spec ✅ and quality approved?";
"Spec ✅ and quality approved?" -> "Append completion to ledger, mark todo complete" [label="yes"];
"Spec ✅ and quality approved?" -> "Finding conflicts with plan text?" [label="no"];
"Finding conflicts with plan text?" -> "Ask human partner which governs" [label="yes"];
"Ask human partner which governs" -> "Fix round R of 5: R≤3 resume implementer; R≥4 fresh implementer, more capable model";
"Finding conflicts with plan text?" -> "Rule on the conflict, ledger the ruling" [label="yes"];
"Rule on the conflict, ledger the ruling" -> "Fix round R of 5: R≤3 resume implementer; R≥4 fresh implementer, more capable model";
"Finding conflicts with plan text?" -> "Fix round R of 5: R≤3 resume implementer; R≥4 fresh implementer, more capable model" [label="no"];
"Fix round R of 5: R≤3 resume implementer; R≥4 fresh implementer, more capable model" -> "Dispatch scoped re-review (./re-review-prompt.md)";
"Dispatch scoped re-review (./re-review-prompt.md)" -> "All findings addressed?";
@@ -95,7 +109,7 @@ digraph process {
"R = 5?" -> "Fix round R of 5: R≤3 resume implementer; R≥4 fresh implementer, more capable model" [label="no - next round"];
"R = 5?" -> "Adjudicate each open finding" [label="yes - breaker trips"];
"Adjudicate each open finding" -> "Any load-bearing finding?";
"Any load-bearing finding?" -> "STOP: report BLOCKED to human partner" [label="yes"];
"Any load-bearing finding?" -> "Rule and continue; stop only if every path forward is a guess" [label="yes"];
"Any load-bearing finding?" -> "Park findings in ledger with rulings" [label="no"];
"Park findings in ledger with rulings" -> "Append completion to ledger, mark todo complete";
"Append completion to ledger, mark todo complete" -> "More tasks remain?";
@@ -140,19 +154,32 @@ a ledger file, not only in todos.
that happens, recover from `git log`.
Read the plan once, note its context and Global Constraints, and create a
todo per task.
todo per task. If the plan names a Spec, read that too: the spec is the
authority the plan argues from, and conflicts inside the plan resolve
against it. A plan with no reachable spec gets a ledger note saying so —
rulings made without one are provisional.
Before dispatching Task 1, scan the plan once for conflicts:
Before dispatching Task 1, scan the plan once for conflicts, writing down
what you checked as you check it:
- tasks that contradict each other or the plan's Global Constraints
- anything the plan explicitly mandates that the review rubric treats as a
defect (a test that asserts nothing, verbatim duplication of a logic block)
Present everything you find to your human partner as one batched question —
each finding beside the plan text that mandates it, asking which governs —
before execution begins, not one interrupt per discovery mid-plan. If the
scan is clean, proceed without comment. The review loop remains the net for
conflicts that only emerge from implementation.
The scan's output is a table, not a verdict. One row for every pair of tasks
that share a file or an interface: the two tasks, what one produces against
what the other consumes, and what you found. One row for every task: whether
its own text agrees with itself — the tests it specifies against the code it
specifies, the files it creates against the files it later touches. "The scan
is clean" without those rows is not a scan you ran.
Write the table to the ledger. Rule on everything you find before execution
begins — each finding against the plan text that mandates it — and record
each ruling in the ledger. If the scan is clean, proceed without comment.
Rule on each conflict it surfaces — the spec is the binding authority, the
plan is its argument — record the ruling beside its row, and dispatch
Task 1. The review loop remains the net for conflicts that only emerge from
implementation.
## Model Selection
@@ -193,10 +220,29 @@ that implementer. Single-file mechanical fixes also take the cheapest tier.
## The Task Loop
**Batch small same-shape work.** When the plan lists several tasks that are
each a small, independent edit of the same kind — the same one-line fix,
constant change, or field addition repeated across files — do not dispatch
one subagent per task. Compose ONE dispatch brief listing every file and
its change, send the whole batch to a single subagent, and review its diff
as one unit. Reserve one-dispatch-per-task for work that needs its own
judgment, its own tests, or its own review surface.
Everything you paste into a dispatch prompt — and everything a subagent
prints back — stays resident in your context for the rest of the session
and is re-read on every later turn. Hand artifacts over as files.
**Waiting on dispatched subagents:** never poll a wait interface with
short timeouts, and never sit in one silent, open-ended wait either.
While you have local work — ledger updates, packaging the next review,
reading reports — keep working; child results arrive on their own.
When you are genuinely idle, wait in bounded stretches (five to ten
minutes, where your platform allows), and between stretches post one
line of status and reconcile your live children: list them, and chase
any that finished without reporting. A bounded stretch keeps nearly
all of a long wait's efficiency while guaranteeing a stuck or lost
child is noticed within minutes, not at the end of the session.
### 1. Dispatch the implementer
Record BASE (`git rev-parse HEAD`) before dispatching — the review package
@@ -223,6 +269,12 @@ and fix-round diffs need it.
later dispatches — a real session's dispatch hit 42k chars of which 99%
was pasted history. A fresh subagent needs its task, the interfaces it
touches, and the global constraints. Nothing else.
- The dispatch carries the no-subagents contract (it is in the
implementer template): the implementer never dispatches subagents —
not helpers, and never a reviewer. Review arrives from you, after the
report. In real sessions, every reviewer a worker spawned duplicated
the task review the controller dispatched anyway — a full extra
review seat per task.
- If an earlier task parked a finding in the area this task touches, carry
a pointer to that ledger entry in the dispatch.
- Record the implementer's agent identity from the dispatch result —
@@ -245,7 +297,7 @@ Implementer subagents report one of four statuses. Handle each appropriately:
1. If it's a context problem, provide more context and re-dispatch with the same model
2. If the task requires more reasoning, re-dispatch with a more capable model
3. If the task is too large, break it into smaller pieces
4. If the plan itself is wrong, escalate to the human
4. If the plan itself is wrong, rule on the correction, ledger it, and re-dispatch with the ruling carried in the dispatch
**Never** ignore an escalation or force the same model to retry without changes. If the implementer said it's stuck, something needs to change.
@@ -312,10 +364,11 @@ Before the loop starts, two routes leave it immediately:
before merge. A roll-up nobody reads is a silent discard. Minor findings
never enter the loop.
- A finding labeled plan-mandated — or any finding that conflicts with
what the plan's text requires — is the human's decision, like any plan
contradiction: present the finding and the plan text, ask which governs.
Do not dismiss the finding because the plan mandates it, and do not
dispatch a fix that contradicts the plan without asking.
what the plan's text requires — is yours to rule on: weigh the finding
against the plan text, decide with the spec as the binding authority, and
ledger the ruling before you act on it. Do not dismiss the finding because
the plan mandates it, and do not dispatch a fix that contradicts the plan
without a recorded ruling.
Everything else enters the loop. A fix round is one fix dispatch plus one
scoped re-review. Five rounds maximum per task:
@@ -360,15 +413,16 @@ dispatching. Adjudicate each open finding yourself — you hold the plan and
the cross-task context the reviewer lacks:
- **The reviewer is wrong, or the point is contestable:** park it —
`Task <N>: parked — <finding> — ruling: <why the code stands>`. The final
`Task <N>: parked — <finding> — Ruling: <why the code stands>`. The final
review sees both sides.
- **Real, but nothing downstream builds on it:** park it the same way, with
a ruling that says it's real and deferred.
- **Real and load-bearing** — a later task builds on it, or it reveals a
plan defect: STOP. Append `Task <N>: BLOCKED — <reason>` and report to
your human partner with the finding, the plan text it collides with, and
the fix history. Parking a structural failure lets every dependent task
build on it and hands the final review a problem it cannot fix either.
plan defect: rule on the smallest change that unblocks the dependent work,
ledger it as `Task <N>: Ruling: <finding> — <what you decided and why>`,
and carry it into the next task's dispatch. Parking a structural failure
silently lets every dependent task build on it. Stop only when the defect
leaves every path forward a guess.
Adjudicate only at the cap. Adjudicating earlier to end a loop is
pre-judging with a different name. Every adjudication is a ledger entry —
@@ -409,12 +463,22 @@ Then run exactly one scoped re-review of the fix wave
(`scripts/review-package PLAN_FILE FIX_BASE HEAD` over the fix range,
[re-review-prompt.md](re-review-prompt.md)).
Adjudicate any residual findings as in the task loop's breaker: park with
rulings, or stop on load-bearing ones. There is no second fix wave —
rulings, or rule on the load-bearing ones and ledger what you decided. Only
the four classes above stop you here. There is no second fix wave —
residual load-bearing findings surface to your human partner when
finishing-a-development-branch presents the options.
## Finish
Before you delete anything, collect every ledger line containing `Ruling:`
preflight rulings, parked findings, breaker adjudications, all of them — into
your final message under "Rulings I made", in the order you made them, each
with what it costs if wrong. The list is exhaustive: if the ledger holds a
ruling, the list holds it. That list is the only place the decisions you
took on your human partner's behalf reach them — they read it and rework
whatever you got wrong. A ruling that dies with the workspace was a decision
made in secret.
When the final whole-branch review is clean and its fixes are merged,
delete this plan's workspace (`rm -rf <workspace>`) — the git history is
the record now. Sibling directories belong to other plans; leave them
@@ -434,6 +498,7 @@ Use superpowers:finishing-a-development-branch.
| "The fix was small, skip the re-review" | Unreviewed fixes are how regressions land. Every round ends with a scoped re-review. |
| "Reviews slow the loop down" | The loop without reviews is just unverified churn. Reviews are the loop's brakes and steering. |
| "Ledger bookkeeping is overhead" | The ledger is what survives compaction. Controllers without one have re-dispatched entire completed task sequences. |
| "The implementer spawned its own reviewer — free extra assurance" | It's a duplicate seat reviewing the same diff; the task review is the gate. A worker-spawned reviewer is a defect to flag, not rigor. |
## Example Workflow
@@ -47,6 +47,18 @@ Subagent (general-purpose):
While iterating, run the focused test for what you're changing; run the
full suite once before committing, not after every edit.
## You Do Not Dispatch Subagents
Do all of this task's work yourself. Never spawn a subagent to
implement part of the task, and above all never spawn a reviewer to
check your work. Self-review (below) means reading your own diff.
Review is the controller's job: after you report, it dispatches a
fresh reviewer against your diff. A reviewer you spawn duplicates
that review at full cost, and its approval counts for nothing in
the process. If you catch yourself thinking "an independent review
would strengthen my report" — that review is already scheduled.
Report instead.
## Code Organization
You reason best about code you can hold in context at once, and your edits are more
@@ -43,6 +43,15 @@ Subagent (general-purpose):
Your review is read-only on this checkout. Do not mutate the working
tree, the index, HEAD, or branch state in any way.
## You Do Not Dispatch Subagents
Do all of this review yourself. Never spawn a subagent to review part
of the diff, and never spawn another reviewer for a second opinion.
This process already provides every review seat the work gets; a
reviewer you spawn duplicates one of them at full cost, and its
verdict counts for nothing. If the diff feels too large for one
pass, review it in passes yourself and say so in your report.
## Scope
Your scope is the findings list and the fix diff. Verdict every finding.
@@ -52,6 +52,15 @@ Subagent (general-purpose):
Your review is read-only on this checkout. Do not mutate the working
tree, the index, HEAD, or branch state in any way.
## You Do Not Dispatch Subagents
Do all of this review yourself. Never spawn a subagent to review part
of the diff, and never spawn another reviewer for a second opinion.
This process already provides every review seat the work gets; a
reviewer you spawn duplicates one of them at full cost, and its
verdict counts for nothing. If the diff feels too large for one
pass, review it in passes yourself and say so in your report.
## Do Not Trust the Report
Treat the implementer's report as unverified claims about the code. It
@@ -75,6 +84,13 @@ Subagent (general-purpose):
Warnings or other noise in the implementer's reported test output are
findings — test output should be pristine.
Evidence you cannot see is not evidence that doesn't exist. If the
report or its test evidence looks truncated, or you cannot locate the
results it claims, re-read the file at its stated path — and if it is
genuinely missing or garbled, report that as a gap for the controller.
Re-running the suite to regenerate what you failed to read is not
verification; illegibility of the evidence is not invalidation of it.
## Part 1: Spec Compliance
Compare the diff against What Was Requested:
@@ -86,6 +102,12 @@ Subagent (general-purpose):
- **Misunderstood:** right feature built the wrong way, wrong problem
solved
If the brief lists several files each with its own change (a batched
dispatch), check the diff against that list file by file: every listed
file must have its corresponding hunk. A listed file the diff never
touches is a Missing finding, no matter how clean the rest of the
batch looks.
If a requirement cannot be verified from this diff alone (it lives in
unchanged code or spans tasks), report it as a ⚠️ item instead of
broadening your search.
@@ -56,6 +56,7 @@ If your harness appears here, read its reference file for special instructions:
- Codex: `references/codex-tools.md`
- Pi: `references/pi-tools.md`
- Antigravity: `references/antigravity-tools.md`
- Hermes Agent: `references/hermes-tools.md`
## User Instructions
@@ -7,7 +7,76 @@ Add to your Codex config (`~/.codex/config.toml`):
multi_agent = true
```
This enables `spawn_agent`, `wait_agent`, and `close_agent` for skills like `dispatching-parallel-agents` and `subagent-driven-development`. When using subagent-driven-development, close reviewer subagents when their review returns. Keep each implementer subagent open until its task's review passes — the fix loop resumes the implementer — then close it. If your harness cannot send another message to a spawned agent, dispatch each fix round as a fresh implementer carrying the brief, the report file, and the findings.
This enables the multi-agent tools that skills like
`dispatching-parallel-agents` and `subagent-driven-development` use.
Which tools you get depends on the multi-agent version your model
preset selects (current presets run V2; older ones run V1). Trust your
actual tool list over any table — including this one — when they
disagree.
- **Spawning:** give children a clean context with
`spawn_agent {fork_turns: "none"}`; the default `"all"` copies your
entire transcript into the child. On Codex 0.145+, role files under
`~/.codex/agents/` attach to isolated forks via `agent_type`.
Full-history forks accept `model` and `reasoning_effort` overrides
(only `agent_type` is refused there) — isolated forks are the SDD
default for context hygiene, not because overrides require them.
- **Fix rounds:** resume the implementer with `followup_task` — it
delivers your message, triggers a turn, and transparently reloads a
child the harness evicted. Never dispatch a fresh implementer on the
theory that a spawned agent cannot be messaged again; on V2 it
always can.
- **Lifecycle:** V2 has no `close_agent`. Finished children are
evicted automatically when slots are needed; leaving them unclosed
costs nothing. Only V1 sessions have `close_agent` — there, close
reviewers when their review returns, and close each implementer
after its task's review passes.
- **Model names:** never copy a model name from a skill, table, or old
session into `spawn_agent` without checking it against your current
spawn allowlist — V2 accepts only V2-capable presets and hard-errors
on the rest.
## Waiting on children
`wait_agent` is an event subscription, not a poll: a long wait wakes
the moment a child produces mailbox activity, with the same latency as
a short one. Short-timeout polling buys nothing and costs a tool call —
and a context rebill — per poll. In measured sessions, roughly
two-thirds of all wait calls were short polls that timed out.
- While you still have local work, do not wait at all. A completed
child's final answer is pushed into your mailbox and arrives with
your next turn.
- When you are genuinely idle with children outstanding, wait in
bounded stretches: `wait_agent` with `timeout_ms` 300000-600000
(5-10 minutes). After each stretch — wake or timeout — post one
status line, run `list_agents`, and chase any child that finished
without reporting. Never stack polls shorter than five minutes; the
event subscription wakes a bounded stretch just as fast as a short
one.
- Completion mail cannot wake an idle controller (it is delivered
without triggering a turn); covering that idle window is
`wait_agent`'s only job. A stretch that times out with no activity
is your cue to reconcile, not to shorten the next stretch.
## Model routing on spawns
Every `spawn_agent` you issue — including when you are yourself a
spawned child running a fan-out — sets `model` AND `reasoning_effort`
explicitly, per the Model Selection rules of the skill you are
executing. Setting `model` alone is a trap: the child's effort
silently resets to that model's default, not to yours.
Ask your human partner to add a machine-level backstop to
`~/.codex/config.toml` so any spawn that slips through still routes to
a deliberate tier instead of silently inheriting the session's most
expensive model:
```toml
[agents]
default_subagent_model = "<a mid-tier model from your spawn allowlist>"
default_subagent_reasoning_effort = "medium"
```
## Environment Detection
@@ -0,0 +1,56 @@
# Hermes Agent Tool Mapping
Skills speak in actions ("dispatch a subagent", "create a todo", "read a file"). On Hermes Agent these resolve to the tools below.
## Tools
| Action skills request | Hermes tool |
|---|---|
| Read a file | `read_file` |
| Create a new file | `write_file` |
| Edit a file (targeted patch) | `patch` |
| Run a shell command | `terminal` |
| Search file contents | `search_files` |
| Find files by name | `terminal` with `find` |
| Fetch a URL / read a webpage | `web_extract(urls=[...])` |
| Search the web | `web_search(query=...)` |
| Dispatch a subagent | `delegate_task(goal=..., context=..., toolsets=[...], role="leaf")` |
| Task tracking | `todo` tool |
| Invoke a skill | `skill_view("skill-name")` |
## Instructions file
When a skill mentions "your instructions file," on Hermes Agent this is **`AGENTS.md`** in the project directory, or **`SOUL.md`** globally at `~/.hermes/SOUL.md`.
## Invoking a skill
Hermes Agent has a `skills` toolset with `skill_view` and `skills_list` tools.
To invoke a superpowers skill, use:
```
skill_view("brainstorming")
skill_view("test-driven-development")
```
If `skill_view` cannot find a superpowers skill (it may not appear in the catalog
until the plugin fully registers it), fall back to reading the SKILL.md directly:
```
read_file(path="~/.hermes/plugins/superpowers/skills/<skill-name>/SKILL.md")
```
This fallback is the same mechanism used by other harnesses without native skill loading.
## Subagent dispatch
Use `delegate_task` to spawn isolated subagents for parallel or sequential workstreams:
```
delegate_task(goal="...", context="...", toolsets=[...], role="leaf")
```
If `delegate_task` is unavailable, do the work inline rather than inventing tool calls.
## Task tracking
Use the `todo` tool for task tracking within a session. For multi-agent task boards, use `hermes kanban` CLI if available. Treat older `TodoWrite` references as the task-tracking action.
@@ -66,6 +66,9 @@ independently testable deliverable.
**Tech Stack:** [Key technologies/libraries]
**Spec:** [path to the spec/design doc this plan implements — the plan
argues from the spec, so the spec travels with it; executors read both]
## Global Constraints
[The spec's project-wide requirements — version floors, dependency limits,
@@ -13,9 +13,9 @@
* Requires: graphviz (dot) installed on system
*/
const fs = require('fs');
const path = require('path');
const { execSync } = require('child_process');
import * as fs from 'fs';
import * as path from 'path';
import { execFileSync } from 'child_process';
function extractDotBlocks(markdown) {
const blocks = [];
@@ -69,7 +69,7 @@ ${bodies.join('\n\n')}
function renderToSvg(dotContent) {
try {
return execSync('dot -Tsvg', {
return execFileSync('dot', ['-Tsvg'], {
input: dotContent,
encoding: 'utf-8',
maxBuffer: 10 * 1024 * 1024
@@ -107,9 +107,10 @@ function main() {
process.exit(1);
}
// Check if dot is available
// Check if dot is available. Run the binary directly rather than probing
// with `which`, which is not a command on Windows.
try {
execSync('which dot', { encoding: 'utf-8' });
execFileSync('dot', ['-V'], { stdio: 'ignore' });
} catch {
console.error('Error: graphviz (dot) not found. Install with:');
console.error(' brew install graphviz # macOS');
@@ -585,6 +585,23 @@ rm -rf .windsurf/skills/ui-ux-pro-max # Windsurf
rm -rf .agents/skills/ui-ux-pro-max # Antigravity / Codex
```
### Claude.ai's "Upload a skill" dialog says "Zip contains too many files (maximum 200)"
Do not upload the full GitHub repository ZIP. It is a development checkout that includes source code, CLI assets, documentation, previews, and multiple bundled skills, so it exceeds Claude's 200-file upload limit. It is not a Claude skill upload artifact, and this project does not currently publish a separate manual-upload ZIP for Claude.ai.
For Claude Code, install through the Marketplace:
```bash
/plugin marketplace add nextlevelbuilder/ui-ux-pro-max-skill
/plugin install ui-ux-pro-max@ui-ux-pro-max-skill
```
Or use the CLI installer:
```bash
npx ui-ux-pro-max-cli init --ai claude
```
### Claude Marketplace install fails with "Zip file contains a symbolic link"
This is a known issue with versions prior to v2.5.1. The repository used symlinks internally which some installation tools can't handle. **Fix:** use the CLI installer instead:
@@ -2,8 +2,8 @@
"sourceId": "ui-ux-pro-max",
"repo": "https://github.com/nextlevelbuilder/ui-ux-pro-max-skill.git",
"ref": "main",
"commit": "abb7f2fd5a083fa1ff55c326a963ff0d95c33f99",
"commit": "97eb2a20032f0833e3d317162208a60385b0f96e",
"adapter": "claude-skill",
"sourcePath": ".claude/skills/ui-ux-pro-max",
"syncedAt": "2026-08-06T16:00:02Z"
"syncedAt": "2026-08-13T08:38:10Z"
}