Files
vibe-coding-cn/.github/context/faqi/data.json
T
tradecatlabsandGitHub a15b488edf refactor: toolbox - Context Skills Extensions三域重构 (#150)
* refactor: toolbox - 收口Context Skills Extensions三域资源

* fix: toolbox - 重定向文集中的嵌套标签链接
2026-10-18 01:42:36 +08:00

788 lines
1.0 MiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{
"format": "vibe-coding-cn/source-archive@1",
"kind": "faqi",
"source_revision": "28e31abadec73e71aadaff1419e5b9e0575785ea",
"documents": {
".github/docs/gongfa/faqi-system.md": {
"mode": "100644",
"encoding": "utf-8",
"data": "# Vibe Coding 法器体系说明\n\n本文说明法器总表的对象边界、重要性分级和维护入口;具体来源事实与逐条分组以登记源和生成总表为准。\n\n## 一句话\n\n法器总表整理 Vibe Coding 流程中使用或依赖的工具、可调用入口及依赖类别,帮助读者理解它们在工作流中的位置。品级按对 Vibe Coding 的重要性暂定,不代表工具质量、运行可用性或任务效果。\n\n## 字多不看\n\n- 方法和能力要求归功法;工具、软件入口及依赖类别按其真实所指另行整理,不因出现在同一依赖图就变成同一种对象。\n- 当前 30 项按重要性分为天阶 4 项、地阶 12 项、玄阶 9 项、黄阶 5 项;品级、名称、重要性范围与分级依据见[法器浏览表](../../tools/faqi-catalog.md),完整登记见[法器登记源](../../metadata/faqi.json)。\n- 天阶强调模型推理与 Agent 协作;地阶强调代码操作、工具执行和运行基础;玄阶强调上下文、验证、复用与产品交付;黄阶强调可替代的专用或便利能力。\n- 每阶高级、中级、初级表示该阶内的重要性次序,不是测试结果带或效能等级。\n- 当前重要性分级与正式任务效果评级是两条独立轴;正式效能量表仍为 draft,阈值尚未校准。\n\n## 对象边界\n\n“法器”是本项目用于组织 Vibe Coding 工具与依赖能力的领域称呼,不等同于某个统一产品类别。登记必须按具体所指区分程序内容、当前运行实例、模型制品、服务/API、硬件资源、候选对象和抽象依赖类别。\n\n总表中的不同记录不能仅凭名称、依赖图位置或功能相似而合并:\n\n- **来源限定实现**:绑定选定的仓内来源和代码内容,不自动代表本机运行版本。\n- **运行实例或具名候选**:记录实际观察到的入口,或依赖图中指向的候选;候选身份、版本和来源可能仍待核。\n- **依赖类别**:例如模型服务、CI 平台、终端接口或检索记忆。用户确认类别纳入范围,不等于确认了某个产品、部署、账号或可用实现。\n- **外部资源行**:索引原资源记录,不等同于一件独立法器,也不单独证明能力、许可或运行效果。\n\n法器不替代功法、任务合同或权限。建议使用某种工具,不代表它是唯一依赖、已获授权或已通过验证;执行一个过程也不自动证明预期效果。\n\n## 重要性分级\n\n本次排序面向一般 Vibe Coding 工作流,综合考虑条目在核心闭环中的作用、对代码执行和验证的支撑程度、适用范围及可替代性。分级是用户确认的导航性判断,并非从版本新旧、依赖图深度、代码规模或烟测结果计算出来的分数。\n\n| 品级方向 | 重要性含义 | 常见角色 |\n|---|---|---|\n| 天阶 | 决定核心 AI 协作链能否成立 | 模型推理、Agent 运行与编排 |\n| 地阶 | 支撑代码真正被操作、运行和管理 | 终端命令、PTY、版本控制、语言与运行环境 |\n| 玄阶 | 扩展复杂任务的上下文、质量和交付范围 | 检索记忆、自动验证、技能复用、部署与数据集成 |\n| 黄阶 | 对特定工作方式有帮助,但通常存在替代路径 | 多会话终端、专用适配与格式转换 |\n\n同阶内按高级、中级、初级表示重要性由高到低。等级只表示相对工作流位置:某项黄阶工具仍可能是某个具体任务的必要条件;高阶条目也不因此成为质量更好或已经可用的产品。\n\n浏览表列品级、名称、重要性范围和分级依据;当前明细及每项完整登记以[登记源](../../metadata/faqi.json)为准。登记中的 10 项来源限定实现、13 条本地路径记录、12 项依赖图具名对象/运行观察和 8 项用户确认的依赖类别属于不同计数视角;依赖图另有 9 条本地关联,只表达关系、不重复计作对象;本地范围排除另有 9 条。158 条外部资源行也不等同于 158 件法器。\n\n## 重要性与效能评级\n\n| 维度 | 回答的问题 | 当前状态 |\n|---|---|---|\n| 重要性分级 | 该工具或类别在 Vibe Coding 工作流中有多关键、可由什么替代? | 已按用户要求形成暂定排序,见法器总表。 |\n| 正式效能评级 | 某一固定实现、版本和任务环境是否达到明确效果合同? | 量表仍为 draft;任务合同、基线和阈值未校准,当前没有正式效能结论。 |\n\n来源审查、版本观察、静态阅读或单次烟测都不能替代固定任务合同和可复核的效果证据。登记状态也不等于独立审查、运行验证、许可证批准或安全授权。正式效能规约及证据条件见[统一本体中的法器品级规约](cultivation-ontology-taxonomy.md#法器品级规约)。\n\n## 选用流程\n\n1. 先定义要完成的任务、验收条件、环境和权限边界,不从最高品级反推工具选择。\n2. 从总表识别可能的工具或依赖类别,再核实具体实现、来源、版本和可用性;抽象类别不能直接当成已安装产品。\n3. 检查数据、网络、外部副作用、许可和恢复方式。类别纳入或版本观察不构成批准。\n4. 在适用任务中运行有界验证,保留成功与失败证据;验证范围不得超过实际测试的输入和环境。\n5. 若要提出正式效能评级,另按固定任务合同、合理基线、校准阈值和可复核结果评定,不沿用本页的重要性分组。\n\n<a id=\"skill-seekers-mcp-static-review\"></a>\n\n## 固定源码复核:Skill Seekers MCP\n\n2026-10-16对固定 pin `26638b248279a3b001b651475e0f28975f5ff069` 新增 S66–S73 支持选区,\n完整路径、一基半开行号、文件及选区 SHA 见[登记源](../../metadata/faqi.json)。这些仍支持同一件程序,不新增运行实例或品级。\n\n- **入口与版本**:兼容入口转交 FastMCP;是否实际加载取决于依赖和运行环境。头注释写34个工具,静态可见40个装饰函数,\n health 返回版本字符串2.1.1;它们不等于运行工具清单,也不能替代 pyproject 的3.5.1源码声明或实际版本核验。\n- **监听与授权**:默认 stdio,HTTP 默认 `127.0.0.1:8000`;选区启用通配 CORS。\n 回环地址只限制默认监听范围,CORS 不是身份认证或调用授权,不能据此断言服务已安全隔离。\n- **打包与凭据**:package 默认允许在存在平台密钥时上传;upload 的显式密钥会进入 `--api-key` 子进程参数,\n Popen 没有显式收窄继承环境。这是源码风险线索,不是已观察到密钥泄露;本轮没有读取实际凭据。\n- **副作用与预览**:install 还编排抓取、AI增强、打包、条件上传及独立 marketplace 发布。\n `auto_upload=False` 不关闭前序步骤或发布支路;scrape_docs 在 unlimited 模式先写临时配置,不能把 dry_run 声明理解为零 I/O。\n 部分输出使用成功字符串或路径回退,不等于阶段完成、产物存在及外部效果均被独立核实。\n- **结论边界**:本轮未导入或执行被审程序、启服务、抓取、上传或安装。\n 数据来源授权、认证、下游调用、环境隔离、超时/取消、异常清理和恢复仍待独立验证;不提升运行、效果、独立审查或许可批准状态。\n\n## 登记与维护\n\n- [法器登记源](../../metadata/faqi.json)是唯一可编辑总登记;字段边界见[Schema](../../metadata/faqi.schema.json)。\n- [法器浏览表](../../tools/faqi-catalog.md)由登记源生成,仅列品级、名称和解释;解释展示重要性范围与分级依据,完整字段以[法器登记源](../../metadata/faqi.json)及各来源所有者的数据为准,不手工编辑。\n- 外部资源的原始名称、地址、状态和风险仍由[外部资源登记](../../assets/external-resources/README.md)维护。\n- 正文类型及正式效能规约以[修仙领域统一本体](cultivation-ontology-taxonomy.md)为准;本页不另建分类树或实现身份库。\n\n更新登记或生成视图时使用:\n\n```bash\nmake sync-faqi-catalog\nmake check-faqi-catalog\nmake test-faqi-catalog\n```\n",
"sha256": "eb80a035218931c3b36890e872937d4f68c0afe6af3038ca0802ff98a69e834a"
},
".github/metadata/faqi.json": {
"mode": "100644",
"encoding": "utf-8",
"data": "{\n \"format_version\": 2,\n \"kind\": \"faqi-master-classification-register\",\n \"reviewed_at\": \"2026-10-16T19:38:16Z\",\n \"source_revision\": \"0a7fdf4ca54d2bb327dcdfc13e816da57ee9c4c2\",\n \"ontology\": {\n \"path\": \".github/docs/gongfa/cultivation-ontology-taxonomy.md\",\n \"sha256\": \"a0479a344248d2c15eb9e967d3d491b51bb1d3c2fe53d5fb990240c1daf4bd1d\"\n },\n \"dependency_graph\": {\n \"source_path\": \".github/docs/gongfa/technology-stack.md\",\n \"source_sha256\": \"88ff3494095c2a794acf130d5d2ccc4eb4b67ccdc8c174e7ef09f35c11a450a2\",\n \"source_anchor\": \"reference-technology-stack-十六技术栈的层级结构\",\n \"observed_at\": \"2026-10-10T12:14:00Z\",\n \"user_confirmation\": {\n \"reviewed_at\": \"2026-10-10T14:28:10Z\",\n \"statement\": \"用户确认此前列出的8类待核依赖均已核查,并要求全部纳入分类。\",\n \"scope\": \"8类依赖均作为已核验范围条目纳入;不据此补造具体产品身份、版本或任务效果等级。\"\n },\n \"objects\": [\n {\n \"id\": \"dep-pi-cli\",\n \"name\": \"Pi Agent CLI(当前 PATH 实例)\",\n \"type_id\": \"software-artifact\",\n \"graph_node\": \"2.1 Agent运行时 / Pi Agent\",\n \"identity_status\": \"runtime_observed\",\n \"version\": \"1.1.0\",\n \"evidence\": \"pi --version 输出 1.1.0;type -a 显示多个同名入口,本记录只绑定当前 shell 选中的入口;先前环境记录为 1.0.4,宿主/路径差异待核,不将此版本绑定到会话服务端。\",\n \"resource_ids\": [],\n \"related_object_id\": null,\n \"grade_id\": null,\n \"grade_status\": \"pending\",\n \"grade_reason\": \"分级量表仍为 draft,初/中/高结果带阈值未校准;本条未建立任务族效果合同。\"\n },\n {\n \"id\": \"dep-codex-cli\",\n \"name\": \"Codex CLI(依赖图替代项)\",\n \"type_id\": \"software-artifact\",\n \"graph_node\": \"2.1 Agent运行时 / Codex替代项\",\n \"identity_status\": \"named_candidate\",\n \"version\": null,\n \"evidence\": \"依赖图及外部资源行指向 Codex CLI 候选;当前安装身份、可执行入口、版本与来源未核。\",\n \"resource_ids\": [\"tools-platforms-codex-cli-362bc20a\"],\n \"related_object_id\": null,\n \"grade_id\": null,\n \"grade_status\": \"pending\",\n \"grade_reason\": \"精确实现/版本、任务合同及分级量表阈值待核。\"\n },\n {\n \"id\": \"dep-wsl2-platform\",\n \"name\": \"WSL 2 承载平台\",\n \"type_id\": \"software-artifact\",\n \"graph_node\": \"6.1 Windows主机 / WSL\",\n \"identity_status\": \"runtime_observed\",\n \"version\": null,\n \"evidence\": \"uname -r 含 microsoft-standard-WSL2,确认当前 Linux 内核运行在 WSL2 兼容环境;Windows宿主版本及 WSL 产品版本未核。\",\n \"resource_ids\": [],\n \"related_object_id\": null,\n \"grade_id\": null,\n \"grade_status\": \"pending\",\n \"grade_reason\": \"承载平台精确版本、任务合同及分级量表阈值待核。\"\n },\n {\n \"id\": \"dep-ubuntu-userland\",\n \"name\": \"Ubuntu 用户空间发行版\",\n \"type_id\": \"software-artifact\",\n \"graph_node\": \"6.1 Linux发行版 / Ubuntu\",\n \"identity_status\": \"runtime_observed\",\n \"version\": \"24.04.3 LTS\",\n \"evidence\": \"/etc/os-release 报告 Ubuntu 24.04.3 LTS(VERSION_ID=24.04)。\",\n \"resource_ids\": [],\n \"related_object_id\": null,\n \"grade_id\": null,\n \"grade_status\": \"pending\",\n \"grade_reason\": \"版本观测不等于具体任务效果;分级量表阈值未校准。\"\n },\n {\n \"id\": \"dep-wsl2-kernel\",\n \"name\": \"WSL2 Linux 内核\",\n \"type_id\": \"software-artifact\",\n \"graph_node\": \"6.1 WSL / 版本对应的Linux内核\",\n \"identity_status\": \"runtime_observed\",\n \"version\": \"6.6.87.2-microsoft-standard-WSL2\",\n \"evidence\": \"uname -r 输出 6.6.87.2-microsoft-standard-WSL2;不据内核版本推断 Windows/WSL 产品版本。\",\n \"resource_ids\": [],\n \"related_object_id\": null,\n \"grade_id\": null,\n \"grade_status\": \"pending\",\n \"grade_reason\": \"版本观测不等于具体任务效果;分级量表阈值未校准。\"\n },\n {\n \"id\": \"dep-bash\",\n \"name\": \"GNU Bash\",\n \"type_id\": \"software-artifact\",\n \"graph_node\": \"6.2 Shell与命令解释器\",\n \"identity_status\": \"runtime_observed\",\n \"version\": \"5.2.21\",\n \"evidence\": \"bash --version 输出 GNU bash 5.2.21。\",\n \"resource_ids\": [],\n \"related_object_id\": null,\n \"grade_id\": null,\n \"grade_status\": \"pending\",\n \"grade_reason\": \"版本观测不等于具体任务效果;分级量表阈值未校准。\"\n },\n {\n \"id\": \"dep-python-runtime\",\n \"name\": \"Python 运行时\",\n \"type_id\": \"software-artifact\",\n \"graph_node\": \"4.3 语言与运行时\",\n \"identity_status\": \"runtime_observed\",\n \"version\": \"3.12.3\",\n \"evidence\": \"python3 --version 输出 Python 3.12.3。\",\n \"resource_ids\": [],\n \"related_object_id\": null,\n \"grade_id\": null,\n \"grade_status\": \"pending\",\n \"grade_reason\": \"版本观测不等于具体任务效果;分级量表阈值未校准。\"\n },\n {\n \"id\": \"dep-nodejs-runtime\",\n \"name\": \"Node.js 运行时\",\n \"type_id\": \"software-artifact\",\n \"graph_node\": \"4.3 语言与运行时\",\n \"identity_status\": \"runtime_observed\",\n \"version\": \"22.23.2\",\n \"evidence\": \"node --version 输出 v22.23.2。\",\n \"resource_ids\": [],\n \"related_object_id\": null,\n \"grade_id\": null,\n \"grade_status\": \"pending\",\n \"grade_reason\": \"版本观测不等于具体任务效果;分级量表阈值未校准。\"\n },\n {\n \"id\": \"dep-npm-npx\",\n \"name\": \"npm / npx 工具\",\n \"type_id\": \"software-artifact\",\n \"graph_node\": \"4.2 包管理器与依赖解析器\",\n \"identity_status\": \"runtime_observed\",\n \"version\": \"10.9.8\",\n \"evidence\": \"npm --version 与 npx --version 均输出 10.9.8;登记为同一当前工具链版本观测,不把命令入口重复计数为两件法器。\",\n \"resource_ids\": [],\n \"related_object_id\": null,\n \"grade_id\": null,\n \"grade_status\": \"pending\",\n \"grade_reason\": \"版本观测不等于具体任务效果;分级量表阈值未校准。\"\n },\n {\n \"id\": \"dep-git-client\",\n \"name\": \"Git 本地客户端\",\n \"type_id\": \"software-artifact\",\n \"graph_node\": \"3.2 文件与代码 / Git本地客户端与工作树\",\n \"identity_status\": \"runtime_observed\",\n \"version\": \"2.43.0\",\n \"evidence\": \"git --version 输出 git version 2.43.0。\",\n \"resource_ids\": [],\n \"related_object_id\": null,\n \"grade_id\": null,\n \"grade_status\": \"pending\",\n \"grade_reason\": \"版本观测不等于具体任务效果;分级量表阈值未校准。\"\n },\n {\n \"id\": \"dep-gnu-make\",\n \"name\": \"GNU Make\",\n \"type_id\": \"software-artifact\",\n \"graph_node\": \"4.3 构建系统\",\n \"identity_status\": \"runtime_observed\",\n \"version\": \"4.3\",\n \"evidence\": \"make --version 输出 GNU Make 4.3。\",\n \"resource_ids\": [],\n \"related_object_id\": null,\n \"grade_id\": null,\n \"grade_status\": \"pending\",\n \"grade_reason\": \"版本观测不等于具体任务效果;分级量表阈值未校准。\"\n },\n {\n \"id\": \"dep-tmux-runtime\",\n \"name\": \"tmux 当前运行实例\",\n \"type_id\": \"software-artifact\",\n \"graph_node\": \"3.2 命令/终端 / tmux复用支路\",\n \"identity_status\": \"runtime_observed\",\n \"version\": \"3.4\",\n \"evidence\": \"2026-10-15T00:45:37Z观察:PATH入口与realpath均为/usr/bin/tmux;dpkg确认由tmux 3.4-1ubuntu0.1(amd64)提供,二进制SHA-256为034b15c64035f783d43862f2775eb4828f61571ca62c8199796000b97d556ecd。关联的faqi-tmux固定submodule为615c27c11789948df2db09e113e882f82dfb3e1c,其configure.ac声明next-3.7;本机运行实例与该固定来源并非同一版本,烟测不验证submodule实现或效果。\",\n \"resource_ids\": [],\n \"related_object_id\": \"faqi-tmux\",\n \"grade_id\": null,\n \"grade_status\": \"pending\",\n \"grade_reason\": \"运行实例与固定源码身份尚未桥接;任务族结果带与分级量表阈值未校准。\"\n }\n ],\n \"local_links\": [\n {\"object_id\": \"faqi-codex-config-installer\", \"graph_node\": \"2.1 Agent运行时 / Codex替代项\", \"relationship\": \"本地配置辅助脚本;不是Codex CLI实现。\"},\n {\"object_id\": \"faqi-auto-skill-create\", \"graph_node\": \"2.3 Harness与上下文 / 可选Skill制作支路\", \"relationship\": \"实现仓内Skill骨架生成入口。\"},\n {\"object_id\": \"faqi-auto-skill-validate\", \"graph_node\": \"2.3 Harness与上下文 / 可选Skill制作支路\", \"relationship\": \"实现仓内Skill结构检查入口。\"},\n {\"object_id\": \"faqi-skill-seekers-adapter\", \"graph_node\": \"2.3 Harness与上下文 / Skill Seekers适配入口\", \"relationship\": \"适配到固定submodule源码;本机依赖状态另核。\"},\n {\"object_id\": \"faqi-skill-seekers\", \"graph_node\": \"2.3 Harness与上下文 / Skill Seekers上游程序\", \"relationship\": \"固定submodule中的上游程序实现。\"},\n {\"object_id\": \"faqi-claude-skill-init\", \"graph_node\": \"2.3 Harness与上下文 / 可选Skill制作支路\", \"relationship\": \"第三方Skill集合中的独立初始化脚本,不等于Claude Code运行时。\"},\n {\"object_id\": \"faqi-auto-tmux\", \"graph_node\": \"3.2 命令/终端 / auto-tmux封装\", \"relationship\": \"依赖PATH中的tmux CLI及Shell。\"},\n {\"object_id\": \"faqi-oh-my-tmux\", \"graph_node\": \"3.2 命令/终端 / oh-my-tmux配置\", \"relationship\": \"依赖tmux与Shell的可执行配置,不是tmux本体。\"},\n {\"object_id\": \"faqi-tmux\", \"graph_node\": \"3.2 命令/终端 / tmux CLI、Server、Socket\", \"relationship\": \"固定源码内容;本地运行实例来源桥接待核。\"}\n ],\n \"dependency_categories\": [\n {\"id\": \"dep-category-cloud-model-api\", \"node\": \"2.2 云端模型服务/API与固定模型版本\", \"disposition\": \"user_confirmed_in_scope\", \"reason\": \"用户确认此依赖类别已核并要求纳入;服务/API与模型制品仍分开登记;本次品级按Vibe Coding重要性分组,正式效能评级另行判断。\"},\n {\"id\": \"dep-category-local-model-stack\", \"node\": \"2.2 本地模型权重、Tokenizer与推理引擎\", \"disposition\": \"user_confirmed_in_scope\", \"reason\": \"用户确认此依赖类别已核并要求纳入;模型制品、Tokenizer与推理程序分别判断;本次品级按Vibe Coding重要性分组,正式效能评级另行判断。\"},\n {\"id\": \"dep-category-terminal-pty\", \"node\": \"3.2 Terminal Emulator / PTY\", \"disposition\": \"user_confirmed_in_scope\", \"reason\": \"用户确认此依赖类别已核并要求纳入;终端模拟器与PTY系统接口分开分类;本次品级按Vibe Coding重要性分组,正式效能评级另行判断。\"},\n {\"id\": \"dep-category-package-sources\", \"node\": \"4.2 包注册表、Git源与可信缓存\", \"disposition\": \"user_confirmed_in_scope\", \"reason\": \"用户确认此依赖类别已核并要求纳入;注册表、Git来源与缓存分开分类;本次品级按Vibe Coding重要性分组,正式效能评级另行判断。\"},\n {\"id\": \"dep-category-ci-platform\", \"node\": \"7.1 Git托管、CI Runner与CI/CD平台\", \"disposition\": \"user_confirmed_in_scope\", \"reason\": \"用户确认此依赖类别已核并要求纳入;托管服务、Runner执行环境与CI/CD平台分开分类;本次品级按Vibe Coding重要性分组,正式效能评级另行判断。\"},\n {\"id\": \"dep-category-deployment-data\", \"node\": \"7.2-7.3 制品注册表、部署目标、产品运行时、数据库与外部API\", \"disposition\": \"user_confirmed_in_scope\", \"reason\": \"用户确认此可选依赖类别已核并要求纳入;注册表、部署环境、运行时、数据库与外部API分别分类;本次品级按Vibe Coding重要性分组,正式效能评级另行判断。\"},\n {\"id\": \"dep-category-infrastructure\", \"node\": \"8 CPU/GPU、内存、存储、网络、电力与数据中心\", \"disposition\": \"user_confirmed_in_scope\", \"reason\": \"用户确认此资源类别已核并要求纳入;物理设备、基础设施与供给服务按所指分别分类;本次品级按Vibe Coding重要性分组,正式效能评级另行判断。\"},\n {\"id\": \"dep-category-retrieval-memory\", \"node\": \"2.3 检索/索引/记忆与向量库\", \"disposition\": \"user_confirmed_in_scope\", \"reason\": \"用户确认此可选依赖类别已核并要求纳入;检索过程、索引、记忆内容与向量存储分别分类;本次品级按Vibe Coding重要性分组,正式效能评级另行判断。\"}\n ]\n },\n \"limits\": {\n \"independent_review\": false,\n \"runtime_verified\": false,\n \"effectiveness_verified\": false,\n \"license_approved\": false,\n \"grades_assigned\": true\n },\n \"provisional_grade_assignments\": [\n {\"subject_id\": \"faqi-prompt-converter\", \"grade_id\": \"faqi-huang-initial\", \"assignment_status\": \"user_directed_provisional\", \"scope\": \"Vibe Coding重要性:提示词资产格式迁移的辅助支路\", \"basis\": \"只负责格式转换,能维护和复用提示词资产但不参与模型推理或代码执行;替代方式多,属低重要性辅助。\"},\n {\"subject_id\": \"faqi-codex-config-installer\", \"grade_id\": \"faqi-xuan-initial\", \"assignment_status\": \"user_directed_provisional\", \"scope\": \"Vibe Coding重要性:特定Agent接入配置\", \"basis\": \"降低特定Agent初始配置成本,但只服务候选运行时且可手工替代;不属于核心模型推理或执行闭环。\"},\n {\"subject_id\": \"faqi-auto-skill-create\", \"grade_id\": \"faqi-xuan-intermediate\", \"assignment_status\": \"user_directed_provisional\", \"scope\": \"Vibe Coding重要性:技能资产扩展与复用\", \"basis\": \"把操作知识封装为可复用Agent技能,能扩展后续任务能力;属于增益支路,不是最小编码闭环的必需组件。\"},\n {\"subject_id\": \"faqi-auto-skill-validate\", \"grade_id\": \"faqi-xuan-intermediate\", \"assignment_status\": \"user_directed_provisional\", \"scope\": \"Vibe Coding重要性:技能资产质量与可载入性\", \"basis\": \"降低扩展技能结构错误造成的接入阻断;不判断语义正确性,属于能力扩展的质量辅助。\"},\n {\"subject_id\": \"faqi-skill-seekers-adapter\", \"grade_id\": \"faqi-xuan-initial\", \"assignment_status\": \"user_directed_provisional\", \"scope\": \"Vibe Coding重要性:Skill Seekers本地适配入口\", \"basis\": \"便于调用特定知识转技能工具;范围受上游工具限制,可直接调用或人工替代。\"},\n {\"subject_id\": \"faqi-skill-seekers\", \"grade_id\": \"faqi-xuan-intermediate\", \"assignment_status\": \"user_directed_provisional\", \"scope\": \"Vibe Coding重要性:外部知识转可复用技能\", \"basis\": \"增加Agent可复用的领域能力和上下文资产;需特定工作流,不能替代通用推理与工具执行。\"},\n {\"subject_id\": \"faqi-auto-tmux\", \"grade_id\": \"faqi-huang-advanced\", \"assignment_status\": \"user_directed_provisional\", \"scope\": \"Vibe Coding重要性:多会话终端协作自动化\", \"basis\": \"多会话与worker协作在复杂并行时有用,但基础单Agent编码有替代路径;本级只表达工作流重要性,不评价实现质量或效能。\"},\n {\"subject_id\": \"faqi-oh-my-tmux\", \"grade_id\": \"faqi-huang-intermediate\", \"assignment_status\": \"user_directed_provisional\", \"scope\": \"Vibe Coding重要性:终端复用器体验配置\", \"basis\": \"改善tmux使用便利性,但不提供模型推理或核心代码执行能力,可由其他终端配置替代。\"},\n {\"subject_id\": \"faqi-tmux\", \"grade_id\": \"faqi-huang-advanced\", \"assignment_status\": \"user_directed_provisional\", \"scope\": \"Vibe Coding重要性:可选的多会话终端复用\", \"basis\": \"支持持久终端与多窗口工作流,复杂长任务可受益;普通编码闭环有替代方案,不属定义性核心。\"},\n {\"subject_id\": \"faqi-claude-skill-init\", \"grade_id\": \"faqi-xuan-initial\", \"assignment_status\": \"user_directed_provisional\", \"scope\": \"Vibe Coding重要性:特定Skill模板初始化\", \"basis\": \"降低Claude Skill结构初始化成本,作用范围绑定特定生态,可手工完成且不影响其他Agent的基础闭环。\"},\n {\"subject_id\": \"dep-pi-cli\", \"grade_id\": \"faqi-tian-advanced\", \"assignment_status\": \"user_directed_provisional\", \"scope\": \"Vibe Coding重要性:当前核心Agent运行与工具编排\", \"basis\": \"直接承接需求、上下文、模型调用和工具执行循环;当前环境的核心交互入口,缺失会改变Vibe Coding核心形态。\"},\n {\"subject_id\": \"dep-codex-cli\", \"grade_id\": \"faqi-tian-intermediate\", \"assignment_status\": \"user_directed_provisional\", \"scope\": \"Vibe Coding重要性:替代Agent运行时\", \"basis\": \"若选用可承担AI代码协作与工具编排核心;当前仅具名候选且可与其他运行时替换,低于已用核心路径。\"},\n {\"subject_id\": \"dep-wsl2-platform\", \"grade_id\": \"faqi-di-initial\", \"assignment_status\": \"user_directed_provisional\", \"scope\": \"Vibe Coding重要性:当前宿主环境实现\", \"basis\": \"为当前工具链提供运行宿主,但Linux、macOS或原生Windows等环境可替代,不是Vibe Coding定义性能力。\"},\n {\"subject_id\": \"dep-ubuntu-userland\", \"grade_id\": \"faqi-di-initial\", \"assignment_status\": \"user_directed_provisional\", \"scope\": \"Vibe Coding重要性:当前Linux用户空间\", \"basis\": \"承载当前工具链和本地命令,但同类操作系统环境可以替代,重要性来自运行基座而非该发行版身份。\"},\n {\"subject_id\": \"dep-wsl2-kernel\", \"grade_id\": \"faqi-di-initial\", \"assignment_status\": \"user_directed_provisional\", \"scope\": \"Vibe Coding重要性:当前运行环境内核\", \"basis\": \"提供当前WSL用户空间的执行底座,但存在其他内核和宿主替代,不属于AI编程核心能力。\"},\n {\"subject_id\": \"dep-bash\", \"grade_id\": \"faqi-di-advanced\", \"assignment_status\": \"user_directed_provisional\", \"scope\": \"Vibe Coding重要性:Agent命令执行与脚本交互\", \"basis\": \"直接承接终端命令、开发脚本和验证操作,是当前Agent落地代码动作的高重要性接口;Shell实现可替代但该角色不可缺。\"},\n {\"subject_id\": \"dep-python-runtime\", \"grade_id\": \"faqi-di-intermediate\", \"assignment_status\": \"user_directed_provisional\", \"scope\": \"Vibe Coding重要性:脚本、工具与项目代码运行\", \"basis\": \"支撑本仓工具及大量Python项目的执行和验证;语言运行时可按项目替代,重要但非所有Vibe Coding任务必需。\"},\n {\"subject_id\": \"dep-nodejs-runtime\", \"grade_id\": \"faqi-di-intermediate\", \"assignment_status\": \"user_directed_provisional\", \"scope\": \"Vibe Coding重要性:前端及工具链代码运行\", \"basis\": \"支撑前端、Node项目和本仓Markdown工具链;具体语言环境可替代,重要性低于通用Agent与终端执行核心。\"},\n {\"subject_id\": \"dep-npm-npx\", \"grade_id\": \"faqi-di-intermediate\", \"assignment_status\": \"user_directed_provisional\", \"scope\": \"Vibe Coding重要性:Node依赖解析与工具调用\", \"basis\": \"让Node生态依赖和命令行工具可安装、解析与调用;作用范围依赖项目技术栈,可由其他生态包管理器替代。\"},\n {\"subject_id\": \"dep-git-client\", \"grade_id\": \"faqi-di-advanced\", \"assignment_status\": \"user_directed_provisional\", \"scope\": \"Vibe Coding重要性:代码变更追踪、比较与恢复\", \"basis\": \"支撑审查AI改动、保留版本历史和安全回退,是可维护代码生成闭环的高重要性基础;版本控制实现可替代。\"},\n {\"subject_id\": \"dep-gnu-make\", \"grade_id\": \"faqi-di-initial\", \"assignment_status\": \"user_directed_provisional\", \"scope\": \"Vibe Coding重要性:可重复构建与检查入口\", \"basis\": \"把构建和验证命令组织成可重复入口有助于交付,但Make可由其他任务运行器或脚本替代。\"},\n {\"subject_id\": \"dep-tmux-runtime\", \"grade_id\": \"faqi-huang-advanced\", \"assignment_status\": \"user_directed_provisional\", \"scope\": \"Vibe Coding重要性:长任务与多会话终端复用\", \"basis\": \"可持久化和并行组织终端工作,复杂协作时有价值;普通单会话开发可替代,不属于核心生成链。\"},\n {\"subject_id\": \"dep-category-cloud-model-api\", \"grade_id\": \"faqi-tian-advanced\", \"assignment_status\": \"user_directed_provisional\", \"scope\": \"Vibe Coding重要性:核心模型推理与代码生成\", \"basis\": \"提供理解需求、推理和生成代码的核心智能能力;没有模型推理路径即失去Vibe Coding的定义性特征,供应商与模型可替换。\"},\n {\"subject_id\": \"dep-category-local-model-stack\", \"grade_id\": \"faqi-tian-intermediate\", \"assignment_status\": \"user_directed_provisional\", \"scope\": \"Vibe Coding重要性:本地/离线模型推理路径\", \"basis\": \"可提供核心模型推理并支持本地化、隐私或离线需求;在通用工作流中可由云端推理替代,故低于定义性核心路径。\"},\n {\"subject_id\": \"dep-category-terminal-pty\", \"grade_id\": \"faqi-di-advanced\", \"assignment_status\": \"user_directed_provisional\", \"scope\": \"Vibe Coding重要性:Agent调用工具与执行开发命令\", \"basis\": \"把Agent计划转成真实文件、构建和测试操作的关键执行边界;没有等价工具执行通道,代码闭环无法完成。\"},\n {\"subject_id\": \"dep-category-package-sources\", \"grade_id\": \"faqi-di-intermediate\", \"assignment_status\": \"user_directed_provisional\", \"scope\": \"Vibe Coding重要性:依赖获取、锁定与复现\", \"basis\": \"支持安装成熟组件、解析代码依赖和重建开发环境;具体注册表与来源有替代,不直接承担AI生成。\"},\n {\"subject_id\": \"dep-category-ci-platform\", \"grade_id\": \"faqi-xuan-advanced\", \"assignment_status\": \"user_directed_provisional\", \"scope\": \"Vibe Coding重要性:自动化验证、协作与持续交付\", \"basis\": \"把代码生成接入可重复测试、审查和协作交付,显著扩展可靠使用范围;本地闭环可运行但难以替代团队级持续验证。\"},\n {\"subject_id\": \"dep-category-deployment-data\", \"grade_id\": \"faqi-xuan-intermediate\", \"assignment_status\": \"user_directed_provisional\", \"scope\": \"Vibe Coding重要性:从代码到产品运行与外部集成\", \"basis\": \"支撑部署、数据库和API集成,使代码进入真实产品场景;并非每次编码必需,故属于重要交付扩展而非核心生成。\"},\n {\"subject_id\": \"dep-category-infrastructure\", \"grade_id\": \"faqi-di-intermediate\", \"assignment_status\": \"user_directed_provisional\", \"scope\": \"Vibe Coding重要性:计算、存储与网络承载\", \"basis\": \"为模型调用、代码执行及数据交换提供资源底座;实现可跨云、主机和本地环境替换,故不是单一核心产品。\"},\n {\"subject_id\": \"dep-category-retrieval-memory\", \"grade_id\": \"faqi-xuan-advanced\", \"assignment_status\": \"user_directed_provisional\", \"scope\": \"Vibe Coding重要性:长程上下文、知识检索与记忆\", \"basis\": \"支撑跨文件和长任务上下文保持、历史知识复用,提升复杂任务可处理范围;短任务仍可不依赖,且实现可替换。\"}\n ],\n \"sources\": [\n {\n \"id\": \"S01\",\n \"purpose\": \"support\",\n \"path\": \".github/tools/prompts-library/README.md\",\n \"repository\": \".\",\n \"revision\": \"0a7fdf4ca54d2bb327dcdfc13e816da57ee9c4c2\",\n \"sha256\": \"4c2d5f97a6cfa67e033e166676d12eeaab6a562fa83c39b0f2474ae2afbcdae2\",\n \"lines\": [\n 1,\n 95\n ],\n \"selection_sha256\": \"4c2d5f97a6cfa67e033e166676d12eeaab6a562fa83c39b0f2474ae2afbcdae2\"\n },\n {\n \"id\": \"S02\",\n \"purpose\": \"implementation\",\n \"path\": \".github/tools/prompts-library/main.py\",\n \"repository\": \".\",\n \"revision\": \"0a7fdf4ca54d2bb327dcdfc13e816da57ee9c4c2\",\n \"sha256\": \"ed0113d3ecbe9c9d4ca48ee7dde2c76c9a6fd1f54a1ae890fd3689d617347691\",\n \"lines\": [\n 625,\n 689\n ],\n \"selection_sha256\": \"757b82c3bba30f1d62359c39f7c110d425463326e854acef2de085f14d90cf6d\"\n },\n {\n \"id\": \"S03\",\n \"purpose\": \"support\",\n \"path\": \".github/tools/chat-vault/README.md\",\n \"repository\": \".\",\n \"revision\": \"0a7fdf4ca54d2bb327dcdfc13e816da57ee9c4c2\",\n \"sha256\": \"938ddcce3ba06fad18a05d072cfc47cb8427064c72745f557e4b782de8a2c753\",\n \"lines\": [\n 1,\n 104\n ],\n \"selection_sha256\": \"deecf873b9392e27cbae073fd6f75fcb1865af9d6461232dd517ba945cafa3d1\"\n },\n {\n \"id\": \"S04\",\n \"purpose\": \"exclusion_evidence\",\n \"path\": \".github/tools/chat-vault/services/chat-vault/src/main.py\",\n \"repository\": \".\",\n \"revision\": \"0a7fdf4ca54d2bb327dcdfc13e816da57ee9c4c2\",\n \"sha256\": \"561c611909714d358f9968c45078f037bd46cdb037969d598cfed27d94affd72\",\n \"lines\": [\n 65,\n 107\n ],\n \"selection_sha256\": \"43279c5004b34ef3de79da4dd5c103e741f0a9ed47683e7c262a79bd35f8b551\"\n },\n {\n \"id\": \"S05\",\n \"purpose\": \"support\",\n \"path\": \".github/tools/config/.codex/README.md\",\n \"repository\": \".\",\n \"revision\": \"0a7fdf4ca54d2bb327dcdfc13e816da57ee9c4c2\",\n \"sha256\": \"4cd23bbafa069d8bd651e9997951ac99252cf13310d1c9fda14dcf01de818a53\",\n \"lines\": [\n 1,\n 78\n ],\n \"selection_sha256\": \"b290d2842b0290ee9701e41c046634d2cd90684c0c53d1e97e3781a05d695e87\"\n },\n {\n \"id\": \"S06\",\n \"purpose\": \"implementation\",\n \"path\": \".github/tools/config/.codex/install.sh\",\n \"repository\": \".\",\n \"revision\": \"0a7fdf4ca54d2bb327dcdfc13e816da57ee9c4c2\",\n \"sha256\": \"a2ba28d5a48d46aa7d508408519be117f8726c8d66e632d8736deab9175b04a4\",\n \"lines\": [\n 43,\n 100\n ],\n \"selection_sha256\": \"99ccf88c8d5ec6f7b7eda53fc4fd3af29a0ca08d9eef74ad3283cdf649d6a7cf\"\n },\n {\n \"id\": \"S07\",\n \"purpose\": \"support\",\n \"path\": \".github/skills/auto-skill/README.md\",\n \"repository\": \".\",\n \"revision\": \"0a7fdf4ca54d2bb327dcdfc13e816da57ee9c4c2\",\n \"sha256\": \"2fd869316c0469d9c4079cd9a19c41698b501bca6ddd2b6cc03617e3f96218f0\",\n \"lines\": [\n 1,\n 21\n ],\n \"selection_sha256\": \"2fd869316c0469d9c4079cd9a19c41698b501bca6ddd2b6cc03617e3f96218f0\"\n },\n {\n \"id\": \"S08\",\n \"purpose\": \"implementation\",\n \"path\": \".github/skills/auto-skill/scripts/create-skill.sh\",\n \"repository\": \".\",\n \"revision\": \"0a7fdf4ca54d2bb327dcdfc13e816da57ee9c4c2\",\n \"sha256\": \"3eb16d2f24cc2af3e7d7a0f4175e06b0258504795d079ba0920be9dd75f2f7fc\",\n \"lines\": [\n 80,\n 182\n ],\n \"selection_sha256\": \"e769660515ada48debbd022fdfb85ec934b4d3413cf3501e06ef075b6d36b1a4\"\n },\n {\n \"id\": \"S09\",\n \"purpose\": \"implementation\",\n \"path\": \".github/skills/auto-skill/scripts/validate-skill.sh\",\n \"repository\": \".\",\n \"revision\": \"0a7fdf4ca54d2bb327dcdfc13e816da57ee9c4c2\",\n \"sha256\": \"deb5cf2529a93c87c8b7323b55ffc6d7798e6b59652351ba795340ac8c0061c9\",\n \"lines\": [\n 67,\n 160\n ],\n \"selection_sha256\": \"dbd460af6a32307709a11281c7b90925b9fd9820128eb04881c80c020a99f0dc\"\n },\n {\n \"id\": \"S10\",\n \"purpose\": \"implementation\",\n \"path\": \".github/skills/auto-skill/scripts/skill-seekers.sh\",\n \"repository\": \".\",\n \"revision\": \"0a7fdf4ca54d2bb327dcdfc13e816da57ee9c4c2\",\n \"sha256\": \"fdbf73b1faa1a0f445663b5c7c1c9792bbfb6dcdf5f5308198503e14ea0c64dc\",\n \"lines\": [\n 28,\n 66\n ],\n \"selection_sha256\": \"f678142dddda161372feb5c5af96bbbf5e1b3e76b9e2c7dc905a4d1ba18070f2\"\n },\n {\n \"id\": \"S11\",\n \"purpose\": \"support\",\n \"path\": \".github/skills/auto-tmux/README.md\",\n \"repository\": \".\",\n \"revision\": \"0a7fdf4ca54d2bb327dcdfc13e816da57ee9c4c2\",\n \"sha256\": \"d21ca4f1c4adb6a799a76f7a7446b1ebca70d2402f73e80600cda1c2a6d24c25\",\n \"lines\": [\n 1,\n 18\n ],\n \"selection_sha256\": \"0c0e46b950949789a6b85addd85f3a9ec0b2945e6a44134f82c7b46acc59b308\"\n },\n {\n \"id\": \"S12\",\n \"purpose\": \"implementation\",\n \"path\": \".github/skills/auto-tmux/scripts/auto-tmux.sh\",\n \"repository\": \".\",\n \"revision\": \"0a7fdf4ca54d2bb327dcdfc13e816da57ee9c4c2\",\n \"sha256\": \"f473fddada7a7f5fd85afe94deccd16e2aba26195423dc87afbac176315b6567\",\n \"lines\": [\n 701,\n 725\n ],\n \"selection_sha256\": \"701db6430b20faa4bf2477001f584b15a1dea31e6c4a9d32747be343988dd3c2\"\n },\n {\n \"id\": \"S13\",\n \"purpose\": \"support\",\n \"path\": \".github/skills/auto-tmux/scripts/auto-tmux.sh\",\n \"repository\": \".\",\n \"revision\": \"0a7fdf4ca54d2bb327dcdfc13e816da57ee9c4c2\",\n \"sha256\": \"f473fddada7a7f5fd85afe94deccd16e2aba26195423dc87afbac176315b6567\",\n \"lines\": [\n 65,\n 95\n ],\n \"selection_sha256\": \"a745cc41ed28208894954fccadc603a2f11e4e7888bd9df4f85d1dc0c84ca564\"\n },\n {\n \"id\": \"S14\",\n \"purpose\": \"support\",\n \"path\": \".github/tools/external/Skill_Seekers-development/pyproject.toml\",\n \"repository\": \".github/tools/external/Skill_Seekers-development\",\n \"revision\": \"26638b248279a3b001b651475e0f28975f5ff069\",\n \"sha256\": \"40820d20d8f56c1dc24c8f432141fa438d54473acbfecfa716fc9d188cbc8294\",\n \"lines\": [\n 1,\n 15\n ],\n \"selection_sha256\": \"8fc8e7df82f18edc826b13f63f097661c1f40b19d2e7ab576e25854b453919e3\"\n },\n {\n \"id\": \"S15\",\n \"purpose\": \"support\",\n \"path\": \".github/tools/external/Skill_Seekers-development/pyproject.toml\",\n \"repository\": \".github/tools/external/Skill_Seekers-development\",\n \"revision\": \"26638b248279a3b001b651475e0f28975f5ff069\",\n \"sha256\": \"40820d20d8f56c1dc24c8f432141fa438d54473acbfecfa716fc9d188cbc8294\",\n \"lines\": [\n 301,\n 327\n ],\n \"selection_sha256\": \"ac6771e334ffad6fe8cb4934797de797375c87d4c33a16afff72de8d1642893f\"\n },\n {\n \"id\": \"S16\",\n \"purpose\": \"implementation\",\n \"path\": \".github/tools/external/Skill_Seekers-development/src/skill_seekers/cli/main.py\",\n \"repository\": \".github/tools/external/Skill_Seekers-development\",\n \"revision\": \"26638b248279a3b001b651475e0f28975f5ff069\",\n \"sha256\": \"8c02660dacd304f51fe8c4a9685d3f6d5324a7eef7779b6baa7325827bf01985\",\n \"lines\": [\n 39,\n 116\n ],\n \"selection_sha256\": \"60fba27fbe444499a1e95b5dc69edc8b0d34d6c26a30039dcbf9d9205ffdfb14\"\n },\n {\n \"id\": \"S17\",\n \"purpose\": \"support\",\n \"path\": \".github/tools/external/.tmux/README.md\",\n \"repository\": \".github/tools/external/.tmux\",\n \"revision\": \"87dcd13a28aeb5f18baee630e24b3f5765ae3a4f\",\n \"sha256\": \"10b0cca6bb2a4ab7af39d76d27f51b91ca1df4dead015315400041695c9471e7\",\n \"lines\": [\n 9,\n 78\n ],\n \"selection_sha256\": \"243d5ab2936723c61f781dd6906e61de92cceea6069e570ca107b6c19236aeb7\"\n },\n {\n \"id\": \"S18\",\n \"purpose\": \"implementation\",\n \"path\": \".github/tools/external/.tmux/.tmux.conf\",\n \"repository\": \".github/tools/external/.tmux\",\n \"revision\": \"87dcd13a28aeb5f18baee630e24b3f5765ae3a4f\",\n \"sha256\": \"6807d44735b7b11e64c4488a0c3fdcbd2809cc73efedcc349d098e80a690aeeb\",\n \"lines\": [\n 150,\n 190\n ],\n \"selection_sha256\": \"e39dd4f98da410b88e110772d21d1eb14d3bfb6e2c6e8c36e2cb19129d9c98f8\"\n },\n {\n \"id\": \"S19\",\n \"purpose\": \"support\",\n \"path\": \".github/tools/external/.tmux/.tmux.conf\",\n \"repository\": \".github/tools/external/.tmux\",\n \"revision\": \"87dcd13a28aeb5f18baee630e24b3f5765ae3a4f\",\n \"sha256\": \"6807d44735b7b11e64c4488a0c3fdcbd2809cc73efedcc349d098e80a690aeeb\",\n \"lines\": [\n 1829,\n 1891\n ],\n \"selection_sha256\": \"3065f39bd62e8cb3bb4095dfaf9784840368d5760137ad01d3f96eb55ede68a1\"\n },\n {\n \"id\": \"S20\",\n \"purpose\": \"support\",\n \"path\": \".github/tools/external/tmux/README\",\n \"repository\": \".github/tools/external/tmux\",\n \"revision\": \"615c27c11789948df2db09e113e882f82dfb3e1c\",\n \"sha256\": \"9fb75e6c7f10c25b73e41b8214336d0dc2acfbe4c99984514ccaf7327192d53e\",\n \"lines\": [\n 1,\n 20\n ],\n \"selection_sha256\": \"68e51dd5a0148fa1d22f5c7565d3da74dc6619207d1c5238658d5fd873c63e5b\"\n },\n {\n \"id\": \"S21\",\n \"purpose\": \"implementation\",\n \"path\": \".github/tools/external/tmux/tmux.c\",\n \"repository\": \".github/tools/external/tmux\",\n \"revision\": \"615c27c11789948df2db09e113e882f82dfb3e1c\",\n \"sha256\": \"58a9bef0d1d424fd2e2a79c6d998dab96aab81ee771b7c2653928451f3bf11a8\",\n \"lines\": [\n 350,\n 492\n ],\n \"selection_sha256\": \"cd3c886c9a155f70dcddaeec88b4a86253c565b2e18753327f83446d92a7e8f4\"\n },\n {\n \"id\": \"S22\",\n \"purpose\": \"support\",\n \"path\": \".github/tools/external/claude-official-skills/README.md\",\n \"repository\": \".github/tools/external/claude-official-skills\",\n \"revision\": \"1ed29a03dc852d30fa6ef2ca53a67dc2c2c2c563\",\n \"sha256\": \"d7c5c2f9b248c7c0b31f093cf22b9a7407f5b093c8ca9ebe75a5b6845b02b76e\",\n \"lines\": [\n 1,\n 28\n ],\n \"selection_sha256\": \"672c572d34a077a534754b7311d19db68a8402c86fe64e35be5e80da3ae7453a\"\n },\n {\n \"id\": \"S23\",\n \"purpose\": \"implementation\",\n \"path\": \".github/tools/external/claude-official-skills/skills/skill-creator/scripts/init_skill.py\",\n \"repository\": \".github/tools/external/claude-official-skills\",\n \"revision\": \"1ed29a03dc852d30fa6ef2ca53a67dc2c2c2c563\",\n \"sha256\": \"cf12790f1d4958799281920d599f56aea38fb5c26e2812a61dd740bf3d4b6b99\",\n \"lines\": [\n 194,\n 304\n ],\n \"selection_sha256\": \"f3ef6ff82946a9596d5cacfc1ed0405765187e5ffec5a4ede6c15f5e8dd248dd\"\n },\n {\n \"id\": \"S24\",\n \"purpose\": \"support\",\n \"path\": \".github/tools/external/html-tools-main/README.md\",\n \"repository\": \".\",\n \"revision\": \"0a7fdf4ca54d2bb327dcdfc13e816da57ee9c4c2\",\n \"sha256\": \"6aeb3fbdd0ad484f15b44b8c0e26caa7228cede0a659292893617d19d99b6df3\",\n \"lines\": [\n 1,\n 18\n ],\n \"selection_sha256\": \"c58731ae7c6b900a386e03571782503c366959db1a623c21c7de2a08fc04442d\"\n },\n {\n \"id\": \"S25\",\n \"purpose\": \"exclusion_evidence\",\n \"path\": \".github/tools/external/html-tools-main/clean_epub_css.html\",\n \"repository\": \".\",\n \"revision\": \"0a7fdf4ca54d2bb327dcdfc13e816da57ee9c4c2\",\n \"sha256\": \"1716a7ea5f4bf4837bc044c9c164e58b3dbb04d492f677b7766b506edd1c0d2a\",\n \"lines\": [\n 317,\n 405\n ],\n \"selection_sha256\": \"4d07dac2850cbf4860f628b5c26d52976aea9cc8dd981851da5141dc7b18a7cb\"\n },\n {\n \"id\": \"S26\",\n \"purpose\": \"exclusion_evidence\",\n \"path\": \".github/tools/external/html-tools-main/markdown-bianjiqi.html\",\n \"repository\": \".\",\n \"revision\": \"0a7fdf4ca54d2bb327dcdfc13e816da57ee9c4c2\",\n \"sha256\": \"e4c76015749bf42e898412ec7b8e1229c847575ef740bcf6900311d7212dc61e\",\n \"lines\": [\n 181,\n 260\n ],\n \"selection_sha256\": \"cbc5a64c27eefb0801c95a87cbf4ed0a149e25000a41e53e3387eb274ca40894\"\n },\n {\n \"id\": \"S27\",\n \"purpose\": \"exclusion_evidence\",\n \"path\": \".github/tools/external/html-tools-main/task card generator.html\",\n \"repository\": \".\",\n \"revision\": \"0a7fdf4ca54d2bb327dcdfc13e816da57ee9c4c2\",\n \"sha256\": \"0eba89d2f674bb0bc26690c4e406f99b7a2bcd40ecd838c1c19e1f970f7b5670\",\n \"lines\": [\n 217,\n 284\n ],\n \"selection_sha256\": \"8b710f5b6f6b1c1f0fcaafead15e6f63e5800684a1c8ae49dad6a7681659eb19\"\n },\n {\n \"id\": \"S28\",\n \"purpose\": \"exclusion_evidence\",\n \"path\": \".github/tools/external/html-tools-main/xhs graphic production.html\",\n \"repository\": \".\",\n \"revision\": \"0a7fdf4ca54d2bb327dcdfc13e816da57ee9c4c2\",\n \"sha256\": \"1835e29563d4cf7f01cb9cf837d3f57d1b2e48304cc202e1061240bccf6e7e0e\",\n \"lines\": [\n 96,\n 147\n ],\n \"selection_sha256\": \"52b9c7a45cd3d5c8409ee1cde59c31296b608e35c0d668c2833bd7b35639a0f8\"\n },\n {\n \"id\": \"S29\",\n \"purpose\": \"exclusion_evidence\",\n \"path\": \".github/tools/external/html-tools-main/xhs graphic production - 1.0.html\",\n \"repository\": \".\",\n \"revision\": \"0a7fdf4ca54d2bb327dcdfc13e816da57ee9c4c2\",\n \"sha256\": \"14a60fa5cc9fa3b7a8beac146277c1ef15729eb5e18cd7889fbcf498d5d1411a\",\n \"lines\": [\n 177,\n 312\n ],\n \"selection_sha256\": \"abe37a7bfbc4b1035be0ff037decbc49b6f336a59e8b8e5501e810d721f45ab9\"\n },\n {\n \"id\": \"S30\",\n \"purpose\": \"support\",\n \"path\": \".github/tools/external/my-nvim/README.md\",\n \"repository\": \".\",\n \"revision\": \"0a7fdf4ca54d2bb327dcdfc13e816da57ee9c4c2\",\n \"sha256\": \"905c3a248d5208f001f3eb6924beaf768454c70cdbc4c41cf67e906dba7ca8c0\",\n \"lines\": [\n 1,\n 36\n ],\n \"selection_sha256\": \"5476e2380b6412a4d29ce37ad4ded76cd39bc5928e5cf716d98749f3ae8a31ea\"\n },\n {\n \"id\": \"S31\",\n \"purpose\": \"support\",\n \"path\": \".github/tools/external/my-nvim/nvim-config/init.lua\",\n \"repository\": \".\",\n \"revision\": \"0a7fdf4ca54d2bb327dcdfc13e816da57ee9c4c2\",\n \"sha256\": \"3b2d6e9976a515b7c8df08ed7c7f61a5751e9c08a6ff5579d621b87312c9e2c6\",\n \"lines\": [\n 1,\n 3\n ],\n \"selection_sha256\": \"3b2d6e9976a515b7c8df08ed7c7f61a5751e9c08a6ff5579d621b87312c9e2c6\"\n },\n {\n \"id\": \"S32\",\n \"purpose\": \"exclusion_evidence\",\n \"path\": \".github/tools/external/my-nvim/nvim-config/lua/config/lazy.lua\",\n \"repository\": \".\",\n \"revision\": \"0a7fdf4ca54d2bb327dcdfc13e816da57ee9c4c2\",\n \"sha256\": \"5fd03a47dc423a46b7c141149d35ba20cbbd96eb2c90f48f74dbff94c202802e\",\n \"lines\": [\n 1,\n 56\n ],\n \"selection_sha256\": \"5fd03a47dc423a46b7c141149d35ba20cbbd96eb2c90f48f74dbff94c202802e\"\n },\n {\n \"id\": \"S33\",\n \"purpose\": \"support\",\n \"path\": \".github/tools/external/MCPlayerTransfer/README.md\",\n \"repository\": \".\",\n \"revision\": \"0a7fdf4ca54d2bb327dcdfc13e816da57ee9c4c2\",\n \"sha256\": \"f48b3081530011171ee6761115613c5eb7811a9ec3059cdec53e3b50c632f0e3\",\n \"lines\": [\n 1,\n 47\n ],\n \"selection_sha256\": \"939c69119628dd9eea9c16461c41428db4e5faf6d7c9ab4024e7a2f8ffa0bce9\"\n },\n {\n \"id\": \"S34\",\n \"purpose\": \"exclusion_evidence\",\n \"path\": \".github/tools/external/MCPlayerTransfer/main.py\",\n \"repository\": \".\",\n \"revision\": \"0a7fdf4ca54d2bb327dcdfc13e816da57ee9c4c2\",\n \"sha256\": \"11bfdb47774247c32ad8cd0de441d56a13a17e9c12bcb3e2d9e81895958e1450\",\n \"lines\": [\n 1,\n 51\n ],\n \"selection_sha256\": \"11bfdb47774247c32ad8cd0de441d56a13a17e9c12bcb3e2d9e81895958e1450\"\n },\n {\n \"id\": \"S35\",\n \"purpose\": \"support\",\n \"path\": \".github/tools/external/XHS-image-to-PDF-conversion/README.md\",\n \"repository\": \".\",\n \"revision\": \"0a7fdf4ca54d2bb327dcdfc13e816da57ee9c4c2\",\n \"sha256\": \"19f65c7b6afe56c57789a30d1aed3c214051474fd21ea97f1ec10cc1ec774f13\",\n \"lines\": [\n 21,\n 51\n ],\n \"selection_sha256\": \"271e08cdfc793b500025c6d2f7d8e768a1ba6f5a03fe86b86f1aee5c5a2517de\"\n },\n {\n \"id\": \"S36\",\n \"purpose\": \"exclusion_evidence\",\n \"path\": \".github/tools/external/XHS-image-to-PDF-conversion/pdf.py\",\n \"repository\": \".\",\n \"revision\": \"0a7fdf4ca54d2bb327dcdfc13e816da57ee9c4c2\",\n \"sha256\": \"ee045272a0ba361676c1ee908758e7316e96438774716c79472fb05cc5055539\",\n \"lines\": [\n 17,\n 120\n ],\n \"selection_sha256\": \"4b4eb47d3545b5bcba80384c1aa81cee4d973d006736ea7a664f69ef9b759e70\"\n },\n {\n \"id\": \"S37\",\n \"purpose\": \"support\",\n \"path\": \".github/tools/external/.tmux/.tmux.conf\",\n \"repository\": \".github/tools/external/.tmux\",\n \"revision\": \"87dcd13a28aeb5f18baee630e24b3f5765ae3a4f\",\n \"sha256\": \"6807d44735b7b11e64c4488a0c3fdcbd2809cc73efedcc349d098e80a690aeeb\",\n \"lines\": [1, 8],\n \"selection_sha256\": \"e9e4b5dd6be906cfd6c4e4fe0a1063332cad79bf10898087c7c88eee87fb11aa\"\n },\n {\n \"id\": \"S38\",\n \"purpose\": \"support\",\n \"path\": \".github/tools/external/.tmux/LICENSE.MIT\",\n \"repository\": \".github/tools/external/.tmux\",\n \"revision\": \"87dcd13a28aeb5f18baee630e24b3f5765ae3a4f\",\n \"sha256\": \"f4c34427d3e29630cece9bca418eda48ac298867630cd6698d73e0f04642d1d0\",\n \"lines\": [1, 19],\n \"selection_sha256\": \"f4c34427d3e29630cece9bca418eda48ac298867630cd6698d73e0f04642d1d0\"\n },\n {\n \"id\": \"S39\",\n \"purpose\": \"support\",\n \"path\": \".github/tools/external/.tmux/LICENSE.WTFPLv2\",\n \"repository\": \".github/tools/external/.tmux\",\n \"revision\": \"87dcd13a28aeb5f18baee630e24b3f5765ae3a4f\",\n \"sha256\": \"ee820ff0db4ce628569e0975ac27dc926052a9f85d102b101edb104311ef4d90\",\n \"lines\": [1, 14],\n \"selection_sha256\": \"ee820ff0db4ce628569e0975ac27dc926052a9f85d102b101edb104311ef4d90\"\n },\n {\n \"id\": \"S40\",\n \"purpose\": \"support\",\n \"path\": \".github/tools/external/tmux/tmux.c\",\n \"repository\": \".github/tools/external/tmux\",\n \"revision\": \"615c27c11789948df2db09e113e882f82dfb3e1c\",\n \"sha256\": \"58a9bef0d1d424fd2e2a79c6d998dab96aab81ee771b7c2653928451f3bf11a8\",\n \"lines\": [1, 18],\n \"selection_sha256\": \"26f34506da997905b214b2878416c618a92298533aca335c60c509e5e0993904\"\n },\n {\n \"id\": \"S41\",\n \"purpose\": \"support\",\n \"path\": \".github/tools/external/tmux/COPYING\",\n \"repository\": \".github/tools/external/tmux\",\n \"revision\": \"615c27c11789948df2db09e113e882f82dfb3e1c\",\n \"sha256\": \"c031bd37f464c534277814f6aa38686fa023d094261d57fd2545ad592bb53ccd\",\n \"lines\": [1, 19],\n \"selection_sha256\": \"c031bd37f464c534277814f6aa38686fa023d094261d57fd2545ad592bb53ccd\"\n },\n {\n \"id\": \"S42\",\n \"purpose\": \"support\",\n \"path\": \".github/tools/external/Skill_Seekers-development/LICENSE\",\n \"repository\": \".github/tools/external/Skill_Seekers-development\",\n \"revision\": \"26638b248279a3b001b651475e0f28975f5ff069\",\n \"sha256\": \"d131d0e96700cd78f8b3fa7ed79a47b019a0653066500faff376233246b6504d\",\n \"lines\": [1, 22],\n \"selection_sha256\": \"d131d0e96700cd78f8b3fa7ed79a47b019a0653066500faff376233246b6504d\"\n },\n {\n \"id\": \"S43\",\n \"purpose\": \"support\",\n \"path\": \".github/tools/external/claude-official-skills/skills/skill-creator/LICENSE.txt\",\n \"repository\": \".github/tools/external/claude-official-skills\",\n \"revision\": \"1ed29a03dc852d30fa6ef2ca53a67dc2c2c2c563\",\n \"sha256\": \"58d1e17ffe5109a7ae296caafcadfdbe6a7d176f0bc4ab01e12a689b0499d8bd\",\n \"lines\": [1, 203],\n \"selection_sha256\": \"58d1e17ffe5109a7ae296caafcadfdbe6a7d176f0bc4ab01e12a689b0499d8bd\"\n },\n {\n \"id\": \"S44\",\n \"purpose\": \"support\",\n \"path\": \".github/tools/external/Skill_Seekers-development/pyproject.toml\",\n \"repository\": \".github/tools/external/Skill_Seekers-development\",\n \"revision\": \"26638b248279a3b001b651475e0f28975f5ff069\",\n \"sha256\": \"40820d20d8f56c1dc24c8f432141fa438d54473acbfecfa716fc9d188cbc8294\",\n \"lines\": [45, 69],\n \"selection_sha256\": \"e892c55c18d3d786696bf226eef30e4651216b0b71b89f35aa957f486ce0210f\"\n },\n {\n \"id\": \"S45\",\n \"purpose\": \"support\",\n \"path\": \".github/tools/external/Skill_Seekers-development/src/skill_seekers/cli/main.py\",\n \"repository\": \".github/tools/external/Skill_Seekers-development\",\n \"revision\": \"26638b248279a3b001b651475e0f28975f5ff069\",\n \"sha256\": \"8c02660dacd304f51fe8c4a9685d3f6d5324a7eef7779b6baa7325827bf01985\",\n \"lines\": [41, 66],\n \"selection_sha256\": \"67527b228def54d21c5adc56b822ae446b51e24d18b4ca82b4a66669ca184d17\"\n },\n {\n \"id\": \"S46\",\n \"purpose\": \"support\",\n \"path\": \".github/tools/external/Skill_Seekers-development/src/skill_seekers/cli/agent_client.py\",\n \"repository\": \".github/tools/external/Skill_Seekers-development\",\n \"revision\": \"26638b248279a3b001b651475e0f28975f5ff069\",\n \"sha256\": \"2fff7e6de630b6c8871db3419661195125c6128ac71d4d76f04e7561f7bdac17\",\n \"lines\": [35, 91],\n \"selection_sha256\": \"8273620e89e199a39cd5b2afd65dcfe4483d6b463ab3435f2dceb59270ec5a59\"\n },\n {\n \"id\": \"S47\",\n \"purpose\": \"support\",\n \"path\": \".github/tools/external/Skill_Seekers-development/src/skill_seekers/cli/agent_client.py\",\n \"repository\": \".github/tools/external/Skill_Seekers-development\",\n \"revision\": \"26638b248279a3b001b651475e0f28975f5ff069\",\n \"sha256\": \"2fff7e6de630b6c8871db3419661195125c6128ac71d4d76f04e7561f7bdac17\",\n \"lines\": [175, 200],\n \"selection_sha256\": \"e1dffcec8fd29c41210478f2516c1a970fa0082d0c5666b8f2f47657e7226608\"\n },\n {\n \"id\": \"S48\",\n \"purpose\": \"support\",\n \"path\": \".github/tools/external/Skill_Seekers-development/src/skill_seekers/cli/agent_client.py\",\n \"repository\": \".github/tools/external/Skill_Seekers-development\",\n \"revision\": \"26638b248279a3b001b651475e0f28975f5ff069\",\n \"sha256\": \"2fff7e6de630b6c8871db3419661195125c6128ac71d4d76f04e7561f7bdac17\",\n \"lines\": [286, 415],\n \"selection_sha256\": \"24bbde0e597053cc6a0430fb83f870b0007bc5d1fac7916645caa6687d65c153\"\n },\n {\n \"id\": \"S49\",\n \"purpose\": \"support\",\n \"path\": \".github/tools/external/Skill_Seekers-development/src/skill_seekers/cli/install_skill.py\",\n \"repository\": \".github/tools/external/Skill_Seekers-development\",\n \"revision\": \"26638b248279a3b001b651475e0f28975f5ff069\",\n \"sha256\": \"146be443d3b73b1e5c706b105fd0780831275baa6d0d61424b3c10d03dfa79aa\",\n \"lines\": [83, 156],\n \"selection_sha256\": \"5d2fde106240cae8b78d502c274a07a764ff5a2f4e745f3f5a977af08dae7cf5\"\n },\n {\n \"id\": \"S50\",\n \"purpose\": \"support\",\n \"path\": \".github/tools/external/Skill_Seekers-development/src/skill_seekers/cli/upload_skill.py\",\n \"repository\": \".github/tools/external/Skill_Seekers-development\",\n \"revision\": \"26638b248279a3b001b651475e0f28975f5ff069\",\n \"sha256\": \"2967da60c32c2495ea993f9122c6472d76ab86d3bcae878831fbeb07c55b0d1e\",\n \"lines\": [33, 89],\n \"selection_sha256\": \"1893b3f3bfc12dc0ef7ff0b2f2e94d1c72e216bd9d229037f8a8d70b7a18b2f5\"\n },\n {\n \"id\": \"S51\",\n \"purpose\": \"support\",\n \"path\": \".github/tools/external/claude-official-skills/skills/skill-creator/SKILL.md\",\n \"repository\": \".github/tools/external/claude-official-skills\",\n \"revision\": \"1ed29a03dc852d30fa6ef2ca53a67dc2c2c2c563\",\n \"sha256\": \"d57b6e3a44535b9c0ef454dad5c86f5df78185fc80a65c7092885b4b5e10f81b\",\n \"lines\": [263, 275],\n \"selection_sha256\": \"a8130ff1f013777e2c076569f5567924a4a0f3b23df7134ab4b0b99dd1aa86e9\"\n },\n {\n \"id\": \"S52\",\n \"purpose\": \"support\",\n \"path\": \".github/tools/external/tmux/README\",\n \"repository\": \".github/tools/external/tmux\",\n \"revision\": \"615c27c11789948df2db09e113e882f82dfb3e1c\",\n \"sha256\": \"9fb75e6c7f10c25b73e41b8214336d0dc2acfbe4c99984514ccaf7327192d53e\",\n \"lines\": [84, 88],\n \"selection_sha256\": \"68980459b47c2af6f48f099a70fa4472b3b6e5066006f7fdf5f63f675dc1f02d\"\n },\n {\n \"id\": \"S53\",\n \"purpose\": \"support\",\n \"path\": \".github/tools/external/tmux/compat/explicit_bzero.c\",\n \"repository\": \".github/tools/external/tmux\",\n \"revision\": \"615c27c11789948df2db09e113e882f82dfb3e1c\",\n \"sha256\": \"7e30bc63946093cd6ed7cb4ce01d2f8c6e329ab173a20df250da60bb0a3c757b\",\n \"lines\": [1, 6],\n \"selection_sha256\": \"02fedc95bf0da5dffe09623d9cb71bc7ebbb8bfd31f5e4fb5a23b135d7f36d0e\"\n },\n {\n \"id\": \"S54\",\n \"purpose\": \"support\",\n \"path\": \".github/tools/external/tmux/compat/getopt_long.c\",\n \"repository\": \".github/tools/external/tmux\",\n \"revision\": \"615c27c11789948df2db09e113e882f82dfb3e1c\",\n \"sha256\": \"0486066fe70fb5a81d79971842f171e3bdcb570dbcab22ce51c1394235b8d21f\",\n \"lines\": [1, 98],\n \"selection_sha256\": \"32af441d6bffc37dbac1c14d03edf334137d91c95fa06c335479fd9c80d7fcb4\"\n },\n {\n \"id\": \"S55\",\n \"purpose\": \"support\",\n \"path\": \".github/tools/external/tmux/xmalloc.c\",\n \"repository\": \".github/tools/external/tmux\",\n \"revision\": \"615c27c11789948df2db09e113e882f82dfb3e1c\",\n \"sha256\": \"8ed468e9903b8abf18d5d5b76d99f030713fc479d02dc107ec3dbaa3a01c702b\",\n \"lines\": [1, 15],\n \"selection_sha256\": \"f28a22fd0a1176583b24e17d8536acaba14afb635f4b253aa9653770cb1449ba\"\n },\n {\n \"id\": \"S56\",\n \"purpose\": \"support\",\n \"path\": \".github/tools/external/tmux/logo/LICENSE\",\n \"repository\": \".github/tools/external/tmux\",\n \"revision\": \"615c27c11789948df2db09e113e882f82dfb3e1c\",\n \"sha256\": \"5fdf604dee98da6f827ea924cf5ae19a9da31555d3814143f2cc6f8e7ee05752\",\n \"lines\": [1, 14],\n \"selection_sha256\": \"5fdf604dee98da6f827ea924cf5ae19a9da31555d3814143f2cc6f8e7ee05752\"\n },\n {\n \"id\": \"S57\",\n \"purpose\": \"support\",\n \"path\": \".github/tools/external/tmux/mdoc2man.awk\",\n \"repository\": \".github/tools/external/tmux\",\n \"revision\": \"615c27c11789948df2db09e113e882f82dfb3e1c\",\n \"sha256\": \"602f3d31ffec414850e697b73f1885e967698ac0cbe8f09efd14800e55abe7ea\",\n \"lines\": [1, 23],\n \"selection_sha256\": \"1d4514630b480519684226c19c6ead79afcc30d0a5857601aa2e40b3831f7b92\"\n },\n {\n \"id\": \"S58\",\n \"purpose\": \"support\",\n \"path\": \".github/tools/external/tmux/tmux.1\",\n \"repository\": \".github/tools/external/tmux\",\n \"revision\": \"615c27c11789948df2db09e113e882f82dfb3e1c\",\n \"sha256\": \"f2966da7a8267abc9aaa216a7a7b46d4d914d60114058dc046c4ff1c75ac9422\",\n \"lines\": [1, 15],\n \"selection_sha256\": \"04972c3c428ff5c92813b5cc03ee0aca9fb4d67f9efcadc6b08ba9ae9ad1a6db\"\n },\n {\n \"id\": \"S59\",\n \"purpose\": \"support\",\n \"path\": \".github/tools/external/tmux/example_tmux.conf\",\n \"repository\": \".github/tools/external/tmux\",\n \"revision\": \"615c27c11789948df2db09e113e882f82dfb3e1c\",\n \"sha256\": \"0ab7c28342180d485434c3d8e286508a1e1c87ac9a2c8f2dc78bcf477a2de437\",\n \"lines\": [1, 5],\n \"selection_sha256\": \"c29f86d0a16523c1ec7df3be70be2c1b0c7c60aa5da95abb23ff3239289beb78\"\n },\n {\n \"id\": \"S60\",\n \"purpose\": \"support\",\n \"path\": \".github/tools/external/tmux/tools/24-bit-color.sh\",\n \"repository\": \".github/tools/external/tmux\",\n \"revision\": \"615c27c11789948df2db09e113e882f82dfb3e1c\",\n \"sha256\": \"cee34d321461577c2455573ec58537833f5968cebe7df8d53aabf08b0e0d9ccf\",\n \"lines\": [1, 15],\n \"selection_sha256\": \"d78c7405e325b792164f733359cfb3339460776aaee44586bddb7d221c15f354\"\n },\n {\n \"id\": \"S61\",\n \"purpose\": \"support\",\n \"path\": \".github/tools/external/tmux/README.ja\",\n \"repository\": \".github/tools/external/tmux\",\n \"revision\": \"615c27c11789948df2db09e113e882f82dfb3e1c\",\n \"sha256\": \"c341a10636227e426a759da4b80b754258ef31f1554a9ac369a79c5afeeadeb6\",\n \"lines\": [59, 60],\n \"selection_sha256\": \"63f1ffb13bd10f6b3a2052d09b4d9c336c41c45262363e035e25a362ffd5c73a\"\n },\n {\n \"id\": \"S62\",\n \"purpose\": \"support\",\n \"path\": \".github/tools/external/tmux/logo/tmux-logo-1-color.eps\",\n \"repository\": \".github/tools/external/tmux\",\n \"revision\": \"615c27c11789948df2db09e113e882f82dfb3e1c\",\n \"sha256\": \"f4da0cd411ea21140efbb3ebd5fc9a76c87183c8eceb7902e6f08d061c17235b\",\n \"lines\": [1, 20],\n \"selection_sha256\": \"2c23a57c4e1dfdf7fdf3d45d0d4cb092413835ab36eb320a3cc25d80b393f0d4\"\n },\n {\n \"id\": \"S63\",\n \"purpose\": \"support\",\n \"path\": \".github/tools/external/tmux/logo/tmux-logo.eps\",\n \"repository\": \".github/tools/external/tmux\",\n \"revision\": \"615c27c11789948df2db09e113e882f82dfb3e1c\",\n \"sha256\": \"13ecb5c04f2b40f5dca7dc7e9be3986de3d7641c6494cc3f139669a3e90dd144\",\n \"lines\": [1, 20],\n \"selection_sha256\": \"2c23a57c4e1dfdf7fdf3d45d0d4cb092413835ab36eb320a3cc25d80b393f0d4\"\n },\n {\n \"id\": \"S64\",\n \"purpose\": \"support\",\n \"path\": \".github/tools/external/tmux/logo/tmux-logomark.eps\",\n \"repository\": \".github/tools/external/tmux\",\n \"revision\": \"615c27c11789948df2db09e113e882f82dfb3e1c\",\n \"sha256\": \"f5afbd939a1675b5b1293cd642273d8b0b9555b906683970b5e7a34f802674fd\",\n \"lines\": [1, 20],\n \"selection_sha256\": \"ecbd0ccba3e5665b62c06509dd78ed90525ad60737c63c29d089fb8b54e23b5b\"\n },\n {\n \"id\": \"S65\",\n \"purpose\": \"support\",\n \"path\": \".github/tools/external/.tmux/.logo/LICENSE\",\n \"repository\": \".github/tools/external/.tmux\",\n \"revision\": \"87dcd13a28aeb5f18baee630e24b3f5765ae3a4f\",\n \"sha256\": \"6ae92da1ac8fc251f218491c42048d258d50d57bc685beb871fb09adf0bcea3e\",\n \"lines\": [1, 17],\n \"selection_sha256\": \"6ae92da1ac8fc251f218491c42048d258d50d57bc685beb871fb09adf0bcea3e\"\n },\n {\n \"id\": \"S66\",\n \"purpose\": \"support\",\n \"path\": \".github/tools/external/Skill_Seekers-development/src/skill_seekers/mcp/server.py\",\n \"repository\": \".github/tools/external/Skill_Seekers-development\",\n \"revision\": \"26638b248279a3b001b651475e0f28975f5ff069\",\n \"sha256\": \"cc6c4f24e5b91ab158f2bfbc4ebb27a38ce84d2937473dd85a6c2d035fc3b851\",\n \"lines\": [217, 232],\n \"selection_sha256\": \"3656ba540327c3b7a1d33dffb02caba7b39ad65539fedb8c1d4d653d6304c994\"\n },\n {\n \"id\": \"S67\",\n \"purpose\": \"support\",\n \"path\": \".github/tools/external/Skill_Seekers-development/src/skill_seekers/mcp/server_fastmcp.py\",\n \"repository\": \".github/tools/external/Skill_Seekers-development\",\n \"revision\": \"26638b248279a3b001b651475e0f28975f5ff069\",\n \"sha256\": \"19ba3010ea3bc5101953e44070932ec239d67908e1a0e992437665f98b827200\",\n \"lines\": [1, 195],\n \"selection_sha256\": \"4aac45465ef6f0be7dd815096a3b9a9fdd1d7dbb53022f407691cf5786305d89\"\n },\n {\n \"id\": \"S68\",\n \"purpose\": \"support\",\n \"path\": \".github/tools/external/Skill_Seekers-development/src/skill_seekers/mcp/server_fastmcp.py\",\n \"repository\": \".github/tools/external/Skill_Seekers-development\",\n \"revision\": \"26638b248279a3b001b651475e0f28975f5ff069\",\n \"sha256\": \"19ba3010ea3bc5101953e44070932ec239d67908e1a0e992437665f98b827200\",\n \"lines\": [1648, 1835],\n \"selection_sha256\": \"06302c5f4aeec783710f5fc8c98d27be93d48c13d10fab5b677a743590787a94\"\n },\n {\n \"id\": \"S69\",\n \"purpose\": \"support\",\n \"path\": \".github/tools/external/Skill_Seekers-development/src/skill_seekers/mcp/server_fastmcp.py\",\n \"repository\": \".github/tools/external/Skill_Seekers-development\",\n \"revision\": \"26638b248279a3b001b651475e0f28975f5ff069\",\n \"sha256\": \"19ba3010ea3bc5101953e44070932ec239d67908e1a0e992437665f98b827200\",\n \"lines\": [887, 1050],\n \"selection_sha256\": \"21c671d1565867a5787f19da94e5cebefbb52993f3833f323afcc324ed59fb5e\"\n },\n {\n \"id\": \"S70\",\n \"purpose\": \"support\",\n \"path\": \".github/tools/external/Skill_Seekers-development/src/skill_seekers/mcp/tools/packaging_tools.py\",\n \"repository\": \".github/tools/external/Skill_Seekers-development\",\n \"revision\": \"26638b248279a3b001b651475e0f28975f5ff069\",\n \"sha256\": \"7654385b60889705d98a3cc8e92602d13cadaf920ead26561e7fbb3a349a1fab\",\n \"lines\": [32, 173],\n \"selection_sha256\": \"a042393939aa45cc7c4b046630c5a32b418895e25421f49b070c66fc6d116f9f\"\n },\n {\n \"id\": \"S71\",\n \"purpose\": \"support\",\n \"path\": \".github/tools/external/Skill_Seekers-development/src/skill_seekers/mcp/tools/packaging_tools.py\",\n \"repository\": \".github/tools/external/Skill_Seekers-development\",\n \"revision\": \"26638b248279a3b001b651475e0f28975f5ff069\",\n \"sha256\": \"7654385b60889705d98a3cc8e92602d13cadaf920ead26561e7fbb3a349a1fab\",\n \"lines\": [232, 298],\n \"selection_sha256\": \"c1abd4a79a92647fd3a4044f1cddc566c6dd953c3aa5d6c6824db8d9e27ba109\"\n },\n {\n \"id\": \"S72\",\n \"purpose\": \"support\",\n \"path\": \".github/tools/external/Skill_Seekers-development/src/skill_seekers/mcp/tools/scraping_tools.py\",\n \"repository\": \".github/tools/external/Skill_Seekers-development\",\n \"revision\": \"26638b248279a3b001b651475e0f28975f5ff069\",\n \"sha256\": \"0073daae89b191d907fb080daf78f044d55d6890a8c929e7dcdc10c9ff19a735\",\n \"lines\": [211, 310],\n \"selection_sha256\": \"361fb788f3029d6990b596a7675a68eb4f81df8d1e70404a6489780f93276f9d\"\n },\n {\n \"id\": \"S73\",\n \"purpose\": \"support\",\n \"path\": \".github/tools/external/Skill_Seekers-development/src/skill_seekers/mcp/tools/packaging_tools.py\",\n \"repository\": \".github/tools/external/Skill_Seekers-development\",\n \"revision\": \"26638b248279a3b001b651475e0f28975f5ff069\",\n \"sha256\": \"7654385b60889705d98a3cc8e92602d13cadaf920ead26561e7fbb3a349a1fab\",\n \"lines\": [433, 904],\n \"selection_sha256\": \"5eef32044bf73950d2c4168ff30faa18e8064400aa0ee4f78dff9029d4fae074\"\n }\n ],\n \"objects\": [\n {\n \"id\": \"faqi-prompt-converter\",\n \"name\": \"提示词格式转换程序\",\n \"type_id\": \"software-artifact\",\n \"implementation\": \"S02\",\n \"support\": [\n \"S01\"\n ],\n \"boundary\": \"指main.py及其转换实现所表达的程序内容;Excel、Markdown和JSONL是输入/输出,不随转换模式复制工具身份。未验证转换正确性。\",\n \"declared_version\": null\n },\n {\n \"id\": \"faqi-codex-config-installer\",\n \"name\": \"Codex配置安装与恢复脚本\",\n \"type_id\": \"software-artifact\",\n \"implementation\": \"S06\",\n \"support\": [\n \"S05\"\n ],\n \"boundary\": \"纳入安装脚本的程序指令;不是Codex CLI实现,不包含账号授权,safe/power配置、全局指令文本另作规约内容。备份/覆盖能力尚未运行验证。\",\n \"declared_version\": null\n },\n {\n \"id\": \"faqi-auto-skill-create\",\n \"name\": \"auto-skill模板生成脚本\",\n \"type_id\": \"software-artifact\",\n \"implementation\": \"S08\",\n \"support\": [\n \"S07\"\n ],\n \"boundary\": \"指渲染Skill模板与建立目录的程序,不是生成出的Skill内容或整个元技能。--force可覆盖目标,未执行。\",\n \"declared_version\": null\n },\n {\n \"id\": \"faqi-auto-skill-validate\",\n \"name\": \"auto-skill结构校验脚本\",\n \"type_id\": \"software-artifact\",\n \"implementation\": \"S09\",\n \"support\": [\n \"S07\"\n ],\n \"boundary\": \"指frontmatter和结构校验程序;成功结构检查不证明Skill语义、执行正确或效果。\",\n \"declared_version\": null\n },\n {\n \"id\": \"faqi-skill-seekers-adapter\",\n \"name\": \"Skill Seekers本地运行适配脚本\",\n \"type_id\": \"software-artifact\",\n \"implementation\": \"S10\",\n \"support\": [\n \"S07\"\n ],\n \"boundary\": \"设置venv/PYTHONPATH并exec上游CLI的本地适配程序。指令内容不同于上游核心,不能把封装当同一副本,也不因同一用途合并其他生成脚本。\",\n \"declared_version\": null\n },\n {\n \"id\": \"faqi-auto-tmux\",\n \"name\": \"auto-tmux命令封装程序\",\n \"type_id\": \"software-artifact\",\n \"implementation\": \"S12\",\n \"support\": [\n \"S11\"\n ],\n \"boundary\": \"指统一操控脚本,不是SKILL.md、tmux二进制、session/pane或某次操作;支持多命令不增加身份。未发送按键、创建会话或读取pane。\",\n \"declared_version\": null\n },\n {\n \"id\": \"faqi-skill-seekers\",\n \"name\": \"Skill Seekers程序\",\n \"type_id\": \"software-artifact\",\n \"implementation\": \"S16\",\n \"support\": [\n \"S14\",\n \"S15\",\n \"S42\",\n \"S44\",\n \"S45\",\n \"S46\",\n \"S47\",\n \"S48\",\n \"S49\",\n \"S50\",\n \"S66\",\n \"S67\",\n \"S68\",\n \"S69\",\n \"S70\",\n \"S71\",\n \"S72\",\n \"S73\"\n ],\n \"boundary\": \"指固定submodule修订的软件实现;多个CLI入口及可选MCP模块不机械复制产品身份。3.5.1仅为pyproject源码声明,不是已核发布或运行版。MCP头注释34项与静态40个装饰函数、health返回2.1.1均不作为运行清单或身份版本证明。\",\n \"declared_version\": \"3.5.1(仅源码声明)\"\n },\n {\n \"id\": \"faqi-oh-my-tmux\",\n \"name\": \"oh-my-tmux可执行配置程序\",\n \"type_id\": \"software-artifact\",\n \"implementation\": \"S18\",\n \"support\": [\n \"S17\",\n \"S19\",\n \"S37\",\n \"S38\",\n \"S39\",\n \"S65\"\n ],\n \"boundary\": \"配置文件含run、cut|sh调用链及可执行shell指令,按实际程序内容归software-artifact,不能仅因.conf后缀归纯规约;不是tmux本身。仓内.logo许可证另由S65绑定;其指向可变tmux/master路径,具体SVG来源关系与许可覆盖范围未核,不能据此批准仓库整体再分发。\",\n \"declared_version\": null\n },\n {\n \"id\": \"faqi-tmux\",\n \"name\": \"tmux终端复用程序\",\n \"type_id\": \"software-artifact\",\n \"implementation\": \"S21\",\n \"support\": [\n \"S20\",\n \"S40\",\n \"S41\",\n \"S52\",\n \"S53\",\n \"S54\",\n \"S55\",\n \"S56\",\n \"S57\",\n \"S58\",\n \"S59\",\n \"S60\",\n \"S61\",\n \"S62\",\n \"S63\",\n \"S64\"\n ],\n \"boundary\": \"指固定源码修订的程序内容,不是物理终端、pane、socket地址或一次会话。Git describe的邻近tag不作为已核发布版本。\",\n \"declared_version\": null\n },\n {\n \"id\": \"faqi-claude-skill-init\",\n \"name\": \"官方Skill初始化脚本\",\n \"type_id\": \"software-artifact\",\n \"implementation\": \"S23\",\n \"support\": [\n \"S22\",\n \"S43\",\n \"S51\"\n ],\n \"boundary\": \"只纳入skill-creator下生成目录/模板的独立Python程序,不把官方Skill集合、自然语言方法、模板或其他全部辅助脚本称作同一程序。\",\n \"declared_version\": null\n }\n ],\n \"local_entries\": [\n {\n \"path\": \".github/tools/prompts-library\",\n \"objects\": [\n \"faqi-prompt-converter\"\n ],\n \"sources\": [\n \"S01\",\n \"S02\"\n ],\n \"boundary\": \"纳入程序,不把提示词资产或生成目录当工具实现。\",\n \"pending\": []\n },\n {\n \"path\": \".github/tools/chat-vault\",\n \"objects\": [],\n \"sources\": [\n \"S03\",\n \"S04\"\n ],\n \"boundary\": \"代码确有会话同步/查询程序所指,但按本轮用户范围排除,不作为当前法器对象。\",\n \"pending\": [\n \"会话文件自动探测、SQLite持久化、搜索/导出及启动时环境创建/安装涉及私人数据和副作用;未运行,也未读取用户数据。\"\n ]\n },\n {\n \"path\": \".github/tools/config/.codex\",\n \"objects\": [\n \"faqi-codex-config-installer\"\n ],\n \"sources\": [\n \"S05\",\n \"S06\"\n ],\n \"boundary\": \"配置与AGENTS文本不等于CLI;脚本本身有独立程序所指。\",\n \"pending\": [\n \"Codex实际程序、已安装版本、权限及账户不由本目录证明。\"\n ]\n },\n {\n \"path\": \".github/skills/auto-skill\",\n \"objects\": [\n \"faqi-auto-skill-create\",\n \"faqi-auto-skill-validate\",\n \"faqi-skill-seekers-adapter\"\n ],\n \"sources\": [\n \"S07\",\n \"S08\",\n \"S09\",\n \"S10\"\n ],\n \"boundary\": \"Skill说明/规约与三个独立入口脚本分离,不把整Skill包登记成一件软件。\",\n \"pending\": [\n \"其他辅助模块未逐模块登记,不能将本次选区称为全包能力审查。\"\n ]\n },\n {\n \"path\": \".github/skills/auto-tmux\",\n \"objects\": [\n \"faqi-auto-tmux\"\n ],\n \"sources\": [\n \"S11\",\n \"S12\",\n \"S13\"\n ],\n \"boundary\": \"Skill方法/规约、执行脚本、被依赖程序及运行入口分别指认。\",\n \"pending\": [\n \"蜂群附属脚本不逐一登记,不启动蜂群,也不将蜂群状态/日志算软件。\",\n \"2026-10-13:将本工作分支内26个.sh入口的Git执行模式从100644改为100755;auto-tmux doctor、26个脚本bash -n及两个help入口通过。完整技能validator与tmux smoke未运行,运行效果仍待验证。\"\n ]\n },\n {\n \"path\": \".github/tools/external/Skill_Seekers-development\",\n \"objects\": [\n \"faqi-skill-seekers\"\n ],\n \"sources\": [\n \"S14\",\n \"S15\",\n \"S16\",\n \"S42\",\n \"S44\",\n \"S45\",\n \"S46\",\n \"S47\",\n \"S48\",\n \"S49\",\n \"S50\",\n \"S66\",\n \"S67\",\n \"S68\",\n \"S69\",\n \"S70\",\n \"S71\",\n \"S72\",\n \"S73\"\n ],\n \"boundary\": \"源码内容与仓库载体、接口规范、抓取过程、输入资料和生成Skill分开。\",\n \"pending\": [\n \"2026-10-14:S45–S50绑定固定CLI路由、AgentClient与install/upload静态选区。CLI映射包含create/enhance/package/upload/install/install-agent等;AgentClient的auto模式按环境密钥选择API或本地代理,API路径将prompt发送给provider,本地subprocess.run未显式限制env;Claude预设含--dangerously-skip-permissions,Codex含--full-auto和--skip-git-repo-check。install将auto_upload设为默认true(可用--no-upload),upload路径调用目标adaptor并可从环境变量取key。仅静态审阅,未运行、联网、上传或读取凭据;完整MCP链路、数据范围/来源授权、子进程权限、环境隔离、外部与本地写入及恢复路径仍待审。\",\n \"仓库LICENSE标注MIT,但版权行保留[Your Name/Username]占位符;权利主体与授权未核,不作许可证批准依据。\",\n \"固定pyproject将PyMuPDF>=1.24.14列为核心依赖;2026-10-14本地Python 3.12.3环境未安装PyMuPDF(pip另有~umpy无效发行警告),运行/doctor/PDF路径未验证。这是环境观察,不等于上游实现缺陷。\",\n \"2026-10-15:在Python 3.12.3环境运行python3 -m pip show PyMuPDF仍显示未安装;未安装依赖、未运行Skill Seekers。运行验证仍为false;此项只是目标环境依赖存在性检查,不是程序测试。\",\n \"2026-10-16:S66–S73只静态复核固定pin的MCP兼容入口、FastMCP、抓取及package/upload/install选区。默认stdio,HTTP默认127.0.0.1:8000,选区配置通配CORS;回环监听与CORS不等于认证授权。package默认auto_upload=true,命中平台密钥时加入上传标志;upload显式api_key被放入--api-key进程参数,Popen未显式限定env,凭据暴露与环境继承边界待核,未读取任何真实值。install除抓取、AI增强和打包外,还含条件上传及marketplace发布分支,auto_upload=false不关闭前序步骤或独立发布支路;scrape_docs的unlimited临时配置写入先于dry_run分支,不能把预览声明推广为零I/O或可完整回滚。源码注释34工具、静态40装饰函数和health的2.1.1字符串都不是运行清单或已核版本。未导入、执行、启服务、抓取、上传或安装;认证、数据来源授权、完整下游副作用、超时/取消及恢复仍待独立验证。\"\n ]\n },\n {\n \"path\": \".github/tools/external/.tmux\",\n \"objects\": [\n \"faqi-oh-my-tmux\"\n ],\n \"sources\": [\n \"S17\",\n \"S18\",\n \"S19\",\n \"S37\",\n \"S38\",\n \"S39\"\n ],\n \"boundary\": \"配置数据与嵌入程序按实际所指区分;本条纳入可执行配置程序,未安装或source配置。\",\n \"pending\": [\n \"源码含条件性kill-server;纳入不等于可安全对当前会话执行。\"\n ]\n },\n {\n \"path\": \".github/tools/external/tmux\",\n \"objects\": [\n \"faqi-tmux\"\n ],\n \"sources\": [\n \"S20\",\n \"S21\",\n \"S40\",\n \"S41\",\n \"S52\",\n \"S53\",\n \"S54\",\n \"S55\",\n \"S56\",\n \"S57\",\n \"S58\",\n \"S59\",\n \"S60\",\n \"S61\",\n \"S62\",\n \"S63\",\n \"S64\"\n ],\n \"boundary\": \"tmux程序与配置、操控封装、终端会话和显示记录分开。\",\n \"pending\": [\n \"S40仅绑定tmux.c文件头许可选区;S41明确COPYING仅供信息参考、许可依文件头。2026-10-15第一轮固定pin许可清点见S52–S56;此轮未覆盖全部313文件、非C/H/Y资产、所有上游来源及再分发兼容性,limits.license_approved仍为false。\",\n \"2026-10-15:pin 615c27c11789948df2db09e113e882f82dfb3e1c有313个tracked文件、无嵌套gitlink。对196个C/H/Y文件作固定字面扫描:182个含ISC式授权句、13个含BSD式再分发句(compat/daemon-darwin.c与compat/getopt_long.c同时含两种),另有xmalloc.c(S55)/xmalloc.h(sha256 8d0a589c43e16549174b0ffb0b59a8581af00d99eb912205bfb4f293502bbeae)的Tatu Ylonen特殊使用与命名条件、compat/explicit_bzero.c的Public domain声明;BSD式文件为compat/bitstring.h、compat/daemon-darwin.c、compat/daemon.c、compat/getline.c、compat/getopt_long.c、compat/memmem.c、compat/queue.h、compat/strcasestr.c、compat/strsep.c、compat/tree.h、compat/unvis.c、compat/vis.c、compat/vis.h。README (S52)、COPYING (S41) 与 README.ja(sha256 c341a10636227e426a759da4b80b754258ef31f1554a9ac369a79c5afeeadeb6)列举的ISC例外不同;README.ja还列出SYNCING(sha256 5243f70e3adbb2f7554e99889d3ea9b5b719d50108ac127db1392ced65e7c61c),本轮未见该文件头许可声明;FAQ/TODO未跟踪。logo/LICENSE由S56单独绑定。getopt_long.c(S54)自述来源于OpenSSH commit b5b405fee7f3e79d44e2d2971a4b6b4cc53f112e,本轮未独立比对上游。该清点是有限静态检索而非法律兼容性意见;正式许可批准、完整文件级/第三方依赖审查仍未完成。\",\n \"2026-10-15第二轮固定pin非C/H/Y许可线索见S57–S64:仅审117个非C/H/Y tracked文件中的8个选区。mdoc2man.awk与tmux.1含逐文件版权、permission及免责声明;example_tmux.conf由作者声明Public domain;tools/24-bit-color.sh标注来源为iTerm2的master并称“presumably covered”于其LICENSE,未冻结或核对上游修订/条款;README.ja:59将本文件、CHANGES、FAQ、SYNCING、TODO列为ISC许可对象,与英文COPYING/README的列举不同;三个EPS文件头各自声明Apple 2000–2004 Copyright/All Rights Reserved,未证实logo/LICENSE是否覆盖。未审其余非C/H/Y文件、其他二进制资产及第三方依赖;不构成完整文件/权利/再分发兼容性审查,limits.license_approved仍为false。\"\n ]\n },\n {\n \"path\": \".github/tools/external/claude-official-skills\",\n \"objects\": [\n \"faqi-claude-skill-init\"\n ],\n \"sources\": [\n \"S22\",\n \"S23\",\n \"S43\",\n \"S51\"\n ],\n \"boundary\": \"集合入口不等于法器身份;指令内容与脚本实现分别判断。\",\n \"pending\": [\n \"README明确部分文档Skill仅source-available,不能把整个集合称为同一开源许可证;skill-creator/LICENSE.txt提供Apache 2.0文本,但其附录版权字段为通用占位符,不能单独证明权利主体或完成全量许可审查。\",\n \"本次不批准再分发/商用许可。\",\n \"S51绑定skill-creator/SKILL.md步骤3和调用形式,证实该文档要求执行S23;它不验证S23实际输入校验或路径限制,且本次未执行脚本。\",\n \"2026-10-14:固定pin 1ed29a03dc852d30fa6ef2ca53a67dc2c2c2c563的S23(init_skill.py:194-303)静态复核:CLI提示skill_name应为小写kebab-case,但main未校验;函数直接拼接Path(path).resolve()/skill_name且未检查目标仍在指定父目录内,若调用方传入含../或绝对路径的名称,输出可越出预期目录。目录/模板创建中途失败只返回错误,不回滚部分输出。风险取决于调用方输入控制;未运行脚本、未创建测试文件,不作可利用性或运行安全结论。其余辅助脚本仍未逐模块展开。\"\n ]\n },\n {\n \"path\": \".github/tools/external/html-tools-main\",\n \"objects\": [],\n \"sources\": [\n \"S24\",\n \"S25\",\n \"S26\",\n \"S27\",\n \"S28\",\n \"S29\"\n ],\n \"boundary\": \"五个不同页面实现均按用户指定从当前法器清单排除;排除不否认其程序实现。\",\n \"pending\": [\n \"如需重新纳入,须逐项复核来源内容、身份、版本、依赖及许可;未进行运行或效果验证。\",\n \"两个Markdown相关实现以及文件名“1.0”的产品同一/版本演化仍待核,不自动合并或填predecessor。\"\n ]\n },\n {\n \"path\": \".github/tools/external/my-nvim\",\n \"objects\": [],\n \"sources\": [\n \"S30\",\n \"S31\",\n \"S32\"\n ],\n \"boundary\": \"配置程序按用户指定从当前法器清单排除;不代表宿主Neovim、LazyVim依赖或整个仓库内容一并纳入/排除。\",\n \"pending\": [\n \"如需重新纳入,须复核固定来源、身份、版本、依赖及许可;配置可能克隆插件并检查更新,未运行或验证效果。\"\n ]\n },\n {\n \"path\": \".github/tools/external/MCPlayerTransfer\",\n \"objects\": [],\n \"sources\": [\n \"S33\",\n \"S34\"\n ],\n \"boundary\": \"代码确有存档角色提取/导入程序所指,但按本轮用户范围排除,不作为当前法器对象。\",\n \"pending\": [\n \"对压缩包extractall、LevelDB角色写入及目标归档直接写入的路径安全、覆盖、完整性和失败恢复未测试。\"\n ]\n },\n {\n \"path\": \".github/tools/external/XHS-image-to-PDF-conversion\",\n \"objects\": [],\n \"sources\": [\n \"S35\",\n \"S36\"\n ],\n \"boundary\": \"代码确有ZIP图片转PDF程序所指,但按本轮用户范围排除,不作为当前法器对象。\",\n \"pending\": [\n \"源码固定temp_extract并先递归删除同名目录,解压外部ZIP、写PDF且成功后删除原ZIP;未运行或验证恢复。\"\n ]\n }\n ],\n \"local_exclusions\": [\n {\n \"path\": \".github/tools/chat-vault\",\n \"name\": \"Chat Vault同步与查询程序\",\n \"decision\": \"excluded_from_faqi_scope\",\n \"source\": \"S04\",\n \"support_sources\": [\"S03\"],\n \"rationale\": \"按用户指定从当前法器清单排除。源码会自动探测Codex/Kiro/Gemini/Claude会话目录,将消息/cwd写入SQLite,并提供搜索、导出、watch和prune;入口在参数解析前会创建虚拟环境并安装依赖。属于私人对话数据、运行安装及持久副作用边界;未读取数据或执行,排除不等于否认其程序实现。\",\n \"reopen_condition\": \"只有明确需要纳入时,再以合成会话和隔离临时目录验证数据最小化、路径授权、日志/数据库访问控制、导出/删除语义、依赖安装副作用及恢复;不得用真实用户会话做验证。\"\n },\n {\n \"path\": \".github/tools/external/MCPlayerTransfer\",\n \"name\": \"Minecraft基岩版角色迁移程序\",\n \"decision\": \"excluded_from_faqi_scope\",\n \"source\": \"S34\",\n \"support_sources\": [\"S33\"],\n \"rationale\": \"按用户指定从当前法器清单排除。源码对.mcworld调用ZIP extractall,读取~local_player LevelDB记录;导入会写入LevelDB并以w模式创建目标归档。未验证不可信归档路径、目标文件覆盖、存档一致性和部分失败恢复;未处理真实存档,排除不等于否认其程序实现。\",\n \"reopen_condition\": \"如明确需要纳入,先在合成存档副本中验证归档路径/资源上限、无覆盖的临时输出、LevelDB读写一致性、失败清理与可恢复性;禁止用唯一真实存档作为测试输入。\"\n },\n {\n \"path\": \".github/tools/external/XHS-image-to-PDF-conversion\",\n \"name\": \"小红书图片ZIP转PDF程序\",\n \"decision\": \"excluded_from_faqi_scope\",\n \"source\": \"S36\",\n \"support_sources\": [\"S35\"],\n \"rationale\": \"按用户指定从当前法器清单排除。源码把外部ZIP解到输入旁固定temp_extract,运行前会递归删除同名目录;保存PDF后会删除原ZIP,异常时也会清理临时目录。缺少路径安全、覆盖保护、备份和失败恢复证据,未处理真实文件;排除不等于否认其程序实现。\",\n \"reopen_condition\": \"如明确需要纳入,先在隔离副本验证ZIP成员路径和展开上限、唯一随机临时目录、输入/PDF不覆盖、原ZIP保留、原子输出和所有失败路径恢复;不得使用真实业务ZIP测试。\"\n },\n {\n \"path\": \".github/tools/external/html-tools-main\",\n \"name\": \"EPUB CSS清理网页程序\",\n \"decision\": \"excluded_from_faqi_scope\",\n \"source\": \"S25\",\n \"support_sources\": [\"S24\"],\n \"rationale\": \"按用户指定从当前法器清单移除。固定来源选区仅保留为该网页实现的排除证据;未运行,不据此批准身份、依赖可用性、效果或许可。\",\n \"reopen_condition\": \"如需重新纳入,重新核定固定来源、身份、依赖和许可,并在隔离副本中验证文件读写及失败恢复;不得把源码存在当作运行证明。\"\n },\n {\n \"path\": \".github/tools/external/html-tools-main\",\n \"name\": \"Markdown预览与文本导出网页程序\",\n \"decision\": \"excluded_from_faqi_scope\",\n \"source\": \"S26\",\n \"support_sources\": [\"S24\"],\n \"rationale\": \"按用户指定从当前法器清单移除。固定来源选区仅保留为该Markdown预览/导出实现的排除证据;未运行,不据此批准身份、依赖可用性、效果或许可。\",\n \"reopen_condition\": \"如需重新纳入,重新核定固定来源、身份、版本、依赖和许可,并在隔离输入下复核预览与导出行为;不得将源码声明当作安全或效果验证。\"\n },\n {\n \"path\": \".github/tools/external/html-tools-main\",\n \"name\": \"任务卡片PNG导出网页程序\",\n \"decision\": \"excluded_from_faqi_scope\",\n \"source\": \"S27\",\n \"support_sources\": [\"S24\"],\n \"rationale\": \"按用户指定从当前法器清单移除。固定来源选区仅保留为该卡片导出实现的排除证据;未运行,不据此批准身份、依赖可用性、效果或许可。\",\n \"reopen_condition\": \"如需重新纳入,重新核定固定来源、身份、依赖和许可,并用合成内容验证导出结果;不使用私人或业务资料。\"\n },\n {\n \"path\": \".github/tools/external/html-tools-main\",\n \"name\": \"小红书内容卡片PNG导出网页程序\",\n \"decision\": \"excluded_from_faqi_scope\",\n \"source\": \"S28\",\n \"support_sources\": [\"S24\"],\n \"rationale\": \"按用户指定从当前法器清单移除。固定来源选区仅保留为该内容卡片导出实现的排除证据;未运行,不据此批准身份、依赖可用性、效果或许可。\",\n \"reopen_condition\": \"如需重新纳入,重新核定固定来源、身份、依赖和许可,并用合成内容验证导出行为及外部脚本边界;不使用私人或业务资料。\"\n },\n {\n \"path\": \".github/tools/external/html-tools-main\",\n \"name\": \"Markdown同步预览与PNG导出网页程序\",\n \"decision\": \"excluded_from_faqi_scope\",\n \"source\": \"S29\",\n \"support_sources\": [\"S24\"],\n \"rationale\": \"按用户指定从当前法器清单移除。固定来源选区仅保留为该Markdown同步预览/导出实现的排除证据;未运行,不据此批准身份、版本、依赖、效果或许可。\",\n \"reopen_condition\": \"如需重新纳入,重新核定固定来源、与其他页面的产品关系、版本、依赖和许可,并以隔离输入复核同步及导出行为。\"\n },\n {\n \"path\": \".github/tools/external/my-nvim\",\n \"name\": \"my-nvim的LazyVim引导配置程序\",\n \"decision\": \"excluded_from_faqi_scope\",\n \"source\": \"S32\",\n \"support_sources\": [\"S30\", \"S31\"],\n \"rationale\": \"按用户指定从当前法器清单移除。Lua配置程序来源仅保留为排除证据;未运行,不据此批准身份、插件依赖、效果或许可。\",\n \"reopen_condition\": \"如需重新纳入,重新核定固定来源、身份、版本、依赖和许可,并在临时HOME/隔离环境验证克隆及更新副作用;不得使用真实用户Neovim配置验证。\"\n }\n ],\n \"external_sources\": [\n {\n \"path\": \".github/assets/external-resources/tools-platforms.yml\",\n \"sha256\": \"07d51650bb219a071dd95c7e70bd30c6e8e247c660c457ddb268f0a0fedac351\"\n },\n {\n \"path\": \".github/assets/external-resources/repo-rules-scaffolds.yml\",\n \"sha256\": \"69c2675a96f2e52bf24bfae66104d010b2958b0266f817f593c1a41745b87132\"\n },\n {\n \"path\": \".github/assets/external-resources/network-payment-services.yml\",\n \"sha256\": \"2b1653c6239e9e5b7b0cfc9e9129a1938dc736c4d64049dde30af58cc9e7ed11\"\n }\n ],\n \"external_reviews\": [\n {\n \"decision\": \"software_candidate\",\n \"rationale\": \"原行明确描述程序、编辑器、CLI、插件、库或生成工具,保留软件实现候选;只有名称/介绍地址,未核具体实现、版本、许可证或能力,不直接赋型/登记。\",\n \"resource_ids\": [\n \"tools-platforms-codex-cli-362bc20a\",\n \"tools-platforms-droid-1b66f6e0\",\n \"tools-platforms-docusaurus-09c54423\",\n \"tools-platforms-vitepress-da10a919\",\n \"tools-platforms-lazyvim-2f22a781\",\n \"tools-platforms-neovim-a8b85739\",\n \"tools-platforms-pearai-0683754c\",\n \"tools-platforms-vs-code-e8f2d385\",\n \"tools-platforms-void-b1594346\",\n \"tools-platforms-django-e05156b6\",\n \"tools-platforms-excalidraw-02ba0cb2\",\n \"tools-platforms-mermaid-cc6f6e7e\",\n \"tools-platforms-dbeaver-aa2fc821\",\n \"tools-platforms-tableplus-9950f31a\",\n \"tools-platforms-warp-14bec77a\",\n \"tools-platforms-claude-code-11b1e88d\",\n \"tools-platforms-opencode-ada070db\",\n \"tools-platforms-gemini-cli-d077e5cc\",\n \"tools-platforms-gemini-cli-row40-d077e5cc\",\n \"tools-platforms-qwen-cli-a1b92a34\",\n \"tools-platforms-bito-0c0619b5\",\n \"tools-platforms-codeium-668488a9\",\n \"tools-platforms-continue-edb7b3bf\",\n \"tools-platforms-cursor-8ebf3977\",\n \"tools-platforms-zed-07b4820e\",\n \"tools-platforms-chatgpt-exporter-a03efe97\",\n \"repo-rules-scaffolds-autogen-fc00be5e\",\n \"repo-rules-scaffolds-browser-use-268f0f95\",\n \"repo-rules-scaffolds-crewai-d9a56566\",\n \"repo-rules-scaffolds-dspy-d8bdba82\",\n \"repo-rules-scaffolds-langchain-089a07ab\",\n \"repo-rules-scaffolds-pydantic-ai-cb69369e\",\n \"repo-rules-scaffolds-smolagents-790ade5e\",\n \"repo-rules-scaffolds-aider-adccc23a\",\n \"repo-rules-scaffolds-claude-code-ef1ef8b6\",\n \"repo-rules-scaffolds-cline-644a6623\",\n \"repo-rules-scaffolds-continue-d5516851\",\n \"repo-rules-scaffolds-gemini-cli-be45a9ce\",\n \"repo-rules-scaffolds-gpt-engineer-eaa2e8a8\",\n \"repo-rules-scaffolds-oh-my-opencode-0348827b\",\n \"repo-rules-scaffolds-open-interpreter-a514262e\",\n \"repo-rules-scaffolds-opencode-e1b762af\",\n \"repo-rules-scaffolds-spec-kit-a9a40ae2\",\n \"repo-rules-scaffolds-avante-nvim-29a0c49f\",\n \"repo-rules-scaffolds-codecompanion-nvim-a6f68dc2\",\n \"repo-rules-scaffolds-codeium-b0b85053\",\n \"repo-rules-scaffolds-copilot-vim-c06b7933\",\n \"repo-rules-scaffolds-gitingest-ee7a3f76\",\n \"repo-rules-scaffolds-jan-c4cdcb50\",\n \"repo-rules-scaffolds-lmstudio-8b9fe81d\",\n \"repo-rules-scaffolds-localai-ea1fbd8b\",\n \"repo-rules-scaffolds-ollama-33222b83\",\n \"repo-rules-scaffolds-repomix-5aa70b79\",\n \"repo-rules-scaffolds-text-generation-webui-8ec0aebb\",\n \"repo-rules-scaffolds-anythingllm-a3e8a5fc\",\n \"repo-rules-scaffolds-dify-4f89d10f\",\n \"repo-rules-scaffolds-privategpt-c615ca94\",\n \"repo-rules-scaffolds-quivr-5cc2ab96\",\n \"repo-rules-scaffolds-ragflow-c92a0918\",\n \"repo-rules-scaffolds-devdocs-62126dcb\",\n \"repo-rules-scaffolds-create-next-app-1bebc93a\",\n \"repo-rules-scaffolds-create-t3-app-daf8fe4b\",\n \"repo-rules-scaffolds-shadcn-ui-d7cf613e\",\n \"repo-rules-scaffolds-vite-3e45b462\",\n \"repo-rules-scaffolds-codex-e3c8be51\",\n \"repo-rules-scaffolds-roo-code-36e77dcc\",\n \"network-payment-services-flclash-a974428b\"\n ]\n },\n {\n \"decision\": \"hosted_entry_candidate\",\n \"rationale\": \"按原行服务功能与网址保留托管入口候选;网址不是实现、部署或设备证据,平台/模型/账号/实际调用仍需分离,未访问账户或核部署版本。\",\n \"resource_ids\": [\n \"tools-platforms-apps-script-e6b8bbbb\",\n \"tools-platforms-google-sheets-32b827b0\",\n \"tools-platforms-mintlify-0f0b6833\",\n \"tools-platforms-mermaid-chart-302f49f0\",\n \"tools-platforms-zread-6c1ee1d6\",\n \"tools-platforms-notebooklm-e1b56ba1\",\n \"tools-platforms-kimi-53c18eae\",\n \"tools-platforms-chatglm-cn-ebc410ba\",\n \"tools-platforms-www-doubao-com-b4d6c78b\",\n \"tools-platforms-tongyi-aliyun-com-a528848f\",\n \"tools-platforms-ai-studio-2cd869be\",\n \"tools-platforms-antigravity-528a772a\",\n \"tools-platforms-chatgpt-935111f5\",\n \"tools-platforms-claude-13dd5e3a\",\n \"tools-platforms-gemini-dc8a36f7\",\n \"tools-platforms-bolt-new-06379d16\",\n \"tools-platforms-devin-f5a69caf\",\n \"tools-platforms-lovable-5eb584a1\",\n \"tools-platforms-replit-agent-bbd1c2ac\",\n \"tools-platforms-v0-by-vercel-fe818ef0\",\n \"repo-rules-scaffolds-github-e755441d\",\n \"repo-rules-scaffolds-github-copilot-102fb5f8\"\n ]\n },\n {\n \"decision\": \"excluded_content\",\n \"rationale\": \"当前条目所指为知识、教程、索引、规则、提示词或模板内容,不作为法器程序登记;不删除原资源,也不断言整个仓库没有程序,其内具体实现须另选来源。\",\n \"resource_ids\": [\n \"tools-platforms-prompt-jsonl-8e9b2066\",\n \"tools-platforms-bilibili-23287176\",\n \"tools-platforms-z-library-31b0d982\",\n \"repo-rules-scaffolds-vibe-coding-e16848e0\",\n \"repo-rules-scaffolds-github-com-e0a40b2e\",\n \"repo-rules-scaffolds-mcaf-47f07717\",\n \"repo-rules-scaffolds-github-topics-bcc7e192\",\n \"repo-rules-scaffolds-github-trending-d46be94c\",\n \"repo-rules-scaffolds-awesome-mcp-servers-d91d6430\",\n \"repo-rules-scaffolds-2025-ai-engineer-reading-list-70f4fbd3\",\n \"repo-rules-scaffolds-ai-547bb859\",\n \"repo-rules-scaffolds-ai-engineering-d04a5b40\",\n \"repo-rules-scaffolds-awesome-explorables-2cedba5b\",\n \"repo-rules-scaffolds-awesome-llm-02e83378\",\n \"repo-rules-scaffolds-generative-ai-for-beginners-3b1db321\",\n \"repo-rules-scaffolds-llm-course-9227aca8\",\n \"repo-rules-scaffolds-lovable-for-beginners-38de2782\",\n \"repo-rules-scaffolds-prompt-engineering-guide-5130a915\",\n \"repo-rules-scaffolds-vibe-vibe-c80a5961\",\n \"repo-rules-scaffolds-awesome-chatgpt-prompts-ebaf3df7\",\n \"repo-rules-scaffolds-awesome-chatgpt-prompts-zh-966cbb5b\",\n \"repo-rules-scaffolds-claude-code-system-prompts-3f0438e1\",\n \"repo-rules-scaffolds-system-prompts-and-models-of-ai-tools-8290b642\",\n \"repo-rules-scaffolds-awesome-cursorrules-7f259f16\",\n \"repo-rules-scaffolds-cursor-directory-807839d9\",\n \"repo-rules-scaffolds-dotcursorrules-ad20d456\",\n \"repo-rules-scaffolds-langgpt-d6b7fb87\",\n \"repo-rules-scaffolds-awesome-chatgpt-prompts-4c4b8064\",\n \"repo-rules-scaffolds-system-prompts-b5948bc8\",\n \"repo-rules-scaffolds-easy-vibe-3c217e96\",\n \"repo-rules-scaffolds-ai-guide-c12bbbfd\",\n \"repo-rules-scaffolds-vibe-coding-guide-cf65840a\",\n \"repo-rules-scaffolds-ai-coding-c221421b\",\n \"repo-rules-scaffolds-vibe-coding-skill-a5e7c42d\",\n \"repo-rules-scaffolds-awesome-vibe-coding-e5ab67eb\",\n \"repo-rules-scaffolds-awesome-vibe-coding-e3ea2b5b\",\n \"repo-rules-scaffolds-claude-code-best-practice-01224898\",\n \"repo-rules-scaffolds-awesome-claude-code-5e3406a1\"\n ]\n },\n {\n \"decision\": \"excluded_model\",\n \"rationale\": \"当前名义所指是模型名称/版本,不当作法器程序;未取得参数/结构版本证据,不批准model-artifact实例,所附平台URL不证明模型与服务同一。\",\n \"resource_ids\": [\n \"tools-platforms-claude-opus-4-6-f751380c\",\n \"tools-platforms-gpt-5-1-codex-1ad522a5\",\n \"tools-platforms-gemini-2-5-pro-0661c69f\",\n \"tools-platforms-dall-e-3-26dc583b\"\n ]\n },\n {\n \"decision\": \"pending_identity\",\n \"rationale\": \"信息不足、对象名/目标不一致或复合包未展开,保留待核;不凭品牌、后缀、Skill/仓库包装复制软件身份,先明确具体模块、入口及版本。\",\n \"resource_ids\": [\n \"tools-platforms-local-history-2b05b2c1\",\n \"tools-platforms-partial-diff-4787875c\",\n \"tools-platforms-zsh-d6d24951\",\n \"tools-platforms-tabnine-0b2c09aa\",\n \"tools-platforms-elevenlabs-5a58d635\",\n \"tools-platforms-ideogram-efb6a3b8\",\n \"tools-platforms-kling-253d44f3\",\n \"tools-platforms-leonardo-ai-26816634\",\n \"tools-platforms-meshy-549051bc\",\n \"tools-platforms-midjourney-976ad67d\",\n \"tools-platforms-runway-6c8ab136\",\n \"tools-platforms-sora-3b1d49f7\",\n \"tools-platforms-suno-fb9344c5\",\n \"tools-platforms-udio-0d39f909\",\n \"tools-platforms-kiro-47d2b0fc\",\n \"tools-platforms-windsurf-fdd489a7\",\n \"repo-rules-scaffolds-scientific-skills-0f3f6b96\",\n \"repo-rules-scaffolds-mcp-servers-5d60dee4\",\n \"repo-rules-scaffolds-ai-for-grant-writing-0a634380\",\n \"repo-rules-scaffolds-fastapi-template-c97cc061\",\n \"repo-rules-scaffolds-ai-coding-lab-6dc927c2\",\n \"repo-rules-scaffolds-cs146s-cn-eaea3651\"\n ]\n },\n {\n \"decision\": \"related_local_source\",\n \"rationale\": \"原仓库网址与已审本地submodule来源对应,仅建立来源参照,不新增重复法器;不把未版本化仓库入口等同本次固定源码版本。\",\n \"resource_ids\": [\n \"repo-rules-scaffolds-skills-cd973130\",\n \"repo-rules-scaffolds-tmux-9f36981a\"\n ]\n },\n {\n \"decision\": \"restricted_service_pending\",\n \"rationale\": \"网络/金融服务品牌、推广入口或账号产品所指待核;保留全部风险与原状态,不批准交易、注册、权限、设备或运行实例。\",\n \"resource_ids\": [\n \"network-payment-services-www-bsmkweb-com-0960fe59\",\n \"network-payment-services-xn-9kqz23b19z-com-a271e5a7\",\n \"network-payment-services-bybit-81d32c91\"\n ]\n }\n ],\n \"resource_notes\": {\n \"tools-platforms-codex-cli-362bc20a\": \"描述混有“最强模型”、CLI、配置与旧地址;只保留CLI候选,不使用宣传赋级,本地Codex安装脚本不等于CLI。\",\n \"tools-platforms-zsh-d6d24951\": \"名称是zsh,但网址指ohmyz.sh;Shell程序与配置框架需消歧,不按标题选择软件身份。\",\n \"tools-platforms-local-history-2b05b2c1\": \"缺链接;同名插件可能有多个实现,需厂商/仓库和版本。\",\n \"tools-platforms-partial-diff-4787875c\": \"缺链接;需补具体插件来源,保留missing-link与needs-review。\",\n \"tools-platforms-gemini-cli-d077e5cc\": \"与另一Gemini CLI行指同一官网,属于重复介绍线索,不把两个资源ID登记为两程序。\",\n \"tools-platforms-gemini-cli-row40-d077e5cc\": \"与前一Gemini CLI行同名同网址,原ID仍保留;还需与GitHub实现核具体版本。\",\n \"tools-platforms-opencode-ada070db\": \"官网品牌与另行opencode-ai/opencode仓库不能凭同名自动合并,需核来源与演化。\",\n \"repo-rules-scaffolds-opencode-e1b762af\": \"仓库URL为opencode-ai/opencode;不据名称与opencode.ai官网或其他研究来源认定同一实现。\",\n \"tools-platforms-claude-opus-4-6-f751380c\": \"claude.ai平台不是Opus参数内容或具体模型版本的验证证据。\",\n \"tools-platforms-dall-e-3-26dc583b\": \"名称指模型,但网址是chatgpt.com;图像模型与其调用平台必须分离。\",\n \"tools-platforms-kimi-53c18eae\": \"仅保留平台网址候选;Kimi K2.5能力描述与服务实现/实际加载模型未核。\",\n \"tools-platforms-chatglm-cn-ebc410ba\": \"平台与GLM-4描述不作为同一对象/版本证据。\",\n \"tools-platforms-www-doubao-com-b4d6c78b\": \"模型与聊天客户端品牌并置,当前只保留网页入口候选。\",\n \"tools-platforms-tongyi-aliyun-com-a528848f\": \"Qwen模型、聊天服务及免费额度声明分别核,不继承“免费”或能力主张。\",\n \"tools-platforms-ai-studio-2cd869be\": \"AI Studio入口、Gemini模型与免费额度不是同一实体。\",\n \"tools-platforms-chatgpt-935111f5\": \"保留对话入口候选,不据GPT-5.1/支持Codex描述批准具体模型或CLI版本。\",\n \"tools-platforms-claude-13dd5e3a\": \"保留平台入口候选,不沿用Opus4.6能力/Artifacts宣传为实现效果。\",\n \"tools-platforms-gemini-dc8a36f7\": \"模型名、免费额度与长上下文宣传未核,网页入口与模型内容分开。\",\n \"tools-platforms-z-library-31b0d982\": \"按本条“电子书资源”所指排除程序登记;保留access-legality-review,不批准访问/下载或许可。\",\n \"repo-rules-scaffolds-scientific-skills-0f3f6b96\": \"Skill集合可能包含方法与脚本,需逐实际内容选区;集合自身不直接注册成一件软件。\",\n \"repo-rules-scaffolds-mcp-servers-5d60dee4\": \"服务器集合需按独立实现选区,不把MCP协议、多个示例、部署和整仓库作同一实例。\",\n \"repo-rules-scaffolds-fastapi-template-c97cc061\": \"模板可能包含可执行应用或生成器,须分清模板内容、应用源码与新生成实例。\",\n \"repo-rules-scaffolds-ai-coding-lab-6dc927c2\": \"项目实战复合仓库包含多种项目类型,不能把教程或整个仓库纳为一程序。\",\n \"repo-rules-scaffolds-cs146s-cn-eaea3651\": \"课程、作业与工具混合,需明确具体程序选区。\",\n \"repo-rules-scaffolds-roo-code-36e77dcc\": \"原描述称archive且status=needs-review;仅保留源码候选,不冒称当前可用或已核归档状态。\",\n \"repo-rules-scaffolds-codeium-b0b85053\": \"此行指codeium.vim插件,不能与Codeium平台或Windsurf品牌合并。\",\n \"repo-rules-scaffolds-github-copilot-102fb5f8\": \"订阅/服务入口与copilot.vim插件、模型或免费资格分别核,原免费描述未核。\",\n \"repo-rules-scaffolds-create-next-app-1bebc93a\": \"链接是CLI文档,文档不是程序;条目所指的生成器实现仍需版本核查。\",\n \"repo-rules-scaffolds-awesome-chatgpt-prompts-ebaf3df7\": \"与另一f/awesome-chatgpt-prompts行是重复来源线索;保原两ID,不登记两个工具。\",\n \"repo-rules-scaffolds-awesome-chatgpt-prompts-4c4b8064\": \"原description=null;仅依原名称和仓库路径关联提示词合集线索,不补造产品能力。\",\n \"repo-rules-scaffolds-system-prompts-b5948bc8\": \"原description=null;与另一同URL条目关联提示词来源线索,不声称模型参数或工具实现。\",\n \"network-payment-services-www-bsmkweb-com-0960fe59\": \"资源自称“币安支付”,网址为bsmkweb.com并带ref;品牌/网址所指一致性未核,不据名称认定官方服务。\",\n \"network-payment-services-xn-9kqz23b19z-com-a271e5a7\": \"注册推广入口只有泛化云服务说明,实际服务、提供方与合规边界待核。\",\n \"network-payment-services-bybit-81d32c91\": \"卡产品/账户/支付过程与网站或程序内容分开,不触发开户或支付。\",\n \"network-payment-services-flclash-a974428b\": \"源码候选仅指代理客户端内容,不授权代理连接或实际网络配置。\"\n },\n \"local_resource_links\": {\n \"repo-rules-scaffolds-skills-cd973130\": \"faqi-skill-seekers\",\n \"repo-rules-scaffolds-tmux-9f36981a\": \"faqi-tmux\"\n },\n \"relations\": [\n {\n \"subject\": \"faqi-auto-tmux\",\n \"predicate\": \"requires\",\n \"target_label\": \"tmux程序(运行版本未知)\",\n \"related_object_id\": \"faqi-tmux\",\n \"evidence\": \"S13\",\n \"boundary\": \"脚本调用PATH中的tmux;本地上游源码仅作相关参照,不证明实际安装二进制来自该修订。\"\n },\n {\n \"subject\": \"faqi-oh-my-tmux\",\n \"predicate\": \"requires\",\n \"target_label\": \"tmux>=2.6及awk/perl/grep/sed\",\n \"related_object_id\": \"faqi-tmux\",\n \"evidence\": \"S17\",\n \"boundary\": \"README声明版本下限,不将配置修订误写成tmux版本,也不保证当前环境满足依赖。\"\n },\n {\n \"subject\": \"faqi-skill-seekers-adapter\",\n \"predicate\": \"requires\",\n \"target_label\": \"链接源码中的skill_seekers.cli.main\",\n \"related_object_id\": \"faqi-skill-seekers\",\n \"evidence\": \"S10\",\n \"boundary\": \"源码路径确由软链接指到选定submodule;这是静态加载意图,venv实际依赖、Python解析和运行结果未核。\"\n }\n ],\n \"references\": [\n {\n \"path\": \".github/skills/auto-skill/scripts/Skill_Seekers-development\",\n \"state\": \"symlink\",\n \"target\": \"../../../tools/external/Skill_Seekers-development\",\n \"related_object_id\": \"faqi-skill-seekers\",\n \"boundary\": \"同一仓库源码的引用入口,不新增法器副本;封装脚本另有指令内容。\"\n },\n {\n \"path\": \".github/skills/claude-official-skills\",\n \"state\": \"symlink\",\n \"target\": \"../tools/external/claude-official-skills\",\n \"related_object_id\": null,\n \"boundary\": \"指向Skill集合而非一件软件,不能再因引用入口登记整集合。\"\n },\n {\n \"path\": \".github/skills/auto-tmux/assets/oh-my-tmux\",\n \"state\": \"symlink\",\n \"target\": \"../../../tools/external/.tmux\",\n \"related_object_id\": \"faqi-oh-my-tmux\",\n \"boundary\": \"当前仓内相对软链接指向已登记的oh-my-tmux submodule;source_revision保留原零字节历史基线,链接状态不代表运行、许可或效果验证。\"\n },\n {\n \"path\": \".github/skills/auto-tmux/assets/tmux-src\",\n \"state\": \"symlink\",\n \"target\": \"../../../tools/external/tmux\",\n \"related_object_id\": \"faqi-tmux\",\n \"boundary\": \"当前仓内相对软链接指向已登记的tmux submodule;source_revision保留原零字节历史基线,链接状态不代表运行、许可或效果验证。\"\n }\n ]\n}",
"sha256": "c977f6b18e41d4ae03c879513e505578b3ab9111e2d6b6dd1251e74123d5cbd0"
},
".github/metadata/faqi.schema.json": {
"mode": "100644",
"encoding": "utf-8",
"data": "{\n \"$schema\": \"https://json-schema.org/draft/2020-12/schema\",\n \"title\": \"Vibe Coding法器总分类与重要性分级登记\",\n \"description\": \"复用唯一BFO树,汇总来源限定实现、依赖图对象、用户确认纳入类别及按Vibe Coding重要性排序的用户授权暂定品级。重要性分级不代表效能验证或正式效能评级;外部资源ID引用原YAML。\",\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\"format_version\", \"kind\", \"reviewed_at\", \"source_revision\", \"ontology\", \"dependency_graph\", \"limits\", \"provisional_grade_assignments\", \"sources\", \"objects\", \"local_entries\", \"local_exclusions\", \"external_sources\", \"external_reviews\", \"resource_notes\", \"local_resource_links\", \"relations\", \"references\"],\n \"properties\": {\n \"format_version\": {\"const\": 2},\n \"kind\": {\"const\": \"faqi-master-classification-register\"},\n \"reviewed_at\": {\"type\": \"string\", \"maxLength\": 40},\n \"source_revision\": {\"$ref\": \"#/$defs/revision\"},\n \"ontology\": {\n \"type\": \"object\", \"additionalProperties\": false, \"required\": [\"path\", \"sha256\"],\n \"properties\": {\"path\": {\"const\": \".github/docs/gongfa/cultivation-ontology-taxonomy.md\"}, \"sha256\": {\"$ref\": \"#/$defs/sha256\"}}\n },\n \"dependency_graph\": {\"$ref\": \"#/$defs/dependency_graph\"},\n \"limits\": {\n \"type\": \"object\", \"additionalProperties\": false,\n \"required\": [\"independent_review\", \"runtime_verified\", \"effectiveness_verified\", \"license_approved\", \"grades_assigned\"],\n \"properties\": {\"independent_review\": {\"const\": false}, \"runtime_verified\": {\"const\": false}, \"effectiveness_verified\": {\"const\": false}, \"license_approved\": {\"const\": false}, \"grades_assigned\": {\"const\": true, \"description\": \"有用户授权的Vibe Coding重要性暂定分级;不代表正式效能评级。\"}}\n },\n \"provisional_grade_assignments\": {\"type\": \"array\", \"minItems\": 1, \"maxItems\": 1024, \"items\": {\"$ref\": \"#/$defs/provisional_grade_assignment\"}},\n \"sources\": {\"type\": \"array\", \"minItems\": 1, \"maxItems\": 128, \"items\": {\"$ref\": \"#/$defs/source\"}},\n \"objects\": {\"type\": \"array\", \"minItems\": 1, \"maxItems\": 512, \"items\": {\"$ref\": \"#/$defs/tool\"}},\n \"local_entries\": {\"type\": \"array\", \"minItems\": 1, \"maxItems\": 128, \"items\": {\"$ref\": \"#/$defs/local\"}},\n \"local_exclusions\": {\"type\": \"array\", \"maxItems\": 128, \"items\": {\"$ref\": \"#/$defs/local_exclusion\"}},\n \"external_sources\": {\n \"type\": \"array\", \"minItems\": 3, \"maxItems\": 3,\n \"items\": {\"type\": \"object\", \"additionalProperties\": false, \"required\": [\"path\", \"sha256\"], \"properties\": {\n \"path\": {\"enum\": [\".github/assets/external-resources/tools-platforms.yml\", \".github/assets/external-resources/repo-rules-scaffolds.yml\", \".github/assets/external-resources/network-payment-services.yml\"]},\n \"sha256\": {\"$ref\": \"#/$defs/sha256\"}\n }}\n },\n \"external_reviews\": {\n \"type\": \"array\", \"minItems\": 1, \"maxItems\": 7,\n \"items\": {\"type\": \"object\", \"additionalProperties\": false, \"required\": [\"decision\", \"rationale\", \"resource_ids\"], \"properties\": {\n \"decision\": {\"enum\": [\"software_candidate\", \"hosted_entry_candidate\", \"excluded_content\", \"excluded_model\", \"pending_identity\", \"related_local_source\", \"restricted_service_pending\"]},\n \"rationale\": {\"$ref\": \"#/$defs/text\"},\n \"resource_ids\": {\"type\": \"array\", \"minItems\": 1, \"maxItems\": 4096, \"uniqueItems\": true, \"items\": {\"$ref\": \"#/$defs/id\"}}\n }}\n },\n \"resource_notes\": {\"type\": \"object\", \"maxProperties\": 4096, \"propertyNames\": {\"$ref\": \"#/$defs/id\"}, \"additionalProperties\": {\"$ref\": \"#/$defs/text\"}},\n \"local_resource_links\": {\"type\": \"object\", \"maxProperties\": 4096, \"propertyNames\": {\"$ref\": \"#/$defs/id\"}, \"additionalProperties\": {\"$ref\": \"#/$defs/id\"}},\n \"relations\": {\n \"type\": \"array\", \"maxItems\": 512,\n \"items\": {\"type\": \"object\", \"additionalProperties\": false, \"required\": [\"subject\", \"predicate\", \"target_label\", \"related_object_id\", \"evidence\", \"boundary\"], \"properties\": {\n \"subject\": {\"$ref\": \"#/$defs/id\"}, \"predicate\": {\"const\": \"requires\"}, \"target_label\": {\"$ref\": \"#/$defs/text\"},\n \"related_object_id\": {\"type\": [\"string\", \"null\"]}, \"evidence\": {\"$ref\": \"#/$defs/id\"}, \"boundary\": {\"$ref\": \"#/$defs/text\"}\n }}\n },\n \"references\": {\n \"type\": \"array\", \"maxItems\": 128,\n \"items\": {\"type\": \"object\", \"additionalProperties\": false, \"required\": [\"path\", \"state\", \"target\", \"related_object_id\", \"boundary\"], \"properties\": {\n \"path\": {\"$ref\": \"#/$defs/path\"}, \"state\": {\"enum\": [\"symlink\", \"empty-placeholder\"]},\n \"target\": {\"type\": [\"string\", \"null\"]}, \"related_object_id\": {\"type\": [\"string\", \"null\"]}, \"boundary\": {\"$ref\": \"#/$defs/text\"}\n }}\n }\n },\n \"$defs\": {\n \"id\": {\"type\": \"string\", \"pattern\": \"^[a-zA-Z0-9][a-zA-Z0-9._-]{0,127}$\"},\n \"sha256\": {\"type\": \"string\", \"pattern\": \"^[a-f0-9]{64}$\"},\n \"revision\": {\"type\": \"string\", \"pattern\": \"^[a-f0-9]{40}$\"},\n \"text\": {\"type\": \"string\", \"minLength\": 1, \"maxLength\": 2400, \"pattern\": \"^[^\\u0000-\\u001f\\u007f]+$\"},\n \"path\": {\"type\": \"string\", \"minLength\": 1, \"maxLength\": 240, \"pattern\": \"^[A-Za-z0-9_./ -]+$\"},\n \"ids\": {\"type\": \"array\", \"maxItems\": 128, \"uniqueItems\": true, \"items\": {\"$ref\": \"#/$defs/id\"}},\n \"source\": {\n \"type\": \"object\", \"additionalProperties\": false, \"required\": [\"id\", \"purpose\", \"path\", \"repository\", \"revision\", \"sha256\", \"lines\", \"selection_sha256\"],\n \"properties\": {\n \"id\": {\"$ref\": \"#/$defs/id\"},\n \"purpose\": {\"enum\": [\"implementation\", \"support\", \"exclusion_evidence\"], \"description\": \"选区的人工初审用途,不凭后缀推断程序;排除证据不可作为纳入对象的实现来源。\"},\n \"path\": {\"$ref\": \"#/$defs/path\"},\n \"repository\": {\"enum\": [\".\", \".github/tools/external/tmux\", \".github/tools/external/.tmux\", \".github/tools/external/Skill_Seekers-development\", \".github/tools/external/claude-official-skills\"]},\n \"revision\": {\"$ref\": \"#/$defs/revision\"}, \"sha256\": {\"$ref\": \"#/$defs/sha256\"},\n \"lines\": {\"type\": \"array\", \"minItems\": 2, \"maxItems\": 2, \"items\": {\"type\": \"integer\", \"minimum\": 1, \"maximum\": 100000}},\n \"selection_sha256\": {\"$ref\": \"#/$defs/sha256\"}\n }\n },\n \"dependency_graph\": {\n \"type\": \"object\", \"additionalProperties\": false,\n \"required\": [\"source_path\", \"source_sha256\", \"source_anchor\", \"observed_at\", \"user_confirmation\", \"objects\", \"local_links\", \"dependency_categories\"],\n \"properties\": {\n \"source_path\": {\"const\": \".github/docs/gongfa/technology-stack.md\"},\n \"source_sha256\": {\"$ref\": \"#/$defs/sha256\"},\n \"source_anchor\": {\"const\": \"reference-technology-stack-十六技术栈的层级结构\"},\n \"observed_at\": {\"type\": \"string\", \"maxLength\": 40, \"pattern\": \"^\\\\d{4}-\\\\d{2}-\\\\d{2}T[^\\\\u0000-\\\\u001f]+Z$\"},\n \"user_confirmation\": {\n \"type\": \"object\", \"additionalProperties\": false, \"required\": [\"reviewed_at\", \"statement\", \"scope\"],\n \"properties\": {\n \"reviewed_at\": {\"type\": \"string\", \"maxLength\": 40, \"pattern\": \"^\\\\d{4}-\\\\d{2}-\\\\d{2}T[^\\\\u0000-\\\\u001f]+Z$\"},\n \"statement\": {\"$ref\": \"#/$defs/text\"}, \"scope\": {\"$ref\": \"#/$defs/text\"}\n }\n },\n \"objects\": {\"type\": \"array\", \"minItems\": 12, \"maxItems\": 64, \"items\": {\"$ref\": \"#/$defs/dependency_object\"}},\n \"local_links\": {\"type\": \"array\", \"minItems\": 1, \"maxItems\": 64, \"items\": {\"$ref\": \"#/$defs/graph_local_link\"}},\n \"dependency_categories\": {\"type\": \"array\", \"minItems\": 1, \"maxItems\": 64, \"items\": {\"$ref\": \"#/$defs/graph_dependency_category\"}}\n }\n },\n \"dependency_object\": {\n \"type\": \"object\", \"additionalProperties\": false,\n \"required\": [\"id\", \"name\", \"type_id\", \"graph_node\", \"identity_status\", \"version\", \"evidence\", \"resource_ids\", \"related_object_id\", \"grade_id\", \"grade_status\", \"grade_reason\"],\n \"properties\": {\n \"id\": {\"$ref\": \"#/$defs/id\"}, \"name\": {\"$ref\": \"#/$defs/text\"},\n \"type_id\": {\"type\": \"string\", \"pattern\": \"^[a-z][a-z0-9-]{0,63}$\"},\n \"graph_node\": {\"$ref\": \"#/$defs/text\"},\n \"identity_status\": {\"enum\": [\"runtime_observed\", \"named_candidate\"]},\n \"version\": {\"type\": [\"string\", \"null\"], \"maxLength\": 120},\n \"evidence\": {\"$ref\": \"#/$defs/text\"}, \"resource_ids\": {\"type\": \"array\", \"maxItems\": 8, \"uniqueItems\": true, \"items\": {\"$ref\": \"#/$defs/id\"}},\n \"related_object_id\": {\"type\": [\"string\", \"null\"]},\n \"grade_id\": {\"const\": null}, \"grade_status\": {\"const\": \"pending\"},\n \"grade_reason\": {\"$ref\": \"#/$defs/text\"}\n }\n },\n \"graph_local_link\": {\n \"type\": \"object\", \"additionalProperties\": false,\n \"required\": [\"object_id\", \"graph_node\", \"relationship\"],\n \"properties\": {\"object_id\": {\"$ref\": \"#/$defs/id\"}, \"graph_node\": {\"$ref\": \"#/$defs/text\"}, \"relationship\": {\"$ref\": \"#/$defs/text\"}}\n },\n \"graph_dependency_category\": {\n \"type\": \"object\", \"additionalProperties\": false,\n \"required\": [\"id\", \"node\", \"disposition\", \"reason\"],\n \"properties\": {\n \"id\": {\"$ref\": \"#/$defs/id\"},\n \"node\": {\"$ref\": \"#/$defs/text\"},\n \"disposition\": {\"enum\": [\"pending_identity\", \"unselected_optional\", \"user_confirmed_in_scope\", \"not_faqi\"]},\n \"reason\": {\"$ref\": \"#/$defs/text\"}\n }\n },\n \"provisional_grade_assignment\": {\n \"type\": \"object\", \"additionalProperties\": false,\n \"required\": [\"subject_id\", \"grade_id\", \"assignment_status\", \"scope\", \"basis\"],\n \"properties\": {\n \"subject_id\": {\"$ref\": \"#/$defs/id\"},\n \"grade_id\": {\"type\": \"string\", \"pattern\": \"^faqi-(huang|xuan|di|tian)-[a-z0-9-]+$\", \"description\": \"本清单按用户指定的Vibe Coding重要性顺序暂定分级,不是效能等级。\"},\n \"assignment_status\": {\"enum\": [\"task_scoped_provisional\", \"user_directed_provisional\"]},\n \"scope\": {\"$ref\": \"#/$defs/text\"},\n \"basis\": {\"$ref\": \"#/$defs/text\"}\n }\n },\n \"tool\": {\n \"type\": \"object\", \"additionalProperties\": false, \"required\": [\"id\", \"name\", \"type_id\", \"implementation\", \"support\", \"boundary\", \"declared_version\"],\n \"properties\": {\n \"id\": {\"$ref\": \"#/$defs/id\"}, \"name\": {\"$ref\": \"#/$defs/text\"}, \"type_id\": {\"const\": \"software-artifact\"},\n \"implementation\": {\"$ref\": \"#/$defs/id\"}, \"support\": {\"$ref\": \"#/$defs/ids\"}, \"boundary\": {\"$ref\": \"#/$defs/text\"},\n \"declared_version\": {\"type\": [\"string\", \"null\"], \"maxLength\": 80}\n }\n },\n \"local\": {\n \"type\": \"object\", \"additionalProperties\": false, \"required\": [\"path\", \"objects\", \"sources\", \"boundary\", \"pending\"],\n \"properties\": {\n \"path\": {\"$ref\": \"#/$defs/path\"}, \"objects\": {\"$ref\": \"#/$defs/ids\"}, \"sources\": {\"$ref\": \"#/$defs/ids\"},\n \"boundary\": {\"$ref\": \"#/$defs/text\"}, \"pending\": {\"type\": \"array\", \"maxItems\": 32, \"items\": {\"$ref\": \"#/$defs/text\"}}\n }\n },\n \"local_exclusion\": {\n \"type\": \"object\", \"additionalProperties\": false,\n \"required\": [\"path\", \"name\", \"decision\", \"source\", \"support_sources\", \"rationale\", \"reopen_condition\"],\n \"properties\": {\n \"path\": {\"$ref\": \"#/$defs/path\"}, \"name\": {\"$ref\": \"#/$defs/text\"},\n \"decision\": {\"const\": \"excluded_from_faqi_scope\"},\n \"source\": {\"$ref\": \"#/$defs/id\"}, \"support_sources\": {\"$ref\": \"#/$defs/ids\"},\n \"rationale\": {\"$ref\": \"#/$defs/text\"}, \"reopen_condition\": {\"$ref\": \"#/$defs/text\"}\n }\n }\n }\n}\n",
"sha256": "90b3d4ced8918927d002b0f935922610ecb5af7a13129c26c086e068eeb41f77"
},
".github/skills/auto-skill/scripts/Skill_Seekers-development": {
"mode": "120000",
"encoding": "utf-8",
"data": "../../../tools/external/Skill_Seekers-development",
"sha256": "c91cb405af1bb8c883aaca70abb295a62c85a3c5a7e8e60c70ac2f58173f7416"
},
".github/skills/auto-skill/scripts/skill-seekers-configs": {
"mode": "120000",
"encoding": "utf-8",
"data": "Skill_Seekers-development/configs",
"sha256": "1ca2057bda1d37e46bec394c71be9cf8ea8a4a57a65f3805bfa3799176feb5f6"
},
".github/skills/auto-skill/scripts/skill-seekers-src": {
"mode": "120000",
"encoding": "utf-8",
"data": "Skill_Seekers-development/src",
"sha256": "2e9f3a1ec779f2d98599d9046f55b919fa9090cafced8c2e8dadbc17b8e92919"
},
".github/skills/claude-official-skills": {
"mode": "120000",
"encoding": "utf-8",
"data": "../tools/external/claude-official-skills",
"sha256": "878c4ccbeb13adffe88ede33403dfa2ff932ee5674cf6b72c49f6e108f6da654"
},
".github/tools/faqi-catalog.md": {
"mode": "100644",
"encoding": "utf-8",
"data": "<!-- generated: sync-faqi-catalog.py -->\n# Vibe Coding法器重要性总表\n\n品级仅表示 Vibe Coding 重要性暂定,不代表效能验证;本页仅供浏览,完整登记见[.github/metadata/faqi.json](../metadata/faqi.json)。\n\n| 品级 | 名称 | 解释 |\n|:---------|:----------------------------------------------------------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------|\n| 天阶高级 | 2.2 云端模型服务/API与固定模型版本 | Vibe Coding重要性:核心模型推理与代码生成;提供理解需求、推理和生成代码的核心智能能力;没有模型推理路径即失去Vibe Coding的定义性特征,供应商与模型可替换。 |\n| 天阶高级 | Pi Agent CLI(当前 PATH 实例) | Vibe Coding重要性:当前核心Agent运行与工具编排;直接承接需求、上下文、模型调用和工具执行循环;当前环境的核心交互入口,缺失会改变Vibe Coding核心形态。 |\n| 天阶中级 | 2.2 本地模型权重、Tokenizer与推理引擎 | Vibe Coding重要性:本地/离线模型推理路径;可提供核心模型推理并支持本地化、隐私或离线需求;在通用工作流中可由云端推理替代,故低于定义性核心路径。 |\n| 天阶中级 | Codex CLI(依赖图替代项) | Vibe Coding重要性:替代Agent运行时;若选用可承担AI代码协作与工具编排核心;当前仅具名候选且可与其他运行时替换,低于已用核心路径。 |\n| 地阶高级 | GNU Bash | Vibe Coding重要性:Agent命令执行与脚本交互;直接承接终端命令、开发脚本和验证操作,是当前Agent落地代码动作的高重要性接口;Shell实现可替代但该角色不可缺。 |\n| 地阶高级 | 3.2 Terminal Emulator / PTY | Vibe Coding重要性:Agent调用工具与执行开发命令;把Agent计划转成真实文件、构建和测试操作的关键执行边界;没有等价工具执行通道,代码闭环无法完成。 |\n| 地阶高级 | Git 本地客户端 | Vibe Coding重要性:代码变更追踪、比较与恢复;支撑审查AI改动、保留版本历史和安全回退,是可维护代码生成闭环的高重要性基础;版本控制实现可替代。 |\n| 地阶中级 | 8 CPU/GPU、内存、存储、网络、电力与数据中心 | Vibe Coding重要性:计算、存储与网络承载;为模型调用、代码执行及数据交换提供资源底座;实现可跨云、主机和本地环境替换,故不是单一核心产品。 |\n| 地阶中级 | 4.2 包注册表、Git源与可信缓存 | Vibe Coding重要性:依赖获取、锁定与复现;支持安装成熟组件、解析代码依赖和重建开发环境;具体注册表与来源有替代,不直接承担AI生成。 |\n| 地阶中级 | Node.js 运行时 | Vibe Coding重要性:前端及工具链代码运行;支撑前端、Node项目和本仓Markdown工具链;具体语言环境可替代,重要性低于通用Agent与终端执行核心。 |\n| 地阶中级 | npm / npx 工具 | Vibe Coding重要性:Node依赖解析与工具调用;让Node生态依赖和命令行工具可安装、解析与调用;作用范围依赖项目技术栈,可由其他生态包管理器替代。 |\n| 地阶中级 | Python 运行时 | Vibe Coding重要性:脚本、工具与项目代码运行;支撑本仓工具及大量Python项目的执行和验证;语言运行时可按项目替代,重要但非所有Vibe Coding任务必需。 |\n| 地阶初级 | GNU Make | Vibe Coding重要性:可重复构建与检查入口;把构建和验证命令组织成可重复入口有助于交付,但Make可由其他任务运行器或脚本替代。 |\n| 地阶初级 | Ubuntu 用户空间发行版 | Vibe Coding重要性:当前Linux用户空间;承载当前工具链和本地命令,但同类操作系统环境可以替代,重要性来自运行基座而非该发行版身份。 |\n| 地阶初级 | WSL2 Linux 内核 | Vibe Coding重要性:当前运行环境内核;提供当前WSL用户空间的执行底座,但存在其他内核和宿主替代,不属于AI编程核心能力。 |\n| 地阶初级 | WSL 2 承载平台 | Vibe Coding重要性:当前宿主环境实现;为当前工具链提供运行宿主,但Linux、macOS或原生Windows等环境可替代,不是Vibe Coding定义性能力。 |\n| 玄阶高级 | 7.1 Git托管、CI Runner与CI/CD平台 | Vibe Coding重要性:自动化验证、协作与持续交付;把代码生成接入可重复测试、审查和协作交付,显著扩展可靠使用范围;本地闭环可运行但难以替代团队级持续验证。 |\n| 玄阶高级 | 2.3 检索/索引/记忆与向量库 | Vibe Coding重要性:长程上下文、知识检索与记忆;支撑跨文件和长任务上下文保持、历史知识复用,提升复杂任务可处理范围;短任务仍可不依赖,且实现可替换。 |\n| 玄阶中级 | 7.2-7.3 制品注册表、部署目标、产品运行时、数据库与外部API | Vibe Coding重要性:从代码到产品运行与外部集成;支撑部署、数据库和API集成,使代码进入真实产品场景;并非每次编码必需,故属于重要交付扩展而非核心生成。 |\n| 玄阶中级 | auto-skill模板生成脚本 | Vibe Coding重要性:技能资产扩展与复用;把操作知识封装为可复用Agent技能,能扩展后续任务能力;属于增益支路,不是最小编码闭环的必需组件。 |\n| 玄阶中级 | auto-skill结构校验脚本 | Vibe Coding重要性:技能资产质量与可载入性;降低扩展技能结构错误造成的接入阻断;不判断语义正确性,属于能力扩展的质量辅助。 |\n| 玄阶中级 | Skill Seekers程序 | Vibe Coding重要性:外部知识转可复用技能;增加Agent可复用的领域能力和上下文资产;需特定工作流,不能替代通用推理与工具执行。 |\n| 玄阶初级 | 官方Skill初始化脚本 | Vibe Coding重要性:特定Skill模板初始化;降低Claude Skill结构初始化成本,作用范围绑定特定生态,可手工完成且不影响其他Agent的基础闭环。 |\n| 玄阶初级 | Codex配置安装与恢复脚本 | Vibe Coding重要性:特定Agent接入配置;降低特定Agent初始配置成本,但只服务候选运行时且可手工替代;不属于核心模型推理或执行闭环。 |\n| 玄阶初级 | Skill Seekers本地运行适配脚本 | Vibe Coding重要性:Skill Seekers本地适配入口;便于调用特定知识转技能工具;范围受上游工具限制,可直接调用或人工替代。 |\n| 黄阶高级 | tmux 当前运行实例 | Vibe Coding重要性:长任务与多会话终端复用;可持久化和并行组织终端工作,复杂协作时有价值;普通单会话开发可替代,不属于核心生成链。 |\n| 黄阶高级 | auto-tmux命令封装程序 | Vibe Coding重要性:多会话终端协作自动化;多会话与worker协作在复杂并行时有用,但基础单Agent编码有替代路径;本级只表达工作流重要性,不评价实现质量或效能。 |\n| 黄阶高级 | tmux终端复用程序 | Vibe Coding重要性:可选的多会话终端复用;支持持久终端与多窗口工作流,复杂长任务可受益;普通编码闭环有替代方案,不属定义性核心。 |\n| 黄阶中级 | oh-my-tmux可执行配置程序 | Vibe Coding重要性:终端复用器体验配置;改善tmux使用便利性,但不提供模型推理或核心代码执行能力,可由其他终端配置替代。 |\n| 黄阶初级 | 提示词格式转换程序 | Vibe Coding重要性:提示词资产格式迁移的辅助支路;只负责格式转换,能维护和复用提示词资产但不参与模型推理或代码执行;替代方式多,属低重要性辅助。 |\n",
"sha256": "92fd5fe897b1deb5de8e7932939636216a99f9c3828c0c6003f143b4658d79be"
},
".github/tools/prompts-library/README.md": {
"mode": "100644",
"encoding": "utf-8",
"data": "# prompts-library\n\n`tools/prompts-library/` 是本仓内的提示词格式转换工具,用于在 Excel、Markdown 和 JSONL 之间转换提示词资产。\n\n它不是独立仓库首页,也不再引用旧的 `tukuaiai/prompt-library` 仓库口径。当前目录作为 `vibe-coding-cn` 的内部工具维护。\n\n## 功能\n\n- Excel -> Markdown:把表格提示词导出为 Markdown 文档目录。\n- Markdown -> Excel:把 Markdown 文档目录还原为 Excel 工作簿。\n- Markdown -> JSONL:把 Markdown 提示词转换为 JSONL。\n- JSONL -> Excel:把 JSONL 数据转换为 Excel。\n- JSONL 目录 -> Excel:把 Excel(JSONL) 导出的工作表级 JSONL 目录重新合并为 Excel。\n- Excel(JSONL) -> JSONL:把内部 JSONL 格式的 Excel 按工作表拆成 JSONL 文件。\n\n## 目录结构\n\n```text\ntools/prompts-library/\n README.md\n AGENTS.md\n main.py\n requirements.txt\n docs/\n scripts/\n```\n\n## 安装依赖\n\n```bash\ncd tools/prompts-library\npython3 -m pip install -r requirements.txt\n```\n\n部分辅助脚本有单独依赖:\n\n```bash\npython3 -m pip install -r scripts/requirements.txt\n```\n\n## 常用命令\n\n查看入口参数:\n\n```bash\npython3 main.py --help\n```\n\n交互式转换:\n\n```bash\npython3 main.py\n```\n\n指定转换模式:\n\n```bash\npython3 main.py --select \"prompt_excel/example.xlsx\" --mode excel2docs\npython3 main.py --select \"prompt_docs/example\" --mode docs2excel\npython3 main.py --select \"prompt_docs/example\" --mode docs2jsonl\npython3 main.py --select \"prompt_jsonl/example.jsonl\" --mode jsonl2excel\npython3 main.py --select \"prompt_jsonl/example_2025_1222_004537\" --mode jsonl2excel\npython3 main.py --select \"prompt_excel/prompt_jsonl.xlsx\" --mode jsonl_excel2jsonl\n```\n\n无交互执行:\n\n```bash\npython3 main.py --select \"prompt_excel/example.xlsx\" --mode excel2docs --non-interactive\n```\n\n## 输入输出约定\n\n- 默认 Excel 输入目录:`prompt_excel/`\n- 默认 Markdown 输入/输出目录:`prompt_docs/`\n- 默认 JSONL 输出目录:`prompt_jsonl/`\n- `prompt_jsonl/` 是生成物,已在 `.gitignore` 中忽略。\n\n## 维护规则\n\n- 修改转换逻辑时,优先阅读 `main.py` 和 `scripts/` 中对应脚本。\n- 新增依赖必须同步更新 `requirements.txt` 或 `scripts/requirements.txt`。\n- 不提交生成目录、缓存、临时导出或本地凭证。\n- 修改后至少运行:\n\n```bash\npython3 main.py --help\n```\n\n如改动影响仓库文档或链接,还需要在仓库根目录运行:\n\n```bash\nmake test\n```\n",
"sha256": "4c2d5f97a6cfa67e033e166676d12eeaab6a562fa83c39b0f2474ae2afbcdae2"
},
".github/tools/prompts-library/main.py": {
"mode": "100644",
"encoding": "utf-8",
"data": "#!/usr/bin/env python3\n# -*- coding: utf-8 -*-\nr\"\"\"\nmain.py\n\nUnified controller for prompt-library conversions.\n\n支持的转换模式\n==============\n1. Excel → Docs : 将 Excel 工作簿转换为 Markdown 文档目录\n2. Docs → Excel : 将 Markdown 文档目录还原为 Excel 工作簿\n3. Docs → JSONL : 将 Markdown 文档转换为 JSONL 格式(保留完整元信息)\n4. JSONL → Excel : 将 JSONL 转换为 Excel(单元格存储 JSON 对象)\n5. Excel(JSONL) → JSONL : 将内部 JSONL 格式的 Excel 转换为 JSONL 目录(自动忽略\"说明\"工作表)\n6. JSONL 目录 → Excel : 将 Excel(JSONL) 导出的工作表级 JSONL 目录重新合并为 Excel\n\n数据格式规范\n============\nExcel 结构:\n - 每个工作表(sheet) = 一个分类(category)\n - 行(row) = 不同提示词\n - 列(col) = 版本迭代\n\nExcel(JSONL) 结构(内部 JSONL 格式):\n - 每个工作表(sheet) = 一个分类(category),\"说明\"工作表会被忽略\n - 每个单元格存储 JSON 对象: {\"title\": \"...\", \"content\": \"...\"}\n\nDocs 结构:\n - prompts/(N)_分类名/ # N = category_id\n - prompts/(N)_分类名/(r,c)_标题.md # r=row, c=col\n\nJSONL 格式 (每行一个 JSON 对象):\n {\n \"category_id\": 2, # 分类编号\n \"category\": \"元提示词\", # 分类名称 \n \"row\": 1, # 原 Excel 行号\n \"col\": 1, # 原 Excel 列号(版本号)\n \"title\": \"...\", # 标题(截断80字符)\n \"content\": \"...\" # 完整内容\n }\n\nJSONL → Excel 单元格格式:\n {\"title\": \"...\", \"content\": \"...\"} # 只保留 title 和 content\n\n目录约定\n========\n- Excel 源文件: ./prompt_excel/\n- Docs 源目录: ./prompt_docs/\n- JSONL 文件: ./prompt_jsonl/\n- 输出:\n - Excel→Docs: ./prompt_docs/prompt_docs_YYYY_MMDD_HHMMSS/\n - Docs→Excel: ./prompt_excel/prompt_excel_YYYY_MMDD_HHMMSS/rebuilt.xlsx\n - Docs→JSONL: ./prompt_jsonl/{docs_name}.jsonl\n - JSONL→Excel: ./prompt_excel/{jsonl_name}.xlsx\n - JSONL目录→Excel: ./prompt_excel/{jsonl_dir_name}.xlsx\n - Excel(JSONL)→JSONL: ./prompt_jsonl/{excel_name}_{timestamp}/<sheet>.jsonl\n\n使用示例\n========\n # 交互式选择\n python3 main.py\n\n # Excel → Docs\n python3 main.py --select \"prompt_excel/prompt.xlsx\"\n\n # Docs → Excel\n python3 main.py --select \"prompt_docs/prompt_docs_2025_1222\"\n\n # Docs → JSONL\n python3 main.py --select \"prompt_docs/prompt_docs_2025_1222\" --mode docs2jsonl\n\n # JSONL → Excel\n python3 main.py --select \"prompt_jsonl/prompt_docs.jsonl\"\n python3 main.py --select \"prompt_jsonl/prompt_jsonl_2025_1222_004537\" --mode jsonl2excel\n\n # Excel(JSONL) → JSONL(自动检测或显式指定)\n python3 main.py --select \"prompt_excel/prompt_jsonl.xlsx\"\n python3 main.py --select \"prompt_excel/prompt_jsonl.xlsx\" --mode jsonl_excel2jsonl\n\"\"\"\nfrom __future__ import annotations\n\nimport argparse\nimport os\nimport subprocess\nimport sys\nfrom dataclasses import dataclass\nfrom pathlib import Path\nfrom typing import List, Optional, Sequence, Tuple\n\n# Optional Rich UI imports (fallback to plain if unavailable)\ntry:\n from rich.console import Console\n from rich.layout import Layout\n from rich.panel import Panel\n from rich.table import Table\n from rich.text import Text\n from rich import box\n from rich.prompt import IntPrompt\n _RICH_AVAILABLE = True\nexcept Exception: # pragma: no cover\n _RICH_AVAILABLE = False\n\n# Optional InquirerPy for arrow-key selection\ntry:\n from InquirerPy import inquirer as _inq\n _INQUIRER_AVAILABLE = True\nexcept Exception: # pragma: no cover\n _INQUIRER_AVAILABLE = False\n\n\n@dataclass\nclass Candidate:\n index: int\n kind: str # \"excel\" | \"docs\" | \"docs2jsonl\" | \"jsonl\" | \"jsonl_dir\" | \"jsonl_excel\"\n path: Path\n label: str\n\n\ndef get_repo_root() -> Path:\n return Path(__file__).resolve().parent\n\n\ndef list_excel_files(excel_dir: Path) -> List[Path]:\n if not excel_dir.exists():\n return []\n return sorted([p for p in excel_dir.iterdir() if p.is_file() and p.suffix.lower() == \".xlsx\"], key=lambda p: p.stat().st_mtime)\n\n\ndef has_prompt_files(directory: Path) -> bool:\n if not directory.exists():\n return False\n # Detect files like \"(r,c)_*.md\" anywhere under the directory\n for file_path in directory.rglob(\"*.md\"):\n name = file_path.name\n if name.startswith(\"(\") and \")_\" in name:\n return True\n return False\n\n\ndef list_doc_sets(docs_dir: Path) -> List[Path]:\n results: List[Path] = []\n if not docs_dir.exists():\n return results\n # If the docs_dir itself looks like a set, include it\n if has_prompt_files(docs_dir):\n results.append(docs_dir)\n # Also include any immediate children that look like a docs set\n for child in sorted(docs_dir.iterdir()):\n if child.is_dir() and has_prompt_files(child):\n results.append(child)\n return results\n\n\ndef run_start_convert(start_convert: Path, mode: str, project_root: Path, select_path: Optional[Path] = None, excel_dir: Optional[Path] = None, docs_dir: Optional[Path] = None) -> int:\n \"\"\"Delegate to scripts/start_convert.py with appropriate flags.\"\"\"\n python_exe = sys.executable\n cmd: List[str] = [python_exe, str(start_convert), \"--mode\", mode]\n if select_path is not None:\n # Always pass as repo-root-relative or absolute string\n cmd.extend([\"--select\", str(select_path)])\n if excel_dir is not None:\n cmd.extend([\"--excel-dir\", str(excel_dir)])\n if docs_dir is not None:\n cmd.extend([\"--docs-dir\", str(docs_dir)])\n\n # Execute in repo root to ensure relative defaults resolve correctly\n proc = subprocess.run(cmd, cwd=str(project_root))\n return proc.returncode\n\n\ndef run_docs_to_jsonl(docs_path: Path, project_root: Path) -> int:\n \"\"\"Convert docs folder to JSONL format.\"\"\"\n import json\n import re\n \n prompts_dir = docs_path / \"prompts\"\n if not prompts_dir.exists():\n print(f\"❌ 找不到 prompts 目录: {prompts_dir}\")\n return 1\n \n output_dir = project_root / \"prompt_jsonl\"\n output_dir.mkdir(parents=True, exist_ok=True)\n output_file = output_dir / f\"{docs_path.name}.jsonl\"\n \n records = []\n for category_dir in sorted(prompts_dir.iterdir()):\n if not category_dir.is_dir():\n continue\n \n m = re.match(r'\\((\\d+)\\)_(.+)', category_dir.name)\n cat_id, cat_name = (m.groups() if m else (0, category_dir.name))\n \n for md_file in sorted(category_dir.glob(\"*.md\")):\n if md_file.name == \"index.md\":\n continue\n \n fm = re.match(r'\\((\\d+),(\\d+)\\)_(.+)\\.md', md_file.name)\n if not fm:\n continue\n \n row, col, title = fm.groups()\n content = md_file.read_text(encoding='utf-8')\n \n records.append({\n \"category_id\": int(cat_id),\n \"category\": cat_name,\n \"row\": int(row),\n \"col\": int(col),\n \"title\": title[:80],\n \"content\": content\n })\n \n with open(output_file, 'w', encoding='utf-8') as f:\n for r in records:\n f.write(json.dumps(r, ensure_ascii=False) + '\\n')\n \n print(f\"✅ Docs→JSONL OK: {docs_path.name} → {output_file.relative_to(project_root)}\")\n return 0\n\n\ndef list_jsonl_files(jsonl_dir: Path) -> List[Path]:\n if not jsonl_dir.exists():\n return []\n return sorted([p for p in jsonl_dir.iterdir() if p.is_file() and p.suffix.lower() == \".jsonl\"], key=lambda p: p.stat().st_mtime)\n\n\ndef list_jsonl_dirs(jsonl_dir: Path) -> List[Path]:\n \"\"\"列出由 Excel(JSONL)→JSONL 生成的工作表级 JSONL 目录。\"\"\"\n if not jsonl_dir.exists():\n return []\n return sorted(\n [\n p\n for p in jsonl_dir.iterdir()\n if p.is_dir() and any(child.is_file() and child.suffix.lower() == \".jsonl\" for child in p.iterdir())\n ],\n key=lambda p: p.stat().st_mtime,\n )\n\n\ndef is_jsonl_excel(excel_path: Path) -> bool:\n \"\"\"检测 Excel 是否为内部 JSONL 格式(单元格存储 JSON 对象)\"\"\"\n import json\n try:\n import pandas as pd\n except ImportError:\n return False\n \n try:\n xlsx = pd.ExcelFile(excel_path)\n for sheet in xlsx.sheet_names[:2]: # 检查前两个工作表\n if sheet == '说明':\n continue\n df = pd.read_excel(xlsx, sheet_name=sheet, header=None, nrows=1)\n if df.empty:\n continue\n first_val = str(df.iloc[0, 0]).strip() if not pd.isna(df.iloc[0, 0]) else \"\"\n # 检查列名或第一个单元格是否为 JSON\n first_col = str(df.columns[0]).strip() if len(df.columns) > 0 else \"\"\n for val in [first_col, first_val]:\n if val.startswith('{') and val.endswith('}'):\n try:\n obj = json.loads(val)\n if 'title' in obj and 'content' in obj:\n return True\n except:\n pass\n return False\n except:\n return False\n\n\ndef sanitize_filename(name: str) -> str:\n \"\"\"将工作表名转换为稳定的文件名片段。\"\"\"\n invalid_chars = '<>:\"/\\\\|?*'\n sanitized = \"\".join(\"_\" if ch in invalid_chars else ch for ch in name).strip()\n return sanitized.rstrip(\". \") or \"sheet\"\n\n\ndef build_text_record(cat_id: int, cat_name: str, row: int, col: int, text: str) -> dict:\n \"\"\"将纯文本单元格兜底转换为 JSONL 记录。\"\"\"\n lines = [line.strip() for line in text.splitlines() if line.strip()]\n title = lines[0] if lines else text.strip()\n return {\n \"category_id\": cat_id,\n \"category\": cat_name,\n \"row\": row,\n \"col\": col,\n \"title\": title[:80],\n \"content\": text,\n }\n\n\ndef run_jsonl_excel_to_jsonl(excel_path: Path, project_root: Path) -> int:\n \"\"\"将内部 JSONL 格式的 Excel 转换为 JSONL 目录(忽略\"说明\"工作表)\"\"\"\n import json\n from datetime import datetime\n try:\n import pandas as pd\n except ImportError:\n print(\"❌ 需要 pandas: pip install pandas openpyxl\")\n return 1\n \n xlsx = pd.ExcelFile(excel_path)\n cat_id = 0\n total_records = 0\n written_files = []\n \n timestamp = datetime.now().strftime(\"%Y_%m%d_%H%M%S\")\n output_dir = project_root / \"prompt_jsonl\" / f\"{excel_path.stem}_{timestamp}\"\n output_dir.mkdir(parents=True, exist_ok=True)\n\n for sheet_index, sheet in enumerate(xlsx.sheet_names, start=1):\n if sheet == '说明':\n continue\n \n cat_id += 1\n cat_name = sheet\n df = pd.read_excel(xlsx, sheet_name=sheet, header=None)\n sheet_lines = []\n fallback_records = []\n \n # 检查列名是否是 JSON 数据\n for col_idx, col_name in enumerate(df.columns):\n col_str = str(col_name).strip()\n if col_str.startswith('{') and col_str.endswith('}'):\n try:\n obj = json.loads(col_str)\n if 'title' in obj and 'content' in obj:\n sheet_lines.append(json.dumps({\n \"category_id\": cat_id,\n \"category\": cat_name,\n \"row\": 1,\n \"col\": col_idx + 1,\n \"title\": obj[\"title\"][:80],\n \"content\": obj[\"content\"]\n }, ensure_ascii=False))\n except:\n pass\n \n # 处理数据行\n for row_idx, row in df.iterrows():\n for col_idx, val in enumerate(row):\n if pd.isna(val):\n continue\n val_str = str(val).strip()\n if not val_str:\n continue\n if val_str.startswith('{') and val_str.endswith('}'):\n try:\n obj = json.loads(val_str)\n if 'title' in obj and 'content' in obj:\n sheet_lines.append(json.dumps({\n \"category_id\": cat_id,\n \"category\": cat_name,\n \"row\": row_idx + 1,\n \"col\": col_idx + 1,\n \"title\": obj[\"title\"][:80],\n \"content\": obj[\"content\"]\n }, ensure_ascii=False))\n except:\n pass\n else:\n # 跳过常见的顶栏广告/元数据噪声,但保留其他纯文本内容作为兜底记录。\n if row_idx == 0 and col_idx == 0 and val_str.startswith(\"广告位\"):\n continue\n fallback_records.append(\n build_text_record(\n cat_id=cat_id,\n cat_name=cat_name,\n row=row_idx + 1,\n col=col_idx + 1,\n text=val_str,\n )\n )\n\n if not sheet_lines and fallback_records:\n sheet_lines = [\n json.dumps(record, ensure_ascii=False)\n for record in fallback_records\n ]\n\n total_records += len(sheet_lines)\n file_stem = sanitize_filename(cat_name)\n output_file = output_dir / f\"{sheet_index:02d}_{file_stem}.jsonl\"\n with open(output_file, 'w', encoding='utf-8') as f:\n if sheet_lines:\n f.write('\\n'.join(sheet_lines) + '\\n')\n written_files.append(output_file)\n\n if not written_files:\n print(f\"❌ 未找到有效的 JSONL 数据: {excel_path}\")\n return 1\n\n print(\n f\"✅ Excel(JSONL)→JSONL OK: {excel_path.name} → \"\n f\"{output_dir.relative_to(project_root)} \"\n f\"({len(written_files)} 个文件 / {total_records} 条记录)\"\n )\n return 0\n\n\ndef read_jsonl_records(jsonl_paths: Sequence[Path]) -> List[dict]:\n import json\n records = []\n\n for jsonl_path in jsonl_paths:\n with open(jsonl_path, 'r', encoding='utf-8') as f:\n for line in f:\n if line.strip():\n records.append(json.loads(line))\n\n return records\n\n\ndef write_records_to_excel(records: List[dict], output_file: Path) -> int:\n \"\"\"将 JSONL 记录写回 Excel,单元格中只保留 title/content JSON。\"\"\"\n import json\n from collections import defaultdict\n try:\n import pandas as pd\n except ImportError:\n print(\"❌ 需要 pandas: pip install pandas openpyxl\")\n return 1\n\n if not records:\n print(\"❌ JSONL 文件为空\")\n return 1\n\n # category -> {row -> {col -> json_string}}\n sheets_data: dict = defaultdict(lambda: defaultdict(dict))\n cat_id_map = {}\n\n for r in records:\n cat_name = r[\"category\"]\n cat_id_map[r[\"category_id\"]] = cat_name\n # 单元格内容只保留 title 和 content\n cell_data = {\"title\": r[\"title\"], \"content\": r[\"content\"]}\n sheets_data[cat_name][r[\"row\"]][r[\"col\"]] = json.dumps(cell_data, ensure_ascii=False)\n\n output_file.parent.mkdir(parents=True, exist_ok=True)\n sorted_cats = sorted(cat_id_map.items(), key=lambda x: x[0])\n\n with pd.ExcelWriter(output_file, engine='openpyxl') as writer:\n for cat_id, cat_name in sorted_cats:\n row_data = sheets_data[cat_name]\n if not row_data:\n continue\n\n max_row = max(row_data.keys())\n max_col = max(c for cols in row_data.values() for c in cols.keys())\n\n data = []\n for row_idx in range(1, max_row + 1):\n row_list = []\n for col_idx in range(1, max_col + 1):\n row_list.append(row_data.get(row_idx, {}).get(col_idx, \"\"))\n data.append(row_list)\n\n df = pd.DataFrame(data)\n sheet_name = cat_name[:31]\n df.to_excel(writer, sheet_name=sheet_name, index=False, header=False)\n\n return len(sorted_cats)\n\n\ndef run_jsonl_to_excel(jsonl_path: Path, project_root: Path) -> int:\n \"\"\"Convert one JSONL file to Excel, each cell contains the full JSON object as string.\"\"\"\n output_dir = project_root / \"prompt_excel\"\n output_file = output_dir / f\"{jsonl_path.stem}.xlsx\"\n sheet_count = write_records_to_excel(read_jsonl_records([jsonl_path]), output_file)\n if sheet_count > 0:\n print(f\"✅ JSONL→Excel OK: {jsonl_path.name} → {output_file.relative_to(project_root)} ({sheet_count} 个工作表)\")\n return 0\n return sheet_count\n\n\ndef run_jsonl_dir_to_excel(jsonl_dir: Path, project_root: Path) -> int:\n \"\"\"Convert a directory of sheet-level JSONL files back to one Excel workbook.\"\"\"\n jsonl_paths = sorted(\n [p for p in jsonl_dir.iterdir() if p.is_file() and p.suffix.lower() == \".jsonl\"],\n key=lambda p: p.name,\n )\n if not jsonl_paths:\n print(f\"❌ JSONL 目录中没有 .jsonl 文件: {jsonl_dir}\")\n return 1\n\n output_dir = project_root / \"prompt_excel\"\n output_file = output_dir / f\"{jsonl_dir.name}.xlsx\"\n sheet_count = write_records_to_excel(read_jsonl_records(jsonl_paths), output_file)\n if sheet_count > 0:\n print(\n f\"✅ JSONL目录→Excel OK: {jsonl_dir.name} → \"\n f\"{output_file.relative_to(project_root)} ({sheet_count} 个工作表 / {len(jsonl_paths)} 个 JSONL 文件)\"\n )\n return 0\n return sheet_count\n\n\ndef build_candidates(project_root: Path, excel_dir: Path, docs_dir: Path) -> List[Candidate]:\n candidates: List[Candidate] = []\n idx = 1\n jsonl_dir = project_root / \"prompt_jsonl\"\n \n for path in list_excel_files(excel_dir):\n label = f\"{path.name}\"\n # 检测是否为内部 JSONL 格式的 Excel\n if is_jsonl_excel(path):\n candidates.append(Candidate(index=idx, kind=\"jsonl_excel\", path=path, label=label))\n else:\n candidates.append(Candidate(index=idx, kind=\"excel\", path=path, label=label))\n idx += 1\n for path in list_doc_sets(docs_dir):\n display = path.relative_to(project_root) if path.is_absolute() else path\n # Docs → Excel\n candidates.append(Candidate(index=idx, kind=\"docs\", path=path, label=f\"{display}\"))\n idx += 1\n # Docs → JSONL\n candidates.append(Candidate(index=idx, kind=\"docs2jsonl\", path=path, label=f\"{display}\"))\n idx += 1\n for path in list_jsonl_files(jsonl_dir):\n label = f\"{path.name}\"\n candidates.append(Candidate(index=idx, kind=\"jsonl\", path=path, label=label))\n idx += 1\n for path in list_jsonl_dirs(jsonl_dir):\n label = f\"{path.name}/\"\n candidates.append(Candidate(index=idx, kind=\"jsonl_dir\", path=path, label=label))\n idx += 1\n return candidates\n\n\ndef select_interactively(candidates: Sequence[Candidate]) -> Optional[Candidate]:\n if not candidates:\n print(\"没有可用的 Excel 或 Docs 源。请将 .xlsx 放到 prompt_excel/ 或将文档放到 prompt_docs/ 下。\")\n return None\n\n # Prefer arrow-key selection if available\n if _INQUIRER_AVAILABLE:\n try:\n choices = [\n {\"name\": f\"[{c.kind.upper()}] {c.label}\", \"value\": c.index}\n for c in candidates\n ]\n selection = _inq.select(\n message=\"选择要转换的源(上下箭头,回车确认,Ctrl+C 取消):\",\n choices=choices,\n default=choices[0][\"value\"],\n ).execute()\n match = next((c for c in candidates if c.index == selection), None)\n return match\n except KeyboardInterrupt:\n return None\n\n if _RICH_AVAILABLE:\n console = Console()\n layout = Layout()\n layout.split_column(\n Layout(name=\"header\", size=3),\n Layout(name=\"list\"),\n Layout(name=\"footer\", size=3),\n )\n header = Panel(Text(\"提示词库转换器\", style=\"bold cyan\"), subtitle=\"选择一个源开始转换\", box=box.ROUNDED)\n\n table = Table(box=box.SIMPLE_HEAVY)\n table.add_column(\"编号\", style=\"bold yellow\", justify=\"right\", width=4)\n table.add_column(\"类型\", style=\"magenta\", width=16)\n table.add_column(\"路径/名称\", style=\"white\")\n kind_labels = {\"excel\": \"Excel→Docs\", \"docs\": \"Docs→Excel\", \"docs2jsonl\": \"Docs→JSONL\", \"jsonl\": \"JSONL→Excel\", \"jsonl_excel\": \"Excel(JSONL)→JSONL\", \"jsonl_dir\": \"JSONL目录→Excel\"}\n for c in candidates:\n table.add_row(str(c.index), kind_labels.get(c.kind, c.kind), c.label)\n\n layout[\"header\"].update(header)\n layout[\"list\"].update(Panel(table, title=\"可选源\", border_style=\"cyan\"))\n layout[\"footer\"].update(Panel(Text(\"输入编号并回车(0 退出)\", style=\"bold\"), box=box.ROUNDED))\n console.print(layout)\n\n while True:\n try:\n choice = IntPrompt.ask(\"编号\", default=0)\n except Exception:\n return None\n if choice == 0:\n return None\n match = next((c for c in candidates if c.index == choice), None)\n if match is not None:\n return match\n console.print(\"[red]编号不存在,请重试[/red]\")\n\n # Plain fallback\n kind_labels = {\"excel\": \"Excel→Docs\", \"docs\": \"Docs→Excel\", \"docs2jsonl\": \"Docs→JSONL\", \"jsonl\": \"JSONL→Excel\", \"jsonl_excel\": \"Excel(JSONL)→JSONL\", \"jsonl_dir\": \"JSONL目录→Excel\"}\n print(\"请选择一个源进行转换:\")\n for c in candidates:\n print(f\" {c.index:2d}. [{kind_labels.get(c.kind, c.kind)}] {c.label}\")\n print(\" 0. 退出\")\n while True:\n try:\n raw = input(\"输入编号后回车:\").strip()\n except EOFError:\n return None\n if not raw:\n continue\n if raw == \"0\":\n return None\n if not raw.isdigit():\n print(\"请输入有效数字。\")\n continue\n choice = int(raw)\n match = next((c for c in candidates if c.index == choice), None)\n if match is None:\n print(\"编号不存在,请重试。\")\n continue\n return match\n\n\ndef parse_args() -> argparse.Namespace:\n p = argparse.ArgumentParser(description=\"prompt-library conversion controller\")\n p.add_argument(\"--excel-dir\", type=str, default=\"prompt_excel\", help=\"Excel sources directory (default: prompt_excel)\")\n p.add_argument(\"--docs-dir\", type=str, default=\"prompt_docs\", help=\"Docs sources directory (default: prompt_docs)\")\n p.add_argument(\"--select\", type=str, default=None, help=\"Path to a specific .xlsx file or a docs folder\")\n p.add_argument(\"--mode\", type=str, choices=[\"excel2docs\", \"docs2excel\", \"docs2jsonl\", \"jsonl2excel\", \"jsonl_excel2jsonl\"], default=None, help=\"Conversion mode (auto-detect if not specified)\")\n p.add_argument(\"--non-interactive\", action=\"store_true\", help=\"Do not prompt; require --select or exit\")\n return p.parse_args()\n\n\ndef main() -> int:\n repo_root = get_repo_root()\n start_convert = repo_root / \"scripts\" / \"start_convert.py\"\n if not start_convert.exists():\n print(\"找不到 scripts/start_convert.py。\")\n return 1\n\n args = parse_args()\n\n excel_dir = (repo_root / args.excel_dir).resolve() if not Path(args.excel_dir).is_absolute() else Path(args.excel_dir).resolve()\n docs_dir = (repo_root / args.docs_dir).resolve() if not Path(args.docs_dir).is_absolute() else Path(args.docs_dir).resolve()\n\n # Non-interactive path with explicit selection\n if args.non_interactive or args.select:\n if not args.select:\n print(\"--non-interactive 需要配合 --select 使用。\")\n return 2\n selected = Path(args.select)\n if not selected.is_absolute():\n selected = (repo_root / selected).resolve()\n if not selected.exists():\n print(f\"选择的路径不存在: {selected}\")\n return 2\n if selected.is_file() and selected.suffix.lower() == \".xlsx\":\n # 检测是否为内部 JSONL 格式或显式指定模式\n if args.mode == \"jsonl_excel2jsonl\" or is_jsonl_excel(selected):\n return run_jsonl_excel_to_jsonl(selected, repo_root)\n return run_start_convert(start_convert, mode=\"excel2docs\", project_root=repo_root, select_path=selected, excel_dir=excel_dir)\n if selected.is_file() and selected.suffix.lower() == \".jsonl\":\n return run_jsonl_to_excel(selected, repo_root)\n if selected.is_dir():\n if args.mode == \"jsonl2excel\" or (\n selected.parent == (repo_root / \"prompt_jsonl\").resolve()\n and any(p.is_file() and p.suffix.lower() == \".jsonl\" for p in selected.iterdir())\n ):\n return run_jsonl_dir_to_excel(selected, repo_root)\n # Check mode or default to docs2excel\n if args.mode == \"docs2jsonl\":\n return run_docs_to_jsonl(selected, repo_root)\n return run_start_convert(start_convert, mode=\"docs2excel\", project_root=repo_root, select_path=selected, docs_dir=docs_dir)\n print(\"无法识别的选择类型。\")\n return 2\n\n # Interactive selection\n candidates = build_candidates(repo_root, excel_dir, docs_dir)\n chosen = select_interactively(candidates)\n if chosen is None:\n return 0\n if chosen.kind == \"excel\":\n return run_start_convert(start_convert, mode=\"excel2docs\", project_root=repo_root, select_path=chosen.path, excel_dir=excel_dir)\n elif chosen.kind == \"jsonl_excel\":\n return run_jsonl_excel_to_jsonl(chosen.path, repo_root)\n elif chosen.kind == \"docs2jsonl\":\n return run_docs_to_jsonl(chosen.path, repo_root)\n elif chosen.kind == \"jsonl\":\n return run_jsonl_to_excel(chosen.path, repo_root)\n elif chosen.kind == \"jsonl_dir\":\n return run_jsonl_dir_to_excel(chosen.path, repo_root)\n else:\n return run_start_convert(start_convert, mode=\"docs2excel\", project_root=repo_root, select_path=chosen.path, docs_dir=docs_dir)\n\n\nif __name__ == \"__main__\":\n sys.exit(main())\n",
"sha256": "ed0113d3ecbe9c9d4ca48ee7dde2c76c9a6fd1f54a1ae890fd3689d617347691"
},
".github/tools/chat-vault/README.md": {
"mode": "100644",
"encoding": "utf-8",
"data": "# Chat Vault Monorepo\n\nAI 聊天记录集中存储与管理平台。\n\n## 项目概述\n\n本项目是一个 monorepo,包含 AI 聊天记录同步工具及相关基础设施。核心功能是将多个 AI CLI 工具(Codex、Kiro、Gemini、Claude)的聊天记录统一存储到 SQLite 数据库。\n\n## 功能特性\n\n- 多 CLI 支持:Codex、Kiro、Gemini、Claude\n- 实时监控:基于 watchdog 的文件变更检测\n- Token 统计:使用 tiktoken (cl100k_base) 精确计数\n- 搜索导出:支持关键词搜索、JSON/CSV 导出\n- 零配置:自动检测默认路径,开箱即用\n\n## 快速开始\n\n### 环境要求\n\n- Python 3.8+\n- Linux / macOS / Windows (WSL)\n\n### 启动服务\n\n```bash\ncd services/chat-vault\n\n# Linux/macOS\n./start.sh\n\n# Windows\nstart.bat\n```\n\n首次运行会自动创建虚拟环境并安装依赖。\n\n## 目录结构\n\n```\nchat-vault/\n├── services/\n│ └── chat-vault/ # 核心同步服务\n│ ├── src/\n│ │ ├── main.py # CLI 入口\n│ │ ├── config.py # 配置与路径检测\n│ │ ├── storage.py # SQLite 存储\n│ │ ├── watcher.py # 文件监控\n│ │ └── parsers/ # 各 CLI 解析器\n│ ├── docs/ # 服务文档\n│ ├── scripts/ # 辅助脚本\n│ ├── requirements.txt\n│ ├── start.sh\n│ └── .env.example\n├── libs/\n│ ├── common/ # 共享库(预留)\n│ ├── database/ # 数据库工具(预留)\n│ └── external/ # 外部依赖入口(不提交整份第三方源码)\n├── monitoring/\n│ ├── grafana/ # Grafana 配置\n│ ├── prometheus/ # Prometheus 配置(预留)\n│ └── alertmanager/ # 告警配置(预留)\n├── scripts/ # 全局脚本\n│ ├── build_all.sh\n│ ├── test_all.sh\n│ └── deploy.sh\n├── docs/ # 全局文档\n├── AGENTS.md\n├── README.md\n└── LICENSE\n```\n\n外部监控工具(例如 btop)按需通过系统包管理器、官方仓库或 Git submodule 引入,不在本仓库内直接提交完整源码镜像。\n\n## 常用命令\n\n在 `services/chat-vault/` 目录下执行:\n\n| 命令 | 说明 |\n|------|------|\n| `python src/main.py` | 同步一次 |\n| `python src/main.py -w` | 持续监控模式 |\n| `python src/main.py --stats` | 显示统计信息 |\n| `python src/main.py --search \"关键词\"` | 搜索消息 |\n| `python src/main.py --export json` | 导出 JSON |\n| `python src/main.py --export csv --source codex` | 导出指定来源 |\n| `python src/main.py --prune` | 清理孤立记录 |\n\n## 配置说明\n\n### 环境变量(可选)\n\n参考 `services/chat-vault/.env.example`:\n\n```bash\n# 自定义路径(逗号分隔多个)\nCODEX_PATHS=~/.codex/sessions\nKIRO_PATHS=~/.local/share/kiro-cli\nGEMINI_PATHS=~/.gemini/tmp\nCLAUDE_PATHS=~/.claude\n\n# WSL 路径支持\nCODEX_PATHS=\\\\wsl.localhost\\Ubuntu\\home\\user\\.codex\\sessions\n```\n\n默认自动检测以下路径:\n- Codex: `~/.codex/sessions`, `~/.codex`\n- Kiro: `~/.local/share/kiro-cli`\n- Gemini: `~/.gemini/tmp`, `~/.gemini`\n- Claude: `~/.claude`\n\n### 输出位置\n\n- 数据库:`services/chat-vault/output/chat_history.db`\n- 日志:`services/chat-vault/output/logs/`\n\n## 数据库结构\n\n详见 `services/chat-vault/docs/schema.md`\n\n主表 `sessions`:\n- `file_path` (PK): 源文件路径\n- `session_id`: 会话 ID\n- `source`: 来源 (codex/kiro/gemini/claude)\n- `messages`: JSON 消息数组\n- `token_count`: Token 数量\n\n## FAQ\n\n**Q: 需要配置吗?**\nA: 不需要,自动检测默认路径。\n\n**Q: 支持 WSL 吗?**\nA: 支持,`\\\\wsl.localhost\\Ubuntu\\...` 格式路径会自动转换。\n\n**Q: 数据安全吗?**\nA: 只读取 AI 工具的文件,不修改原始数据。\n\n## 贡献\n\n欢迎提交 Issue 和 Pull Request。\n\n## 许可证\n\nMIT License\n",
"sha256": "938ddcce3ba06fad18a05d072cfc47cb8427064c72745f557e4b782de8a2c753"
},
".github/tools/chat-vault/services/chat-vault/src/main.py": {
"mode": "100644",
"encoding": "utf-8",
"data": "#!/usr/bin/env python3\n# -*- coding: utf-8 -*-\n\"\"\"\nAI 聊天记录集中存储工具\n\n命令:\n python main.py # 同步一次\n python main.py --watch # 持续监控\n python main.py --prune # 清理孤立记录\n python main.py --stats # 显示统计\n python main.py --search <keyword> # 搜索\n python main.py --export json|csv [--source codex|kiro|gemini|claude]\n\"\"\"\nimport os\nimport sys\nimport subprocess\n\n# 项目根目录\nPROJECT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))\nVENV_DIR = os.path.join(PROJECT_DIR, '.venv')\nREQUIREMENTS = os.path.join(PROJECT_DIR, 'requirements.txt')\n\ndef ensure_venv():\n \"\"\"检测并创建虚拟环境,安装依赖\"\"\"\n # 打包版本跳过\n if getattr(sys, 'frozen', False):\n return\n \n # 已在虚拟环境中运行则跳过\n if sys.prefix != sys.base_prefix:\n return\n \n # 检查 .venv 是否存在\n venv_python = os.path.join(VENV_DIR, 'bin', 'python') if os.name != 'nt' else os.path.join(VENV_DIR, 'Scripts', 'python.exe')\n \n if not os.path.exists(venv_python):\n print(\"首次运行,创建虚拟环境...\")\n subprocess.run([sys.executable, '-m', 'venv', VENV_DIR], check=True)\n print(\"安装依赖...\")\n pip = os.path.join(VENV_DIR, 'bin', 'pip') if os.name != 'nt' else os.path.join(VENV_DIR, 'Scripts', 'pip.exe')\n subprocess.run([pip, 'install', '-r', REQUIREMENTS, '-q'], check=True)\n print(\"环境准备完成,重新启动...\\n\")\n \n # 使用虚拟环境重新执行\n os.execv(venv_python, [venv_python] + sys.argv)\n\n# 启动前检测虚拟环境\nensure_venv()\n\n# 支持 PyInstaller 打包\nif getattr(sys, 'frozen', False):\n BASE_DIR = sys._MEIPASS\n sys.path.insert(0, os.path.join(BASE_DIR, 'src'))\nelse:\n BASE_DIR = os.path.dirname(os.path.abspath(__file__))\n\nimport argparse\nfrom config import CONFIG\nfrom parsers import CodexParser, GeminiParser, ClaudeParser, KiroParser\nfrom storage import ChatStorage\nfrom logger import setup_logger, get_logger\n\nstorage: ChatStorage = None\n\ndef main():\n global storage\n \n parser = argparse.ArgumentParser(description='AI Chat Converter')\n parser.add_argument('-w', '--watch', action='store_true', help='持续监控模式')\n parser.add_argument('--prune', action='store_true', help='清理孤立记录')\n parser.add_argument('--stats', action='store_true', help='显示统计信息')\n parser.add_argument('--search', type=str, help='搜索关键词')\n parser.add_argument('--export', choices=['json', 'csv'], help='导出格式')\n parser.add_argument('--source', choices=['codex', 'kiro', 'gemini', 'claude'], help='指定来源')\n parser.add_argument('--output', type=str, help='导出文件路径')\n args = parser.parse_args()\n \n # 初始化\n setup_logger(CONFIG[\"log_dir\"])\n log = get_logger()\n \n storage = ChatStorage(CONFIG[\"db_path\"])\n \n # 命令分发\n if args.prune:\n cmd_prune()\n elif args.stats:\n cmd_stats()\n elif args.search:\n cmd_search(args.search, args.source)\n elif args.export:\n cmd_export(args.export, args.source, args.output)\n elif args.watch:\n cmd_sync()\n cmd_watch()\n else:\n cmd_sync()\n\ndef cmd_sync():\n log = get_logger()\n log.info(\"=\" * 50)\n log.info(\"AI 聊天记录 → 集中存储\")\n log.info(\"=\" * 50)\n log.info(f\"数据库: {CONFIG['db_path']}\")\n \n total_added, total_updated, total_skipped, total_errors = 0, 0, 0, 0\n \n for cli, key, parser_cls in [\n ('codex', 'codex_paths', lambda: CodexParser('codex')),\n ('kiro', 'kiro_paths', KiroParser),\n ('gemini', 'gemini_paths', GeminiParser),\n ('claude', 'claude_paths', ClaudeParser),\n ]:\n paths = CONFIG.get(key, [])\n if not paths:\n continue\n \n parser = parser_cls()\n if cli in ('claude', 'kiro'):\n a, u, s, e = process_multi(parser, paths, cli)\n else:\n a, u, s, e = process(parser, paths)\n \n log.info(f\"[{cli.capitalize()}] 新增:{a} 更新:{u} 跳过:{s} 错误:{e}\")\n update_cli_meta(cli)\n total_added += a\n total_updated += u\n total_skipped += s\n total_errors += e\n \n total = storage.get_total_stats()\n storage.update_total_meta(total['sessions'], total['messages'], total['tokens'])\n \n log.info(\"=\" * 50)\n log.info(f\"总计: {total['sessions']} 会话, {total['messages']} 消息\")\n if total_errors > 0:\n log.warning(f\"错误: {total_errors} 个文件解析失败\")\n log.info(\"✓ 同步完成!\")\n \n print_token_stats()\n\ndef cmd_watch():\n from watcher import ChatWatcher\n from datetime import datetime\n \n log = get_logger()\n log.info(\"\")\n log.info(\"=\" * 50)\n log.info(\"实时监听模式 (watchdog)\")\n log.info(\"=\" * 50)\n \n watch_paths = []\n path_source_map = {}\n \n for cli, key in [('codex', 'codex_paths'), ('kiro', 'kiro_paths'), \n ('gemini', 'gemini_paths'), ('claude', 'claude_paths')]:\n for p in CONFIG.get(key, []):\n if os.path.isdir(p) or os.path.isfile(p):\n watch_paths.append(p)\n path_source_map[p] = cli\n \n def on_change(file_path, event_type):\n now = datetime.now().strftime('%H:%M:%S')\n source = None\n for p, s in path_source_map.items():\n if file_path.startswith(p) or file_path == p:\n source = s\n break\n if not source:\n return\n \n try:\n if source == 'kiro':\n parser = KiroParser()\n for sess in parser.parse_file(file_path):\n storage.upsert_session(sess.session_id, sess.source, sess.file_path, sess.cwd, sess.messages, int(sess.file_mtime), sess.start_time)\n log.info(f\"[{now}] kiro 更新\")\n elif source == 'claude':\n parser = ClaudeParser()\n for sess in parser.parse_file(file_path):\n fp = f\"claude:{sess.session_id}\"\n storage.upsert_session(sess.session_id, sess.source, fp, sess.cwd, sess.messages, int(sess.file_mtime), sess.start_time)\n log.info(f\"[{now}] claude 更新\")\n else:\n parser = CodexParser(source) if source == 'codex' else GeminiParser()\n sess = parser.parse_file(file_path)\n fp = os.path.abspath(sess.file_path)\n storage.upsert_session(sess.session_id, sess.source, fp, sess.cwd, sess.messages, int(sess.file_mtime), sess.start_time)\n log.info(f\"[{now}] {source} {event_type}: {os.path.basename(file_path)}\")\n \n update_cli_meta(source)\n total = storage.get_total_stats()\n storage.update_total_meta(total['sessions'], total['messages'], total['tokens'])\n except Exception as e:\n log.error(f\"[{now}] 处理失败 {file_path}: {e}\")\n \n log.info(f\"监听目录: {len(watch_paths)} 个\")\n watcher = ChatWatcher(watch_paths, on_change)\n watcher.start()\n\ndef cmd_prune():\n log = get_logger()\n log.info(\"清理孤立记录...\")\n removed = storage.prune()\n total = sum(removed.values())\n if total > 0:\n for cli, count in removed.items():\n if count > 0:\n log.info(f\" {cli}: 删除 {count} 条\")\n log.info(f\"✓ 共清理 {total} 条孤立记录\")\n else:\n log.info(\"✓ 无孤立记录\")\n\ndef cmd_stats():\n log = get_logger()\n meta = storage.get_total_meta()\n tokens = storage.get_token_stats()\n \n log.info(\"=\" * 50)\n log.info(\"统计信息\")\n log.info(\"=\" * 50)\n log.info(f\"数据库: {CONFIG['db_path']}\")\n log.info(f\"总会话: {meta['total_sessions']}\")\n log.info(f\"总消息: {meta['total_messages']}\")\n log.info(f\"最后同步: {meta['last_sync']}\")\n log.info(\"\")\n log.info(\"Token 统计 (tiktoken):\")\n total_tokens = 0\n for source in ['codex', 'kiro', 'gemini', 'claude']:\n t = tokens.get(source, 0)\n if t > 0:\n log.info(f\" {source}: {t:,}\")\n total_tokens += t\n log.info(f\" 总计: {total_tokens:,}\")\n\ndef cmd_search(keyword: str, source: str = None):\n log = get_logger()\n results = storage.search(keyword, source)\n log.info(f\"搜索 '{keyword}' 找到 {len(results)} 个会话:\")\n for r in results[:20]:\n log.info(f\" [{r['source']}] {r['session_id']} - {r['cwd'] or 'N/A'}\")\n\ndef cmd_export(fmt: str, source: str = None, output: str = None):\n log = get_logger()\n if not output:\n output = os.path.join(CONFIG[\"output_dir\"], f\"export.{fmt}\")\n \n if fmt == 'json':\n count = storage.export_json(output, source)\n else:\n count = storage.export_csv(output, source)\n \n log.info(f\"✓ 导出 {count} 条到 {output}\")\n\ndef print_token_stats():\n log = get_logger()\n tokens = storage.get_token_stats()\n log.info(\"\")\n log.info(\"=== Token 统计 (tiktoken) ===\")\n total = 0\n for source in ['codex', 'kiro', 'gemini', 'claude']:\n t = tokens.get(source, 0)\n if t > 0:\n log.info(f\" {source}: {t:,} tokens\")\n total += t\n log.info(f\" 总计: {total:,} tokens\")\n\ndef update_cli_meta(cli: str):\n stats = storage.get_cli_stats(cli)\n path = CONFIG.get(f\"{cli}_paths\", [\"\"])[0] if CONFIG.get(f\"{cli}_paths\") else \"\"\n storage.update_cli_meta(cli, path, stats['sessions'], stats['messages'], stats['tokens'])\n\ndef process(parser, paths) -> tuple:\n log = get_logger()\n added, updated, skipped, errors = 0, 0, 0, 0\n for f in parser.find_files(paths):\n try:\n s = parser.parse_file(f)\n file_path = os.path.abspath(s.file_path)\n db_mtime = storage.get_file_mtime(file_path)\n file_mtime = int(s.file_mtime)\n if db_mtime == 0:\n storage.upsert_session(s.session_id, s.source, file_path, s.cwd, s.messages, file_mtime, s.start_time)\n added += 1\n elif file_mtime > db_mtime:\n storage.upsert_session(s.session_id, s.source, file_path, s.cwd, s.messages, file_mtime, s.start_time)\n updated += 1\n else:\n skipped += 1\n except Exception as e:\n log.debug(f\"解析失败 {f}: {e}\")\n errors += 1\n return added, updated, skipped, errors\n\ndef process_multi(parser, paths, source: str) -> tuple:\n \"\"\"处理返回多个会话的解析器(Claude/Kiro)\"\"\"\n log = get_logger()\n added, updated, skipped, errors = 0, 0, 0, 0\n for f in parser.find_files(paths):\n try:\n for s in parser.parse_file(f):\n file_path = s.file_path # kiro:xxx 或 claude:xxx\n db_mtime = storage.get_file_mtime(file_path)\n file_mtime = int(s.file_mtime)\n if db_mtime == 0:\n storage.upsert_session(s.session_id, s.source, file_path, s.cwd, s.messages, file_mtime, s.start_time)\n added += 1\n elif file_mtime > db_mtime:\n storage.upsert_session(s.session_id, s.source, file_path, s.cwd, s.messages, file_mtime, s.start_time)\n updated += 1\n else:\n skipped += 1\n except Exception as e:\n log.debug(f\"解析失败 {f}: {e}\")\n errors += 1\n return added, updated, skipped, errors\n\nif __name__ == '__main__':\n main()\n",
"sha256": "561c611909714d358f9968c45078f037bd46cdb037969d598cfed27d94affd72"
},
".github/tools/config/.codex/README.md": {
"mode": "100644",
"encoding": "utf-8",
"data": "# Codex CLI 配置基线\n\n本目录把 Codex CLI 全局配置做成可审阅、可安装、可回滚的公开基线。\n\n## 字多不看\n\n- 默认安装 `safe` 配置:不写入本机路径,不启用 `danger-full-access`,不设置 `approval_policy = \"never\"`。\n- 需要全自动高权限体验时,显式安装 `power` 配置。\n- 安装前会备份用户现有 `~/.codex/config.toml` 和 `~/.codex/AGENTS.md`。\n- 每次安装都会生成恢复脚本,误覆盖后可以一键恢复。\n- 支持通过 `CODEX_HOME` 指定 Codex Home。\n\n## 一键安装\n\n安全默认版:\n\n```bash\ncurl -fsSL https://raw.githubusercontent.com/tukuaiai/vibe-coding-cn/develop/tools/config/.codex/install.sh | bash\n```\n\n高权限版:\n\n```bash\ncurl -fsSL https://raw.githubusercontent.com/tukuaiai/vibe-coding-cn/develop/tools/config/.codex/install.sh | bash -s -- --profile power\n```\n\n指定 Codex Home:\n\n```bash\ncurl -fsSL https://raw.githubusercontent.com/tukuaiai/vibe-coding-cn/develop/tools/config/.codex/install.sh | CODEX_HOME=\"$HOME/.codex\" bash\n```\n\n## 恢复\n\n恢复最近一次安装前的配置:\n\n```bash\nbash ~/.codex/backups/vibe-coding-cn/LATEST/restore.sh\n```\n\n也可以恢复某一次具体备份:\n\n```bash\nbash ~/.codex/backups/vibe-coding-cn/YYYYMMDD-HHMMSS/restore.sh\n```\n\n备份目录包含:\n\n- `config.toml`:安装前的用户原配置;如果原文件不存在,会写入 `.missing-config.toml` 标记。\n- `AGENTS.md`:安装前的用户原指令;如果原文件不存在,会写入 `.missing-AGENTS.md` 标记。\n- `MANIFEST.txt`:安装来源、profile、目标路径和恢复脚本位置。\n- `restore.sh`:恢复脚本。\n\n## 文件说明\n\n| 文件 | 用途 |\n|:---|:---|\n| `install.sh` | 一键安装、备份和恢复入口 |\n| `config.toml` | 公开安全默认配置 |\n| `config.power.toml` | 高权限配置,显式 `--profile power` 才安装 |\n| `AGENTS.safe.md` | 公开安全默认全局指令 |\n| `AGENTS.md` | 高强度个人工作流指令,配合 `power` profile 使用 |\n\n## 安全边界\n\n`safe` profile 适合新手和公共分发:\n\n- 不自动信任任何本机项目路径。\n- 不放开全盘读写和命令执行权限。\n- 不关闭审批确认。\n\n`power` profile 只适合完全可信的本地环境:\n\n- 会写入 `sandbox_mode = \"danger-full-access\"`。\n- 会写入 `approval_policy = \"never\"`。\n- 会安装更强势的全局 `AGENTS.md`。\n\n如果你不确定该选哪个,使用默认 `safe`。\n\n## 本地仓库内安装\n\n如果你已经 clone 本仓库,也可以在仓库根目录执行:\n\n```bash\nbash tools/config/.codex/install.sh\n```\n\n安装高权限版:\n\n```bash\nbash tools/config/.codex/install.sh --profile power\n```\n\n## 路径示例\n\nLinux / WSL:\n\n- `~/.codex/config.toml`\n- `~/.codex/AGENTS.md`\n\nWindows 原生:\n\n- `C:\\Users\\<你的用户名>\\.codex\\config.toml`\n- `C:\\Users\\<你的用户名>\\.codex\\AGENTS.md`\n\n如果你自己的 Codex Home 被改到了其它位置,请通过 `CODEX_HOME` 或 `--codex-home` 指定。\n",
"sha256": "4cd23bbafa069d8bd651e9997951ac99252cf13310d1c9fda14dcf01de818a53"
},
".github/tools/config/.codex/install.sh": {
"mode": "100755",
"encoding": "utf-8",
"data": "#!/usr/bin/env bash\nset -euo pipefail\n\nRAW_BASE_DEFAULT=\"https://raw.githubusercontent.com/tukuaiai/vibe-coding-cn/develop/tools/config/.codex\"\nRAW_BASE=\"${VIBE_CODING_CODEX_RAW_BASE:-$RAW_BASE_DEFAULT}\"\nCODEX_HOME=\"${CODEX_HOME:-$HOME/.codex}\"\nPROFILE=\"safe\"\nDRY_RUN=\"0\"\nRESTORE_LATEST=\"0\"\n\nusage() {\n cat <<'USAGE'\nInstall vibe-coding-cn Codex CLI config with backup and rollback.\n\nUsage:\n install.sh [--profile safe|power] [--codex-home PATH] [--restore-latest] [--dry-run]\n\nProfiles:\n safe Public default. No danger-full-access, no approval_policy=never.\n power High-permission local profile. Requires a fully trusted machine/repo.\n\nEnvironment:\n CODEX_HOME Target Codex home. Default: ~/.codex\n VIBE_CODING_CODEX_RAW_BASE Source base URL or local directory for assets.\n\nExamples:\n curl -fsSL https://raw.githubusercontent.com/tukuaiai/vibe-coding-cn/develop/tools/config/.codex/install.sh | bash\n curl -fsSL https://raw.githubusercontent.com/tukuaiai/vibe-coding-cn/develop/tools/config/.codex/install.sh | bash -s -- --profile power\n bash ~/.codex/backups/vibe-coding-cn/LATEST/restore.sh\nUSAGE\n}\n\nlog() {\n printf '[vibe-coding-cn codex] %s\\n' \"$*\"\n}\n\ndie() {\n printf '[vibe-coding-cn codex] ERROR: %s\\n' \"$*\" >&2\n exit 1\n}\n\nwhile [ \"$#\" -gt 0 ]; do\n case \"$1\" in\n --profile)\n [ \"$#\" -ge 2 ] || die \"--profile requires safe or power\"\n PROFILE=\"$2\"\n shift 2\n ;;\n --codex-home)\n [ \"$#\" -ge 2 ] || die \"--codex-home requires a path\"\n CODEX_HOME=\"$2\"\n shift 2\n ;;\n --restore-latest)\n RESTORE_LATEST=\"1\"\n shift\n ;;\n --dry-run)\n DRY_RUN=\"1\"\n shift\n ;;\n -h|--help)\n usage\n exit 0\n ;;\n *)\n die \"unknown argument: $1\"\n ;;\n esac\ndone\n\ncase \"$PROFILE\" in\n safe)\n SOURCE_CONFIG=\"config.toml\"\n SOURCE_AGENTS=\"AGENTS.safe.md\"\n ;;\n power)\n SOURCE_CONFIG=\"config.power.toml\"\n SOURCE_AGENTS=\"AGENTS.md\"\n ;;\n *)\n die \"unsupported profile: $PROFILE\"\n ;;\nesac\n\nCODEX_HOME=\"${CODEX_HOME/#\\~/$HOME}\"\nBACKUP_ROOT=\"$CODEX_HOME/backups/vibe-coding-cn\"\nLATEST_LINK=\"$BACKUP_ROOT/LATEST\"\n\nrestore_latest() {\n [ -e \"$LATEST_LINK/restore.sh\" ] || die \"missing latest restore script: $LATEST_LINK/restore.sh\"\n log \"restoring latest backup from $LATEST_LINK\"\n bash \"$LATEST_LINK/restore.sh\"\n}\n\nif [ \"$RESTORE_LATEST\" = \"1\" ]; then\n restore_latest\n exit 0\nfi\n\nfetch_asset() {\n local name=\"$1\"\n local out=\"$2\"\n\n if [ -d \"$RAW_BASE\" ]; then\n cp \"$RAW_BASE/$name\" \"$out\"\n else\n command -v curl >/dev/null 2>&1 || die \"curl is required when RAW_BASE is remote\"\n curl -fsSL \"$RAW_BASE/$name\" -o \"$out\"\n fi\n}\n\nbackup_one() {\n local name=\"$1\"\n local src=\"$CODEX_HOME/$name\"\n local dst=\"$BACKUP_DIR/$name\"\n\n if [ -f \"$src\" ]; then\n cp \"$src\" \"$dst\"\n else\n : > \"$BACKUP_DIR/.missing-$name\"\n fi\n}\n\nwrite_restore_script() {\n local codex_home_q backup_dir_q\n printf -v codex_home_q '%q' \"$CODEX_HOME\"\n printf -v backup_dir_q '%q' \"$BACKUP_DIR\"\n\n cat > \"$BACKUP_DIR/restore.sh\" <<RESTORE\n#!/usr/bin/env bash\nset -euo pipefail\n\nCODEX_HOME=$codex_home_q\nBACKUP_DIR=$backup_dir_q\n\nrestore_file() {\n local name=\"\\$1\"\n mkdir -p \"\\$CODEX_HOME\"\n if [ -f \"\\$BACKUP_DIR/\\$name\" ]; then\n cp \"\\$BACKUP_DIR/\\$name\" \"\\$CODEX_HOME/\\$name\"\n printf '[vibe-coding-cn codex] restored %s\\n' \"\\$CODEX_HOME/\\$name\"\n elif [ -f \"\\$BACKUP_DIR/.missing-\\$name\" ]; then\n rm -f \"\\$CODEX_HOME/\\$name\"\n printf '[vibe-coding-cn codex] removed %s because it did not exist before install\\n' \"\\$CODEX_HOME/\\$name\"\n else\n printf '[vibe-coding-cn codex] skip %s: no backup marker\\n' \"\\$name\"\n fi\n}\n\nrestore_file config.toml\nrestore_file AGENTS.md\nRESTORE\n chmod +x \"$BACKUP_DIR/restore.sh\"\n}\n\ninstall_one() {\n local src=\"$1\"\n local name=\"$2\"\n install -m 600 \"$src\" \"$CODEX_HOME/$name\"\n log \"installed $CODEX_HOME/$name\"\n}\n\nTIMESTAMP=\"$(date +%Y%m%d-%H%M%S)\"\nBACKUP_DIR=\"$BACKUP_ROOT/$TIMESTAMP\"\nTMP_DIR=\"$(mktemp -d)\"\ntrap 'rm -rf \"$TMP_DIR\"' EXIT\n\nlog \"profile=$PROFILE\"\nlog \"source=$RAW_BASE\"\nlog \"codex_home=$CODEX_HOME\"\n\nif [ \"$DRY_RUN\" = \"1\" ]; then\n log \"dry run only; no files will be changed\"\n exit 0\nfi\n\nmkdir -p \"$CODEX_HOME\" \"$BACKUP_DIR\"\nbackup_one config.toml\nbackup_one AGENTS.md\nwrite_restore_script\n\ncat > \"$BACKUP_DIR/MANIFEST.txt\" <<MANIFEST\nprofile=$PROFILE\nsource=$RAW_BASE\ncodex_home=$CODEX_HOME\ncreated_at=$TIMESTAMP\nrestore=$BACKUP_DIR/restore.sh\nMANIFEST\n\nrm -rf \"$LATEST_LINK\"\nif ! ln -s \"$BACKUP_DIR\" \"$LATEST_LINK\" 2>/dev/null; then\n mkdir -p \"$LATEST_LINK\"\n cp \"$BACKUP_DIR/restore.sh\" \"$LATEST_LINK/restore.sh\"\n printf '%s\\n' \"$BACKUP_DIR\" > \"$LATEST_LINK/BACKUP_DIR\"\nfi\n\nfetch_asset \"$SOURCE_CONFIG\" \"$TMP_DIR/config.toml\"\nfetch_asset \"$SOURCE_AGENTS\" \"$TMP_DIR/AGENTS.md\"\n\ninstall_one \"$TMP_DIR/config.toml\" config.toml\ninstall_one \"$TMP_DIR/AGENTS.md\" AGENTS.md\n\nlog \"backup saved: $BACKUP_DIR\"\nlog \"restore command: bash $BACKUP_DIR/restore.sh\"\nlog \"latest restore command: bash $LATEST_LINK/restore.sh\"\n",
"sha256": "a2ba28d5a48d46aa7d508408519be117f8726c8d66e632d8736deab9175b04a4"
},
".github/skills/auto-skill/README.md": {
"mode": "100644",
"encoding": "utf-8",
"data": "# auto-skill\n\n`auto-skill` 是本仓库保留的 Skills 元技能,用于生成、升级、重构和校验 Claude/Codex 风格的 Skill。\n\n## 入口\n\n- `SKILL.md`:技能说明与执行规则。\n- `AGENTS.md`:本目录维护规则。\n- `references/`:技能设计、校验和迁移参考资料。\n- `scripts/`:技能校验与辅助脚本。\n- `assets/`:技能内部可复用资产。\n\n## 使用\n\n修改本技能后,至少运行:\n\n```bash\nskills/auto-skill/scripts/validate-skill.sh skills/auto-skill --strict\nmake test\n```\n",
"sha256": "2fd869316c0469d9c4079cd9a19c41698b501bca6ddd2b6cc03617e3f96218f0"
},
".github/skills/auto-skill/scripts/create-skill.sh": {
"mode": "100755",
"encoding": "utf-8",
"data": "#!/usr/bin/env bash\n\nset -euo pipefail\n\n# ==================== Help ====================\n\nusage() {\n cat <<'EOF'\nUsage:\n create-skill.sh <skill-name> [--minimal|--full] [--output <dir>] [--force]\n\nNotes:\n - <skill-name> MUST be lowercase, start with a letter, and only contain letters, digits, and hyphens\n - Default mode: --full\n - Default output: current directory (creates ./<skill-name>/)\n\nExamples:\n ./skills/auto-skill/scripts/create-skill.sh postgresql --full --output skills\n ./skills/auto-skill/scripts/create-skill.sh my-api --minimal --output skills\nEOF\n}\n\ndie() {\n echo \"Error: $*\" >&2\n exit 1\n}\n\n# ==================== Arg Parsing ====================\n\nskill_name=\"\"\nmode=\"full\"\noutput_dir=\".\"\nforce=0\n\nwhile [[ $# -gt 0 ]]; do\n case \"$1\" in\n -h|--help)\n usage\n exit 0\n ;;\n --minimal)\n mode=\"minimal\"\n shift\n ;;\n --full)\n mode=\"full\"\n shift\n ;;\n -o|--output)\n [[ $# -ge 2 ]] || die \"--output requires a directory argument\"\n output_dir=\"$2\"\n shift 2\n ;;\n -f|--force)\n force=1\n shift\n ;;\n --)\n shift\n break\n ;;\n -*)\n die \"Unknown argument: $1 (use --help)\"\n ;;\n *)\n if [[ -z \"$skill_name\" ]]; then\n skill_name=\"$1\"\n shift\n else\n die \"Extra argument: $1 (only one <skill-name> is allowed)\"\n fi\n ;;\n esac\ndone\n\n[[ -n \"$skill_name\" ]] || { usage; exit 1; }\n\nif [[ ! \"$skill_name\" =~ ^[a-z][a-z0-9-]*$ ]]; then\n die \"skill-name must be lowercase, start with a letter, and only contain letters/digits/hyphens (e.g. my-skill-name)\"\nfi\n\nscript_dir=\"$(cd -- \"$(dirname -- \"${BASH_SOURCE[0]}\")\" && pwd)\"\nassets_dir=\"${script_dir}/../assets\"\n\ntemplate_path=\"\"\ncase \"$mode\" in\n minimal) template_path=\"${assets_dir}/template-minimal.md\" ;;\n full) template_path=\"${assets_dir}/template-complete.md\" ;;\n *) die \"Internal error: unknown mode=$mode\" ;;\nesac\n\n[[ -f \"$template_path\" ]] || die \"Template not found: $template_path\"\n\nmkdir -p \"$output_dir\"\n\ntarget_dir=\"${output_dir%/}/${skill_name}\"\n\nif [[ -e \"$target_dir\" && \"$force\" -ne 1 ]]; then\n die \"Target already exists: $target_dir (use --force to overwrite)\"\nfi\n\nmkdir -p \"$target_dir\"/{assets,scripts,references}\n\n# ==================== Write Files ====================\n\nrender_template() {\n local src=\"$1\"\n local dest=\"$2\"\n sed \"s/{{skill_name}}/${skill_name}/g\" \"$src\" > \"$dest\"\n}\n\nrender_template \"$template_path\" \"$target_dir/SKILL.md\"\n\ncat > \"$target_dir/references/index.md\" <<EOF\n# ${skill_name} Reference Index\n\n## Quick Links\n\n- Getting started: \\`getting_started.md\\`\n- API/CLI/config: \\`api.md\\` (if applicable)\n- Examples: \\`examples.md\\`\n- Troubleshooting: \\`troubleshooting.md\\`\n\n## Notes\n\n- Put long-form content here: excerpts, evidence links, edge cases, FAQ\n- Keep \\`SKILL.md\\` Quick Reference short and directly usable\nEOF\n\nif [[ \"$mode\" == \"full\" ]]; then\n cat > \"$target_dir/references/getting_started.md\" <<'EOF'\n# Getting Started & Vocabulary\n\n## Goals\n\n- Define the 10 most important terms in this domain\n- Provide the shortest path from zero to working\nEOF\n\n cat > \"$target_dir/references/api.md\" <<'EOF'\n# API / CLI / Config Reference (If Applicable)\n\n## Suggested Structure\n\n- Organize by use case, not alphabetically\n- Key parameters: defaults, boundaries, common misuse\n- Common errors: message -> cause -> fix steps\nEOF\n\n cat > \"$target_dir/references/examples.md\" <<'EOF'\n# Long Examples\n\nPut examples longer than ~20 lines here, split by use case:\n\n- Use case 1: ...\n- Use case 2: ...\nEOF\n\n cat > \"$target_dir/references/troubleshooting.md\" <<'EOF'\n# Troubleshooting & Edge Cases\n\nWrite as: symptom -> likely causes -> diagnosis -> fix.\nEOF\nfi\n\n# ==================== Summary ====================\n\necho \"\"\necho \"OK: Skill generated: $target_dir/\"\necho \"\"\necho \"Layout:\"\necho \" $target_dir/\"\necho \" |-- SKILL.md\"\necho \" |-- assets/\"\necho \" |-- scripts/\"\necho \" \\\\-- references/\"\necho \" \\\\-- index.md\"\necho \"\"\necho \"Next steps:\"\necho \" 1) Edit $target_dir/SKILL.md (triggers/boundaries/quick reference/examples)\"\necho \" 2) Put long-form docs into $target_dir/references/ and update index.md\"\n",
"sha256": "3eb16d2f24cc2af3e7d7a0f4175e06b0258504795d079ba0920be9dd75f2f7fc"
},
".github/skills/auto-skill/scripts/validate-skill.sh": {
"mode": "100755",
"encoding": "utf-8",
"data": "#!/usr/bin/env bash\n\nset -euo pipefail\n\nusage() {\n cat <<'EOF'\nUsage:\n validate-skill.sh <skill-dir> [--strict]\n\nWhat it does:\n - Validates SKILL.md YAML frontmatter (name/description)\n - Performs lightweight structural checks\n - In --strict mode, enforces the recommended section layout\n\nExamples:\n ./skills/auto-skill/scripts/validate-skill.sh skills/postgresql\n ./skills/auto-skill/scripts/validate-skill.sh skills/my-skill --strict\nEOF\n}\n\ndie() {\n echo \"Error: $*\" >&2\n exit 1\n}\n\nwarn() {\n echo \"Warning: $*\" >&2\n}\n\nstrict=0\nskill_dir=\"\"\n\nwhile [[ $# -gt 0 ]]; do\n case \"$1\" in\n -h|--help)\n usage\n exit 0\n ;;\n --strict)\n strict=1\n shift\n ;;\n --)\n shift\n break\n ;;\n -*)\n die \"Unknown argument: $1 (use --help)\"\n ;;\n *)\n if [[ -z \"$skill_dir\" ]]; then\n skill_dir=\"$1\"\n shift\n else\n die \"Extra argument: $1 (only one <skill-dir> is allowed)\"\n fi\n ;;\n esac\ndone\n\n[[ -n \"$skill_dir\" ]] || { usage; exit 1; }\n[[ -d \"$skill_dir\" ]] || die \"Not a directory: $skill_dir\"\n\nskill_md=\"$skill_dir/SKILL.md\"\n[[ -f \"$skill_md\" ]] || die \"Missing SKILL.md: $skill_md\"\n\nbase_name=\"$(basename -- \"${skill_dir%/}\")\"\n\n# -------------------- Parse YAML frontmatter --------------------\n\nfrontmatter=\"\"\nif frontmatter=\"$(\n awk '\n BEGIN { in_fm=0; closed=0 }\n NR==1 {\n if ($0 != \"---\") exit 2\n in_fm=1\n next\n }\n in_fm==1 {\n if ($0 == \"---\") { closed=1; exit 0 }\n print\n next\n }\n END {\n if (closed == 0) exit 3\n }\n ' \"$skill_md\"\n)\"; then\n :\nelse\n rc=$?\n case \"$rc\" in\n 2) die \"SKILL.md must start with YAML frontmatter (--- as the first line)\" ;;\n 3) die \"YAML frontmatter is not closed (missing ---)\" ;;\n *) die \"Failed to parse YAML frontmatter (awk exit=$rc)\" ;;\n esac\nfi\n\nname=\"$(\n printf \"%s\\n\" \"$frontmatter\" | awk -F: '\n tolower($1) ~ /^name$/ {\n sub(/^[^:]*:[[:space:]]*/, \"\", $0)\n gsub(/[[:space:]]+$/, \"\", $0)\n print\n exit\n }\n '\n)\"\n\ndescription=\"$(\n printf \"%s\\n\" \"$frontmatter\" | awk -F: '\n tolower($1) ~ /^description$/ {\n sub(/^[^:]*:[[:space:]]*/, \"\", $0)\n gsub(/[[:space:]]+$/, \"\", $0)\n print\n exit\n }\n '\n)\"\n\n[[ -n \"$name\" ]] || die \"Missing frontmatter field: name\"\n[[ -n \"$description\" ]] || die \"Missing frontmatter field: description\"\n\nif [[ ! \"$name\" =~ ^[a-z][a-z0-9-]*$ ]]; then\n die \"Invalid name: '$name' (expected ^[a-z][a-z0-9-]*$)\"\nfi\n\nif [[ \"$strict\" -eq 1 && \"$name\" != \"$base_name\" ]]; then\n die \"Strict mode: frontmatter name ('$name') must match directory name ('$base_name')\"\nfi\n\n# -------------------- Strip fenced code blocks for section checks --------------------\n\nfiltered_md=\"$(mktemp)\"\ntrap 'rm -f \"$filtered_md\"' EXIT\n\nawk '\n BEGIN { in_fence=0 }\n /^[[:space:]]*```/ { in_fence = !in_fence; next }\n in_fence==0 { print }\n' \"$skill_md\" > \"$filtered_md\"\n\n# -------------------- Structural checks --------------------\n\nrequired_h2=(\n \"When to Use This Skill\"\n \"Not For / Boundaries\"\n \"Quick Reference\"\n \"Examples\"\n \"References\"\n \"Maintenance\"\n)\n\nfor title in \"${required_h2[@]}\"; do\n if ! grep -Eq \"^##[[:space:]]+${title}([[:space:]]*)$\" \"$filtered_md\"; then\n if [[ \"$strict\" -eq 1 ]]; then\n die \"Strict mode: missing required section heading: '## ${title}'\"\n fi\n warn \"Missing recommended section heading: '## ${title}'\"\n fi\ndone\n\n# references/index.md presence (only enforced in strict mode when references/ exists)\nif [[ -d \"$skill_dir/references\" && \"$strict\" -eq 1 && ! -f \"$skill_dir/references/index.md\" ]]; then\n die \"Strict mode: references/ exists but references/index.md is missing\"\nfi\n\n# -------------------- Heuristics: Quick Reference size --------------------\n\nquick_start=\"$(awk 'match($0, /^##[[:space:]]+Quick Reference([[:space:]]*)$/){print NR; exit}' \"$filtered_md\" || true)\"\nif [[ -n \"$quick_start\" ]]; then\n quick_end=\"$(awk -v s=\"$quick_start\" 'NR>s && match($0, /^##[[:space:]]+/){print NR; exit}' \"$filtered_md\" || true)\"\n total_lines=\"$(wc -l < \"$filtered_md\" | tr -d ' ')\"\n if [[ -z \"$quick_end\" ]]; then\n quick_end=\"$((total_lines + 1))\"\n fi\n quick_len=\"$((quick_end - quick_start - 1))\"\n if [[ \"$quick_len\" -gt 250 ]]; then\n if [[ \"$strict\" -eq 1 ]]; then\n die \"Strict mode: Quick Reference section is too long (${quick_len} lines). Move long-form text into references/.\"\n fi\n warn \"Quick Reference section is large (${quick_len} lines). Consider moving long-form text into references/.\"\n fi\nfi\n\n# -------------------- Heuristics: Examples count --------------------\n\nexamples_start=\"$(awk 'match($0, /^##[[:space:]]+Examples([[:space:]]*)$/){print NR; exit}' \"$filtered_md\" || true)\"\nif [[ -n \"$examples_start\" ]]; then\n examples_end=\"$(awk -v s=\"$examples_start\" 'NR>s && match($0, /^##[[:space:]]+/){print NR; exit}' \"$filtered_md\" || true)\"\n total_lines=\"$(wc -l < \"$filtered_md\" | tr -d ' ')\"\n if [[ -z \"$examples_end\" ]]; then\n examples_end=\"$((total_lines + 1))\"\n fi\n\n example_count=\"$(\n awk -v s=\"$examples_start\" -v e=\"$examples_end\" '\n NR>s && NR<e && match($0, /^###[[:space:]]+Example([[:space:]]|$)/) { c++ }\n END { print c+0 }\n ' \"$filtered_md\"\n )\"\n\n if [[ \"$example_count\" -lt 3 ]]; then\n if [[ \"$strict\" -eq 1 ]]; then\n die \"Strict mode: expected >= 3 examples (found ${example_count}).\"\n fi\n warn \"Recommended: >= 3 examples (found ${example_count}).\"\n fi\nfi\n\necho \"OK: $skill_dir\"\n",
"sha256": "deb5cf2529a93c87c8b7323b55ffc6d7798e6b59652351ba795340ac8c0061c9"
},
".github/skills/auto-skill/scripts/skill-seekers.sh": {
"mode": "100755",
"encoding": "utf-8",
"data": "#!/usr/bin/env bash\n\nset -euo pipefail\n\n# ==================== Purpose ====================\n# Run Skill Seekers from linked source with a local venv.\n#\n# This script does NOT auto-install dependencies.\n# Run skill-seekers-bootstrap.sh once if you see ImportError.\n\nusage() {\n cat <<'EOF'\nUsage:\n skill-seekers.sh [--venv <dir>] -- <skill-seekers args...>\n\nExamples:\n ./skills/auto-skill/scripts/skill-seekers.sh -- --version\n ./skills/auto-skill/scripts/skill-seekers.sh -- scrape --config ./skills/auto-skill/scripts/Skill_Seekers-development/configs/react.json\n ./skills/auto-skill/scripts/skill-seekers.sh -- github --repo facebook/react --name react\nEOF\n}\n\ndie() {\n echo \"Error: $*\" >&2\n exit 1\n}\n\nscript_dir=\"$(cd -- \"$(dirname -- \"${BASH_SOURCE[0]}\")\" && pwd)\"\ntool_dir=\"${script_dir}/Skill_Seekers-development\"\ntool_src=\"${tool_dir}/src\"\ndefault_venv=\"${script_dir}/.venv-skill-seekers\"\n\nvenv_dir=\"$default_venv\"\n\nwhile [[ $# -gt 0 ]]; do\n case \"$1\" in\n -h|--help)\n usage\n exit 0\n ;;\n --venv)\n [[ $# -ge 2 ]] || die \"--venv requires a directory argument\"\n venv_dir=\"$2\"\n shift 2\n ;;\n --)\n shift\n break\n ;;\n *)\n die \"Expected '--' before skill-seekers arguments (use --help)\"\n ;;\n esac\ndone\n\n[[ -d \"$tool_src\" ]] || die \"Missing linked source dir: $tool_src\"\n\npython_bin=\"python3\"\nif [[ -x \"$venv_dir/bin/python\" ]]; then\n python_bin=\"$venv_dir/bin/python\"\nfi\n\nexport PYTHONPATH=\"$tool_src${PYTHONPATH:+:$PYTHONPATH}\"\n\nexec \"$python_bin\" -m skill_seekers.cli.main \"$@\"\n",
"sha256": "fdbf73b1faa1a0f445663b5c7c1c9792bbfb6dcdf5f5308198503e14ea0c64dc"
},
".github/skills/auto-tmux/README.md": {
"mode": "100644",
"encoding": "utf-8",
"data": "# auto-tmux\n\n`auto-tmux` 是 tmux 自动化操控技能,用于读取 pane 输出、发送按键、批量巡检、救援卡住的终端,以及组织多 AI 终端协作。\n\n## 入口\n\n- [SKILL.md](./SKILL.md) - 技能触发条件、命令片段、规则和质量门禁。\n- [scripts/](./scripts/) - 安全封装的 tmux 自动化脚本。\n- [references/](./references/) - tmux / oh-my-tmux 参考、示例和故障排查。\n- [assets/](./assets/) - 指向仓库外部 submodule 的只读软链接入口。\n\n## 资产来源\n\n| 入口 | 指向 | 用途 |\n|:---|:---|:---|\n| `assets/oh-my-tmux` | `tools/external/.tmux` | gpakosz/oh-my-tmux 配置参考 |\n| `assets/tmux-src` | `tools/external/tmux` | tmux 上游源码参考 |\n\n## 快速验证\n\n```bash\nbash -n skills/auto-tmux/scripts/auto-tmux.sh\nbash -n skills/auto-tmux/scripts/swarm-state.sh\nbash -n skills/auto-tmux/scripts/swarm-brief.sh\nbash -n skills/auto-tmux/scripts/swarm-watch.sh\nbash -n skills/auto-tmux/scripts/swarm-archive.sh\nbash -n skills/auto-tmux/scripts/swarm-board.sh\nbash -n skills/auto-tmux/scripts/swarm-deps-graph.sh\nbash -n skills/auto-tmux/scripts/swarm-export.sh\nbash -n skills/auto-tmux/scripts/swarm-timeline.sh\nbash -n skills/auto-tmux/scripts/swarm-blockers.sh\nbash -n skills/auto-tmux/scripts/swarm-results.sh\nbash -n skills/auto-tmux/scripts/swarm-report-pack.sh\nbash -n skills/auto-tmux/scripts/swarm-assign.sh\nbash -n skills/auto-tmux/scripts/swarm-health.sh\nbash -n skills/auto-tmux/scripts/remote-readonly.sh\nbash -n skills/auto-tmux/scripts/record-summary.sh\nbash -n skills/auto-tmux/scripts/check-jsonl.sh\nbash -n skills/auto-tmux/scripts/review-checklist.sh\nbash -n skills/auto-tmux/scripts/verify-report-pack.sh\nbash -n skills/auto-tmux/scripts/completion.bash\nbash -n skills/auto-tmux/scripts/safety-check.sh\nbash -n skills/auto-tmux/scripts/render-swarm-prompt.sh\nbash -n skills/auto-tmux/scripts/swarm-dispatch.sh\nbash -n skills/auto-tmux/scripts/validate-auto-tmux.sh\nskills/auto-tmux/scripts/auto-tmux.sh help\nskills/auto-tmux/scripts/swarm-state.sh help\nskills/auto-tmux/scripts/swarm-brief.sh --help\nskills/auto-tmux/scripts/safety-check.sh --text \"make test\"\nskills/auto-tmux/scripts/render-swarm-prompt.sh commander --session ai-hub --task \"smoke\"\nskills/auto-tmux/scripts/auto-tmux-smoke-test.sh\nskills/auto-tmux/scripts/validate-auto-tmux.sh\nskills/auto-skill/scripts/validate-skill.sh skills/auto-tmux --strict\n```\n\n## 使用边界\n\n- 优先使用 `scripts/auto-tmux.sh`,需要低层调试时再直接使用 tmux 原生命令。\n- 发送按键前必须先 `capture-pane` 复核目标上下文;脚本会默认打印最近上下文。\n- 发送长文本、粘贴文件或下发 prompt 前先运行 `scripts/safety-check.sh`。\n- SSH/远程场景默认只读,先用 `scripts/remote-readonly.sh` 采集证据,再按 `references/session-safety.md` 判断是否需要人工确认升级。\n- 批量操作前必须先列出 session/window/pane 白名单。\n- 多 worker 并发前用 `swarm-state.sh` 管理任务、锁和状态,避免重复修改同一资源。\n- 不在未知 pane 中发送破坏性命令。\n- 不在本目录复制或修改上游 tmux / oh-my-tmux 源码。\n",
"sha256": "d21ca4f1c4adb6a799a76f7a7446b1ebca70d2402f73e80600cda1c2a6d24c25"
},
".github/skills/auto-tmux/scripts/auto-tmux.sh": {
"mode": "100755",
"encoding": "utf-8",
"data": "#!/usr/bin/env bash\n# auto-tmux: safe tmux automation wrapper for Codex/AI operator workflows.\nset -euo pipefail\n\nPROG=\"${0##*/}\"\nDEFAULT_LINES=120\nDEFAULT_RESCUE_PATTERN='(\\(y/n\\)|\\[y/N\\]|\\[Y/n\\]|continue\\?|proceed\\?|confirm|确认|是否继续)'\nDANGEROUS_PATTERN='(^|[[:space:];|&])(rm[[:space:]]+-rf|mkfs|dd[[:space:]]+if=|shutdown|reboot|halt|poweroff|tmux[[:space:]]+kill-server|git[[:space:]]+reset[[:space:]]+--hard|git[[:space:]]+clean[[:space:]]+-fd|DROP[[:space:]]+(DATABASE|TABLE))'\n\nusage() {\n cat <<'EOF'\nauto-tmux: safe tmux automation wrapper\n\nUsage:\n auto-tmux.sh help\n auto-tmux.sh doctor [--session NAME]\n auto-tmux.sh topology [--session NAME]\n auto-tmux.sh inspect -t TARGET [-n LINES] [--no-redact]\n auto-tmux.sh capture -t TARGET [-n LINES] [--save FILE] [--no-redact]\n auto-tmux.sh send -t TARGET (--text TEXT | --key KEY) [--enter] [--clear] [--force] [--dry-run]\n auto-tmux.sh paste -t TARGET --file FILE [--enter] [--clear] [--force] [--dry-run]\n auto-tmux.sh broadcast --session NAME (--text TEXT | --key KEY) [--enter] [--clear] [--force] [--dry-run]\n auto-tmux.sh rescue -t TARGET [--pattern REGEX] [--reply TEXT] [-n LINES] [--force] [--dry-run]\n auto-tmux.sh scan [--session NAME] [-n LINES] [--pattern REGEX] [--rescue] [--reply TEXT] [--save-dir DIR]\n auto-tmux.sh record start -t TARGET [--dir DIR]\n auto-tmux.sh record stop -t TARGET\n auto-tmux.sh snapshot [--session NAME] [--dir DIR] [-n LINES]\n auto-tmux.sh hub [--session NAME] [--workers N] [--cmd CMD] [--commander-cmd CMD] [--attach]\n auto-tmux.sh cleanup --session NAME [--dry-run] [--force]\n auto-tmux.sh wait -t TARGET --pattern REGEX [--timeout SEC] [--interval SEC] [-n LINES]\n\nTarget format:\n <session>:<window>.<pane>\n\nExamples:\n auto-tmux.sh doctor --session ai-hub\n auto-tmux.sh topology\n auto-tmux.sh inspect -t <target-from-topology> -n 40\n auto-tmux.sh capture -t <target-from-topology> -n 80\n auto-tmux.sh send -t <target-from-topology> --text \"make test\" --enter\n auto-tmux.sh paste -t <target-from-topology> --file /tmp/prompt.md --enter --dry-run\n auto-tmux.sh broadcast --session ai-hub --text \"pwd\" --enter --dry-run\n auto-tmux.sh rescue -t <target-from-topology> --pattern \"(y/n)\" --reply y\n auto-tmux.sh scan --session ai-hub --pattern \"ERROR|Traceback\"\n auto-tmux.sh snapshot --session ai-hub --dir /tmp/auto-tmux-snapshot\n auto-tmux.sh hub --session ai-hub --workers 3 --cmd \"codex\"\n auto-tmux.sh cleanup --session ai-hub --dry-run\nEOF\n}\n\ndie() {\n printf 'error: %s\\n' \"$*\" >&2\n exit 1\n}\n\nwarn() {\n printf 'warn: %s\\n' \"$*\" >&2\n}\n\nstatus_line() {\n local status=\"$1\"\n local message=\"$2\"\n printf '[%s] %s\\n' \"$status\" \"$message\"\n}\n\nrequire_tmux() {\n command -v tmux >/dev/null 2>&1 || die \"tmux is not installed or not in PATH\"\n tmux list-sessions >/dev/null 2>&1 || die \"no tmux server/session found\"\n}\n\ntarget_exists() {\n local target=\"$1\"\n tmux display-message -pt \"$target\" '#{pane_id}' >/dev/null 2>&1\n}\n\nrequire_target() {\n local target=\"$1\"\n [[ -n \"$target\" ]] || die \"missing -t TARGET\"\n target_exists \"$target\" || die \"tmux target not found: $target\"\n}\n\nredact() {\n sed -E \\\n -e 's/(OPENAI_API_KEY|ANTHROPIC_API_KEY|GITHUB_TOKEN|GH_TOKEN|API_KEY|TOKEN|PASSWORD|SECRET)=([^[:space:]]+)/\\1=<redacted>/g' \\\n -e 's/(Bearer[[:space:]]+)[A-Za-z0-9._~+\\/=-]+/\\1<redacted>/g' \\\n -e 's/(sk-[A-Za-z0-9_-]{12,})/<redacted-openai-key>/g'\n}\n\ncapture_raw() {\n local target=\"$1\"\n local lines=\"$2\"\n tmux capture-pane -t \"$target\" -p -S \"-$lines\"\n}\n\ncapture_print() {\n local target=\"$1\"\n local lines=\"$2\"\n local no_redact=\"$3\"\n if [[ \"$no_redact\" == \"1\" ]]; then\n capture_raw \"$target\" \"$lines\"\n else\n capture_raw \"$target\" \"$lines\" | redact\n fi\n}\n\nis_dangerous_text() {\n local text=\"$1\"\n echo \"$text\" | grep -Eiq \"$DANGEROUS_PATTERN\"\n}\n\ncancel_copy_mode_if_needed() {\n local target=\"$1\"\n local in_mode\n in_mode=\"$(tmux display-message -pt \"$target\" '#{pane_in_mode}' 2>/dev/null || echo 0)\"\n if [[ \"$in_mode\" == \"1\" ]]; then\n tmux send-keys -t \"$target\" -X cancel\n fi\n}\n\npane_list() {\n local session=\"$1\"\n if [[ -n \"$session\" ]]; then\n tmux list-panes -a -F '#S:#I.#P' | awk -F: -v s=\"$session\" '$1 == s {print}'\n else\n tmux list-panes -a -F '#S:#I.#P'\n fi\n}\n\ncmd_doctor() {\n local session=\"\"\n while [[ $# -gt 0 ]]; do\n case \"$1\" in\n --session) session=\"${2:-}\"; shift 2 ;;\n -h|--help) usage; exit 0 ;;\n *) die \"unknown doctor option: $1\" ;;\n esac\n done\n\n local failures=0\n local script_dir\n script_dir=\"$(cd \"$(dirname \"${BASH_SOURCE[0]}\")\" && pwd)\"\n\n if command -v tmux >/dev/null 2>&1; then\n status_line \"OK\" \"tmux found: $(tmux -V)\"\n else\n status_line \"FAIL\" \"tmux not found in PATH\"\n failures=$((failures + 1))\n fi\n\n if tmux list-sessions >/dev/null 2>&1; then\n status_line \"OK\" \"tmux server is reachable\"\n else\n status_line \"WARN\" \"tmux server has no reachable session yet\"\n fi\n\n for script in auto-tmux.sh swarm-state.sh swarm-brief.sh swarm-watch.sh swarm-archive.sh swarm-board.sh swarm-deps-graph.sh swarm-export.sh swarm-timeline.sh swarm-blockers.sh swarm-results.sh swarm-report-pack.sh swarm-assign.sh swarm-health.sh remote-readonly.sh record-summary.sh check-jsonl.sh review-checklist.sh verify-report-pack.sh incident-report.sh safety-check.sh render-swarm-prompt.sh swarm-dispatch.sh auto-tmux-smoke-test.sh validate-auto-tmux.sh; do\n if [[ -x \"$script_dir/$script\" ]]; then\n status_line \"OK\" \"script executable: $script\"\n else\n status_line \"FAIL\" \"script missing or not executable: $script\"\n failures=$((failures + 1))\n fi\n done\n\n local root\n root=\"$(git -C \"$script_dir\" rev-parse --show-toplevel 2>/dev/null || true)\"\n if [[ -n \"$root\" ]]; then\n for rel in skills/auto-tmux/assets/oh-my-tmux skills/auto-tmux/assets/tmux-src; do\n if [[ -e \"$root/$rel\" ]]; then\n status_line \"OK\" \"asset exists: $rel\"\n else\n status_line \"WARN\" \"asset missing: $rel (run git submodule update --init --recursive)\"\n fi\n done\n else\n status_line \"WARN\" \"not inside a git worktree; skipped asset checks\"\n fi\n\n if [[ -n \"$session\" ]]; then\n if tmux has-session -t \"$session\" 2>/dev/null; then\n status_line \"OK\" \"session exists: $session\"\n tmux list-panes -t \"$session\" -F ' pane #S:#{window_index}.#{pane_index} cmd=#{pane_current_command}'\n else\n status_line \"FAIL\" \"session not found: $session\"\n failures=$((failures + 1))\n fi\n fi\n\n if (( failures > 0 )); then\n return 1\n fi\n}\n\ncmd_topology() {\n local session=\"\"\n while [[ $# -gt 0 ]]; do\n case \"$1\" in\n --session) session=\"${2:-}\"; shift 2 ;;\n -h|--help) usage; exit 0 ;;\n *) die \"unknown topology option: $1\" ;;\n esac\n done\n\n require_tmux\n if [[ -n \"$session\" ]]; then\n tmux has-session -t \"$session\" 2>/dev/null || die \"session not found: $session\"\n printf 'session: %s\\n' \"$session\"\n tmux list-windows -t \"$session\" -F ' window #{window_index}: #{window_name} #{window_flags}'\n tmux list-panes -a -F '#S #S:#{window_index}.#{pane_index} #{pane_current_command} #{pane_current_path}' |\n awk -v s=\"$session\" '$1 == s {print \" pane target=\" $2 \" cmd=\" $3 \" path=\" $4}'\n else\n tmux list-sessions -F 'session: #{session_name} windows=#{session_windows} attached=#{session_attached}'\n tmux list-windows -a -F ' window #S:#{window_index}: #{window_name} #{window_flags}'\n tmux list-panes -a -F ' pane #S:#{window_index}.#{pane_index} cmd=#{pane_current_command} path=#{pane_current_path}'\n fi\n}\n\ncmd_inspect() {\n local target=\"\"\n local lines=40\n local no_redact=\"0\"\n while [[ $# -gt 0 ]]; do\n case \"$1\" in\n -t|--target) target=\"${2:-}\"; shift 2 ;;\n -n|--lines) lines=\"${2:-}\"; shift 2 ;;\n --no-redact) no_redact=\"1\"; shift ;;\n -h|--help) usage; exit 0 ;;\n *) die \"unknown inspect option: $1\" ;;\n esac\n done\n\n require_tmux\n require_target \"$target\"\n printf '# pane inspect\\n\\n'\n tmux display-message -pt \"$target\" 'target=#{session_name}:#{window_index}.#{pane_index}'\n tmux display-message -pt \"$target\" 'pane_id=#{pane_id}'\n tmux display-message -pt \"$target\" 'window=#{window_name}'\n tmux display-message -pt \"$target\" 'command=#{pane_current_command}'\n tmux display-message -pt \"$target\" 'pid=#{pane_pid}'\n tmux display-message -pt \"$target\" 'path=#{pane_current_path}'\n tmux display-message -pt \"$target\" 'title=#{pane_title}'\n tmux display-message -pt \"$target\" 'in_mode=#{pane_in_mode}'\n tmux display-message -pt \"$target\" 'size=#{pane_width}x#{pane_height}'\n printf '\\n## recent output\\n\\n'\n capture_print \"$target\" \"$lines\" \"$no_redact\"\n}\n\ncmd_broadcast() {\n local session=\"\"\n local text=\"\"\n local key=\"\"\n local enter=\"0\"\n local clear=\"0\"\n local force=\"0\"\n local dry_run=\"0\"\n while [[ $# -gt 0 ]]; do\n case \"$1\" in\n --session) session=\"${2:-}\"; shift 2 ;;\n --text) text=\"${2:-}\"; shift 2 ;;\n --key) key=\"${2:-}\"; shift 2 ;;\n --enter) enter=\"1\"; shift ;;\n --clear) clear=\"1\"; shift ;;\n --force) force=\"1\"; shift ;;\n --dry-run) dry_run=\"1\"; shift ;;\n -h|--help) usage; exit 0 ;;\n *) die \"unknown broadcast option: $1\" ;;\n esac\n done\n\n require_tmux\n [[ -n \"$session\" ]] || die \"broadcast requires --session NAME\"\n tmux has-session -t \"$session\" 2>/dev/null || die \"session not found: $session\"\n [[ -n \"$text\" || -n \"$key\" ]] || die \"broadcast requires --text TEXT or --key KEY\"\n [[ -z \"$text\" || -z \"$key\" ]] || die \"broadcast accepts only one of --text or --key\"\n if [[ -n \"$text\" && \"$force\" != \"1\" ]] && is_dangerous_text \"$text\"; then\n die \"refusing dangerous broadcast text without --force: $text\"\n fi\n\n local panes=()\n mapfile -t panes < <(pane_list \"$session\")\n [[ \"${#panes[@]}\" -gt 0 ]] || die \"no panes found in session: $session\"\n printf 'broadcast targets (%s):\\n' \"${#panes[@]}\"\n printf ' %s\\n' \"${panes[@]}\"\n\n local pane\n for pane in \"${panes[@]}\"; do\n if [[ \"$dry_run\" == \"1\" ]]; then\n printf '[dry-run] would send to %s\\n' \"$pane\"\n continue\n fi\n if [[ -n \"$text\" ]]; then\n local args=(-t \"$pane\" --text \"$text\")\n [[ \"$enter\" == \"1\" ]] && args+=(--enter)\n [[ \"$clear\" == \"1\" ]] && args+=(--clear)\n [[ \"$force\" == \"1\" ]] && args+=(--force)\n cmd_send \"${args[@]}\"\n else\n local args=(-t \"$pane\" --key \"$key\")\n [[ \"$enter\" == \"1\" ]] && args+=(--enter)\n [[ \"$clear\" == \"1\" ]] && args+=(--clear)\n [[ \"$force\" == \"1\" ]] && args+=(--force)\n cmd_send \"${args[@]}\"\n fi\n done\n}\n\ncmd_capture() {\n local target=\"\"\n local lines=\"$DEFAULT_LINES\"\n local save_file=\"\"\n local no_redact=\"0\"\n while [[ $# -gt 0 ]]; do\n case \"$1\" in\n -t|--target) target=\"${2:-}\"; shift 2 ;;\n -n|--lines) lines=\"${2:-}\"; shift 2 ;;\n --save) save_file=\"${2:-}\"; shift 2 ;;\n --no-redact) no_redact=\"1\"; shift ;;\n -h|--help) usage; exit 0 ;;\n *) die \"unknown capture option: $1\" ;;\n esac\n done\n\n require_tmux\n require_target \"$target\"\n if [[ -n \"$save_file\" ]]; then\n mkdir -p \"$(dirname \"$save_file\")\"\n capture_print \"$target\" \"$lines\" \"$no_redact\" | tee \"$save_file\"\n else\n capture_print \"$target\" \"$lines\" \"$no_redact\"\n fi\n}\n\ncmd_send() {\n local target=\"\"\n local text=\"\"\n local key=\"\"\n local enter=\"0\"\n local clear=\"0\"\n local force=\"0\"\n local dry_run=\"0\"\n while [[ $# -gt 0 ]]; do\n case \"$1\" in\n -t|--target) target=\"${2:-}\"; shift 2 ;;\n --text) text=\"${2:-}\"; shift 2 ;;\n --key) key=\"${2:-}\"; shift 2 ;;\n --enter) enter=\"1\"; shift ;;\n --clear) clear=\"1\"; shift ;;\n --force) force=\"1\"; shift ;;\n --dry-run) dry_run=\"1\"; shift ;;\n -h|--help) usage; exit 0 ;;\n *) die \"unknown send option: $1\" ;;\n esac\n done\n\n require_tmux\n require_target \"$target\"\n [[ -n \"$text\" || -n \"$key\" ]] || die \"send requires --text TEXT or --key KEY\"\n [[ -z \"$text\" || -z \"$key\" ]] || die \"send accepts only one of --text or --key\"\n\n printf -- '--- current context: %s ---\\n' \"$target\" >&2\n capture_print \"$target\" 40 0 >&2 || true\n\n if [[ -n \"$text\" && \"$force\" != \"1\" ]] && is_dangerous_text \"$text\"; then\n die \"refusing dangerous text without --force: $text\"\n fi\n\n if [[ \"$dry_run\" == \"1\" ]]; then\n printf '[dry-run] target=%s clear=%s text=%q key=%q enter=%s\\n' \"$target\" \"$clear\" \"$text\" \"$key\" \"$enter\"\n return 0\n fi\n\n cancel_copy_mode_if_needed \"$target\"\n if [[ \"$clear\" == \"1\" ]]; then\n tmux send-keys -t \"$target\" C-u\n fi\n if [[ -n \"$text\" ]]; then\n tmux send-keys -t \"$target\" -l \"$text\"\n else\n tmux send-keys -t \"$target\" \"$key\"\n fi\n if [[ \"$enter\" == \"1\" ]]; then\n tmux send-keys -t \"$target\" Enter\n fi\n}\n\ncmd_paste() {\n local target=\"\"\n local file=\"\"\n local enter=\"0\"\n local clear=\"0\"\n local force=\"0\"\n local dry_run=\"0\"\n while [[ $# -gt 0 ]]; do\n case \"$1\" in\n -t|--target) target=\"${2:-}\"; shift 2 ;;\n --file) file=\"${2:-}\"; shift 2 ;;\n --enter) enter=\"1\"; shift ;;\n --clear) clear=\"1\"; shift ;;\n --force) force=\"1\"; shift ;;\n --dry-run) dry_run=\"1\"; shift ;;\n -h|--help) usage; exit 0 ;;\n *) die \"unknown paste option: $1\" ;;\n esac\n done\n\n require_tmux\n require_target \"$target\"\n [[ -n \"$file\" ]] || die \"paste requires --file FILE\"\n [[ -f \"$file\" ]] || die \"paste file not found: $file\"\n\n printf -- '--- current context: %s ---\\n' \"$target\" >&2\n capture_print \"$target\" 40 0 >&2 || true\n\n if [[ \"$force\" != \"1\" ]] && is_dangerous_text \"$(cat \"$file\")\"; then\n die \"refusing dangerous paste file without --force: $file\"\n fi\n\n if [[ \"$dry_run\" == \"1\" ]]; then\n printf '[dry-run] target=%s clear=%s file=%s bytes=%s enter=%s\\n' \\\n \"$target\" \"$clear\" \"$file\" \"$(wc -c < \"$file\" | tr -d ' ')\" \"$enter\"\n return 0\n fi\n\n cancel_copy_mode_if_needed \"$target\"\n if [[ \"$clear\" == \"1\" ]]; then\n tmux send-keys -t \"$target\" C-u\n fi\n local buffer_name=\"auto-tmux-paste-$$\"\n tmux load-buffer -b \"$buffer_name\" \"$file\"\n tmux paste-buffer -t \"$target\" -b \"$buffer_name\" -d\n if [[ \"$enter\" == \"1\" ]]; then\n tmux send-keys -t \"$target\" Enter\n fi\n}\n\ncmd_rescue() {\n local target=\"\"\n local pattern=\"$DEFAULT_RESCUE_PATTERN\"\n local reply=\"y\"\n local lines=80\n local force=\"0\"\n local dry_run=\"0\"\n while [[ $# -gt 0 ]]; do\n case \"$1\" in\n -t|--target) target=\"${2:-}\"; shift 2 ;;\n --pattern) pattern=\"${2:-}\"; shift 2 ;;\n --reply) reply=\"${2:-}\"; shift 2 ;;\n -n|--lines) lines=\"${2:-}\"; shift 2 ;;\n --force) force=\"1\"; shift ;;\n --dry-run) dry_run=\"1\"; shift ;;\n -h|--help) usage; exit 0 ;;\n *) die \"unknown rescue option: $1\" ;;\n esac\n done\n\n require_tmux\n require_target \"$target\"\n local output\n output=\"$(capture_raw \"$target\" \"$lines\")\"\n printf '%s\\n' \"$output\" | redact\n if printf '%s\\n' \"$output\" | grep -Eiq \"$pattern\"; then\n printf '[match] target=%s pattern=%s reply=%q\\n' \"$target\" \"$pattern\" \"$reply\" >&2\n if [[ \"$dry_run\" == \"1\" ]]; then\n printf '[dry-run] would send reply to %s\\n' \"$target\"\n else\n if [[ \"$force\" == \"1\" ]]; then\n cmd_send -t \"$target\" --text \"$reply\" --enter --force\n else\n cmd_send -t \"$target\" --text \"$reply\" --enter\n fi\n fi\n else\n printf '[skip] no rescue pattern matched for %s\\n' \"$target\" >&2\n fi\n}\n\ncmd_scan() {\n local session=\"\"\n local lines=80\n local pattern=\"\"\n local rescue=\"0\"\n local reply=\"y\"\n local save_dir=\"\"\n while [[ $# -gt 0 ]]; do\n case \"$1\" in\n --session) session=\"${2:-}\"; shift 2 ;;\n -n|--lines) lines=\"${2:-}\"; shift 2 ;;\n --pattern) pattern=\"${2:-}\"; shift 2 ;;\n --rescue) rescue=\"1\"; shift ;;\n --reply) reply=\"${2:-}\"; shift 2 ;;\n --save-dir) save_dir=\"${2:-}\"; shift 2 ;;\n -h|--help) usage; exit 0 ;;\n *) die \"unknown scan option: $1\" ;;\n esac\n done\n\n require_tmux\n if [[ -n \"$save_dir\" ]]; then\n mkdir -p \"$save_dir\"\n fi\n\n local pane output safe_name\n while IFS= read -r pane; do\n [[ -n \"$pane\" ]] || continue\n printf '\\n===== [%s] =====\\n' \"$pane\"\n output=\"$(capture_raw \"$pane\" \"$lines\")\"\n printf '%s\\n' \"$output\" | redact\n if [[ -n \"$save_dir\" ]]; then\n safe_name=\"${pane//[:.]/-}.log\"\n printf '%s\\n' \"$output\" | redact > \"$save_dir/$safe_name\"\n fi\n if [[ -n \"$pattern\" ]] && printf '%s\\n' \"$output\" | grep -Eiq \"$pattern\"; then\n printf '[match] %s matched %s\\n' \"$pane\" \"$pattern\" >&2\n if [[ \"$rescue\" == \"1\" ]]; then\n cmd_send -t \"$pane\" --text \"$reply\" --enter\n fi\n fi\n done < <(pane_list \"$session\")\n}\n\ncmd_record() {\n local action=\"${1:-}\"\n [[ -n \"$action\" ]] || die \"record requires start or stop\"\n shift || true\n\n local target=\"\"\n local dir=\"/tmp/auto-tmux-records\"\n while [[ $# -gt 0 ]]; do\n case \"$1\" in\n -t|--target) target=\"${2:-}\"; shift 2 ;;\n --dir) dir=\"${2:-}\"; shift 2 ;;\n -h|--help) usage; exit 0 ;;\n *) die \"unknown record option: $1\" ;;\n esac\n done\n\n require_tmux\n require_target \"$target\"\n case \"$action\" in\n start)\n mkdir -p \"$dir\"\n local safe_name=\"${target//[:.]/-}.log\"\n local file=\"$dir/$safe_name\"\n tmux pipe-pane -t \"$target\" -o \"cat >> '$file'\"\n printf 'recording %s -> %s\\n' \"$target\" \"$file\"\n ;;\n stop)\n tmux pipe-pane -t \"$target\"\n printf 'recording stopped for %s\\n' \"$target\"\n ;;\n *)\n die \"record action must be start or stop\"\n ;;\n esac\n}\n\ncmd_snapshot() {\n local session=\"\"\n local dir=\"/tmp/auto-tmux-snapshot-$(date +%Y%m%d-%H%M%S)\"\n local lines=120\n while [[ $# -gt 0 ]]; do\n case \"$1\" in\n --session) session=\"${2:-}\"; shift 2 ;;\n --dir) dir=\"${2:-}\"; shift 2 ;;\n -n|--lines) lines=\"${2:-}\"; shift 2 ;;\n -h|--help) usage; exit 0 ;;\n *) die \"unknown snapshot option: $1\" ;;\n esac\n done\n\n require_tmux\n mkdir -p \"$dir/panes\"\n {\n printf 'auto-tmux snapshot\\n'\n printf 'created_at=%s\\n' \"$(date -Is)\"\n printf 'session=%s\\n\\n' \"${session:-<all>}\"\n cmd_topology ${session:+--session \"$session\"}\n } > \"$dir/topology.txt\"\n\n local pane safe_name\n while IFS= read -r pane; do\n [[ -n \"$pane\" ]] || continue\n safe_name=\"${pane//[:.]/-}.log\"\n capture_print \"$pane\" \"$lines\" 0 > \"$dir/panes/$safe_name\"\n done < <(pane_list \"$session\")\n\n printf 'snapshot written: %s\\n' \"$dir\"\n}\n\ncmd_hub() {\n local session=\"ai-hub\"\n local workers=3\n local worker_cmd=\"bash\"\n local commander_cmd=\"bash\"\n local attach=\"0\"\n while [[ $# -gt 0 ]]; do\n case \"$1\" in\n --session) session=\"${2:-}\"; shift 2 ;;\n --workers) workers=\"${2:-}\"; shift 2 ;;\n --cmd) worker_cmd=\"${2:-}\"; shift 2 ;;\n --commander-cmd) commander_cmd=\"${2:-}\"; shift 2 ;;\n --attach) attach=\"1\"; shift ;;\n -h|--help) usage; exit 0 ;;\n *) die \"unknown hub option: $1\" ;;\n esac\n done\n\n command -v tmux >/dev/null 2>&1 || die \"tmux is not installed or not in PATH\"\n if tmux has-session -t \"$session\" 2>/dev/null; then\n warn \"session already exists: $session\"\n tmux list-windows -t \"$session\" -F '#S:#I #{window_name}'\n else\n tmux new-session -d -s \"$session\" -n commander \"$commander_cmd\"\n local i\n for i in $(seq 1 \"$workers\"); do\n tmux new-window -t \"$session\" -n \"worker$i\" \"$worker_cmd\"\n done\n tmux select-window -t \"$session:commander\"\n printf 'created tmux AI hub: %s workers=%s cmd=%q\\n' \"$session\" \"$workers\" \"$worker_cmd\"\n fi\n if [[ \"$attach\" == \"1\" ]]; then\n tmux attach -t \"$session\"\n fi\n}\n\ncmd_cleanup() {\n local session=\"\"\n local dry_run=\"0\"\n local force=\"0\"\n while [[ $# -gt 0 ]]; do\n case \"$1\" in\n --session) session=\"${2:-}\"; shift 2 ;;\n --dry-run) dry_run=\"1\"; shift ;;\n --force) force=\"1\"; shift ;;\n -h|--help) usage; exit 0 ;;\n *) die \"unknown cleanup option: $1\" ;;\n esac\n done\n\n command -v tmux >/dev/null 2>&1 || die \"tmux is not installed or not in PATH\"\n [[ -n \"$session\" ]] || die \"cleanup requires --session NAME\"\n tmux has-session -t \"$session\" 2>/dev/null || die \"session not found: $session\"\n\n local attached windows\n attached=\"$(tmux display-message -pt \"$session\" '#{session_attached}' 2>/dev/null || printf '0')\"\n windows=\"$(tmux display-message -pt \"$session\" '#{session_windows}' 2>/dev/null || printf '?')\"\n printf 'cleanup target: session=%s windows=%s attached=%s\\n' \"$session\" \"$windows\" \"$attached\"\n\n if [[ \"$dry_run\" == \"1\" ]]; then\n printf '[dry-run] would kill session: %s\\n' \"$session\"\n return 0\n fi\n [[ \"$force\" == \"1\" ]] || die \"cleanup requires --force without --dry-run\"\n if [[ \"$attached\" != \"0\" ]]; then\n warn \"session is attached; killing anyway because --force was provided\"\n fi\n tmux kill-session -t \"$session\"\n printf 'session killed: %s\\n' \"$session\"\n}\n\ncmd_wait() {\n local target=\"\"\n local pattern=\"\"\n local timeout=60\n local interval=2\n local lines=80\n while [[ $# -gt 0 ]]; do\n case \"$1\" in\n -t|--target) target=\"${2:-}\"; shift 2 ;;\n --pattern) pattern=\"${2:-}\"; shift 2 ;;\n --timeout) timeout=\"${2:-}\"; shift 2 ;;\n --interval) interval=\"${2:-}\"; shift 2 ;;\n -n|--lines) lines=\"${2:-}\"; shift 2 ;;\n -h|--help) usage; exit 0 ;;\n *) die \"unknown wait option: $1\" ;;\n esac\n done\n\n require_tmux\n require_target \"$target\"\n [[ -n \"$pattern\" ]] || die \"wait requires --pattern REGEX\"\n\n local start now output\n start=\"$(date +%s)\"\n while true; do\n output=\"$(capture_raw \"$target\" \"$lines\")\"\n if printf '%s\\n' \"$output\" | grep -Eiq \"$pattern\"; then\n printf '%s\\n' \"$output\" | redact\n printf '[matched] target=%s pattern=%s\\n' \"$target\" \"$pattern\" >&2\n return 0\n fi\n now=\"$(date +%s)\"\n if (( now - start >= timeout )); then\n printf '%s\\n' \"$output\" | redact\n die \"timeout waiting for pattern: $pattern\"\n fi\n sleep \"$interval\"\n done\n}\n\nmain() {\n local cmd=\"${1:-help}\"\n shift || true\n case \"$cmd\" in\n help|-h|--help) usage ;;\n doctor) cmd_doctor \"$@\" ;;\n topology) cmd_topology \"$@\" ;;\n inspect) cmd_inspect \"$@\" ;;\n capture) cmd_capture \"$@\" ;;\n send) cmd_send \"$@\" ;;\n paste) cmd_paste \"$@\" ;;\n broadcast) cmd_broadcast \"$@\" ;;\n rescue) cmd_rescue \"$@\" ;;\n scan) cmd_scan \"$@\" ;;\n record) cmd_record \"$@\" ;;\n snapshot) cmd_snapshot \"$@\" ;;\n hub) cmd_hub \"$@\" ;;\n cleanup) cmd_cleanup \"$@\" ;;\n wait) cmd_wait \"$@\" ;;\n *) die \"unknown command: $cmd\" ;;\n esac\n}\n\nmain \"$@\"\n",
"sha256": "f473fddada7a7f5fd85afe94deccd16e2aba26195423dc87afbac176315b6567"
},
".github/tools/external/Skill_Seekers-development/pyproject.toml": {
"mode": "100644",
"encoding": "utf-8",
"data": "[build-system]\nrequires = [\"setuptools>=61.0\", \"wheel\"]\nbuild-backend = \"setuptools.build_meta\"\n\n[project]\nname = \"skill-seekers\"\nversion = \"3.5.1\"\ndescription = \"Convert documentation websites, GitHub repositories, and PDFs into Claude AI skills. International support with Chinese (简体中文) documentation.\"\nreadme = \"README.md\"\nrequires-python = \">=3.10\"\nlicense = {text = \"MIT\"}\nauthors = [\n {name = \"Yusuf Karaaslan\"}\n]\nkeywords = [\n \"claude\",\n \"ai\",\n \"documentation\",\n \"scraping\",\n \"skills\",\n \"llm\",\n \"mcp\",\n \"automation\",\n \"i18n\",\n \"chinese\",\n \"international\"\n]\nclassifiers = [\n \"Development Status :: 4 - Beta\",\n \"Intended Audience :: Developers\",\n \"License :: OSI Approved :: MIT License\",\n \"Operating System :: OS Independent\",\n \"Programming Language :: Python :: 3\",\n \"Programming Language :: Python :: 3.10\",\n \"Programming Language :: Python :: 3.11\",\n \"Programming Language :: Python :: 3.12\",\n \"Programming Language :: Python :: 3.13\",\n \"Topic :: Software Development :: Documentation\",\n \"Topic :: Software Development :: Libraries :: Python Modules\",\n \"Topic :: Text Processing :: Markup :: Markdown\",\n \"Natural Language :: English\",\n \"Natural Language :: Chinese (Simplified)\",\n]\n\n# Core dependencies\ndependencies = [\n \"requests>=2.32.5\",\n \"beautifulsoup4>=4.14.2\",\n \"PyGithub>=2.5.0\",\n \"GitPython>=3.1.40\",\n \"httpx>=0.28.1\", # Required for async scraping (core feature)\n \"anthropic>=0.76.0\", # Required for AI enhancement (core feature)\n \"PyMuPDF>=1.24.14\",\n \"Pillow>=11.0.0\",\n \"pydantic>=2.12.3\",\n \"pydantic-settings>=2.11.0\",\n \"python-dotenv>=1.1.1\",\n \"jsonschema>=4.25.1\",\n \"click>=8.3.0\",\n \"Pygments>=2.19.2\",\n \"pathspec>=0.12.1\",\n \"networkx>=3.0\",\n \"tomli>=2.0.0; python_version < '3.11'\", # TOML parser for version reading\n \"schedule>=1.2.0\", # Required for sync monitoring\n \"PyYAML>=6.0\", # Required for workflow preset management\n \"langchain>=1.2.10\",\n \"llama-index>=0.14.15\",\n]\n\n[project.optional-dependencies]\n# MCP server dependencies (NOW TRULY OPTIONAL)\nmcp = [\n \"mcp>=1.25,<2\",\n \"httpx>=0.28.1\",\n \"httpx-sse>=0.4.3\",\n \"uvicorn>=0.38.0\",\n \"starlette>=0.48.0\",\n \"sse-starlette>=3.0.2\",\n]\n\n# LLM platform-specific dependencies\n# Google Gemini support\ngemini = [\n \"google-generativeai>=0.8.0\",\n]\n\n# OpenAI ChatGPT support\nopenai = [\n \"openai>=1.0.0\",\n]\n\n# MiniMax AI support (uses OpenAI-compatible API)\nminimax = [\n \"openai>=1.0.0\",\n]\n\n# Kimi (Moonshot AI) support (uses OpenAI-compatible API)\nkimi = [\n \"openai>=1.0.0\",\n]\n\n# DeepSeek AI support (uses OpenAI-compatible API)\ndeepseek = [\n \"openai>=1.0.0\",\n]\n\n# Qwen (Alibaba) support (uses OpenAI-compatible API)\nqwen = [\n \"openai>=1.0.0\",\n]\n\n# OpenRouter support (uses OpenAI-compatible API)\nopenrouter = [\n \"openai>=1.0.0\",\n]\n\n# Together AI support (uses OpenAI-compatible API)\ntogether = [\n \"openai>=1.0.0\",\n]\n\n# Fireworks AI support (uses OpenAI-compatible API)\nfireworks = [\n \"openai>=1.0.0\",\n]\n\n# All LLM platforms combined\nall-llms = [\n \"google-generativeai>=0.8.0\",\n \"openai>=1.0.0\",\n]\n\n# Cloud storage support\ns3 = [\n \"boto3>=1.34.0\",\n]\n\ngcs = [\n \"google-cloud-storage>=2.10.0\",\n]\n\nazure = [\n \"azure-storage-blob>=12.19.0\",\n]\n\n# Word document (.docx) support\ndocx = [\n \"mammoth>=1.6.0\",\n \"python-docx>=1.1.0\",\n]\n\n# EPUB (.epub) support\nepub = [\n \"ebooklib>=0.18\",\n]\n\n# Video processing (lightweight: YouTube transcripts + metadata)\nvideo = [\n \"yt-dlp>=2024.12.0\",\n \"youtube-transcript-api>=1.2.0\",\n]\n\n# Video processing (full: + Whisper + visual extraction)\n# NOTE: easyocr removed — it pulls torch with the wrong GPU variant.\n# Use: skill-seekers video --setup (auto-detects GPU, installs correct PyTorch + easyocr)\nvideo-full = [\n \"yt-dlp>=2024.12.0\",\n \"youtube-transcript-api>=1.2.0\",\n \"faster-whisper>=1.0.0\",\n \"scenedetect[opencv]>=0.6.4\",\n \"opencv-python-headless>=4.9.0\",\n \"pytesseract>=0.3.13\",\n]\n\n# RAG vector database upload support\nchroma = [\n \"chromadb>=0.4.0\",\n]\n\nweaviate = [\n \"weaviate-client>=3.25.0\",\n]\n\nsentence-transformers = [\n \"sentence-transformers>=2.2.0\",\n]\n\npinecone = [\n \"pinecone>=5.0.0\",\n]\n\nrag-upload = [\n \"chromadb>=0.4.0\",\n \"weaviate-client>=3.25.0\",\n \"sentence-transformers>=2.2.0\",\n \"pinecone>=5.0.0\",\n]\n\n# All cloud storage providers combined\nall-cloud = [\n \"boto3>=1.34.0\",\n \"google-cloud-storage>=2.10.0\",\n \"azure-storage-blob>=12.19.0\",\n]\n\n# New source type dependencies (v3.2.0+)\njupyter = [\n \"nbformat>=5.9.0\",\n]\n\nasciidoc = [\n \"asciidoc>=10.0.0\",\n]\n\npptx = [\n \"python-pptx>=0.6.21\",\n]\n\nconfluence = [\n \"atlassian-python-api>=3.41.0\",\n]\n\nnotion = [\n \"notion-client>=2.0.0\",\n]\n\nrss = [\n \"feedparser>=6.0.0\",\n]\n\nchat = [\n \"slack-sdk>=3.27.0\",\n]\n\n# Headless browser for JavaScript SPA sites\nbrowser = [\n \"playwright>=1.40.0\",\n]\n\n# Embedding server support\nembedding = [\n \"fastapi>=0.109.0\",\n \"uvicorn>=0.27.0\",\n \"sentence-transformers>=2.3.0\",\n \"numpy>=1.24.0\",\n \"voyageai>=0.2.0\",\n]\n\n# All optional dependencies combined (dev dependencies now in [dependency-groups])\n# Note: video-full deps (opencv, easyocr, faster-whisper) excluded due to heavy\n# native dependencies. Install separately: pip install skill-seekers[video-full]\nall = [\n \"mammoth>=1.6.0\",\n \"python-docx>=1.1.0\",\n \"ebooklib>=0.18\",\n \"yt-dlp>=2024.12.0\",\n \"youtube-transcript-api>=1.2.0\",\n \"mcp>=1.25,<2\",\n \"httpx>=0.28.1\",\n \"httpx-sse>=0.4.3\",\n \"uvicorn>=0.38.0\",\n \"starlette>=0.48.0\",\n \"sse-starlette>=3.0.2\",\n \"google-generativeai>=0.8.0\",\n \"openai>=1.0.0\",\n \"boto3>=1.34.0\",\n \"google-cloud-storage>=2.10.0\",\n \"azure-storage-blob>=12.19.0\",\n \"chromadb>=0.4.0\",\n \"weaviate-client>=3.25.0\",\n \"pinecone>=5.0.0\",\n \"fastapi>=0.109.0\",\n \"sentence-transformers>=2.3.0\",\n \"numpy>=1.24.0\",\n \"voyageai>=0.2.0\",\n # New source types (v3.2.0+)\n \"nbformat>=5.9.0\",\n \"asciidoc>=10.0.0\",\n \"python-pptx>=0.6.21\",\n \"atlassian-python-api>=3.41.0\",\n \"notion-client>=2.0.0\",\n \"feedparser>=6.0.0\",\n \"slack-sdk>=3.27.0\",\n]\n\n[project.urls]\nHomepage = \"https://skillseekersweb.com/\"\nWebsite = \"https://skillseekersweb.com/\"\nRepository = \"https://github.com/yusufkaraaslan/Skill_Seekers\"\n\"Bug Tracker\" = \"https://github.com/yusufkaraaslan/Skill_Seekers/issues\"\nDocumentation = \"https://skillseekersweb.com/\"\n\"Config Browser\" = \"https://skillseekersweb.com/\"\n\"中文文档 (Chinese)\" = \"https://github.com/yusufkaraaslan/Skill_Seekers/blob/main/README.zh-CN.md\"\n\"Author\" = \"https://x.com/_yUSyUS_\"\n\"Website Repository\" = \"https://github.com/yusufkaraaslan/skillseekersweb\"\n\"Community Configs\" = \"https://github.com/yusufkaraaslan/skill-seekers-configs\"\n\"GitHub Action\" = \"https://github.com/yusufkaraaslan/skill-seekers-action\"\n\"Plugin\" = \"https://github.com/yusufkaraaslan/skill-seekers-plugin\"\n\"Homebrew Tap\" = \"https://github.com/yusufkaraaslan/homebrew-skill-seekers\"\n\n[project.scripts]\n# Main CLI entry point\nskill-seekers = \"skill_seekers.cli.main:main\"\n\n# Core commands\nskill-seekers-create = \"skill_seekers.cli.create_command:main\"\nskill-seekers-enhance = \"skill_seekers.cli.enhance_command:main\"\nskill-seekers-enhance-status = \"skill_seekers.cli.enhance_status:main\"\nskill-seekers-package = \"skill_seekers.cli.package_skill:main\"\nskill-seekers-upload = \"skill_seekers.cli.upload_skill:main\"\nskill-seekers-install = \"skill_seekers.cli.install_skill:main\"\nskill-seekers-install-agent = \"skill_seekers.cli.install_agent:main\"\n\n# Analysis & utilities\nskill-seekers-estimate = \"skill_seekers.cli.estimate_pages:main\"\nskill-seekers-patterns = \"skill_seekers.cli.pattern_recognizer:main\"\nskill-seekers-how-to-guides = \"skill_seekers.cli.how_to_guide_builder:main\"\nskill-seekers-quality = \"skill_seekers.cli.quality_metrics:main\"\nskill-seekers-workflows = \"skill_seekers.cli.workflows_command:main\"\n\n# Configuration & setup\nskill-seekers-config = \"skill_seekers.cli.config_command:main\"\nskill-seekers-doctor = \"skill_seekers.cli.doctor:main\"\nskill-seekers-setup = \"skill_seekers.cli.setup_wizard:main\"\nskill-seekers-resume = \"skill_seekers.cli.resume_command:main\"\nskill-seekers-sync-config = \"skill_seekers.cli.sync_config:main\"\n\n# Advanced\nskill-seekers-cloud = \"skill_seekers.cli.cloud_storage_cli:main\"\nskill-seekers-embed = \"skill_seekers.embedding.server:main\"\nskill-seekers-sync = \"skill_seekers.cli.sync_cli:main\"\nskill-seekers-benchmark = \"skill_seekers.cli.benchmark_cli:main\"\nskill-seekers-stream = \"skill_seekers.cli.streaming_ingest:main\"\nskill-seekers-update = \"skill_seekers.cli.incremental_updater:main\"\nskill-seekers-multilang = \"skill_seekers.cli.multilang_support:main\"\n\n[tool.setuptools]\npackage-dir = {\"\" = \"src\"}\n\n[tool.setuptools.packages.find]\nwhere = [\"src\"]\ninclude = [\"skill_seekers*\"]\nnamespaces = false\n\n[tool.setuptools.package-data]\nskill_seekers = [\"py.typed\", \"workflows/*.yaml\", \"cli/defaults.json\"]\n\n[tool.pytest.ini_options]\ntestpaths = [\"tests\"]\npython_files = [\"test_*.py\"]\npython_classes = [\"Test*\"]\npython_functions = [\"test_*\"]\naddopts = \"-v --tb=short --strict-markers\"\nmarkers = [\n \"asyncio: mark test as an async test\",\n \"slow: mark test as slow running (>5 seconds)\",\n \"integration: mark test as integration test (requires external services)\",\n \"e2e: mark test as end-to-end (resource-intensive, may create files)\",\n \"venv: mark test as requiring virtual environment setup\",\n \"bootstrap: mark test as bootstrap feature specific\",\n \"benchmark: mark test as performance benchmark\",\n]\nasyncio_mode = \"auto\"\nasyncio_default_fixture_loop_scope = \"function\"\n\n[tool.coverage.run]\nsource = [\"src/skill_seekers\"]\nomit = [\"*/tests/*\", \"*/__pycache__/*\", \"*/venv/*\"]\n\n[tool.coverage.report]\nexclude_lines = [\n \"pragma: no cover\",\n \"def __repr__\",\n \"raise AssertionError\",\n \"raise NotImplementedError\",\n \"if __name__ == .__main__.:\",\n \"if TYPE_CHECKING:\",\n \"@abstractmethod\",\n]\n\n[tool.ruff]\nline-length = 100\ntarget-version = \"py310\"\nsrc = [\"src\", \"tests\"]\n\n[tool.ruff.lint]\nselect = [\n \"E\", # pycodestyle errors\n \"W\", # pycodestyle warnings\n \"F\", # Pyflakes\n \"I\", # isort\n \"B\", # flake8-bugbear\n \"C4\", # flake8-comprehensions\n \"UP\", # pyupgrade\n \"ARG\", # flake8-unused-arguments\n \"SIM\", # flake8-simplify\n]\nignore = [\n \"E501\", # line too long (handled by formatter)\n \"F541\", # f-string without placeholders (style preference)\n \"ARG002\", # unused method argument (often needed for interface compliance)\n \"B007\", # loop control variable not used (sometimes intentional)\n \"I001\", # import block unsorted (handled by formatter)\n \"SIM114\", # combine if branches (style preference, can reduce readability)\n]\n\n[tool.ruff.lint.isort]\nknown-first-party = [\"skill_seekers\"]\n\n[tool.mypy]\npython_version = \"3.10\"\nwarn_return_any = true\nwarn_unused_configs = true\ndisallow_untyped_defs = false\ndisallow_incomplete_defs = false\ncheck_untyped_defs = true\nignore_missing_imports = true\nshow_error_codes = true\npretty = true\n\n[[tool.mypy.overrides]]\nmodule = \"tests.*\"\ndisallow_untyped_defs = false\ncheck_untyped_defs = false\n\n[dependency-groups]\ndev = [\n # Core testing\n \"pytest>=8.4.2\",\n \"pytest-asyncio>=0.24.0\",\n \"pytest-cov>=7.0.0\",\n \"coverage>=7.11.0\",\n\n # Code quality\n \"ruff>=0.14.13\",\n \"mypy>=1.19.1\",\n\n # Test dependencies (Kimi's finding #3)\n \"psutil>=5.9.0\", # Process utilities for testing\n \"numpy>=1.24.0\", # Numerical operations\n \"starlette>=0.31.0\", # HTTP transport testing\n \"httpx>=0.24.0\", # HTTP client for testing\n\n # Cloud storage testing (Kimi's finding #2)\n \"boto3>=1.26.0\", # AWS S3\n \"google-cloud-storage>=2.10.0\", # Google Cloud Storage\n \"azure-storage-blob>=12.17.0\", # Azure Blob Storage\n]\n",
"sha256": "40820d20d8f56c1dc24c8f432141fa438d54473acbfecfa716fc9d188cbc8294"
},
".github/tools/external/Skill_Seekers-development/src/skill_seekers/cli/main.py": {
"mode": "100644",
"encoding": "utf-8",
"data": "#!/usr/bin/env python3\n\"\"\"\nSkill Seekers - Unified CLI Entry Point\n\nConvert documentation, codebases, and repositories into AI skills.\n\nUsage:\n skill-seekers <command> [options]\n\nCommands:\n create Create skill from any source (auto-detects type)\n enhance AI-powered enhancement (auto: API or LOCAL mode)\n enhance-status Check enhancement status (for background/daemon modes)\n package Package skill into .zip file\n upload Upload skill to target platform\n install One-command workflow (scrape + enhance + package + upload)\n install-agent Install skill to AI agent directories\n estimate Estimate page count before scraping\n extract-test-examples Extract usage examples from test files\n resume Resume interrupted scraping job\n config Configure GitHub tokens, API keys, and settings\n doctor Health check for dependencies and configuration\n\nExamples:\n skill-seekers create https://react.dev\n skill-seekers create owner/repo\n skill-seekers create ./document.pdf\n skill-seekers create configs/unity-spine.json\n skill-seekers create configs/unity-spine.json --enhance-workflow unity-game-dev\n skill-seekers enhance output/react/\n skill-seekers package output/react/\n\"\"\"\n\nimport argparse\nimport importlib\nimport sys\n\nfrom skill_seekers.cli import __version__\n\n\n# Command module mapping (command name -> module path)\nCOMMAND_MODULES = {\n # Skill creation — unified entry point for all 18 source types\n \"create\": \"skill_seekers.cli.create_command\",\n # Enhancement & packaging\n \"enhance\": \"skill_seekers.cli.enhance_command\",\n \"enhance-status\": \"skill_seekers.cli.enhance_status\",\n \"package\": \"skill_seekers.cli.package_skill\",\n \"upload\": \"skill_seekers.cli.upload_skill\",\n \"install\": \"skill_seekers.cli.install_skill\",\n \"install-agent\": \"skill_seekers.cli.install_agent\",\n # Utilities\n \"estimate\": \"skill_seekers.cli.estimate_pages\",\n \"extract-test-examples\": \"skill_seekers.cli.test_example_extractor\",\n \"resume\": \"skill_seekers.cli.resume_command\",\n \"quality\": \"skill_seekers.cli.quality_metrics\",\n # Configuration & workflows\n \"config\": \"skill_seekers.cli.config_command\",\n \"doctor\": \"skill_seekers.cli.doctor\",\n \"workflows\": \"skill_seekers.cli.workflows_command\",\n \"sync-config\": \"skill_seekers.cli.sync_config\",\n # Advanced (less common)\n \"stream\": \"skill_seekers.cli.streaming_ingest\",\n \"update\": \"skill_seekers.cli.incremental_updater\",\n \"multilang\": \"skill_seekers.cli.multilang_support\",\n}\n\n\ndef create_parser() -> argparse.ArgumentParser:\n \"\"\"Create the main argument parser with subcommands.\"\"\"\n from skill_seekers.cli.parsers import register_parsers\n\n parser = argparse.ArgumentParser(\n prog=\"skill-seekers\",\n description=\"Convert documentation, GitHub repos, and PDFs into AI skills\",\n formatter_class=argparse.RawDescriptionHelpFormatter,\n epilog=\"\"\"\nExamples:\n # Create skill from documentation (auto-detects source type)\n skill-seekers create https://docs.react.dev --name react\n\n # Create skill from GitHub repository\n skill-seekers create microsoft/TypeScript --name typescript\n\n # Create skill from PDF file\n skill-seekers create ./documentation.pdf --name mydocs\n\n # AI-powered enhancement\n skill-seekers enhance output/react/\n\n # Package and upload\n skill-seekers package output/react/\n skill-seekers upload output/react.zip\n\nFor more information: https://github.com/yusufkaraaslan/Skill_Seekers\n \"\"\",\n )\n\n parser.add_argument(\"--version\", action=\"version\", version=f\"%(prog)s {__version__}\")\n\n # Create subparsers\n subparsers = parser.add_subparsers(\n dest=\"command\",\n title=\"commands\",\n description=\"Available Skill Seekers commands\",\n help=\"Command to run\",\n )\n\n # Register all subcommand parsers\n register_parsers(subparsers)\n\n return parser\n\n\ndef _reconstruct_argv(command: str, args: argparse.Namespace) -> list[str]:\n \"\"\"Reconstruct sys.argv from args namespace for command module.\n\n DEPRECATED: Use ExecutionContext instead. This function is kept for\n backward compatibility and will be removed in a future version.\n\n Args:\n command: Command name\n args: Parsed arguments namespace\n\n Returns:\n List of command-line arguments for the command module\n \"\"\"\n argv = [f\"{command}_command.py\"]\n\n # Convert args to sys.argv format\n for key, value in vars(args).items():\n if key == \"command\":\n continue\n\n # Handle internal/progressive help flags for create command\n # Convert _help_web to --help-web etc.\n if key.startswith(\"_help_\"):\n if value:\n # Convert _help_web -> --help-web\n help_flag = key.replace(\"_help_\", \"help-\")\n argv.append(f\"--{help_flag}\")\n continue\n\n # Handle positional arguments (no -- prefix)\n if key in [\n \"source\", # create command\n \"directory\",\n \"file\",\n \"job_id\",\n \"skill_directory\",\n \"zip_file\",\n \"input_file\",\n ]:\n if value is not None and value != \"\":\n argv.append(str(value))\n continue\n\n # Handle flags and options\n arg_name = f\"--{key.replace('_', '-')}\"\n\n if isinstance(value, bool):\n if value:\n argv.append(arg_name)\n elif isinstance(value, list):\n for item in value:\n argv.extend([arg_name, str(item)])\n elif value is not None:\n argv.extend([arg_name, str(value)])\n\n return argv\n\n\ndef main(argv: list[str] | None = None) -> int:\n \"\"\"Main entry point for the unified CLI.\n\n Args:\n argv: Command-line arguments (defaults to sys.argv)\n\n Returns:\n Exit code (0 for success, non-zero for error)\n \"\"\"\n if argv is None:\n argv = sys.argv[1:]\n\n parser = create_parser()\n args = parser.parse_args(argv)\n\n if not args.command:\n parser.print_help()\n return 1\n\n # Note: ExecutionContext is initialized by individual commands (e.g., create_command,\n # enhance_command) with the correct config_path and source_info. Do NOT initialize\n # it here — commands need to set config_path which requires source detection first.\n\n # Get command module\n module_name = COMMAND_MODULES.get(args.command)\n if not module_name:\n print(f\"Error: Unknown command '{args.command}'\", file=sys.stderr)\n parser.print_help()\n return 1\n\n # create command: call directly with parsed args (no argv reconstruction)\n if args.command == \"create\":\n # Handle --help-* flags before execute (no source needed for help)\n from skill_seekers.cli.arguments.create import add_create_arguments\n\n help_modes = {\n \"_help_web\": \"web\",\n \"_help_github\": \"github\",\n \"_help_local\": \"local\",\n \"_help_pdf\": \"pdf\",\n \"_help_word\": \"word\",\n \"_help_epub\": \"epub\",\n \"_help_video\": \"video\",\n \"_help_config\": \"config\",\n \"_help_advanced\": \"advanced\",\n \"_help_all\": \"all\",\n }\n for attr, mode in help_modes.items():\n if getattr(args, attr, False):\n help_parser = argparse.ArgumentParser(\n prog=\"skill-seekers create\",\n description=f\"Create skill — {mode} options\",\n formatter_class=argparse.RawDescriptionHelpFormatter,\n )\n add_create_arguments(help_parser, mode=mode)\n help_parser.print_help()\n return 0\n\n from skill_seekers.cli.create_command import CreateCommand\n\n command = CreateCommand(args)\n return command.execute()\n\n # Standard delegation for all other commands\n try:\n # Import and execute command module\n module = importlib.import_module(module_name)\n\n # Reconstruct sys.argv for command module\n original_argv = sys.argv.copy()\n sys.argv = _reconstruct_argv(args.command, args)\n\n # Execute command\n try:\n result = module.main()\n return result if result is not None else 0\n finally:\n sys.argv = original_argv\n\n except KeyboardInterrupt:\n print(\"\\n\\nInterrupted by user\", file=sys.stderr)\n return 130\n except Exception as e:\n error_msg = str(e) if str(e) else f\"{type(e).__name__} occurred\"\n print(f\"Error: {error_msg}\", file=sys.stderr)\n\n # Show traceback in verbose mode\n import traceback\n\n if hasattr(args, \"verbose\") and getattr(args, \"verbose\", False):\n traceback.print_exc()\n\n return 1\n\n\nif __name__ == \"__main__\":\n sys.exit(main())\n",
"sha256": "8c02660dacd304f51fe8c4a9685d3f6d5324a7eef7779b6baa7325827bf01985"
},
".github/tools/external/.tmux/README.md": {
"mode": "100644",
"encoding": "utf-8",
"data": "<p align=\"center\">\n <picture>\n <source media=\"(prefers-color-scheme: light)\" srcset=\".logo/logomark+wordmark.svg\">\n <source media=\"(prefers-color-scheme: dark)\" srcset=\".logo/logomark+wordmark.svg\">\n <img alt=\"Oh my tmux! logo and wordmark\" src=\".logo/logomark+wordmark.svg\">\n </picture>\n</p>\n\n˗ˏˋ ★ ˎˊ˗ My self-contained, pretty and versatile tmux configuration, made with ❤️ ˗ˏˋ ★ ˎˊ˗\n\n<p align=\"center\">\n <picture>\n <source media=\"(prefers-color-scheme: light)\" srcset=\"https://cloud.githubusercontent.com/assets/553208/19740585/85596a5a-9bbf-11e6-8aa1-7c8d9829c008.gif\">\n <source media=\"(prefers-color-scheme: dark)\" srcset=\"https://cloud.githubusercontent.com/assets/553208/19740585/85596a5a-9bbf-11e6-8aa1-7c8d9829c008.gif\">\n <img alt=\"Oh my tmux! in action\" src=\"https://cloud.githubusercontent.com/assets/553208/19740585/85596a5a-9bbf-11e6-8aa1-7c8d9829c008.gif\">\n </picture>\n</p>\n\nInstallation\n------------\n\n**Requirements:**\n\n - tmux **`>= 2.6`** running on Linux, macOS, OpenBSD, Windows (WSL or Cygwin)\n - awk, perl (with Time::HiRes support), grep, and sed\n - Outside of tmux, the `TERM` environment variable must be set to\n `xterm-256color`\n\n⚠️ Before installing, you may want to backup your existing configuration.\n\nYou can install Oh my tmux! at any of the following locations:\n- `~`\n- `$XDG_CONFIG_HOME/tmux`\n- `~/.config/tmux`\n\n**Automatic installation**\n\nCopy the following command and paste it in your terminal.\n```\ncurl -fsSL \"https://github.com/gpakosz/.tmux/raw/refs/heads/master/install.sh#$(date +%s)\" | bash\n```\n\n**Manual installation in `~`**\n```\n$ cd\n$ git clone --single-branch https://github.com/gpakosz/.tmux.git\n$ ln -s -f .tmux/.tmux.conf\n$ cp .tmux/.tmux.conf.local .\n```\n\n**Manual installation in `$XDG_CONFIG_HOME/tmux`**\n```\n$ git clone --single-branch https://github.com/gpakosz/.tmux.git \"/path/to/oh-my-tmux\"\n$ mkdir -p \"$XDG_CONFIG_HOME/tmux\"\n$ ln -s /path/to/oh-my-tmux/.tmux.conf \"$XDG_CONFIG_HOME/tmux/tmux.conf\"\n$ cp /path/to/oh-my-tmux/.tmux.conf.local \"$XDG_CONFIG_HOME/tmux/tmux.conf.local\"\n```\n\n**Manual installation `~/.config/tmux`**\n```\n$ git clone --single-branch https://github.com/gpakosz/.tmux.git \"/path/to/oh-my-tmux\"\n$ mkdir -p ~/.config/tmux\n$ ln -s /path/to/oh-my-tmux/.tmux.conf ~/.config/tmux/tmux.conf\n$ cp /path/to/oh-my-tmux/.tmux.conf.local ~/.config/tmux/tmux.conf.local\n```\n⚠️ When installing `$XDG_CONFIG_HOME/tmux` or `~/.config/tmux`, the configuration\nfile names don't have a leading `.` character.\n\n🚨 **You should never alter the main `.tmux.conf` or `tmux.conf` file. If you do,\nyou're on your own. Instead, every customization should happen in your\n`.tmux.conf.local` or `tmux.conf.local` customization file copy.**\n\nIf you're a Vim user, setting the `VIUAL` or `EDITOR` environment variable to\n`vim` will enable and further customize the `vi-style` key bindings (see tmux\nmanual).\n\nIf you're new to tmux, I recommend you to read the [tmux getting started\nguide][getting-started], as well as the [tmux 3: Productive Mouse-Free\nDevelopment][bhtmux3] book by [@bphogan].\n\nNow proceed to [adjust] your `.local` customization file copy.\n\n[getting-started]: https://github.com/tmux/tmux/wiki/Getting-Started\n[bhtmux3]: https://pragprog.com/titles/bhtmux3/tmux-3/\n[@bphogan]: https://bphogan.com/\n[adjust]: #configuration\n\nTroubleshooting\n---------------\n\n - **I believe something's not quite right**\n\n Please, try make sure no tmux client or server process is currently running.\n\n Then launch tmux with:\n ```\n $ tmux -f /dev/null -L test\n ```\n\n Which launches a new tmux client/server pair without loading any\n configuration.\n\n If the issue is still reproducing, please reach out to the tmux project for\n support.\n\n Otherwise, please open an issue describing what doesn't work and I'll do my\n best to address it.\n\n - **I tried to used `set`, `bind` and `unbind` in my `.local` customization\n file, but Oh my tmux! overwrites my preferences**\n\n When that happens append `#!important` to the line:\n\n ```\n bind c new-window -c '#{pane_current_path}' #!important\n ```\n\n ```\n set -g default-terminal \"screen-256color\" #!important\n ```\n\n - **Status line is broken and/or gets duplicated at the bottom of the screen**\n\n This could happen on Linux when the distribution provides a version of glib\n that received Unicode 9.0 upgrades (glib `>= 2.50.1`) while providing a\n version of glibc that didn't (glibc `< 2.26`). You may also configure\n `LC_CTYPE` to use an `UTF-8` locale. Typically VTE based terminal emulators\n rely on glib's `g_unichar_iswide()` function while tmux relies on glibc's\n `wcwidth()` function. When these two functions disagree, display gets messed\n up.\n\n This can also happen on macOS when using iTerm2 and \"Use Unicode version 9\n character widths\" is enabled in `Preferences... > Profiles > Text`\n\n For that reason, the sample `.local` customization file stopped using\n Unicode characters for which width changed in between Unicode 8.0 and 9.0\n standards, as well as Emojis.\n\n - **I installed Powerline and/or (patched) fonts but I can't see the Powerline\n symbols**\n\n **🤯 Please realize that you don't need to install [Powerline].**\n\n You only need fonts patched with Powerline symbols or the standalone\n `PowerlineSymbols.otf` font.\n\n Then make sure your `.local` customization file copy uses the [Powerline\n code points] for the\n `tmux_conf_theme_left_separator_main`,\n `tmux_conf_theme_left_separator_sub`,\n `tmux_conf_theme_right_separator_main`\n and `tmux_conf_theme_right_separator_sub` variables.\n\n[Powerline]: https://github.com/Lokaltog/powerline\n[Powerline code points]: #enabling-the-powerline-look\n\nFeatures\n--------\n\n - `C-a` acts as secondary prefix, while keeping default `C-b` prefix\n - Visual theme inspired by [Powerline][]\n - [Maximize any pane to a new window with `<prefix> +`][maximize-pane]\n - Mouse mode toggle with `<prefix> m`\n - Laptop battery status line information\n - Uptime status line information\n - Optional highlight of focused pane\n - Configurable new sessions, windows and panes behavior (to optionally retain\n the current path)\n - SSH/Mosh aware username and hostname status line information\n - SSH/Mosh aware pane splitting (with automatic reconnection to the remote\n server)\n - Copy to OS clipboard (needs `xsel`, `xclip`, or `wl-copy` on Linux)\n - Support for 4-digit hexadecimal Unicode characters\n - [PathPicker][] integration, if available\n - [Urlscan][] (preferred) or [Urlview][] integration, if available\n\n[maximize-pane]: http://pempek.net/articles/2013/04/14/maximizing-tmux-pane-new-window/\n[PathPicker]: https://facebook.github.io/PathPicker/\n[Urlview]: https://packages.debian.org/stable/misc/urlview\n[Urlscan]: https://github.com/firecat53/urlscan\n\nThe \"Maximize any pane to a new window with `<prefix> +`\" feature is different\nfrom the builtin `resize-pane -Z` command, as it allows you to further split a maximized\npane. It's also more flexible by allowing you to maximize a pane to a new\nwindow, then change window, then go back and the pane is still in maximized\nstate in its own window. You can then minimize a pane by using `<prefix> +`\neither from the source window or the maximized window.\n\n<p align=\"center\">\n <picture>\n <source media=\"(prefers-color-scheme: light)\" srcset=\"https://cloud.githubusercontent.com/assets/553208/9890858/ee3c0ca6-5c02-11e5-890e-05d825a46c92.gif\">\n <source media=\"(prefers-color-scheme: dark)\" srcset=\"https://cloud.githubusercontent.com/assets/553208/9890858/ee3c0ca6-5c02-11e5-890e-05d825a46c92.gif\">\n <img alt=\"Maximizing a pane\" src=\"https://cloud.githubusercontent.com/assets/553208/9890858/ee3c0ca6-5c02-11e5-890e-05d825a46c92.gif\">\n </picture>\n</p>\n\nMouse mode allows you to set the active window, set the active pane, resize\npanes and automatically switches to copy-mode to select text.\n\n<p align=\"center\">\n <picture>\n <source media=\"(prefers-color-scheme: light)\" srcset=\"https://cloud.githubusercontent.com/assets/553208/9890797/8dffe542-5c02-11e5-9c06-a25b452e6fcc.gif\">\n <source media=\"(prefers-color-scheme: dark)\" srcset=\"https://cloud.githubusercontent.com/assets/553208/9890797/8dffe542-5c02-11e5-9c06-a25b452e6fcc.gif\">\n <img alt=\"Mouse mode\" src=\"https://cloud.githubusercontent.com/assets/553208/9890797/8dffe542-5c02-11e5-9c06-a25b452e6fcc.gif\">\n </picture>\n</p>\n\nBindings\n--------\n\ntmux may be controlled from an attached client by using a key combination of a\nprefix key, followed by a command key. This configuration uses `C-a` as a\nsecondary prefix while keeping `C-b` as the default prefix. In the following\nlist of key bindings:\n - `<prefix>` means you have to either hit <kbd>Ctrl</kbd> + <kbd>a</kbd> or <kbd>Ctrl</kbd> + <kbd>b</kbd>\n - `<prefix> c` means you have to hit <kbd>Ctrl</kbd> + <kbd>a</kbd> or <kbd>Ctrl</kbd> + <kbd>b</kbd> followed by <kbd>c</kbd>\n - `<prefix> C-c` means you have to hit <kbd>Ctrl</kbd> + <kbd>a</kbd> or <kbd>Ctrl</kbd> + <kbd>b</kbd> followed by <kbd>Ctrl</kbd> + <kbd>c</kbd>\n\nThis configuration uses the following bindings:\n\n - `<prefix> e` opens the `.local` customization file copy with the editor\n defined by the `VISUAL` or `EDITOR` environment variable (defaults to `vim`\n when empty)\n - `<prefix> r` reloads the configuration\n - `C-l` clears both the screen **and** the tmux history\n\n - `<prefix> C-c` creates a new session\n - `<prefix> C-f` lets you switch to another session by name\n\n - `<prefix> C-h` and `<prefix> C-l` let you navigate windows (default\n `<prefix> n` is unbound and `<prefix> p` is repurposed)\n - `<prefix> Tab` brings you to the last active window\n\n - `<prefix> -` splits the current pane vertically\n - `<prefix> _` splits the current pane horizontally\n - `<prefix> h`, `<prefix> j`, `<prefix> k` and `<prefix> l` let you navigate\n panes ala Vim\n - `<prefix> H`, `<prefix> J`, `<prefix> K`, `<prefix> L` let you resize panes\n - `<prefix> <` and `<prefix> >` let you swap panes\n - `<prefix> +` maximizes the current pane to a new window\n\n - `<prefix> m` toggles mouse mode on or off\n\n - `<prefix> U` launches Urlscan (preferred) or Urlview, if available\n - `<prefix> F` launches Facebook PathPicker, if available\n\n - `<prefix> Enter` enters copy-mode\n - `<prefix> b` lists the paste-buffers\n - `<prefix> p` pastes from the top paste-buffer\n - `<prefix> P` lets you choose the paste-buffer to paste from\n\nAdditionally, `copy-mode-vi` matches [my own Vim configuration]\n\n[my own Vim configuration]: https://github.com/gpakosz/.vim.git\n\nBindings for `copy-mode-vi`:\n\n - `v` begins selection / visual mode\n - `C-v` toggles between blockwise visual mode and visual mode\n - `H` jumps to the start of line\n - `L` jumps to the end of line\n - `y` copies the selection to the top paste-buffer\n - `Escape` cancels the current operation\n\nIt's also possible to preserve the tmux stock bindings by setting the\n`tmux_conf_preserve_stock_bindings` variable to `true` in your `.local`\ncustomization file copy.\n\nConfiguration\n-------------\n\nWhile this configuration tries to bring sane default settings, you may want to\ncustomize it further to your needs.\n\n🚨 Again, you should never alter the main `.tmux.conf` or `tmux.conf` file.\nIf you do, you're on your own.\n\nPlease refer to the sample `.local` customization file to know more about the\nvariables that allow you to alter different behaviors. Upon successful\ninstallation, pressing `<prefix> e` will open your `.local` customization file\ncopy with the editor defined by the `VISUAL` or `EDITOR` environment variable\n(defaults to `vim` when empty).\n\n### Enabling the Powerline look\n\nPowerline originated as a status-line plugin for Vim. Its popular eye-catching\nlook is based on the use of special symbols:\n\n<p align=\"center\">\n <picture>\n <source media=\"(prefers-color-scheme: light)\" srcset=\"https://github.com/user-attachments/assets/55afd317-150b-42f0-9ef3-fa619be7b160\">\n <source media=\"(prefers-color-scheme: dark)\" srcset=\"https://github.com/user-attachments/assets/55afd317-150b-42f0-9ef3-fa619be7b160\">\n <img alt=\"Powerline symbols\" src=\"https://github.com/user-attachments/assets/55afd317-150b-42f0-9ef3-fa619be7b160\">\n </picture>\n</p>\n\nTo make use of these symbols, there are several options:\n\n - Use a font that already bundles those: this is the case of the [Source Code\n Pro][source code pro] font\n - Use a [pre-patched font][powerline patched fonts]\n - Use your preferred font along with the standalone [Powerline font][powerline\n font] (that only contains the Powerline symbols): [this highly depends on\n your operating system and your terminal emulator][terminal support], for\n instance here's a screenshot of iTerm2 configured to use\n `PowerlineSymbols.otf` for non ASCII symbols:\n <p align=\"center\">\n <picture>\n <source media=\"(prefers-color-scheme: light)\" srcset=\"https://user-images.githubusercontent.com/553208/62243890-8232f500-b3de-11e9-9b8c-51a5d38bdaa8.png\">\n <source media=\"(prefers-color-scheme: dark)\" srcset=\"https://user-images.githubusercontent.com/553208/62243890-8232f500-b3de-11e9-9b8c-51a5d38bdaa8.png\">\n <img alt=\"iTerm2 + Powerline font\" src=\"https://user-images.githubusercontent.com/553208/62243890-8232f500-b3de-11e9-9b8c-51a5d38bdaa8.png\">\n </picture>\n </p>\n\n[source code pro]: https://github.com/adobe-fonts/source-code-pro/releases/latest\n[powerline patched fonts]: https://github.com/powerline/fonts\n[powerline font]: https://github.com/powerline/powerline/raw/develop/font/PowerlineSymbols.otf\n[terminal support]: http://powerline.readthedocs.io/en/master/usage.html#usage-terminal-emulators\n\nThen edit your `.local` customization file copy (with `<prefix> e`) and adjust\nthe following variables:\n\n```\ntmux_conf_theme_left_separator_main='\\uE0B0'\ntmux_conf_theme_left_separator_sub='\\uE0B1'\ntmux_conf_theme_right_separator_main='\\uE0B2'\ntmux_conf_theme_right_separator_sub='\\uE0B3'\n```\n\nThe [Powerline manual] contains further details on how to install fonts\ncontaining the Powerline symbols.\n\n[Powerline manual]: http://powerline.readthedocs.org/en/latest/installation.html#fonts-installation\n\n### Configuring the status line\n\nEdit your `.local` customization file copy (`<prefix> e`) and adjust the\n`tmux_conf_theme_status_left` and `tmux_conf_theme_status_right` variables to\nyour liking.\n\nThis configuration supports the following builtin variables:\n\n - `#{battery_bar}`: horizontal battery charge bar\n - `#{battery_hbar}`: 1 character wide, horizontal battery charge bar\n - `#{battery_vbar}`: 1 character wide, vertical battery charge bar\n - `#{battery_percentage}`: battery percentage\n - `#{battery_status}`: is battery charging or discharging?\n - `#{circled_session_name}`: circled session number (from ⓪) to ⑳)\n - `#{hostname}`: SSH/Mosh aware hostname information\n - `#{hostname_ssh}`: SSH/Mosh aware hostname information, blank when not\n connected to a remote server through SSH/Mosh\n - `#{loadavg}`: load average\n - `#{pairing}`: is the current session attached to more than one client?\n - `#{pretty_pane_current_path}`: prettified `#{pane_current_path}` when its\n length is too long\n - `#{prefix}`: is prefix being depressed?\n - `#{root}`: is the current user root?\n - `#{synchronized}`: are the panes synchronized?\n - `#{uptime_y}`: uptime years\n - `#{uptime_d}`: uptime days, modulo 365 when `#{uptime_y}` is used\n - `#{uptime_h}`: uptime hours\n - `#{uptime_m}`: uptime minutes\n - `#{uptime_s}`: uptime seconds\n - `#{username}`: SSH/Mosh aware username information\n - `#{username_ssh}`: SSH aware username information, blank when not connected\n to a remote server through SSH/Mosh\n\nBeside the variables mentioned above, the `tmux_conf_theme_status_left` and\n`tmux_conf_theme_status_right` variables support the usual tmux syntax, e.g.\nusing `#()` to call an external command that inserts weather information\nprovided by [wttr.in]:\n```\ntmux_conf_theme_status_right='#{prefix}#{pairing}#{synchronized} #(curl -m 1 wttr.in?format=3 2>/dev/null; sleep 900) , %R , %d %b | #{username}#{root} | #{hostname} '\n```\nThe `sleep 900` call makes sure the network request is issued at most every 15\nminutes whatever the value of `status-interval`.\n\n<p align=\"center\">\n <picture>\n <source media=\"(prefers-color-scheme: light)\" srcset=\"https://user-images.githubusercontent.com/553208/52175490-07797c00-27a5-11e9-9fb6-42eec4fe4188.png\">\n <source media=\"(prefers-color-scheme: dark)\" srcset=\"https://user-images.githubusercontent.com/553208/52175490-07797c00-27a5-11e9-9fb6-42eec4fe4188.png\">\n <img alt=\"Weather information from wttr.in\" src=\"https://user-images.githubusercontent.com/553208/52175490-07797c00-27a5-11e9-9fb6-42eec4fe4188.png\">\n </picture>\n</p>\n\n[wttr.in]: https://github.com/chubin/wttr.in#one-line-output\n\n💡 You can also define your own custom variables by defining your own POSIX\nshell functions, see the sample `.local` customization file for instructions.\n\nFinally, remember that `tmux_conf_theme_status_left` and\n`tmux_conf_theme_status_right` end up being given to tmux as `status-left` and\n`status-right` which means they're passed through `strftime()`. As such, the `%`\ncharacter has a special meaning and needs to be escaped by doubling it, e.g.\n```\ntmux_conf_theme_status_right='#(echo foo %% bar)'\n```\nSee also `man 3 strftime`.\n\n### Using TPM plugins\n\nThis configuration comes with built-in [TPM] support:\n\n - Use the `set -g @plugin ...` syntax to enable a plugin\n - Whenever a plugin introduces a variable to be used in `status-left` or\n `status-right`, you can use it in the `tmux_conf_theme_status_left` and\n `tmux_conf_theme_status_right` variables, see instructions above 👆\n - ⚠️ Do not add `set -g @plugin 'tmux-plugins/tpm'` to any configuration file\n - ⛔️ Do not add `run '~/.tmux/plugins/tpm/tpm'` to any configuration file\n\n⚠️ The TPM bindings differ slightly from upstream:\n - Installing plugins: `<prefix> + I`\n - Uninstalling plugins: `<prefix> + Alt + u`\n - Updating plugins: `<prefix> + u`\n\nSee the sample `.local` customization file for further instructions.\n\n[TPM]: https://github.com/tmux-plugins/tpm\n\n### Using Oh my tmux! on Windows\n\n<p align=\"center\">\n <picture>\n <source media=\"(prefers-color-scheme: light)\" srcset=\"https://github.com/user-attachments/assets/7f84a687-fb4d-4817-a445-419e63ccfac5\">\n <source media=\"(prefers-color-scheme: dark)\" srcset=\"https://github.com/user-attachments/assets/7f84a687-fb4d-4817-a445-419e63ccfac5\">\n <img alt=\"Windows Terminal + WSL\" src=\"https://github.com/user-attachments/assets/7f84a687-fb4d-4817-a445-419e63ccfac5\">\n </picture>\n</p>\n\n⚠️ I don't recommend running this configuration with [Cygwin] anymore. Forking\nunder Cygwin is extremely slow and this configuration issues a fair amount\n`run-shell` commands under the hood. As such, you will experience high CPU\nusage.\n\nInstead I recommend [Windows Subsystem for Linux][WSL] along with [Windows\nTerminal]. As an alternative, you may also consider using [Mintty as a terminal\nfor WSL][wsltty].\n\n[Cygwin]: https://www.cygwin.com\n[WSL]: https://learn.microsoft.com/en-us/windows/wsl\n[wsltty]: https://github.com/mintty/wsltty\n[Windows Terminal]: https://aka.ms/terminal\n",
"sha256": "10b0cca6bb2a4ab7af39d76d27f51b91ca1df4dead015315400041695c9471e7"
},
".github/tools/external/.tmux/.tmux.conf": {
"mode": "100644",
"encoding": "utf-8",
"data": "# : << 'EOF'\n# Oh my tmux!\n# 💛🩷💙🖤❤️🤍\n# https://github.com/gpakosz/.tmux\n# (‑●‑●)> dual licensed under the WTFPL v2 license and the MIT license,\n# without any warranty.\n# Copyright 2012— Gregory Pakosz (@gpakosz).\n#\n# ------------------------------------------------------------------------------\n# 🚨 DO NOT MODIFY THIS FILE\n# instead, override your .local customization file copy, see README.md\n# ------------------------------------------------------------------------------\n\n\n# -- general -------------------------------------------------------------------\n\nset -g default-terminal \"screen-256color\"\n\n%if #{>=:#{version},3.2}\nset -g extended-keys #{?#{||:#{m/ri:mintty|iTerm,#{TERM_PROGRAM}},#{!=:#{XTERM_VERSION},}},on,off} # needed by Control + Shift bindings\n%endif\nset -s escape-time 10 # faster command sequences\nset -sg repeat-time 600 # increase repeat timeout\nset -s focus-events on\n\nset -g prefix2 C-a # GNU-Screen compatible prefix\nbind C-a send-prefix -2\n\nset -q -g status-utf8 on # expect UTF-8 (tmux < 2.2)\nsetw -q -g utf8 on\n\nset -g history-limit 5000 # boost history\n\n# edit configuration\nbind e new-window -n \"#{TMUX_CONF_LOCAL}\" sh -c '_E=${VISUAL:-${EDITOR:-vim}}; case \"$_E\" in *vim*) $_E -c \":set syntax=tmux\" \"$TMUX_CONF_LOCAL\";; *) $_E \"$TMUX_CONF_LOCAL\";; esac && \"$TMUX_PROGRAM\" ${TMUX_SOCKET:+-S \"$TMUX_SOCKET\"} source \"$TMUX_CONF\" \\; display \"$TMUX_CONF_LOCAL sourced\"'\n\n# reload configuration\nbind r run \"sh -c '\\\"\\$TMUX_PROGRAM\\\" \\${TMUX_SOCKET:+-S \\\"\\$TMUX_SOCKET\\\"} source \\\"\\$TMUX_CONF\\\"'\" \\; display \"#{TMUX_CONF} sourced\"\n\n\n# -- display -------------------------------------------------------------------\n\nset -g base-index 1 # start windows numbering at 1\nsetw -g pane-base-index 1 # make pane numbering consistent with windows\n\nsetw -g automatic-rename on # rename window to reflect current program\nset -g renumber-windows on # renumber windows when a window is closed\n\nset -g set-titles on # set terminal title\n\nset -g display-panes-time 800 # slightly longer pane indicators display time\nset -g display-time 1000 # slightly longer status messages display time\n\nset -g status-interval 10 # redraw status line every 10 seconds\n\n# clear both screen and history\nbind -n C-l send-keys C-l \\; run 'sleep 0.2' \\; clear-history\n\n# activity\nset -g monitor-activity on\nset -g visual-activity off\n\n\n# -- navigation ----------------------------------------------------------------\n\n# create session\nbind C-c new-session\n\n# find session\nbind C-f command-prompt -p find-session 'switch-client -t %%'\n\n# session navigation\nbind BTab switch-client -l # move to last session\n\n# split current window horizontally\nbind - split-window -v\n# split current window vertically\nbind _ split-window -h\n\n# pane navigation\nbind -r h select-pane -L # move left\nbind -r j select-pane -D # move down\nbind -r k select-pane -U # move up\nbind -r l select-pane -R # move right\nbind > swap-pane -D # swap current pane with the next one\nbind < swap-pane -U # swap current pane with the previous one\n\n# maximize current pane\nbind + run \"cut -c3- '#{TMUX_CONF}' | sh -s _maximize_pane '#{session_name}' '#D'\"\n\n# pane resizing\nbind -r H resize-pane -L 2\nbind -r J resize-pane -D 2\nbind -r K resize-pane -U 2\nbind -r L resize-pane -R 2\n\n# window navigation\nunbind n\nunbind p\nbind -r C-h previous-window # select previous window\nbind -r C-l next-window # select next window\nbind -r C-S-H swap-window -t -1 \\; select-window -t -1 # swap current window with the previous one\nbind -r C-S-L swap-window -t +1 \\; select-window -t +1 # swap current window with the next one\nbind Tab last-window # move to last active window\n\n# toggle mouse\nbind m run \"cut -c3- '#{TMUX_CONF}' | sh -s _toggle_mouse\"\n\n\n# -- facebook pathpicker -------------------------------------------------------\n\nbind F run \"cut -c3- '#{TMUX_CONF}' | sh -s _fpp '#{pane_id}' '#{pane_current_path}'\"\n\n\n# -- copy mode -----------------------------------------------------------------\n\nbind Enter copy-mode # enter copy mode\n\nbind -T copy-mode-vi v send -X begin-selection\nbind -T copy-mode-vi C-v send -X rectangle-toggle\nbind -T copy-mode-vi y send -X copy-selection-and-cancel\nbind -T copy-mode-vi Escape send -X cancel\nbind -T copy-mode-vi H send -X start-of-line\nbind -T copy-mode-vi L send -X end-of-line\n\n# copy to X11 clipboard\nif -b 'command -v xsel > /dev/null 2>&1' 'bind y run -b \"\\\"\\$TMUX_PROGRAM\\\" \\${TMUX_SOCKET:+-S \\\"\\$TMUX_SOCKET\\\"} save-buffer - | xsel -i -b\"'\nif -b '! command -v xsel > /dev/null 2>&1 && command -v xclip > /dev/null 2>&1' 'bind y run -b \"\\\"\\$TMUX_PROGRAM\\\" \\${TMUX_SOCKET:+-S \\\"\\$TMUX_SOCKET\\\"} save-buffer - | xclip -i -selection clipboard >/dev/null 2>&1\"'\n# copy to Wayland clipboard\nif -b '[ \"$XDG_SESSION_TYPE\" = \"wayland\" ] && command -v wl-copy > /dev/null 2>&1' 'bind y run -b \"\\\"\\$TMUX_PROGRAM\\\" \\${TMUX_SOCKET:+-S \\\"\\$TMUX_SOCKET\\\"} save-buffer - | wl-copy\"'\n# copy to macOS clipboard\nif -b 'command -v pbcopy > /dev/null 2>&1' 'bind y run -b \"\\\"\\$TMUX_PROGRAM\\\" \\${TMUX_SOCKET:+-S \\\"\\$TMUX_SOCKET\\\"} save-buffer - | pbcopy\"'\n# copy to Windows clipboard\nif -b 'command -v clip.exe > /dev/null 2>&1' 'bind y run -b \"\\\"\\$TMUX_PROGRAM\\\" \\${TMUX_SOCKET:+-S \\\"\\$TMUX_SOCKET\\\"} save-buffer - | clip.exe\"'\nif -b '[ -c /dev/clipboard ]' 'bind y run -b \"\\\"\\$TMUX_PROGRAM\\\" \\${TMUX_SOCKET:+-S \\\"\\$TMUX_SOCKET\\\"} save-buffer - > /dev/clipboard\"'\n\n\n# -- buffers -------------------------------------------------------------------\n\nbind b list-buffers # list paste buffers\nbind p paste-buffer -p # paste from the top paste buffer\nbind P choose-buffer # choose which buffer to paste from\n\n\n# -- 8< ------------------------------------------------------------------------\n\n%if #{==:#{TMUX_PROGRAM},}\n run \"exec sh -c 'TMUX_PROGRAM=\\\"\\$(LSOF=\\$(PATH=\\\"\\$PATH:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin\\\" command -v lsof); \\$LSOF -b -w -a -d txt -p #{pid} -Fn 2>/dev/null | perl -n -e \\\"if (s/^n((?:.(?!dylib\\$|so\\$))+)\\$/\\\\1/g && s/(?:\\s+\\\\([^\\\\s]+?\\\\))?\\$//g) { print; exit } } exit 1; {\\\" 2>/dev/null || readlink \\\"/proc/#{pid}/exe\\\" 2>/dev/null)\\\"; [ \\\"\\$(\\\"\\$TMUX_PROGRAM\\\" display -p \\\"#{l:#{pid}}\\\" 2>/dev/null)\\\" = \\\"#{pid}\\\" ] || TMUX_PROGRAM=\\\"\\$(command -v tmux || printf tmux)\\\"; \\\"\\$TMUX_PROGRAM\\\" -S #{socket_path} set-environment -g TMUX_PROGRAM \\\"\\$TMUX_PROGRAM\\\"'\"\n%endif\n%if #{==:#{TMUX_SOCKET},}\n run \"exec sh -c '\\\"\\$TMUX_PROGRAM\\\" -S #{socket_path} set-environment -g TMUX_SOCKET \\\"#{socket_path}\\\"'\"\n%endif\n%if #{==:#{TMUX_CONF},}\n run \"exec sh -c '\\\"\\$TMUX_PROGRAM\\\" set-environment -g TMUX_CONF \\$(for conf in \\\"\\$HOME/.tmux.conf\\\" \\\"\\$XDG_CONFIG_HOME/tmux/tmux.conf\\\" \\\"\\$HOME/.config/tmux/tmux.conf\\\"; do [ -f \\\"\\$conf\\\" ] && printf \\\"%s\\\" \\\"\\$conf\\\" && break; done)'\"\n%endif\n%if #{==:#{TMUX_CONF_LOCAL},}\n run \"exec sh -c '\\\"\\$TMUX_PROGRAM\\\" set-environment -g TMUX_CONF_LOCAL \\\"\\$TMUX_CONF.local\\\"'\"\n%endif\n\nrun '\"$TMUX_PROGRAM\" -S #{socket_path} source \"$TMUX_CONF_LOCAL\"'\nrun 'cut -c3- \"$TMUX_CONF\" | sh -s _apply_configuration'\n\n# EOF\n#\n# # exit the script if any statement returns a non-true return value\n# set -e\n#\n# unset SHELL\n#\n# unset GREP_OPTIONS\n# export LC_NUMERIC=C\n# # shellcheck disable=SC3041\n# if (set +H 2>/dev/null); then\n# set +H\n# fi\n#\n# if ! printf '' | sed -E 's///' 2>/dev/null; then\n# if printf '' | sed -r 's///' 2>/dev/null; then\n# sed() {\n# n=$#; while [ \"$n\" -gt 0 ]; do arg=$1; shift; case $arg in -E*) arg=-r${arg#-E};; esac; set -- \"$@\" \"$arg\"; n=$(( n - 1 )); done\n# command sed \"$@\"\n# }\n# fi\n# fi\n#\n# _uname_s=$(uname -s)\n#\n# [ -z \"$TMUX\" ] && exit 255\n# if [ -z \"$TMUX_SOCKET\" ]; then\n# TMUX_SOCKET=$(printf '%s' \"$TMUX\" | cut -d, -f1)\n# fi\n# if [ -z \"$TMUX_PROGRAM\" ]; then\n# TMUX_PID=$(printf '%s' \"$TMUX\" | cut -d, -f2)\n# TMUX_PROGRAM=$(lsof -b -w -a -d txt -p \"$TMUX_PID\" -Fn 2>/dev/null | perl -n -e \"if (s/^n((?:.(?!dylib$|so$))+)$/\\1/g) { print; exit } } exit 1; {\" 2>/dev/null || readlink \"/proc/$TMUX_PID/exe\" 2>/dev/null)\n# [ \"$(\"$TMUX_PROGRAM\" -S \"$TMUX_SOCKET\" display -p '#{pid}' 2>/dev/null)\" = \"$TMUX_PID\" ] || TMUX_PROGRAM=$(command -v tmux || printf tmux)\n# fi\n# if [ \"$TMUX_PROGRAM\" = \"tmux\" ]; then\n# tmux() {\n# command tmux ${TMUX_SOCKET:+-S \"$TMUX_SOCKET\"} \"$@\"\n# }\n# else\n# tmux() {\n# \"$TMUX_PROGRAM\" ${TMUX_SOCKET:+-S \"$TMUX_SOCKET\"} \"$@\"\n# }\n# fi\n#\n# _tmux_version=$(tmux -V | perl -n -e '($l, $r) = $_ =~ /^[^0-9]+([0-9.]+)([a-z])?(-rc.*)?$/; print $l * 1000 + ($r eq \"\" ? 0 : ord($r) - 96)')\n#\n# _is_true() {\n# case \"$1\" in\n# true|yes|1)\n# return 0\n# ;;\n# *)\n# return 1\n# ;;\n# esac\n# }\n#\n# _is_enabled() {\n# [ \"$1\" = \"enabled\" ]\n# }\n#\n# _is_disabled() {\n# [ \"$1\" = \"disabled\" ]\n# }\n#\n# _circled() {\n# circled_digits='⓪ ① ② ③ ④ ⑤ ⑥ ⑦ ⑧ ⑨ ⑩ ⑪ ⑫ ⑬ ⑭ ⑮ ⑯ ⑰ ⑱ ⑲ ⑳'\n# if [ \"$1\" -le 20 ] 2>/dev/null; then\n# i=$(( $1 + 1 ))\n# eval set -- \"$circled_digits\"\n# eval echo \"\\${$i}\"\n# else\n# echo \"$1\"\n# fi\n# }\n#\n# _decode_unicode_escapes() {\n# printf '%s' \"$*\" | perl -CS -pe 's/(\\\\u([0-9A-Fa-f]{1,4})|\\\\U([0-9A-Fa-f]{1,8}))/chr(hex($2.$3))/eg' 2>/dev/null\n# }\n#\n# _pretty_path() {\n# max_length=${1:-auto}; shift\n# if [ \"$max_length\" = \"auto\" ]; then\n# max_length=$(($(tmux -q display -p '#{client_width}') / 4))\n# fi\n# { cd \"$*\" && pwd || printf '%s' \"$*\"; } | perl -s -p -E '\n# s|^$HOME|~|;\n# /^.{0,$max_length}$/ || s|(~?/[^/]+)(/[^/]+)(?:/.+)?(/[^/]+)$|$1$2/...$3|g;\n# /^.{0,$max_length}$/ || s|(~?/[^/]+)(/[^/]+)(?:/.+)(/[^/]+)$|$1/...$3|g;' -- -HOME=\"$HOME\" -max_length=\"$max_length\"\n# }\n#\n# if command -v pkill > /dev/null 2>&1; then\n# _pkillf() {\n# pkill -f \"$@\" || true\n# }\n# else\n# case \"$_uname_s\" in\n# *CYGWIN*)\n# _pkillf() {\n# while IFS= read -r pid; do\n# kill \"$pid\" || true\n# done << EOF\n# $(grep -Eao \"$@\" /proc/*/cmdline | xargs -0 | sed -E -n 's,/proc/([0-9]+)/.+$,\\1,pg')\n# EOF\n# }\n# ;;\n# *)\n# # shellcheck disable=SC2009\n# _pkillf() {\n# while IFS= read -r pid; do\n# kill \"$pid\" || true\n# done << EOF\n# $(ps -x -o pid= -o command= | grep -E \"$@\" | cut -d' ' -f1)\n# EOF\n# }\n# ;;\n# esac\n# fi\n#\n# if perl -MTime::HiRes -e1; then\n# _timestamp() {\n# while IFS= read -r line; do\n# printf '\\t%s\\n' \"$line\" | perl -MPOSIX=strftime -MTime::HiRes=gettimeofday -pe '($s, $us) = gettimeofday(); printf (\"[%s.%03d]\", strftime(\"%Y-%m-%d %H:%M:%S\", localtime $s), $us / 1000)'\n# done\n# }\n# else\n# case \"$_uname_s\" in\n# Darwin)\n# _timestamp() {\n# while IFS= read -r line; do\n# printf '[%s]\\t%s\\n' \"$(date +\"%Y-%m-%d %H:%M:%S.000\")\" \"$line\"\n# done\n# }\n# ;;\n# *)\n# _timestamp() {\n# while IFS= read -r line; do\n# printf '[%s]\\t%s\\n' \"$(date +\"%Y-%m-%d %H:%M:%S.%3N\")\" \"$line\"\n# done\n# }\n# ;;\n# esac\n# fi\n#\n# _bar() {\n# bar_palette=$(printf '%s' \"$1\" | tr ';' ',')\n# bar_symbol_empty=$2\n# bar_symbol_full=$3\n# bar_length=$4 # \"auto\" or number of columns\n# bar_value=$5 # value between 0 and 1\n#\n# if [ \"$bar_length\" = \"auto\" ]; then\n# columns=${6:-$(tmux -q display -p '#{client_width}' 2> /dev/null || echo 80)}\n# if [ \"$columns\" -ge 160 ]; then\n# bar_length=12\n# elif [ \"$columns\" -ge 130 ]; then\n# bar_length=10\n# elif [ \"$columns\" -ge 120 ]; then\n# bar_length=8\n# elif [ \"$columns\" -ge 100 ]; then\n# bar_length=6\n# else\n# bar_length=4\n# fi\n# fi\n#\n# if printf '%s' \"$bar_palette\" | grep -q -E '^(heat|gradient|gradient\\((\\s*[#a-zA-Z0-9]{7,9},?)+\\))(\\s*,\\s*[#a-zA-Z0-9]{7,9})?$'; then\n# # shellcheck disable=SC2086\n# { set -f; IFS=', '; set -- $bar_palette; unset IFS; set +f; }\n# palette_style=$1\n# shift\n#\n# case \"$palette_style\" in\n# gradient)\n# palette=\"colour196 colour202 colour208 colour214 colour220 colour226 colour190 colour154 colour118 colour82 colour46\"\n# ;;\n# heat)\n# palette=\"colour243 colour245 colour247 colour144 colour143 colour142 colour184 colour214 colour208 colour202 colour196\"\n# ;;\n# gradient*)\n# palette=${palette_style##gradient(}\n# while [ $# -gt 0 ]; do\n# palette=\"$palette${1+ }${1%%)}\"\n# [ \"$1\" != \"${1%%)}\" ] && break\n# shift\n# done\n# ;;\n# esac\n# bg=${2:-none}\n#\n# palette=$(printf '%s' \"$palette\" | awk -v n=\"$bar_length\" '{ for (i = 0; i < n - 1; ++i) printf \"%s \", $(1 + i * NF / n); printf $NF }')\n# # shellcheck disable=SC2086\n# set -- $palette\n#\n# full=$(awk \"BEGIN { printf \\\"%.0f\\\", ($bar_value) * $bar_length }\")\n# bar=\"#[bg=$bg]\"\n# if [ \"$full\" -gt 0 ]; then\n# # shellcheck disable=SC2046\n# bar=\"$bar$(printf \"#[fg=%s]$bar_symbol_full\" $(printf '%s' \"$palette\" | cut -d' ' -f1-\"$full\"))\"\n# fi\n# empty=$((bar_length - full))\n# if [ \"$empty\" -gt 0 ]; then\n# # shellcheck disable=SC2046\n# bar=\"$bar$(printf \"#[fg=%s]$bar_symbol_empty\" $(printf '%s' \"$palette\" | cut -d' ' -f$((full + 1))-$((full + empty))))\"\n# fi\n# eval bar=\"$bar#[fg=\\${$((full == 0 ? 1 : full))}]\"\n# elif printf '%s' \"$bar_palette\" | grep -q -E '^(([#a-zA-Z0-9]{7,9}|none),?){3}$'; then\n# # shellcheck disable=SC2086\n# { set -f; IFS=,; set -- $bar_palette; unset IFS; set +f; }\n# full_fg=$1\n# empty_fg=$2\n# bg=${3:-none}\n#\n# full=$(awk \"BEGIN { printf \\\"%.0f\\\", ($bar_value) * $bar_length }\")\n# bar=\"#[bg=$bg]\"\n# if [ \"$full\" -gt 0 ]; then\n# bar=\"$bar#[fg=$full_fg]$(printf \"%0.s$bar_symbol_full\" $(seq 1 \"$full\"))\"\n# fi\n# empty=$((bar_length - full))\n# if [ \"$empty\" -gt 0 ]; then\n# bar=\"$bar#[fg=$empty_fg]$(printf \"%0.s$bar_symbol_empty\" $(seq 1 \"$empty\"))#[fg=$empty_fg]\"\n# fi\n# fi\n#\n# printf '%s' \"$bar\"\n# }\n#\n# _hbar() {\n# hbar_palette=$(printf '%s' \"$1\" | tr ';' ',')\n# hbar_value=$2\n#\n# if printf '%s' \"$hbar_palette\" | grep -q -E '^(heat|gradient|gradient\\((\\s*[#a-zA-Z0-9]{7,9},?)+\\))(\\s*,\\s*[#a-zA-Z0-9]{7,9})?$'; then\n# # shellcheck disable=SC2086\n# { set -f; IFS=', '; set -- $hbar_palette; unset IFS; set +f; }\n# palette_style=$1\n# shift\n#\n# case \"$palette_style\" in\n# gradient)\n# palette=\"colour196 colour202 colour208 colour214 colour220 colour226 colour190 colour154 colour118 colour82 colour46\"\n# ;;\n# heat)\n# palette=\"colour243 colour245 colour247 colour144 colour143 colour142 colour184 colour214 colour208 colour202 colour196\"\n# ;;\n# gradient*)\n# palette=${palette_style##gradient(}\n# while [ $# -gt 0 ]; do\n# palette=\"$palette${1+ }${1%%)}\"\n# [ \"$1\" != \"${1%%)}\" ] && break\n# shift\n# done\n# ;;\n# esac\n# bg=${2:-none}\n#\n# palette=$(printf '%s' \"$palette\" | awk -v n=8 '{ for (i = 0; i < n - 1; ++i) printf \"%s \", $(1 + i * NF / n); printf $NF }')\n# # shellcheck disable=SC2086\n# set -- $palette\n#\n# full=$(awk \"BEGIN { printf \\\"%.0f\\\", ($hbar_value) * 8 }\")\n# eval hbar_fg=\"\\${$((full == 0 ? 1 : full))}\"\n# elif printf '%s' \"$hbar_palette\" | grep -q -E '^([#a-zA-Z0-9]{7,9},?){3}$'; then\n# # shellcheck disable=SC2086\n# { set -f; IFS=,; set -- $hbar_palette; unset IFS; set +f; }\n#\n# # shellcheck disable=SC2046\n# eval $(awk \"BEGIN { printf \\\"hbar_fg=$%d\\\", (($hbar_value) - 0.001) * $# + 1 }\")\n# fi\n#\n# set -- ▏ ▎ ▍ ▌ ▋ ▊ ▉ █\n# # shellcheck disable=SC2046\n# eval $(awk \"BEGIN { printf \\\"hbar_symbol=$%d\\\", ($hbar_value) * ($# - 1) + 1 }\")\n# hbar=\"#[bg=$bg]#[fg=${hbar_fg?}]${hbar_symbol?}\"\n#\n# printf '%s' \"$hbar\"\n# }\n#\n# _vbar() {\n# vbar_palette=$(printf '%s' \"$1\" | tr ';' ',')\n# vbar_value=$2\n#\n# if printf '%s' \"$vbar_palette\" | grep -q -E '^(heat|gradient|gradient\\((\\s*[#a-zA-Z0-9]{7,9},?)+\\))(\\s*,\\s*[#a-zA-Z0-9]{7,9})?$'; then\n# # shellcheck disable=SC2086\n# { set -f; IFS=', '; set -- $vbar_palette; unset IFS; set +f; }\n# palette_style=$1\n# shift\n#\n# case \"$palette_style\" in\n# gradient)\n# palette=\"colour196 colour202 colour208 colour214 colour220 colour226 colour190 colour154 colour118 colour82 colour46\"\n# ;;\n# heat)\n# palette=\"colour243 colour245 colour247 colour144 colour143 colour142 colour184 colour214 colour208 colour202 colour196\"\n# ;;\n# gradient*)\n# palette=${palette_style##gradient(}\n# while [ $# -gt 0 ]; do\n# palette=\"$palette${1+ }${1%%)}\"\n# [ \"$1\" != \"${1%%)}\" ] && break\n# shift\n# done\n# ;;\n# esac\n# bg=${2:-none}\n#\n# palette=$(printf '%s' \"$palette\" | awk -v n=8 '{ for (i = 0; i < n - 1; ++i) printf \"%s \", $(1 + i * NF / n); printf $NF }')\n# # shellcheck disable=SC2086\n# set -- $palette\n#\n# full=$(awk \"BEGIN { printf \\\"%.0f\\\", ($vbar_value) * 8 }\")\n# eval vbar_fg=\"\\${$((full == 0 ? 1 : full))}\"\n# elif printf '%s' \"$vbar_palette\" | grep -q -E '^([#a-zA-Z0-9]{7,9},?){3}$'; then\n# # shellcheck disable=SC2086\n# { set -f; IFS=,; set -- $vbar_palette; unset IFS; set +f; }\n#\n# # shellcheck disable=SC2046\n# eval $(awk \"BEGIN { printf \\\"vbar_fg=$%d\\\", (($vbar_value) - 0.001) * $# + 1 }\")\n# fi\n#\n# set -- ▁ ▂ ▃ ▄ ▅ ▆ ▇ █\n# # shellcheck disable=SC2046\n# eval $(awk \"BEGIN { printf \\\"vbar_symbol=$%d\\\", ($vbar_value) * ($# - 1) + 1 }\")\n# vbar=\"#[bg=$bg]#[fg=${vbar_fg?}]${vbar_symbol?}\"\n#\n# printf '%s' \"$vbar\"\n# }\n#\n# _maximize_pane() {\n# current_session=${1:-$(tmux display -p '#{session_name}')}\n# current_pane=${2:-$(tmux display -p '#{pane_id}')}\n#\n# dead_panes=$(tmux list-panes -s -t \"$current_session\" -F '#{pane_dead} #{pane_id} #{pane_start_command}' | grep -E -o '^1 %.+maximized.+$' || true)\n# restore=$(printf \"%s\" \"$dead_panes\" | sed -n -E -e \"s/^1 $current_pane .+maximized.+'(%[0-9]+)'\\\"?$/tmux swap-pane -s \\1 -t $current_pane \\; kill-pane -t $current_pane/p\"\\\n# -e \"s/^1 (%[0-9]+) .+maximized.+'$current_pane'\\\"?$/tmux swap-pane -s \\1 -t $current_pane \\; kill-pane -t \\1/p\")\n#\n# if [ -z \"$restore\" ]; then\n# [ \"$(tmux list-panes -t \"$current_session:\" | wc -l | sed 's/^ *//g')\" -eq 1 ] && tmux display \"Can't maximize with only one pane\" && return\n# info=$(tmux new-window -t \"$current_session:\" -F \"#{session_name}:#{window_index}.#{pane_id}\" -P \"maximized... 2>/dev/null & \\\"$TMUX_PROGRAM\\\" ${TMUX_SOCKET:+-S \\\"$TMUX_SOCKET\\\"} setw -t \\\"$current_session:\\\" remain-on-exit on; printf \\\"\\\\033[\\$(tput lines);0fPane has been maximized, press <prefix>+ to restore\\n\\\" '$current_pane'\")\n# session_window=${info%.*}\n# new_pane=${info#*.}\n#\n# retry=20\n# while [ \"$(\"$TMUX_PROGRAM\" ${TMUX_SOCKET:+-S \"$TMUX_SOCKET\"} list-panes -t \"$session_window\" -F '#{session_name}:#{window_index}.#{pane_id} #{pane_dead}' 2>/dev/null)\" != \"$info 1\" ] && [ \"$retry\" -ne 0 ]; do\n# sleep 0.1\n# retry=$((retry - 1))\n# done\n# if [ \"$retry\" -eq 0 ]; then\n# tmux display 'Unable to maximize pane'\n# fi\n#\n# tmux setw -t \"$session_window\" remain-on-exit off \\; swap-pane -s \"$current_pane\" -t \"$new_pane\"\n# else\n# $restore || tmux kill-pane\n# fi\n# }\n#\n# _toggle_mouse() {\n# old=$(tmux show -gv mouse)\n# new=\"\"\n#\n# if [ \"$old\" = \"on\" ]; then\n# new=\"off\"\n# else\n# new=\"on\"\n# fi\n#\n# tmux set -g mouse $new\n# }\n#\n# _battery_info() {\n# battery_count=0\n# battery_charge=0\n# case \"$_uname_s\" in\n# *Darwin*)\n# while IFS= read -r line; do\n# [ -z \"$line\" ] && continue\n# percentage=$(printf '%s' \"$line\" | grep -E -o '[0-9]+%' || echo \"0%\")\n# battery_charge=$(awk -v charge=\"$battery_charge\" -v percentage=\"${percentage%%%}\" 'BEGIN { print charge + percentage / 100 }')\n# battery_count=$((battery_count + 1))\n# done << EOF\n# $(pmset -g batt | grep 'InternalBattery')\n# EOF\n# ;;\n# *Linux*)\n# while IFS= read -r batpath; do\n# [ -z \"$batpath\" ] && continue\n# grep -i -q device \"$batpath/scope\" 2> /dev/null && continue\n#\n# bat_capacity=\"$batpath/capacity\"\n# if [ -r \"$bat_capacity\" ]; then\n# battery_charge=$(awk -v charge=\"$battery_charge\" -v capacity=\"$(cat \"$bat_capacity\")\" 'BEGIN { print charge + (capacity > 100 ? 100 : capacity) / 100 }')\n# else\n# bat_energy_full=\"$batpath/energy_full\"\n# bat_energy_now=\"$batpath/energy_now\"\n# if [ -r \"$bat_energy_full\" ] && [ -r \"$bat_energy_now\" ]; then\n# battery_charge=$(awk -v charge=\"$battery_charge\" -v energy_now=\"$(cat \"$bat_energy_now\")\" -v energy_full=\"$(cat \"$bat_energy_full\")\" 'BEGIN { print charge + energy_now / energy_full }')\n# fi\n# fi\n# battery_count=$((battery_count + 1))\n# done << EOF\n# $(find /sys/class/power_supply -maxdepth 1 -iname '*bat*')\n# EOF\n# ;;\n# *CYGWIN*|*MSYS*|*MINGW*)\n# while IFS= read -r line; do\n# [ -z \"$line\" ] && continue\n# battery_charge=$(printf '%s' \"$line\" | awk -v charge=\"$battery_charge\" '{ print charge + $2 / 100 }')\n# battery_count=$((battery_count + 1))\n# done << EOF\n# $(wmic path Win32_Battery get BatteryStatus, EstimatedChargeRemaining 2> /dev/null | tr -d '\\r' | tail -n +2 || true)\n# EOF\n# ;;\n# *OpenBSD*)\n# for batid in 0 1 2; do\n# sysctl -n \"hw.sensors.acpibat$batid.raw0\" 2>&1 | grep -q 'not found' && continue\n# if sysctl -n \"hw.sensors.acpibat$batid\" | grep -q amphour; then\n# battery_charge=$(awk -v charge=\"$battery_charge\" -v remaining=\"$(sysctl -n hw.sensors.acpibat$batid.amphour3 | cut -d' ' -f1)\" -v full=\"$(sysctl -n hw.sensors.acpibat$batid.amphour0 | cut -d' ' -f1)\" 'BEGIN { print charge + remaining / full }')\n# else\n# battery_charge=$(awk -v charge=\"$battery_charge\" -v remaining=\"$(sysctl -n hw.sensors.acpibat$batid.watthour3 | cut -d' ' -f1)\" -v full=\"$(sysctl -n hw.sensors.acpibat$batid.watthour0 | cut -d' ' -f1)\" 'BEGIN { print charge + remaining / full }')\n# fi\n# battery_count=$((battery_count + 1))\n# done\n# ;;\n# *FreeBSD*)\n# battery_charge=$(awk -v charge=\"$(sysctl -n 'hw.acpi.battery.life')\" 'BEGIN { print charge / 100 }')\n# battery_count=1\n# ;;\n# esac\n# if [ \"$battery_count\" -ne 0 ]; then\n# battery_charge=$(awk -v charge=\"$battery_charge\" -v count=\"$battery_count\" 'BEGIN { print charge / count }')\n# fi\n#\n# if [ \"$battery_charge\" = 0 ]; then\n# tmux set -ug '@battery_percentage' \\;\\\n# set -ug '@battery_charge'\n# else\n# battery_percentage=\"$(awk \"BEGIN { printf \\\"%.0f%%\\\", ($battery_charge) * 100 }\")\"\n#\n# tmux set -g '@battery_percentage' \"$battery_percentage\" \\;\\\n# set -g '@battery_charge' \"$battery_charge\"\n# fi\n# }\n#\n# _battery_status() {\n# battery_status_charging=$1\n# battery_status_discharging=$2\n#\n# case \"$_uname_s\" in\n# *Darwin*)\n# while IFS= read -r line; do\n# [ -z \"$line\" ] && continue\n# battery_discharging=$(printf '%s' \"$line\" | grep -qi \"discharging\" && echo \"true\" || echo \"false\")\n# done << EOF\n# $(pmset -g batt | grep 'InternalBattery')\n# EOF\n# ;;\n# *Linux*)\n# while IFS= read -r batpath; do\n# [ -z \"$batpath\" ] && continue\n# grep -i -q device \"$batpath/scope\" 2> /dev/null && continue\n#\n# battery_discharging=$(grep -qi \"discharging\" \"$batpath/status\" && echo \"true\" || echo \"false\")\n# done << EOF\n# $(find /sys/class/power_supply -maxdepth 1 -iname '*bat*')\n# EOF\n# ;;\n# *CYGWIN*|*MSYS*|*MINGW*)\n# while IFS= read -r line; do\n# [ -z \"$line\" ] && continue\n# battery_discharging=$(printf '%s' \"$line\" | awk '{ s = ($1 == 1) ? \"true\" : \"false\"; print s }')\n# done << EOF\n# $(wmic path Win32_Battery get BatteryStatus, EstimatedChargeRemaining 2> /dev/null | tr -d '\\r' | tail -n +2 || true)\n# EOF\n# ;;\n# *OpenBSD*)\n# for batid in 0 1 2; do\n# battery_discharging=$(sysctl -n \"hw.sensors.acpibat$batid.raw0\" | grep -q 1 && echo \"true\" || echo \"false\")\n# done\n# ;;\n# *FreeBSD*)\n# battery_discharging=$(sysctl -n 'hw.acpi.battery.state' | grep -q 1 && echo \"true\" || echo \"false\")\n# ;;\n# esac\n#\n# if [ -z \"$battery_discharging\" ]; then\n# tmux set -ug '@battery_status'\n# return\n# fi\n#\n# if [ \"$battery_discharging\" = \"true\" ]; then\n# battery_status=\"$battery_status_discharging\"\n# else\n# battery_status=\"$battery_status_charging\"\n# fi\n#\n# tmux set -g '@battery_status' \"$battery_status\" >/dev/null 2>/dev/null\n# }\n#\n# _pane_info() {\n# pane_pid=\"$1\"\n# pane_tty=\"${2##/dev/}\"\n# case \"$_uname_s\" in\n# *CYGWIN*)\n# ps -al | tail -n +2 | awk -v pane_pid=\"$pane_pid\" -v tty=\"$pane_tty\" -v ssh=\"$(command -v ssh)\" '\n# ((/ssh/ && !/-W/ && !/tsh proxy ssh/ && !/sss_ssh_knownhostsproxy/) || !/ssh/) && !/tee/ && $5 == tty {\n# user[$1] = $6; if (!child[$2]) child[$2] = $1\n# }\n# END {\n# pid = pane_pid\n# while (child[pid]) {\n# if (match(command[pid], \"^\" ssh \" |^ssh \")) {\n# break\n# }\n# pid = child[pid]\n# }\n#\n# file = \"/proc/\" pid \"/cmdline\"; getline command < file; close(file)\n# gsub(/\\0/, \" \", command)\n# \"id -un \" user[pid] | getline username\n# print pid\":\"username\":\"command\n# }\n# '\n# ;;\n# *Linux*)\n# ps -t \"$pane_tty\" --sort=lstart -o user=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX -o pid= -o ppid= -o command= | awk -v pane_pid=\"$pane_pid\" -v ssh=\"$(command -v ssh)\" '\n# ((/ssh/ && !/-W/ && !/tsh proxy ssh/ && !/sss_ssh_knownhostsproxy/) || !/ssh/) && !/tee/ {\n# user[$2] = $1; if (!child[$3]) child[$3] = $2; pid=$2; $1 = $2 = $3 = \"\"; command[pid] = substr($0,4)\n# }\n# END {\n# pid = pane_pid\n# while (child[pid]) {\n# if (match(command[pid], \"^\" ssh \" |^ssh \")) {\n# break\n# }\n# pid = child[pid]\n# }\n#\n# print pid\":\"user[pid]\":\"command[pid]\n# }\n# '\n# ;;\n# *)\n# ps -t \"/dev/$pane_tty\" -o user=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX -o pid= -o ppid= -o command= | awk -v pane_pid=\"$pane_pid\" -v ssh=\"$(command -v ssh)\" '\n# ((/ssh/ && !/-W/ && !/tsh proxy ssh/ && !/sss_ssh_knownhostsproxy/) || !/ssh/) && !/tee/ {\n# user[$2] = $1; if (!child[$3]) child[$3] = $2; pid=$2; $1 = $2 = $3 = \"\"; command[pid] = substr($0,4)\n# }\n# END {\n# pid = pane_pid\n# while (child[pid]) {\n# if (match(command[pid], \"^\" ssh \" |^ssh \")) {\n# break\n# }\n# pid = child[pid]\n# }\n#\n# print pid\":\"user[pid]\":\"command[pid]\n# }\n# '\n# ;;\n# esac\n# }\n#\n# _ssh_or_mosh_args() {\n# case \"$1\" in\n# *ssh*)\n# args=$(printf '%s' \"$1\" | perl -n -e 'print if s/.*?\\bssh[\\w_-]*\\s*(.*)/\\1/')\n# ;;\n# *mosh-client*)\n# args=$(printf '%s' \"$1\" | sed -E -e 's/.*mosh-client -# (.*)\\|.*$/\\1/' -e 's/-[^ ]*//g' -e 's/\\d:\\d//g')\n# ;;\n# esac\n#\n# printf '%s' \"$args\"\n# }\n#\n# _username() {\n# pane_pid=${1:-$(tmux display -p '#{pane_pid}')}\n# pane_tty=${2:-$(tmux display -p '#{b:pane_tty}')}\n# ssh_only=$3\n#\n# pane_info=$(_pane_info \"$pane_pid\" \"$pane_tty\")\n# command=${pane_info#*:}\n# command=${command#*:}\n#\n# ssh_or_mosh_args=$(_ssh_or_mosh_args \"$command\")\n# if [ -n \"$ssh_or_mosh_args\" ]; then\n# # shellcheck disable=SC2086\n# username=$(ssh -G $ssh_or_mosh_args 2>/dev/null | awk '/^user / { print $2; exit }')\n# # shellcheck disable=SC2086\n# [ -z \"$username\" ] && username=$(ssh $ssh_or_mosh_args -T -o ControlPath=none -o ProxyCommand=\"sh -c 'echo %%username%% %r >&2'\" 2>&1 | awk '/^%username% / { print $2; exit }')\n# # shellcheck disable=SC2086\n# [ -z \"$username\" ] && username=$(ssh $ssh_or_mosh_args -v -T -o ControlPath=none -o ProxyCommand=false -o IdentityFile='%%username%%/%r' 2>&1 | awk '/%username%/ { print substr($4,12); exit }')\n# else\n# if ! _is_true \"$ssh_only\"; then\n# username=${pane_info#*:}\n# username=${username%%:*}\n# fi\n# fi\n#\n# printf '%s\\n' \"$username\"\n# }\n#\n# _hostname() {\n# pane_pid=${1:-$(tmux display -p '#{pane_pid}')}\n# pane_tty=${2:-$(tmux display -p '#{b:pane_tty}')}\n# ssh_only=$3\n# full=$4\n# h_or_H=$5\n#\n# pane_info=$(_pane_info \"$pane_pid\" \"$pane_tty\")\n# command=${pane_info#*:}\n# command=${command#*:}\n#\n# ssh_or_mosh_args=$(_ssh_or_mosh_args \"$command\")\n# if [ -n \"$ssh_or_mosh_args\" ]; then\n# # shellcheck disable=SC2086\n# hostname=$(ssh -G $ssh_or_mosh_args 2>/dev/null | awk '/^hostname / { print $2; exit }')\n# # shellcheck disable=SC2086\n# [ -z \"$hostname\" ] && hostname=$(ssh -T -o ControlPath=none -o ProxyCommand=\"sh -c 'echo %%hostname%% %h >&2'\" $ssh_or_mosh_args 2>&1 | awk '/^%hostname% / { print $2; exit }')\n#\n# if ! _is_true \"$full\"; then\n# case \"$hostname\" in\n# *[a-z-].*)\n# hostname=${hostname%%.*}\n# ;;\n# 127.0.0.1)\n# hostname=\"localhost\"\n# ;;\n# esac\n# fi\n# else\n# if ! _is_true \"$ssh_only\"; then\n# hostname=\"$h_or_H\"\n# fi\n# fi\n#\n# printf '%s\\n' \"$hostname\"\n# }\n#\n# _uptime() {\n# case \"$_uname_s\" in\n# *Darwin*|*FreeBSD*)\n# boot=$(sysctl -n kern.boottime 2>/dev/null | awk -F'[ ,:]+' '{ print $4 }')\n# now=$(date +%s)\n# ;;\n# *Linux*|*CYGWIN*|*MSYS*|*MINGW*)\n# boot=0\n# now=$(cut -d' ' -f1 < /proc/uptime)\n# ;;\n# *OpenBSD*)\n# boot=$(sysctl -n kern.boottime)\n# now=$(date +%s)\n# esac\n# # shellcheck disable=SC1004\n# awk -v tmux=\"$TMUX_PROGRAM ${TMUX_SOCKET:+-S \"$TMUX_SOCKET\"}\" -v boot=\"$boot\" -v now=\"$now\" '\n# BEGIN {\n# uptime = now - boot\n# y = int(uptime / 31536000)\n# dy = int(uptime / 86400) % 365\n# d = int(uptime / 86400)\n# h = int(uptime / 3600) % 24\n# m = int(uptime / 60) % 60\n# s = int(uptime) % 60\n#\n# system(tmux \" set -g @uptime_y \" y + 0 \" \\\\;\" \\\n# \" set -g @uptime_dy \" dy + 0 \" \\\\;\" \\\n# \" set -g @uptime_d \" d + 0 \" \\\\;\" \\\n# \" set -g @uptime_h \" h + 0 \" \\\\;\" \\\n# \" set -g @uptime_m \" m + 0 \" \\\\;\" \\\n# \" set -g @uptime_s \" s + 0)\n# }'\n# }\n#\n# _loadavg() {\n# case \"$_uname_s\" in\n# *Darwin*|*FreeBSD*)\n# tmux set -g @loadavg \"$(sysctl -n vm.loadavg 2>/dev/null | cut -d' ' -f2)\"\n# ;;\n# *Linux*|*CYGWIN*)\n# tmux set -g @loadavg \"$(cut -d' ' -f1 < /proc/loadavg)\"\n# ;;\n# *OpenBSD*)\n# tmux set -g @loadavg \"$(sysctl -n vm.loadavg 2>/dev/null | cut -d' ' -f1)\"\n# ;;\n# esac\n# }\n#\n# _new_window_ssh() {\n# pane_pid=${1:-$(tmux display -p '#{pane_pid}')}\n# pane_tty=${2:-$(tmux display -p '#{b:pane_tty}')}\n# shift 2\n#\n# pane_info=$(_pane_info \"$pane_pid\" \"$pane_tty\")\n# command=${pane_info#*:}\n# command=${command#*:}\n#\n# case \"$command\" in\n# *mosh-client*)\n# # shellcheck disable=SC2046\n# tmux new-window \"$@\" mosh $(echo \"$command\" | sed -E -e 's/.*mosh-client -# (.*)\\|.*$/\\1/')\n# ;;\n# *ssh*)\n# # shellcheck disable=SC2046\n# tmux new-window \"$@\" $(echo \"$command\" | sed -e 's/;/\\\\;/g')\n# ;;\n# *)\n# tmux new-window \"$@\"\n# esac\n# }\n#\n# _new_window() {\n# _new_window_ssh \"$@\"\n# }\n#\n# _split_window_ssh() {\n# pane_pid=${1:-$(tmux display -p '#{pane_pid}')}\n# pane_tty=${2:-$(tmux display -p '#{b:pane_tty}')}\n# shift 2\n#\n# pane_info=$(_pane_info \"$pane_pid\" \"$pane_tty\")\n# command=${pane_info#*:}\n# command=${command#*:}\n#\n# case \"$command\" in\n# *mosh-client*)\n# # shellcheck disable=SC2046\n# tmux split-window \"$@\" mosh $(echo \"$command\" | sed -E -e 's/.*mosh-client -# (.*)\\|.*$/\\1/')\n# ;;\n# *ssh*)\n# # shellcheck disable=SC2046\n# tmux split-window \"$@\" $(echo \"$command\" | sed -e 's/;/\\\\;/g')\n# ;;\n# *)\n# tmux split-window \"$@\"\n# esac\n# }\n#\n# _split_window() {\n# _split_window_ssh \"$@\"\n# }\n#\n# _apply_tmux_256color() {\n# case \"$(tmux show -gv default-terminal)\" in\n# tmux-256color|tmux-direct)\n# return\n# ;;\n# esac\n#\n# # when tmux-256color is available, use it\n# # on macOS though, make sure to use /usr/bin/infocmp to probe if it's availalbe system wide\n# case \"$_uname_s\" in\n# *Darwin*)\n# if /usr/bin/infocmp -x tmux-256color > /dev/null 2>&1; then\n# tmux set -g default-terminal 'tmux-256color'\n# fi\n# ;;\n# *)\n# if command infocmp -x tmux-256color > /dev/null 2>&1; then\n# tmux set -g default-terminal 'tmux-256color'\n# fi\n# ;;\n# esac\n# }\n#\n# _apply_24b() {\n# tmux_conf_theme_24b_colour=${tmux_conf_theme_24b_colour:-auto}\n# tmux_conf_24b_colour=${tmux_conf_24b_colour:-$tmux_conf_theme_24b_colour}\n# if [ \"$tmux_conf_24b_colour\" = \"auto\" ]; then\n# case \"$COLORTERM\" in\n# truecolor|24bit)\n# apply_24b=true\n# ;;\n# esac\n# if [ \"$apply_24b\" = \"\" ] && [ \"$(tput colors)\" = \"16777216\" ]; then\n# apply_24b=true\n# fi\n# elif _is_true \"$tmux_conf_24b_colour\"; then\n# apply_24b=true\n# fi\n# if [ \"$apply_24b\" = \"true\" ]; then\n# case \"$TERM\" in\n# screen-*|tmux-*)\n# ;;\n# *)\n# tmux set-option -ga terminal-overrides \",*256col*:Tc\"\n# ;;\n# esac\n# fi\n# }\n#\n# _apply_bindings() {\n# cfg=$(mktemp) && trap 'rm -f $cfg*' EXIT\n#\n# tmux_conf_preserve_stock_bindings=${tmux_conf_preserve_stock_bindings:-false}\n# tmux list-keys | grep -vF 'TMUX_CONF_LOCAL' | grep -E 'new-window|split(-|_)window|new-session|copy-selection|copy-pipe' > \"$cfg\"\n# if _is_true \"$tmux_conf_preserve_stock_bindings\"; then\n# probe_socket=\"$(dirname \"$TMUX_SOCKET\")/tmux-stock-bindings-$$\"\n# TMUX_SOCKET=\"$probe_socket\" tmux -f /dev/null list-keys >> \"$cfg\"\n# rm -f \"$probe_socket\"\n# fi\n#\n# # tmux 3.0 doesn't include 02254d1e5c881be95fd2fc37b4c4209640b6b266 and the\n# # output of list-keys can be truncated\n# perl -p -i -e \"s/'#\\{\\?window_zoomed_flag,Unzoom,Zoom\\}' 'z' \\{resize-pane -$/'#{?window_zoomed_flag,Unzoom,Zoom}' 'z' {resize-pane -Z}\\\"/g\" \"$cfg\"\n#\n# tmux_conf_new_window_retain_current_path=${tmux_conf_new_window_retain_current_path:-true}\n# if ! _is_disabled \"$tmux_conf_new_window_retain_current_path\"; then\n# perl -p -i -e \"\n# s/\\brun-shell\\b\\s+(\\\"|')cut\\s+-c3-\\s+(.+?)\\s+\\|\\s+sh\\s+-s\\s+_new_window\\s+#\\{pane_pid\\}\\s+#\\{b:pane_tty\\}([^\\n\\1]*?)(?:\\s+-c\\s+((?:\\\\\\\\{1,3}\\\")?|\\\"?|'?)#\\{pane_current_path\\}\\4)([^\\n\\1]*?)\\1/run-shell \\1cut -c3- \\2 | sh -s _new_window #\\{pane_pid\\} #\\{b:pane_tty\\}\\3\\5\\1/g\n# ;\n# s/\\brun-shell\\b\\s+(\\\"|')cut\\s+-c3-\\s+.+?\\s+\\|\\s+sh\\s+-s\\s+_new_window\\s+#\\{pane_pid\\}\\s+#\\{b:pane_tty\\}(\\s+.+?)?\\1/new-window\\2/g\n# ;\n# s/\\bnew-window\\b([^;}\\n]*?)(?:\\s+-c\\s+((?:\\\\\\\\\\\")?|\\\"?|'?)#\\{pane_current_path\\}\\2)/new-window\\1/g\" \\\n# \"$cfg\"\n# fi\n#\n# perl -p -i -e \"\n# s,\\bnew-window\\b((?:(?:[ \\t]+-[bdfhIvP])|(?:[ \\t]+-[celtF][ \\t]+(?!\\bssh\\b)[^\\s]+))*)?(?:\\s+(\\bssh\\b))((?:(?:[ \\t]+-[bdfhIvP])|(?:[ \\t]+-[celtF][ \\t]+(?!\\bssh\\b)[^\\s]+))*)?,run-shell 'cut -c3- \\\"$TMUX_CONF\\\" | sh -s _new_window_ssh #\\{pane_pid\\} #\\{b:pane_tty\\}\\1',g if /\\bnew-window\\b((?:(?:[ \\t]+-[bdfhIvP])|(?:[ \\t]+-[celtF][ \\t]+(?!ssh)[^\\s]+))*)?(?:\\s+(ssh))((?:(?:[ \\t]+-[bdfhIvP])|(?:[ \\t]+-[celtF][ \\t]+(?!ssh)[^\\s]+))*)?/\"\\\n# \"$cfg\"\n#\n# tmux_conf_new_window_reconnect_ssh=${tmux_conf_new_window_reconnect_ssh:-false}\n# if ! _is_disabled \"$tmux_conf_new_window_reconnect_ssh\" && _is_true \"$tmux_conf_new_window_reconnect_ssh\"; then\n# perl -p -i -e \"s,\\bnew-window\\b([^;}\\n\\\"]*),run-shell 'cut -c3- \\\"$TMUX_CONF\\\" | sh -s _new_window #\\{pane_pid\\} #\\{b:pane_tty\\}\\1',g\" \"$cfg\"\n# fi\n#\n# tmux_conf_new_window_retain_current_path=${tmux_conf_new_window_retain_current_path:-false}\n# if ! _is_disabled \"$tmux_conf_new_window_retain_current_path\" && _is_true \"$tmux_conf_new_window_retain_current_path\"; then\n# perl -p -i -e \"\n# s/\\bnew-window\\b(?!\\s+(?:-|}))/{$&}/g if /\\bdisplay-menu\\b/\n# ;\n# s/\\bnew-window\\b/new-window -c '#{pane_current_path}'/g\n# ;\n# s/\\brun-shell\\b\\s+'cut\\s+-c3-\\s+(.+?)\\s+\\|\\s+sh\\s+-s\\s+_new_window(_ssh)?\\s+#\\{pane_pid\\}\\s+#\\{b:pane_tty\\}([^}\\n']*)'/run-shell 'cut -c3- \\1 | sh -s _new_window\\2 #\\{pane_pid\\} #\\{b:pane_tty\\} -c \\\\\\\\\\\"#\\{pane_current_path\\}\\\\\\\\\\\"\\3'/g if /\\bdisplay-menu\\b/\n# ;\n# s/\\brun-shell\\b\\s+'cut\\s+-c3-\\s+(.+?)\\s+\\|\\s+sh\\s+-s\\s+_new_window(_ssh)?\\s+#\\{pane_pid\\}\\s+#\\{b:pane_tty\\}([^}\\n']*)'/run-shell 'cut -c3- \\1 | sh -s _new_window\\2 #\\{pane_pid\\} #\\{b:pane_tty\\} -c \\\"#\\{pane_current_path\\}\\\"\\3'/g\" \\\n# \"$cfg\"\n# fi\n#\n# tmux_conf_new_pane_retain_current_path=${tmux_conf_new_pane_retain_current_path:-true}\n# if ! _is_disabled \"$tmux_conf_new_pane_retain_current_path\"; then\n# perl -p -i -e \"\n# s/\\brun-shell\\b\\s+(\\\"|')cut\\s+-c3-\\s+(.+?)\\s+\\|\\s+sh\\s+-s\\s+_split_window\\s+#\\{pane_pid\\}\\s+#\\{b:pane_tty\\}([^\\n\\1]*?)(?:\\s+-c\\s+((?:\\\\\\\\{1,3}\\\")?|\\\"?|'?)#\\{pane_current_path\\}\\4)([^\\n\\1]*?)\\1/run-shell \\1cut -c3- \\2 | sh -s _split_window #\\{pane_pid\\} #\\{b:pane_tty\\}\\3\\5\\1/g\n# ;\n# s/\\brun-shell\\b\\s+(\\\"|')cut\\s+-c3-\\s+.+?\\s+\\|\\s+sh\\s+-s\\s+_split_window\\s+#\\{pane_pid\\}\\s+#\\{b:pane_tty\\}(\\s+.+?)?\\1/split-window\\2/g\n# ;\n# s/\\bsplit-window\\b([^;}\\n]*?)(?:\\s+-c\\s+((?:\\\\\\\\\\\")?|\\\"?|'?)#\\{pane_current_path\\}\\2)/split-window\\1/g\" \\\n# \"$cfg\"\n# fi\n#\n# perl -p -i -e \"\n# s,\\bsplit-window\\b((?:(?:[ \\t]+-[bdfhIvP])|(?:[ \\t]+-[celtF][ \\t]+(?!\\bssh\\b)[^\\s]+))*)?(?:\\s+(\\bssh\\b))((?:(?:[ \\t]+-[bdfhIvP])|(?:[ \\t]+-[celtF][ \\t]+(?!\\bssh\\b)[^\\s]+))*)?,run-shell 'cut -c3- \\\"$TMUX_CONF\\\" | sh -s _split_window_ssh #\\{pane_pid\\} #\\{b:pane_tty\\}\\1',g if /\\bsplit-window\\b((?:(?:[ \\t]+-[bdfhIvP])|(?:[ \\t]+-[celtF][ \\t]+(?!ssh)[^\\s]+))*)?(?:\\s+(ssh))((?:(?:[ \\t]+-[bdfhIvP])|(?:[ \\t]+-[celtF][ \\t]+(?!ssh)[^\\s]+))*)?/\"\\\n# \"$cfg\"\n#\n# tmux_conf_new_pane_reconnect_ssh=${tmux_conf_new_pane_reconnect_ssh:-false}\n# if ! _is_disabled \"$tmux_conf_new_pane_reconnect_ssh\" && _is_true \"$tmux_conf_new_pane_reconnect_ssh\"; then\n# perl -p -i -e \"s,\\bsplit-window\\b([^;}\\n\\\"]*),run-shell 'cut -c3- \\\"$TMUX_CONF\\\" | sh -s _split_window #\\{pane_pid\\} #\\{b:pane_tty\\}\\1',g\" \"$cfg\"\n# fi\n#\n# if ! _is_disabled \"$tmux_conf_new_pane_retain_current_path\" && _is_true \"$tmux_conf_new_pane_retain_current_path\"; then\n# perl -p -i -e \"\n# s/\\bsplit-window\\b(?!\\s+(?:-|}))/{$&}/g if /\\bdisplay-menu\\b/\n# ;\n# s/\\bsplit-window\\b/split-window -c '#{pane_current_path}'\\1/g\n# ;\n# s/\\brun-shell\\b\\s+'cut\\s+-c3-\\s+(.+?)\\s+\\|\\s+sh\\s+-s\\s+_split_window(_ssh)?\\s+#\\{pane_pid\\}\\s+#\\{b:pane_tty\\}([^}\\n']*)'/run-shell 'cut -c3- \\1 | sh -s _split_window\\2 #\\{pane_pid\\} #\\{b:pane_tty\\} -c \\\\\\\\\\\"#\\{pane_current_path\\}\\\\\\\\\\\"\\3'/g if /\\bdisplay-menu\\b/\n# ;\n# s/\\brun-shell\\b\\s+'cut\\s+-c3-\\s+(.+?)\\s+\\|\\s+sh\\s+-s\\s+_split_window(_ssh)?\\s+#\\{pane_pid\\}\\s+#\\{b:pane_tty\\}([^}\\n']*)'/run-shell 'cut -c3- \\1 | sh -s _split_window\\2 #\\{pane_pid\\} #\\{b:pane_tty\\} -c \\\"#\\{pane_current_path\\}\\\"\\3'/g\" \\\n# \"$cfg\"\n# fi\n#\n# tmux_conf_new_session_prompt=${tmux_conf_new_session_prompt:-false}\n# if ! _is_disabled \"$tmux_conf_new_session_prompt\" && _is_true \"$tmux_conf_new_session_prompt\"; then\n# perl -p -i -e \"\n# s/(?<!command-prompt -p )\\b(new-session)\\b(?!\\s+(?:-|}))/{$&}/g if /\\bdisplay-menu\\b/\n# ;\n# s/(?<!\\bcommand-prompt -p )\\bnew-session\\b(?! -s)/command-prompt -p new-session \\\"new-session -s '%%'\\\"/g\" \\\n# \"$cfg\"\n# else\n# perl -p -i -e \"s/\\bcommand-prompt\\s+-p\\s+new-session\\s+\\\"new-session\\s+-s\\s+'%%'\\\"/new-session/g\" \"$cfg\"\n# fi\n#\n# tmux_conf_new_session_retain_current_path=${tmux_conf_new_session_retain_current_path:-false}\n# if ! _is_disabled \"$tmux_conf_new_session_retain_current_path\" && _is_true \"$tmux_conf_new_session_retain_current_path\"; then\n# perl -p -i -e \"\n# s/(?<!\\bcommand-prompt -p )\\bnew-session\\b/new-session -c '#{pane_current_path}'/g\" \\\n# \"$cfg\"\n# else\n# perl -p -i -e \"\n# s/\\bnew-session\\b([^;}\\n]*?)(?:\\s+-c\\s+((?:\\\\\\\\\\\")?|\\\"?|'?)#\\{pane_current_path\\}\\2)/new-session\\1/g\" \\\n# \"$cfg\"\n# fi\n#\n# tmux_conf_copy_to_os_clipboard=${tmux_conf_copy_to_os_clipboard:-false}\n# command -v xsel > /dev/null 2>&1 && command='xsel -i -b'\n# ! command -v xsel > /dev/null 2>&1 && command -v xclip > /dev/null 2>&1 && command='xclip -i -selection clipboard > \\/dev\\/null 2>\\&1'\n# [ \"$XDG_SESSION_TYPE\" = \"wayland\" ] && command -v wl-copy > /dev/null 2>&1 && command='wl-copy'\n# command -v pbcopy > /dev/null 2>&1 && command='pbcopy'\n# command -v clip.exe > /dev/null 2>&1 && command='clip\\.exe'\n# [ -c /dev/clipboard ] && command='cat > \\/dev\\/clipboard'\n#\n# if [ -n \"$command\" ]; then\n# if ! _is_disabled \"$tmux_conf_copy_to_os_clipboard\" && _is_true \"$tmux_conf_copy_to_os_clipboard\"; then\n# perl -p -i -e \"s/(?!.*?$command)\\bcopy-(?:selection|pipe)(-end-of-line|-and-cancel|-end-of-line-and-cancel|-no-clear)?\\b/copy-pipe\\1 '$command'/g\" \"$cfg\"\n# else\n# if [ \"$_tmux_version\" -ge 3200 ]; then\n# perl -p -i -e \"s/\\bcopy-pipe(-end-of-line|-and-cancel|end-of-line-and-cancel|-no-clear)?\\b\\s+(\\\"|')?$command\\2?/copy-pipe\\1/g\" \"$cfg\"\n# else\n# perl -p -i -e \"s/\\bcopy-pipe(-end-of-line|-and-cancel|end-of-line-and-cancel|-no-clear)?\\b\\s+(\\\"|')?$command\\2?/copy-selection\\1/g\" \"$cfg\"\n# fi\n# fi\n# fi\n#\n# # until tmux >= 3.0, output of tmux list-keys can't be consumed back by tmux source-file without applying some escapings\n# awk < \"$cfg\" \\\n# '{i = $2 == \"-T\" ? 4 : 5; gsub(/^[;]$/, \"\\\\\\\\&\", $i); gsub(/^[$\"#~]$/, \"'\"'\"'&'\"'\"'\", $i); gsub(/^['\"'\"']$/, \"\\\"&\\\"\", $i); print}' > \"$cfg.in\"\n#\n# # ignore bindings with errors\n# if ! tmux source-file \"$cfg.in\"; then\n# if tmux source-file -v /dev/null 2> /dev/null; then\n# verbose_flag='-v'\n# fi\n# while ! out=$(tmux source-file \"${verbose_flag:+$verbose_flag}\" \"$cfg.in\"); do\n# line=$(printf \"%s\" \"$out\" | tail -1 | cut -d':' -f2)\n# perl -n -i -e \"if ($. != $line) { print }\" \"$cfg.in\"\n# done\n# fi\n#\n# tmux_conf_urlscan_options=${tmux_conf_urlscan_options:---compact --dedupe}\n# if command -v urlscan > /dev/null 2>&1; then\n# tmux bind U run \"cut -c3- '#{TMUX_CONF}' | sh -s _urlscan '#{pane_id}' $tmux_conf_urlscan_options\"\n# elif command -v urlview > /dev/null 2>&1; then\n# tmux bind U run \"cut -c3- '#{TMUX_CONF}' | sh -s _urlview '#{pane_id}'\"\n# fi\n# }\n#\n# _apply_theme() {\n# tmux_conf_theme=${tmux_conf_theme:-enabled}\n# if ! _is_disabled \"$tmux_conf_theme\"; then\n#\n# # -- default theme -------------------------------------------------------\n#\n# tmux_conf_theme_colour_1=${tmux_conf_theme_colour_1:-#080808} # dark gray\n# tmux_conf_theme_colour_2=${tmux_conf_theme_colour_2:-#303030} # gray\n# tmux_conf_theme_colour_3=${tmux_conf_theme_colour_3:-#8a8a8a} # light gray\n# tmux_conf_theme_colour_4=${tmux_conf_theme_colour_4:-#00afff} # light blue\n# tmux_conf_theme_colour_5=${tmux_conf_theme_colour_5:-#ffff00} # yellow\n# tmux_conf_theme_colour_6=${tmux_conf_theme_colour_6:-#080808} # dark gray\n# tmux_conf_theme_colour_7=${tmux_conf_theme_colour_7:-#e4e4e4} # white\n# tmux_conf_theme_colour_8=${tmux_conf_theme_colour_8:-#080808} # dark gray\n# tmux_conf_theme_colour_9=${tmux_conf_theme_colour_9:-#ffff00} # yellow\n# tmux_conf_theme_colour_10=${tmux_conf_theme_colour_10:-#ff00af} # pink\n# tmux_conf_theme_colour_11=${tmux_conf_theme_colour_11:-#5fff00} # green\n# tmux_conf_theme_colour_12=${tmux_conf_theme_colour_12:-#8a8a8a} # light gray\n# tmux_conf_theme_colour_13=${tmux_conf_theme_colour_13:-#e4e4e4} # white\n# tmux_conf_theme_colour_14=${tmux_conf_theme_colour_14:-#080808} # dark gray\n# tmux_conf_theme_colour_15=${tmux_conf_theme_colour_15:-#080808} # dark gray\n# tmux_conf_theme_colour_16=${tmux_conf_theme_colour_16:-#d70000} # red\n# tmux_conf_theme_colour_17=${tmux_conf_theme_colour_17:-#e4e4e4} # white\n#\n# # -- panes ---------------------------------------------------------------\n#\n# tmux_conf_theme_window_fg=${tmux_conf_theme_window_fg:-default}\n# tmux_conf_theme_window_bg=${tmux_conf_theme_window_bg:-default}\n# tmux_conf_theme_highlight_focused_pane=${tmux_conf_theme_highlight_focused_pane:-false}\n# tmux_conf_theme_focused_pane_fg=${tmux_conf_theme_focused_pane_fg:-default}\n# tmux_conf_theme_focused_pane_bg=${tmux_conf_theme_focused_pane_bg:-$tmux_conf_theme_colour_2}\n#\n# window_style=\"fg=$tmux_conf_theme_window_fg,bg=$tmux_conf_theme_window_bg\"\n# if _is_true \"$tmux_conf_theme_highlight_focused_pane\"; then\n# window_active_style=\"fg=$tmux_conf_theme_focused_pane_fg,bg=$tmux_conf_theme_focused_pane_bg\"\n# else\n# window_active_style=\"default\"\n# fi\n#\n# tmux_conf_theme_pane_border_style=${tmux_conf_theme_pane_border_style:-thin}\n# tmux_conf_theme_pane_border=${tmux_conf_theme_pane_border:-$tmux_conf_theme_colour_2}\n# tmux_conf_theme_pane_active_border=${tmux_conf_theme_pane_active_border:-$tmux_conf_theme_colour_4}\n# tmux_conf_theme_pane_border_fg=${tmux_conf_theme_pane_border_fg:-$tmux_conf_theme_pane_border}\n# tmux_conf_theme_pane_active_border_fg=${tmux_conf_theme_pane_active_border_fg:-$tmux_conf_theme_pane_active_border}\n# case \"$tmux_conf_theme_pane_border_style\" in\n# fat)\n# tmux_conf_theme_pane_border_bg=${tmux_conf_theme_pane_border_bg:-$tmux_conf_theme_pane_border_fg}\n# tmux_conf_theme_pane_active_border_bg=${tmux_conf_theme_pane_active_border_bg:-$tmux_conf_theme_pane_active_border_fg}\n# ;;\n# thin|*)\n# tmux_conf_theme_pane_border_bg=${tmux_conf_theme_pane_border_bg:-default}\n# tmux_conf_theme_pane_active_border_bg=${tmux_conf_theme_pane_active_border_bg:-default}\n# ;;\n# esac\n#\n# tmux_conf_theme_pane_indicator=${tmux_conf_theme_pane_indicator:-$tmux_conf_theme_colour_4}\n# tmux_conf_theme_pane_active_indicator=${tmux_conf_theme_pane_active_indicator:-$tmux_conf_theme_colour_4}\n#\n# # -- status line ---------------------------------------------------------\n#\n# tmux_conf_theme_left_separator_main=$(_decode_unicode_escapes \"${tmux_conf_theme_left_separator_main-}\")\n# tmux_conf_theme_left_separator_sub=$(_decode_unicode_escapes \"${tmux_conf_theme_left_separator_sub-|}\")\n# tmux_conf_theme_right_separator_main=$(_decode_unicode_escapes \"${tmux_conf_theme_right_separator_main-}\")\n# tmux_conf_theme_right_separator_sub=$(_decode_unicode_escapes \"${tmux_conf_theme_right_separator_sub-|}\")\n#\n# tmux_conf_theme_message_fg=${tmux_conf_theme_message_fg:-$tmux_conf_theme_colour_1}\n# tmux_conf_theme_message_bg=${tmux_conf_theme_message_bg:-$tmux_conf_theme_colour_5}\n# tmux_conf_theme_message_attr=${tmux_conf_theme_message_attr:-bold}\n#\n# tmux_conf_theme_message_command_fg=${tmux_conf_theme_message_command_fg:-$tmux_conf_theme_colour_5}\n# tmux_conf_theme_message_command_bg=${tmux_conf_theme_message_command_bg:-$tmux_conf_theme_colour_1}\n# tmux_conf_theme_message_command_attr=${tmux_conf_theme_message_command_attr:-bold}\n#\n# tmux_conf_theme_mode_fg=${tmux_conf_theme_mode_fg:-$tmux_conf_theme_colour_1}\n# tmux_conf_theme_mode_bg=${tmux_conf_theme_mode_bg:-$tmux_conf_theme_colour_5}\n# tmux_conf_theme_mode_attr=${tmux_conf_theme_mode_attr:-bold}\n#\n# tmux_conf_theme_status_fg=${tmux_conf_theme_status_fg:-$tmux_conf_theme_colour_3}\n# tmux_conf_theme_status_bg=${tmux_conf_theme_status_bg:-$tmux_conf_theme_colour_1}\n# tmux_conf_theme_status_attr=${tmux_conf_theme_status_attr:-none}\n#\n# tmux_conf_theme_terminal_title=${tmux_conf_theme_terminal_title:-#h ❐ #S ● #I #W}\n#\n# tmux_conf_theme_window_status_fg=${tmux_conf_theme_window_status_fg:-$tmux_conf_theme_colour_3}\n# tmux_conf_theme_window_status_bg=${tmux_conf_theme_window_status_bg:-$tmux_conf_theme_colour_1}\n# tmux_conf_theme_window_status_attr=${tmux_conf_theme_window_status_attr:-none}\n# tmux_conf_theme_window_status_format=${tmux_conf_theme_window_status_format:-'#I #W#{?#{||:#{window_bell_flag},#{window_zoomed_flag}}, ,}#{?window_bell_flag,!,}#{?window_zoomed_flag,Z,}'}\n#\n# tmux_conf_theme_window_status_current_fg=${tmux_conf_theme_window_status_current_fg:-$tmux_conf_theme_colour_1}\n# tmux_conf_theme_window_status_current_bg=${tmux_conf_theme_window_status_current_bg:-$tmux_conf_theme_colour_4}\n# tmux_conf_theme_window_status_current_attr=${tmux_conf_theme_window_status_current_attr:-bold}\n# tmux_conf_theme_window_status_current_format=${tmux_conf_theme_window_status_current_format:-'#I #W#{?#{||:#{window_bell_flag},#{window_zoomed_flag}}, ,}#{?window_bell_flag,!,}#{?window_zoomed_flag,Z,}'}\n#\n# tmux_conf_theme_window_status_activity_fg=${tmux_conf_theme_window_status_activity_fg:-default}\n# tmux_conf_theme_window_status_activity_bg=${tmux_conf_theme_window_status_activity_bg:-default}\n# tmux_conf_theme_window_status_activity_attr=${tmux_conf_theme_window_status_activity_attr:-underscore}\n#\n# tmux_conf_theme_window_status_bell_fg=${tmux_conf_theme_window_status_bell_fg:-$tmux_conf_theme_colour_5}\n# tmux_conf_theme_window_status_bell_bg=${tmux_conf_theme_window_status_bell_bg:-default}\n# tmux_conf_theme_window_status_bell_attr=${tmux_conf_theme_window_status_bell_attr:-blink,bold}\n#\n# tmux_conf_theme_window_status_last_fg=${tmux_conf_theme_window_status_last_fg:-$tmux_conf_theme_colour_4}\n# tmux_conf_theme_window_status_last_bg=${tmux_conf_theme_window_status_last_bg:-default}\n# tmux_conf_theme_window_status_last_attr=${tmux_conf_theme_window_status_last_attr:-none}\n#\n# if [ \"$tmux_conf_theme_window_status_bg\" = \"$tmux_conf_theme_status_bg\" ] || [ \"$tmux_conf_theme_window_status_bg\" = \"default\" ]; then\n# spacer=''\n# spacer_current=' '\n# else\n# spacer=' '\n# spacer_current=' '\n# fi\n# if [ \"$tmux_conf_theme_window_status_last_bg\" = \"$tmux_conf_theme_status_bg\" ] || [ \"$tmux_conf_theme_window_status_last_bg\" = \"default\" ] ; then\n# spacer_last=''\n# else\n# spacer_last=' '\n# fi\n# if [ \"$tmux_conf_theme_window_status_activity_bg\" = \"$tmux_conf_theme_status_bg\" ] || [ \"$tmux_conf_theme_window_status_activity_bg\" = \"default\" ] ; then\n# spacer_activity=''\n# spacer_last_activity=\"$spacer_last\"\n# else\n# spacer_activity=' '\n# spacer_last_activity=' '\n# fi\n# if [ \"$tmux_conf_theme_window_status_bell_bg\" = \"$tmux_conf_theme_status_bg\" ] || [ \"$tmux_conf_theme_window_status_bell_bg\" = \"default\" ] ; then\n# spacer_bell=''\n# spacer_last_bell=\"$spacer_last\"\n# spacer_activity_bell=\"$spacer_activity\"\n# spacer_last_activity_bell=\"$spacer_last_activity\"\n# else\n# spacer_bell=' '\n# spacer_last_bell=' '\n# spacer_activity_bell=' '\n# spacer_last_activity_bell=' '\n# fi\n# spacer=\"#{?window_last_flag,#{?window_activity_flag,#{?window_bell_flag,$spacer_last_activity_bell,$spacer_last_activity},#{?window_bell_flag,$spacer_last_bell,$spacer_last}},#{?window_activity_flag,#{?window_bell_flag,$spacer_activity_bell,$spacer_activity},#{?window_bell_flag,$spacer_bell,$spacer}}}\"\n# if [ \"$(tmux show -g -v status-justify)\" = \"right\" ]; then\n# if [ -z \"$tmux_conf_theme_right_separator_main\" ]; then\n# window_status_separator=' '\n# else\n# window_status_separator=''\n# fi\n# window_status_format=\"#[fg=$tmux_conf_theme_window_status_bg,bg=$tmux_conf_theme_status_bg,none]#{?window_last_flag,$(printf '%s' \"$tmux_conf_theme_window_status_last_bg\" | perl -n -e \"s/.+/#[fg=$&]/; print if !/default/\"),}#{?window_activity_flag,$(printf '%s' \"$tmux_conf_theme_window_status_activity_bg\" | perl -n -e \"s/.+/#[fg=$&]/; print if !/default/\"),}#{?window_bell_flag,$(printf '%s' \"$tmux_conf_theme_window_status_bell_bg\" | perl -n -e \"s/.+/#[fg=$&]/; print if !/default/\"),}$tmux_conf_theme_right_separator_main#[fg=$tmux_conf_theme_window_status_fg,bg=$tmux_conf_theme_window_status_bg,$tmux_conf_theme_window_status_attr]#{?window_last_flag,$(printf '%s' \"$tmux_conf_theme_window_status_last_fg\" | perl -n -e \"s/.+/#[fg=$&]/; print if !/default/\"),}#{?window_last_flag,$(printf '%s' \"$tmux_conf_theme_window_status_last_bg\" | perl -n -e \"s/.+/#[bg=$&]/; print if !/default/\"),}#{?window_activity_flag,$(printf '%s' \"$tmux_conf_theme_window_status_activity_fg\" | perl -n -e \"s/.+/#[fg=$&]/; print if !/default/\"),}#{?window_activity_flag,$(printf '%s' \"$tmux_conf_theme_window_status_activity_bg\" | perl -n -e \"s/.+/#[bg=$&]/; print if !/default/\"),}#{?window_bell_flag,$(printf '%s' \"$tmux_conf_theme_window_status_bell_fg\" | perl -n -e \"s/.+/#[fg=$&]/; print if !/default/\"),}#{?window_bell_flag,$(printf '%s' \"$tmux_conf_theme_window_status_bell_bg\" | perl -n -e \"s/.+/#[bg=$&]/; print if !/default/\"),}$spacer$(printf '%s' \"$tmux_conf_theme_window_status_last_attr\" | perl -n -e 'print \"#{?window_last_flag,#[none],}\" if !/default/ ; s/([a-z]+),?/#{?window_last_flag,#[\\1],}/g; print if !/default/')$(printf '%s' \"$tmux_conf_theme_window_status_activity_attr\" | perl -n -e 'print \"#{?window_activity_flag?,#[none],}\" if !/default/ ; s/([a-z]+),?/#{?window_activity_flag,#[\\1],}/g; print if !/default/')$(printf '%s' \"$tmux_conf_theme_window_status_bell_attr\" | perl -n -e 'print \"#{?window_bell_flag,#[none],}\" if !/default/ ; s/([a-z]+),?/#{?window_bell_flag,#[\\1],}/g; print if !/default/')$tmux_conf_theme_window_status_format#[none]$spacer#[fg=$tmux_conf_theme_status_bg,bg=$tmux_conf_theme_window_status_bg]#{?window_last_flag,$(printf '%s' \"$tmux_conf_theme_window_status_last_bg\" | perl -n -e \"s/.+/#[bg=$&]/; print if !/default/\"),}#{?window_activity_flag,$(printf '%s' \"$tmux_conf_theme_window_status_activity_bg\" | perl -n -e \"s/.+/#[bg=$&]/; print if !/default/\"),}#{?window_bell_flag,$(printf '%s' \"$tmux_conf_theme_window_status_bell_bg\" | perl -n -e \"s/.+/#[bg=$&]/; print if !/default/\"),}#[none]$tmux_conf_theme_right_separator_main\"\n# window_status_current_format=\"#[fg=$tmux_conf_theme_window_status_current_bg,bg=$tmux_conf_theme_status_bg,none]$tmux_conf_theme_right_separator_main#[fg=$tmux_conf_theme_window_status_current_fg,bg=$tmux_conf_theme_window_status_current_bg,$tmux_conf_theme_window_status_current_attr]$spacer_current$tmux_conf_theme_window_status_current_format$spacer_current#[fg=$tmux_conf_theme_status_bg,bg=$tmux_conf_theme_window_status_current_bg,none]$tmux_conf_theme_right_separator_main\"\n# else\n# if [ -z \"$tmux_conf_theme_left_separator_main\" ]; then\n# window_status_separator=' '\n# else\n# window_status_separator=''\n# fi\n# window_status_format=\"#[fg=$tmux_conf_theme_status_bg,bg=$tmux_conf_theme_window_status_bg,none]#{?window_last_flag,$(printf '%s' \"$tmux_conf_theme_window_status_last_bg\" | perl -n -e \"s/.+/#[bg=$&]/; print if !/default/\"),}#{?window_activity_flag,$(printf '%s' \"$tmux_conf_theme_window_status_activity_bg\" | perl -n -e \"s/.+/#[bg=$&]/; print if !/default/\"),}#{?window_bell_flag,$(printf '%s' \"$tmux_conf_theme_window_status_bell_bg\" | perl -n -e \"s/.+/#[bg=$&]/; print if !/default/\"),}$tmux_conf_theme_left_separator_main#[fg=$tmux_conf_theme_window_status_fg,bg=$tmux_conf_theme_window_status_bg,$tmux_conf_theme_window_status_attr]#{?window_last_flag,$(printf '%s' \"$tmux_conf_theme_window_status_last_fg\" | perl -n -e \"s/.+/#[fg=$&]/; print if !/default/\"),}#{?window_last_flag,$(printf '%s' \"$tmux_conf_theme_window_status_last_bg\" | perl -n -e \"s/.+/#[bg=$&]/; print if !/default/\"),}#{?window_activity_flag,$(printf '%s' \"$tmux_conf_theme_window_status_activity_fg\" | perl -n -e \"s/.+/#[fg=$&]/; print if !/default/\"),}#{?window_activity_flag,$(printf '%s' \"$tmux_conf_theme_window_status_activity_bg\" | perl -n -e \"s/.+/#[bg=$&]/; print if !/default/\"),}#{?window_bell_flag,$(printf '%s' \"$tmux_conf_theme_window_status_bell_fg\" | perl -n -e \"s/.+/#[fg=$&]/; print if !/default/\"),}#{?window_bell_flag,$(printf '%s' \"$tmux_conf_theme_window_status_bell_bg\" | perl -n -e \"s/.+/#[bg=$&]/; print if !/default/\"),}$spacer$(printf '%s' \"$tmux_conf_theme_window_status_last_attr\" | perl -n -e 'print \"#{?window_last_flag,#[none],}\" if !/default/ ; s/([a-z]+),?/#{?window_last_flag,#[\\1],}/g; print if !/default/')$(printf '%s' \"$tmux_conf_theme_window_status_activity_attr\" | perl -n -e 'print \"#{?window_activity_flag,#[none],}\" if !/default/ ; s/([a-z]+),?/#{?window_activity_flag,#[\\1],}/g; print if !/default/')$(printf '%s' \"$tmux_conf_theme_window_status_bell_attr\" | perl -n -e 'print \"#{?window_bell_flag,#[none],}\" if /!default/ ; s/([a-z]+),?/#{?window_bell_flag,#[\\1],}/g; print if !/default/')$tmux_conf_theme_window_status_format#[none]$spacer#[fg=$tmux_conf_theme_window_status_bg,bg=$tmux_conf_theme_status_bg]#{?window_last_flag,$(printf '%s' \"$tmux_conf_theme_window_status_last_bg\" | perl -n -e \"s/.+/#[fg=$&]/; print if !/default/\"),}#{?window_activity_flag,$(printf '%s' \"$tmux_conf_theme_window_status_activity_bg\" | perl -n -e \"s/.+/#[fg=$&]/; print if !/default/\"),}#{?window_bell_flag,$(printf '%s' \"$tmux_conf_theme_window_status_bell_bg\" | perl -n -e \"s/.+/#[fg=$&]/; print if !/default/\"),}$tmux_conf_theme_left_separator_main\"\n# window_status_current_format=\"#[fg=$tmux_conf_theme_status_bg,bg=$tmux_conf_theme_window_status_current_bg,none]$tmux_conf_theme_left_separator_main#[fg=$tmux_conf_theme_window_status_current_fg,bg=$tmux_conf_theme_window_status_current_bg,$tmux_conf_theme_window_status_current_attr]$spacer_current$tmux_conf_theme_window_status_current_format$spacer_current#[fg=$tmux_conf_theme_window_status_current_bg,bg=$tmux_conf_theme_status_bg]$tmux_conf_theme_left_separator_main\"\n# fi\n#\n# # -- indicators\n#\n# tmux_conf_theme_pairing=${tmux_conf_theme_pairing:-⚇} # U+2687\n# tmux_conf_theme_pairing_fg=${tmux_conf_theme_pairing_fg:-none}\n# tmux_conf_theme_pairing_bg=${tmux_conf_theme_pairing_bg:-none}\n# tmux_conf_theme_pairing_attr=${tmux_conf_theme_pairing_attr:-none}\n#\n# tmux_conf_theme_prefix=${tmux_conf_theme_prefix:-⌨} # U+2328\n# tmux_conf_theme_prefix_fg=${tmux_conf_theme_prefix_fg:-none}\n# tmux_conf_theme_prefix_bg=${tmux_conf_theme_prefix_bg:-none}\n# tmux_conf_theme_prefix_attr=${tmux_conf_theme_prefix_attr:-none}\n#\n# tmux_conf_theme_mouse=${tmux_conf_theme_mouse:-↗} # U+2197\n# tmux_conf_theme_mouse_fg=${tmux_conf_theme_mouse_fg:-none}\n# tmux_conf_theme_mouse_bg=${tmux_conf_theme_mouse_bg:-none}\n# tmux_conf_theme_mouse_attr=${tmux_conf_theme_mouse_attr:-none}\n#\n# tmux_conf_theme_root=${tmux_conf_theme_root:-!}\n# tmux_conf_theme_root_fg=${tmux_conf_theme_root_fg:-none}\n# tmux_conf_theme_root_bg=${tmux_conf_theme_root_bg:-none}\n# tmux_conf_theme_root_attr=${tmux_conf_theme_root_attr:-bold,blink}\n#\n# tmux_conf_theme_synchronized=${tmux_conf_theme_synchronized:-⚏} # U+268F\n# tmux_conf_theme_synchronized_fg=${tmux_conf_theme_synchronized_fg:-none}\n# tmux_conf_theme_synchronized_bg=${tmux_conf_theme_synchronized_bg:-none}\n# tmux_conf_theme_synchronized_attr=${tmux_conf_theme_synchronized_attr:-none}\n#\n# # -- status-left style\n#\n# tmux_conf_theme_status_left=${tmux_conf_theme_status_left-' ❐ #S | ↑#{?uptime_y, #{uptime_y}y,}#{?uptime_d, #{uptime_d}d,}#{?uptime_h, #{uptime_h}h,}#{?uptime_m, #{uptime_m}m,} '}\n# tmux_conf_theme_status_left_fg=${tmux_conf_theme_status_left_fg:-$tmux_conf_theme_colour_6,$tmux_conf_theme_colour_7,$tmux_conf_theme_colour_8}\n# tmux_conf_theme_status_left_bg=${tmux_conf_theme_status_left_bg:-$tmux_conf_theme_colour_9,$tmux_conf_theme_colour_10,$tmux_conf_theme_colour_11}\n# tmux_conf_theme_status_left_attr=${tmux_conf_theme_status_left_attr:-bold,none,none}\n#\n# if [ -n \"$tmux_conf_theme_status_left\" ]; then\n# status_left=$(echo \"$tmux_conf_theme_status_left\" | sed \\\n# -e \"s/#{pairing}/#[fg=$tmux_conf_theme_pairing_fg]#[bg=$tmux_conf_theme_pairing_bg]#[$tmux_conf_theme_pairing_attr]#{pairing}#[inherit]/g\" \\\n# -e \"s/#{prefix}/#[fg=$tmux_conf_theme_prefix_fg]#[bg=$tmux_conf_theme_prefix_bg]#[$tmux_conf_theme_prefix_attr]#{prefix}#[inherit]/g\" \\\n# -e \"s/#{mouse}/#[fg=$tmux_conf_theme_mouse_fg]#[bg=$tmux_conf_theme_mouse_bg]#[$tmux_conf_theme_mouse_attr]#{mouse}#[inherit]/g\" \\\n# -e \"s/#{synchronized}/#[fg=$tmux_conf_theme_synchronized_fg]#[bg=$tmux_conf_theme_synchronized_bg]#[$tmux_conf_theme_synchronized_attr]#{synchronized}#[inherit]/g\" \\\n# -e \"s/#{root}/#[fg=$tmux_conf_theme_root_fg]#[bg=$tmux_conf_theme_root_bg]#[$tmux_conf_theme_root_attr]#{root}#[inherit]/g\")\n#\n# status_left=$(printf '%s' \"$status_left\" | awk \\\n# -v status_bg=\"$tmux_conf_theme_status_bg\" \\\n# -v fg_=\"$tmux_conf_theme_status_left_fg\" \\\n# -v bg_=\"$tmux_conf_theme_status_left_bg\" \\\n# -v attr_=\"$tmux_conf_theme_status_left_attr\" \\\n# -v mainsep=\"$tmux_conf_theme_left_separator_main\" \\\n# -v subsep=\"$tmux_conf_theme_left_separator_sub\" '\n# function subsplit(s, l, i, a, r)\n# {\n# l = split(s, a, \",\")\n# for (i = 1; i <= l; ++i)\n# {\n# o = split(a[i], _, \"(\") - 1\n# c = split(a[i], _, \")\") - 1\n# open += o - c\n# o_ = split(a[i], _, \"{\") - 1\n# c_ = split(a[i], _, \"}\") - 1\n# open_ += o_ - c_\n# o__ = split(a[i], _, \"[\") - 1\n# c__ = split(a[i], _, \"]\") - 1\n# open__ += o__ - c__\n#\n# if (i == l)\n# r = sprintf(\"%s%s\", r, a[i])\n# else if (open || open_ || open__)\n# r = sprintf(\"%s%s,\", r, a[i])\n# else\n# r = sprintf(\"%s%s#[fg=%s,bg=%s,%s]%s\", r, a[i], fg[j], bg[j], attr[j], subsep)\n# }\n#\n# gsub(/#\\[inherit\\]/, sprintf(\"#[default]#[fg=%s,bg=%s,%s]\", fg[j], bg[j], attr[j]), r)\n# return r\n# }\n# BEGIN {\n# FS = \"|\"\n# l1 = split(fg_, fg, \",\")\n# l2 = split(bg_, bg, \",\")\n# l3 = split(attr_, attr, \",\")\n# l = l1 < l2 ? (l1 < l3 ? l1 : l3) : (l2 < l3 ? l2 : l3)\n# }\n# {\n# for (i = j = 1; i <= NF; ++i)\n# {\n# if (open || open_ || open__)\n# printf \"|%s\", subsplit($i)\n# else\n# {\n# if (i > 1)\n# printf \"#[fg=%s,bg=%s,none]%s#[fg=%s,bg=%s,%s]%s\", bg[j_], bg[j], mainsep, fg[j], bg[j], attr[j], subsplit($i)\n# else\n# printf \"#[fg=%s,bg=%s,%s]%s\", fg[j], bg[j], attr[j], subsplit($i)\n# }\n#\n# if (!open && !open_ && !open__)\n# {\n# j_ = j\n# j = j % l + 1\n# }\n# }\n# printf \"#[fg=%s,bg=%s,none]%s\", bg[j_], status_bg, mainsep\n# }')\n# fi\n# status_left=\"$status_left \"\n#\n# # -- status-right style\n#\n# tmux_conf_theme_status_right=${tmux_conf_theme_status_right-' #{prefix}#{mouse}#{pairing}#{synchronized}#{?battery_status, #{battery_status},}#{?battery_bar, #{battery_bar},}#{?battery_percentage, #{battery_percentage},} , %R , %d %b | #{username}#{root} | #{hostname} '}\n# tmux_conf_theme_status_right_fg=${tmux_conf_theme_status_right_fg:-$tmux_conf_theme_colour_12,$tmux_conf_theme_colour_13,$tmux_conf_theme_colour_14}\n# tmux_conf_theme_status_right_bg=${tmux_conf_theme_status_right_bg:-$tmux_conf_theme_colour_15,$tmux_conf_theme_colour_16,$tmux_conf_theme_colour_17}\n# tmux_conf_theme_status_right_attr=${tmux_conf_theme_status_right_attr:-none,none,bold}\n#\n# if [ -n \"$tmux_conf_theme_status_right\" ]; then\n# status_right=$(echo \"$tmux_conf_theme_status_right\" | sed \\\n# -e \"s/#{pairing}/#[fg=$tmux_conf_theme_pairing_fg]#[bg=$tmux_conf_theme_pairing_bg]#[$tmux_conf_theme_pairing_attr]#{pairing}#[inherit]/g\" \\\n# -e \"s/#{prefix}/#[fg=$tmux_conf_theme_prefix_fg]#[bg=$tmux_conf_theme_prefix_bg]#[$tmux_conf_theme_prefix_attr]#{prefix}#[inherit]/g\" \\\n# -e \"s/#{mouse}/#[fg=$tmux_conf_theme_mouse_fg]#[bg=$tmux_conf_theme_mouse_bg]#[$tmux_conf_theme_mouse_attr]#{mouse}#[inherit]/g\" \\\n# -e \"s/#{synchronized}/#[fg=$tmux_conf_theme_synchronized_fg]#[bg=$tmux_conf_theme_synchronized_bg]#[$tmux_conf_theme_synchronized_attr]#{synchronized}#[inherit]/g\" \\\n# -e \"s/#{root}/#[fg=$tmux_conf_theme_root_fg]#[bg=$tmux_conf_theme_root_bg]#[$tmux_conf_theme_root_attr]#{root}#[inherit]/g\")\n#\n# status_right=$(printf '%s' \"$status_right\" | awk \\\n# -v status_bg=\"$tmux_conf_theme_status_bg\" \\\n# -v fg_=\"$tmux_conf_theme_status_right_fg\" \\\n# -v bg_=\"$tmux_conf_theme_status_right_bg\" \\\n# -v attr_=\"$tmux_conf_theme_status_right_attr\" \\\n# -v mainsep=\"$tmux_conf_theme_right_separator_main\" \\\n# -v subsep=\"$tmux_conf_theme_right_separator_sub\" '\n# function subsplit(s, l, i, a, r)\n# {\n# l = split(s, a, \",\")\n# for (i = 1; i <= l; ++i)\n# {\n# o = split(a[i], _, \"(\") - 1\n# c = split(a[i], _, \")\") - 1\n# open += o - c\n# o_ = split(a[i], _, \"{\") - 1\n# c_ = split(a[i], _, \"}\") - 1\n# open_ += o_ - c_\n# o__ = split(a[i], _, \"[\") - 1\n# c__ = split(a[i], _, \"]\") - 1\n# open__ += o__ - c__\n#\n# if (i == l)\n# r = sprintf(\"%s%s\", r, a[i])\n# else if (open || open_ || open__)\n# r = sprintf(\"%s%s,\", r, a[i])\n# else\n# r = sprintf(\"%s%s#[fg=%s,bg=%s,%s]%s\", r, a[i], fg[j], bg[j], attr[j], subsep)\n# }\n#\n# gsub(/#\\[inherit\\]/, sprintf(\"#[default]#[fg=%s,bg=%s,%s]\", fg[j], bg[j], attr[j]), r)\n# return r\n# }\n# BEGIN {\n# FS = \"|\"\n# l1 = split(fg_, fg, \",\")\n# l2 = split(bg_, bg, \",\")\n# l3 = split(attr_, attr, \",\")\n# l = l1 < l2 ? (l1 < l3 ? l1 : l3) : (l2 < l3 ? l2 : l3)\n# }\n# {\n# for (i = j = 1; i <= NF; ++i)\n# {\n# if (open_ || open || open__)\n# printf \"|%s\", subsplit($i)\n# else\n# printf \"#[fg=%s,bg=%s,none]%s#[fg=%s,bg=%s,%s]%s\", bg[j], (i == 1) ? status_bg : bg[j_], mainsep, fg[j], bg[j], attr[j], subsplit($i)\n#\n# if (!open && !open_ && !open__)\n# {\n# j_ = j\n# j = j % l + 1\n# }\n# }\n# }')\n# fi\n# status_right=${status_right-}\n#\n# # -- clock ---------------------------------------------------------------\n#\n# tmux_conf_theme_clock_colour=${tmux_conf_theme_clock_colour:-$tmux_conf_theme_colour_4}\n# tmux_conf_theme_clock_style=${tmux_conf_theme_clock_style:-24}\n#\n# tmux setw -g window-style \"$window_style\" \\; setw -g window-active-style \"$window_active_style\" \\;\\\n# setw -g pane-border-style \"fg=$tmux_conf_theme_pane_border_fg,bg=$tmux_conf_theme_pane_border_bg\" \\; set -g pane-active-border-style \"fg=$tmux_conf_theme_pane_active_border_fg,bg=$tmux_conf_theme_pane_active_border_bg\" \\;\\\n# set -g display-panes-colour \"$tmux_conf_theme_pane_indicator\" \\; set -g display-panes-active-colour \"$tmux_conf_theme_pane_active_indicator\" \\;\\\n# set -g message-style \"fg=$tmux_conf_theme_message_fg,bg=$tmux_conf_theme_message_bg,$tmux_conf_theme_message_attr\" \\;\\\n# set -g message-command-style \"fg=$tmux_conf_theme_message_command_fg,bg=$tmux_conf_theme_message_command_bg,$tmux_conf_theme_message_command_attr\" \\;\\\n# setw -g mode-style \"fg=$tmux_conf_theme_mode_fg,bg=$tmux_conf_theme_mode_bg,$tmux_conf_theme_mode_attr\" \\;\\\n# set -g status-style \"fg=$tmux_conf_theme_status_fg,bg=$tmux_conf_theme_status_bg,$tmux_conf_theme_status_attr\" \\;\\\n# set -g status-left-style \"fg=$tmux_conf_theme_status_fg,bg=$tmux_conf_theme_status_bg,$tmux_conf_theme_status_attr\" \\;\\\n# set -g status-right-style \"fg=$tmux_conf_theme_status_fg,bg=$tmux_conf_theme_status_bg,$tmux_conf_theme_status_attr\" \\;\\\n# setw -g window-status-style \"fg=$tmux_conf_theme_window_status_fg,bg=$tmux_conf_theme_window_status_bg,$tmux_conf_theme_window_status_attr\" \\;\\\n# setw -g window-status-current-style \"fg=$tmux_conf_theme_window_status_current_fg,bg=$tmux_conf_theme_window_status_current_bg,$tmux_conf_theme_window_status_current_attr\" \\;\\\n# setw -g window-status-activity-style \"fg=$tmux_conf_theme_window_status_activity_fg,bg=$tmux_conf_theme_window_status_activity_bg,$tmux_conf_theme_window_status_activity_attr\" \\;\\\n# setw -g window-status-bell-style \"fg=$tmux_conf_theme_window_status_bell_fg,bg=$tmux_conf_theme_window_status_bell_bg,$tmux_conf_theme_window_status_bell_attr\" \\;\\\n# setw -g window-status-last-style \"fg=$tmux_conf_theme_window_status_last_fg,bg=$tmux_conf_theme_window_status_last_bg,$tmux_conf_theme_window_status_last_attr\" \\;\\\n# setw -g window-status-separator \"$window_status_separator\" \\;\\\n# setw -g clock-mode-colour \"$tmux_conf_theme_clock_colour\" \\;\\\n# setw -g clock-mode-style \"$tmux_conf_theme_clock_style\"\n# fi\n#\n# # -- variables -------------------------------------------------------------\n#\n# set_titles_string=$(printf '%s' \"${tmux_conf_theme_terminal_title:-$(tmux show -gv set-titles-string)}\" | sed \\\n# -e \"s%#{circled_window_index}%#(cut -c3- '$TMUX_CONF' | sh -s _circled '#I')%g\" \\\n# -e \"s%#{circled_session_name}%#(cut -c3- '$TMUX_CONF' | sh -s _circled '#S')%g\" \\\n# -e \"s%#{pretty_pane_current_path}%#(cut -c3- '$TMUX_CONF' | sh -s _pretty_path auto '#{pane_current_path}')%g\" \\\n# -e \"s%#{username}%#(cut -c3- '$TMUX_CONF' | sh -s _username '#{pane_pid}' '#{b:pane_tty}' false '#D')%g\" \\\n# -e \"s%#{hostname}%#(cut -c3- '$TMUX_CONF' | sh -s _hostname '#{pane_pid}' '#{b:pane_tty}' false false '#h' '#D')%g\" \\\n# -e \"s%#{hostname_full}%#(cut -c3- '$TMUX_CONF' | sh -s _hostname '#{pane_pid}' '#{b:pane_tty}' false true '#H' '#D')%g\" \\\n# -e \"s%#{username_ssh}%#(cut -c3- '$TMUX_CONF' | sh -s _username '#{pane_pid}' '#{b:pane_tty}' true '#D')%g\" \\\n# -e \"s%#{hostname_ssh}%#(cut -c3- '$TMUX_CONF' | sh -s _hostname '#{pane_pid}' '#{b:pane_tty}' true false '#h' '#D')%g\" \\\n# -e \"s%#{hostname_full_ssh}%#(cut -c3- '$TMUX_CONF' | sh -s _hostname '#{pane_pid}' '#{b:pane_tty}' true true '#H' '#D')%g\")\n#\n# window_status_format=$(printf '%s' \"${window_status_format:-$(tmux show -gv window-status-format)}\" | sed \\\n# -e \"s%#{circled_window_index}%#(cut -c3- '$TMUX_CONF' | sh -s _circled '#I')%g\" \\\n# -e \"s%#{circled_session_name}%#(cut -c3- '$TMUX_CONF' | sh -s _circled '#S')%g\" \\\n# -e \"s%#{pretty_pane_current_path}%#(cut -c3- '$TMUX_CONF' | sh -s _pretty_path auto '#{pane_current_path}')%g\" \\\n# -e \"s%#{username}%#(cut -c3- '$TMUX_CONF' | sh -s _username '#{pane_pid}' '#{b:pane_tty}' false '#D')%g\" \\\n# -e \"s%#{hostname}%#(cut -c3- '$TMUX_CONF' | sh -s _hostname '#{pane_pid}' '#{b:pane_tty}' false false '#h' '#D')%g\" \\\n# -e \"s%#{hostname_full}%#(cut -c3- '$TMUX_CONF' | sh -s _hostname '#{pane_pid}' '#{b:pane_tty}' false true '#H' '#D')%g\" \\\n# -e \"s%#{username_ssh}%#(cut -c3- '$TMUX_CONF' | sh -s _username '#{pane_pid}' '#{b:pane_tty}' true '#D')%g\" \\\n# -e \"s%#{hostname_ssh}%#(cut -c3- '$TMUX_CONF' | sh -s _hostname '#{pane_pid}' '#{b:pane_tty}' true false '#h' '#D')%g\" \\\n# -e \"s%#{hostname_full_ssh}%#(cut -c3- '$TMUX_CONF' | sh -s _hostname '#{pane_pid}' '#{b:pane_tty}' true true '#H' '#D')%g\")\n#\n# window_status_current_format=$(printf '%s' \"${window_status_current_format:-$(tmux show -gv window-status-current-format)}\" | sed \\\n# -e \"s%#{circled_window_index}%#(cut -c3- '$TMUX_CONF' | sh -s _circled '#I')%g\" \\\n# -e \"s%#{circled_session_name}%#(cut -c3- '$TMUX_CONF' | sh -s _circled '#S')%g\" \\\n# -e \"s%#{pretty_pane_current_path}%#(cut -c3- '$TMUX_CONF' | sh -s _pretty_path auto '#{pane_current_path}')%g\" \\\n# -e \"s%#{username}%#(cut -c3- '$TMUX_CONF' | sh -s _username '#{pane_pid}' '#{b:pane_tty}' false '#D')%g\" \\\n# -e \"s%#{hostname}%#(cut -c3- '$TMUX_CONF' | sh -s _hostname '#{pane_pid}' '#{b:pane_tty}' false false '#h' '#D')%g\" \\\n# -e \"s%#{hostname_full}%#(cut -c3- '$TMUX_CONF' | sh -s _hostname '#{pane_pid}' '#{b:pane_tty}' false true '#H' '#D')%g\" \\\n# -e \"s%#{username_ssh}%#(cut -c3- '$TMUX_CONF' | sh -s _username '#{pane_pid}' '#{b:pane_tty}' true '#D')%g\" \\\n# -e \"s%#{hostname_ssh}%#(cut -c3- '$TMUX_CONF' | sh -s _hostname '#{pane_pid}' '#{b:pane_tty}' true false '#h' '#D')%g\" \\\n# -e \"s%#{hostname_full_ssh}%#(cut -c3- '$TMUX_CONF' | sh -s _hostname '#{pane_pid}' '#{b:pane_tty}' true true '#H' '#D')%g\")\n#\n# status_left=$(printf '%s' \"${status_left-$(tmux show -gv status-left)}\" | sed \\\n# -e \"s/#{pairing}/#{?session_many_attached,$tmux_conf_theme_pairing ,}/g\" \\\n# -e \"s/#{prefix}/#{?client_prefix,$tmux_conf_theme_prefix ,$(printf '%s' \"$tmux_conf_theme_prefix\" | sed -e 's/./ /g') }/g\" \\\n# -e \"s/#{mouse}/#{?mouse,$tmux_conf_theme_mouse ,$(printf '%s' \"$tmux_conf_theme_mouse\" | sed -e 's/./ /g') }/g\" \\\n# -e \"s%#{synchronized}%#{?pane_synchronized,$tmux_conf_theme_synchronized ,}%g\" \\\n# -e \"s%#{circled_session_name}%#(cut -c3- '$TMUX_CONF' | sh -s _circled '#S')%g\" \\\n# -e \"s%#{pretty_pane_current_path}%#(cut -c3- '$TMUX_CONF' | sh -s _pretty_path auto '#{pane_current_path}')%g\" \\\n# -e \"s%#{root}%#{?#{==:#(cut -c3- '$TMUX_CONF' | sh -s _username '#{pane_pid}' '#{b:pane_tty}' '#D'),root},$tmux_conf_theme_root,}%g\")\n#\n# status_right=$(printf '%s' \"${status_right-$(tmux show -gv status-right)}\" | sed \\\n# -e \"s/#{pairing}/#{?session_many_attached,$tmux_conf_theme_pairing ,}/g\" \\\n# -e \"s/#{prefix}/#{?client_prefix,$tmux_conf_theme_prefix ,$(printf '%s' \"$tmux_conf_theme_prefix\" | sed -e 's/./ /g') }/g\" \\\n# -e \"s/#{mouse}/#{?mouse,$tmux_conf_theme_mouse ,$(printf '%s' \"$tmux_conf_theme_mouse\" | sed -e 's/./ /g') }/g\" \\\n# -e \"s%#{synchronized}%#{?pane_synchronized,$tmux_conf_theme_synchronized ,}%g\" \\\n# -e \"s%#{circled_session_name}%#(cut -c3- '$TMUX_CONF' | sh -s _circled '#S')%g\" \\\n# -e \"s%#{pretty_pane_current_path}%#(cut -c3- '$TMUX_CONF' | sh -s _pretty_path auto '#{pane_current_path}')%g\" \\\n# -e \"s%#{root}%#{?#{==:#(cut -c3- '$TMUX_CONF' | sh -s _username '#{pane_pid}' '#{b:pane_tty}' '#D'),root},$tmux_conf_theme_root,}%g\")\n#\n# tmux_conf_battery_bar_symbol_full=$(_decode_unicode_escapes \"${tmux_conf_battery_bar_symbol_full:-◼}\")\n# tmux_conf_battery_bar_symbol_empty=$(_decode_unicode_escapes \"${tmux_conf_battery_bar_symbol_empty:-◻}\")\n# tmux_conf_battery_bar_length=${tmux_conf_battery_bar_length:-auto}\n# tmux_conf_battery_bar_palette=${tmux_conf_battery_bar_palette:-gradient}\n# tmux_conf_battery_hbar_palette=${tmux_conf_battery_hbar_palette:-gradient}\n# tmux_conf_battery_vbar_palette=${tmux_conf_battery_vbar_palette:-gradient}\n# tmux_conf_battery_status_charging=$(_decode_unicode_escapes \"${tmux_conf_battery_status_charging:-↑}\") # U+2191\n# tmux_conf_battery_status_discharging=$(_decode_unicode_escapes \"${tmux_conf_battery_status_discharging:-↓}\") # U+2193\n#\n# _pkillf 'sh -s _battery_info'\n# _battery_info\n# if [ \"$battery_charge\" != 0 ]; then\n# case \"$status_left $status_right\" in\n# *'#{battery_'*|*'#{?battery_'*)\n# status_left=$(echo \"$status_left\" | sed -E \\\n# -e 's%#\\{\\?battery_bar%#\\{?@battery_percentage%g' \\\n# -e 's%#\\{\\?battery_hbar%#\\{?@battery_percentage%g' \\\n# -e 's%#\\{\\?battery_vbar%#\\{?@battery_percentage%g' \\\n# -e \"s%#\\{battery_bar\\}%#(nice cut -c3- '$TMUX_CONF' | sh -s _bar '$(printf '%s' \"$tmux_conf_battery_bar_palette\" | tr ',' ';')' '$tmux_conf_battery_bar_symbol_empty' '$tmux_conf_battery_bar_symbol_full' '$tmux_conf_battery_bar_length' '#{@battery_charge}' '#{client_width}')%g\" \\\n# -e \"s%#\\{battery_hbar\\}%#(nice cut -c3- '$TMUX_CONF' | sh -s _hbar '$(printf '%s' \"$tmux_conf_battery_hbar_palette\" | tr ',' ';')' '#{@battery_charge}')%g\" \\\n# -e \"s%#\\{battery_vbar\\}%#(nice cut -c3- '$TMUX_CONF' | sh -s _vbar '$(printf '%s' \"$tmux_conf_battery_vbar_palette\" | tr ',' ';')' '#{@battery_charge}')%g\" \\\n# -e 's%#\\{(\\?)?battery_status%#\\{\\1@battery_status%g' \\\n# -e 's%#\\{(\\?)?battery_percentage%#\\{\\1@battery_percentage%g')\n# status_right=$(echo \"$status_right\" | sed -E \\\n# -e 's%#\\{\\?battery_bar%#\\{?@battery_percentage%g' \\\n# -e 's%#\\{\\?battery_hbar%#\\{?@battery_percentage%g' \\\n# -e 's%#\\{\\?battery_vbar%#\\{?@battery_percentage%g' \\\n# -e \"s%#\\{battery_bar\\}%#(nice cut -c3- '$TMUX_CONF' | sh -s _bar '$(printf '%s' \"$tmux_conf_battery_bar_palette\" | tr ',' ';')' '$tmux_conf_battery_bar_symbol_empty' '$tmux_conf_battery_bar_symbol_full' '$tmux_conf_battery_bar_length' '#{@battery_charge}' '#{client_width}')%g\" \\\n# -e \"s%#\\{battery_hbar\\}%#(nice cut -c3- '$TMUX_CONF' | sh -s _hbar '$(printf '%s' \"$tmux_conf_battery_hbar_palette\" | tr ',' ';')' '#{@battery_charge}')%g\" \\\n# -e \"s%#\\{battery_vbar\\}%#(nice cut -c3- '$TMUX_CONF' | sh -s _vbar '$(printf '%s' \"$tmux_conf_battery_vbar_palette\" | tr ',' ';')' '#{@battery_charge}')%g\" \\\n# -e 's%#\\{(\\?)?battery_status%#\\{\\1@battery_status%g' \\\n# -e 's%#\\{(\\?)?battery_percentage%#\\{\\1@battery_percentage%g')\n# status_right=\"#(echo; nice cut -c3- '$TMUX_CONF' | sh -s _battery_status '$tmux_conf_battery_status_charging' '$tmux_conf_battery_status_discharging')$status_right\"\n# interval=60\n# if [ \"$_tmux_version\" -eq 3500 ]; then\n# tmux run -b \"exec sh -c 'trap \\\"[ -n \\\\\\\\\\\"\\\\\\\\\\$sleep_pid\\\\\\\\\\\" ] && kill -9 \\\\\\\\\\\"\\\\\\\\\\$sleep_pid\\\\\\\\\\\"; exit 0\\\" TERM; while [ \\\"\\$(\\\"$TMUX_PROGRAM\\\" -S \\\"#{socket_path}\\\" display -p \\\"#{l:#{pid}}\\\")\\\" = \\\"#{pid}\\\" ]; do nice cut -c3- \\\"$TMUX_CONF\\\" | sh -s _battery_info; sleep $interval & sleep_pid=\\$!; wait \\\"\\$sleep_pid\\\"; sleep_pid=; done'\"\n# elif [ \"$_tmux_version\" -ge 3200 ]; then\n# tmux run -b \"trap '[ -n \\\"\\$sleep_pid\\\" ] && kill -9 \\\"\\$sleep_pid\\\"; exit 0' TERM; while [ \\\"\\$(\\\"$TMUX_PROGRAM\\\" -S '#{socket_path}' display -p '#{l:#{pid}}')\\\" = \\\"#{pid}\\\" ]; do nice cut -c3- '$TMUX_CONF' | sh -s _battery_info; sleep $interval & sleep_pid=\\$!; wait \\\"\\$sleep_pid\\\"; sleep_pid=; done\"\n# elif [ \"$_tmux_version\" -ge 2800 ]; then\n# status_right=\"#(echo; while [ \\\"\\$(\\\"$TMUX_PROGRAM\\\" -S '#{socket_path}' display -p '#{l:#{pid}}')\\\" = \\\"#{pid}\\\" ]; do nice cut -c3- '$TMUX_CONF' | sh -s _battery_info; sleep $interval; done)$status_right\"\n# elif [ \"$_tmux_version\" -gt 2400 ]; then\n# status_right=\"#(echo; while :; do nice cut -c3- '$TMUX_CONF' | sh -s _battery_info; sleep $interval; done)$status_right\"\n# else\n# status_right=\"#(nice cut -c3- '$TMUX_CONF' | sh -s _battery_info)$status_right\"\n# fi\n# ;;\n# esac\n# fi\n#\n# case \"$status_left $status_right\" in\n# *'#{username}'*|*'#{hostname}'*|*'#{hostname_full}'*|*'#{username_ssh}'*|*'#{hostname_ssh}'*|*'#{hostname_full_ssh}'*)\n# status_left=$(echo \"$status_left\" | sed \\\n# -e \"s%#{username}%#(cut -c3- '$TMUX_CONF' | sh -s _username '#{pane_pid}' '#{b:pane_tty}' false '#D')%g\" \\\n# -e \"s%#{hostname}%#(cut -c3- '$TMUX_CONF' | sh -s _hostname '#{pane_pid}' '#{b:pane_tty}' false false '#h' '#D')%g\" \\\n# -e \"s%#{hostname_full}%#(cut -c3- '$TMUX_CONF' | sh -s _hostname '#{pane_pid}' '#{b:pane_tty}' false true '#H' '#D')%g\" \\\n# -e \"s%#{username_ssh}%#(cut -c3- '$TMUX_CONF' | sh -s _username '#{pane_pid}' '#{b:pane_tty}' true '#D')%g\" \\\n# -e \"s%#{hostname_ssh}%#(cut -c3- '$TMUX_CONF' | sh -s _hostname '#{pane_pid}' '#{b:pane_tty}' true false '#h' '#D')%g\" \\\n# -e \"s%#{hostname_full_ssh}%#(cut -c3- '$TMUX_CONF' | sh -s _hostname '#{pane_pid}' '#{b:pane_tty}' true true '#H' '#D')%g\")\n# status_right=$(echo \"$status_right\" | sed \\\n# -e \"s%#{username}%#(cut -c3- '$TMUX_CONF' | sh -s _username '#{pane_pid}' '#{b:pane_tty}' false '#D')%g\" \\\n# -e \"s%#{hostname}%#(cut -c3- '$TMUX_CONF' | sh -s _hostname '#{pane_pid}' '#{b:pane_tty}' false false '#h' '#D')%g\" \\\n# -e \"s%#{hostname_full}%#(cut -c3- '$TMUX_CONF' | sh -s _hostname '#{pane_pid}' '#{b:pane_tty}' false true '#H' '#D')%g\" \\\n# -e \"s%#{username_ssh}%#(cut -c3- '$TMUX_CONF' | sh -s _username '#{pane_pid}' '#{b:pane_tty}' true '#D')%g\" \\\n# -e \"s%#{hostname_ssh}%#(cut -c3- '$TMUX_CONF' | sh -s _hostname '#{pane_pid}' '#{b:pane_tty}' true false '#h' '#D')%g\" \\\n# -e \"s%#{hostname_full_ssh}%#(cut -c3- '$TMUX_CONF' | sh -s _hostname '#{pane_pid}' '#{b:pane_tty}' true true '#H' '#D')%g\")\n# ;;\n# esac\n#\n# _pkillf 'sh -s _uptime'\n# case \"$status_left $status_right\" in\n# *'#{uptime_'*|*'#{?uptime_'*)\n# status_left=$(echo \"$status_left\" | perl -p -e '\n# ; s/#\\{(\\?)?uptime_y\\b/#\\{\\1\\@uptime_y/g\n# ; s/#\\{(\\?)?uptime_d\\b/#\\{\\1\\@uptime_d/g\n# ; s/\\@uptime_d\\b/\\@uptime_dy/g if /\\@uptime_y\\b/\n# ; s/#\\{(\\?)?uptime_h\\b/#\\{\\1\\@uptime_h/g\n# ; s/#\\{(\\?)?uptime_m\\b/#\\{\\1\\@uptime_m/g\n# ; s/#\\{(\\?)?uptime_s\\b/#\\{\\1\\@uptime_s/g')\n# status_right=$(echo \"$status_right\" | perl -p -e '\n# ; s/#\\{(\\?)?uptime_y\\b/#\\{\\1\\@uptime_y/g\n# ; s/#\\{(\\?)?uptime_d\\b/#\\{\\1\\@uptime_d/g\n# ; s/\\@uptime_d\\b/\\@uptime_dy/g if /\\@uptime_y\\b/\n# ; s/#\\{(\\?)?uptime_h\\b/#\\{\\1\\@uptime_h/g\n# ; s/#\\{(\\?)?uptime_m\\b/#\\{\\1\\@uptime_m/g\n# ; s/#\\{(\\?)?uptime_s\\b/#\\{\\1\\@uptime_s/g')\n# interval=60\n# case \"$status_left $status_right\" in\n# *'#{@uptime_s}'*)\n# interval=$(tmux show -gv status-interval)\n# ;;\n# esac\n# if [ \"$_tmux_version\" -eq 3500 ]; then\n# tmux run -b \"exec sh -c 'trap \\\"[ -n \\\\\\\\\\\"\\\\\\\\\\$sleep_pid\\\\\\\\\\\" ] && kill -9 \\\\\\\\\\\"\\\\\\\\\\$sleep_pid\\\\\\\\\\\"; exit 0\\\" TERM; while [ \\\"\\$(\\\"$TMUX_PROGRAM\\\" -S \\\"#{socket_path}\\\" display -p \\\"#{l:#{pid}}\\\")\\\" = \\\"#{pid}\\\" ]; do nice cut -c3- \\\"$TMUX_CONF\\\" | sh -s _uptime; sleep $interval & sleep_pid=\\$!; wait \\\"\\$sleep_pid\\\"; sleep_pid=; done'\"\n# elif [ \"$_tmux_version\" -ge 3200 ]; then\n# tmux run -b \"trap '[ -n \\\"\\$sleep_pid\\\" ] && kill -9 \\\"\\$sleep_pid\\\"; exit 0' TERM; while [ \\\"\\$(\\\"$TMUX_PROGRAM\\\" -S '#{socket_path}' display -p '#{l:#{pid}}')\\\" = \\\"#{pid}\\\" ]; do nice cut -c3- '$TMUX_CONF' | sh -s _uptime; sleep $interval & sleep_pid=\\$!; wait \\\"\\$sleep_pid\\\"; sleep_pid=; done\"\n# elif [ \"$_tmux_version\" -ge 2800 ]; then\n# status_right=\"#(echo; while [ \\\"\\$(\\\"$TMUX_PROGRAM\\\" -S '#{socket_path}' display -p '#{l:#{pid}}')\\\" = \\\"#{pid}\\\" ]; do nice cut -c3- '$TMUX_CONF' | sh -s _uptime; sleep $interval; done)$status_right\"\n# elif [ \"$_tmux_version\" -gt 2400 ]; then\n# status_right=\"#(echo; while :; do nice cut -c3- '$TMUX_CONF' | sh -s _uptime; sleep $interval; done)$status_right\"\n# else\n# status_right=\"#(nice cut -c3- '$TMUX_CONF' | sh -s _uptime)$status_right\"\n# fi\n# ;;\n# esac\n#\n# _pkillf 'sh -s _loadavg'\n# case \"$status_left $status_right\" in\n# *'#{loadavg'*|*'#{?loadavg'*)\n# status_left=$(echo \"$status_left\" | sed -E \\\n# -e 's/#\\{(\\?)?loadavg/#\\{\\1@loadavg/g')\n# status_right=$(echo \"$status_right\" | sed -E \\\n# -e 's/#\\{(\\?)?loadavg/#\\{\\1@loadavg/g')\n# interval=$(tmux show -gv status-interval)\n# if [ \"$_tmux_version\" -eq 3500 ]; then\n# tmux run -b \"exec sh -c 'trap \\\"[ -n \\\\\\\\\\\"\\\\\\\\\\$sleep_pid\\\\\\\\\\\" ] && kill -9 \\\\\\\\\\\"\\\\\\\\\\$sleep_pid\\\\\\\\\\\"; exit 0\\\" TERM; while [ \\\"\\$(\\\"$TMUX_PROGRAM\\\" -S \\\"#{socket_path}\\\" display -p \\\"#{l:#{pid}}\\\")\\\" = \\\"#{pid}\\\" ]; do nice cut -c3- \\\"$TMUX_CONF\\\" | sh -s _loadavg; sleep $interval & sleep_pid=\\$!; wait \\\"\\$sleep_pid\\\"; sleep_pid=; done'\"\n# elif [ \"$_tmux_version\" -ge 3200 ]; then\n# tmux run -b \"trap '[ -n \\\"\\$sleep_pid\\\" ] && kill -9 \\\"\\$sleep_pid\\\"; exit 0' TERM; while [ \\\"\\$(\\\"$TMUX_PROGRAM\\\" -S '#{socket_path}' display -p '#{l:#{pid}}')\\\" = \\\"#{pid}\\\" ]; do nice cut -c3- '$TMUX_CONF' | sh -s _loadavg; sleep $interval & sleep_pid=\\$!; wait \\\"\\$sleep_pid\\\"; sleep_pid=; done\"\n# elif [ \"$_tmux_version\" -ge 2800 ]; then\n# status_right=\"#(echo; while [ \\\"\\$(\\\"$TMUX_PROGRAM\\\" -S '#{socket_path}' display -p '#{l:#{pid}}')\\\" = \\\"#{pid}\\\" ]; do nice cut -c3- '$TMUX_CONF' | sh -s _loadavg; sleep $interval; done)$status_right\"\n# elif [ \"$_tmux_version\" -gt 2400 ]; then\n# status_right=\"#(echo; while :; do nice cut -c3- '$TMUX_CONF' | sh -s _loadavg; sleep $interval; done)$status_right\"\n# else\n# status_right=\"#(nice cut -c3- '$TMUX_CONF' | sh -s _loadavg)$status_right\"\n# fi\n# ;;\n# esac\n#\n# # -- custom variables ------------------------------------------------------\n#\n# if [ -f \"$TMUX_CONF_LOCAL\" ] && [ \"$(cut -c3- \"$TMUX_CONF_LOCAL\" | sh 2>/dev/null -s printf probe)\" = \"probe\" ]; then\n# replacements=$(perl -n -e 'print if s!^#\\s+([^_][^()\\s]+)\\s*\\(\\)\\s*{\\s*(?:#.*)?\\n!s%#\\\\\\{\\1((?:\\\\s+(?:[^\\{\\}]+?|#\\\\{(?:[^\\{\\}]+?)\\}))*)\\\\\\}%#(cut -c3- '\"'\"$TMUX_CONF_LOCAL\"'\"' | sh -s \\1\\\\1)%g; !p' \"$TMUX_CONF_LOCAL\")\n# status_left=$(echo \"$status_left\" | perl -p -e \"$replacements\" || echo \"$status_left\")\n# status_right=$(echo \"$status_right\" | perl -p -e \"$replacements\" || echo \"$status_right\")\n# fi\n#\n# # --------------------------------------------------------------------------\n#\n# tmux set -g set-titles-string \"$(_decode_unicode_escapes \"$set_titles_string\")\" \\;\\\n# setw -g window-status-format \"$(_decode_unicode_escapes \"$window_status_format\")\" \\;\\\n# setw -g window-status-current-format \"$(_decode_unicode_escapes \"$window_status_current_format\")\" \\;\\\n# set -g status-left-length 1000 \\; set -g status-left \"$(_decode_unicode_escapes \"$status_left\")\" \\;\\\n# set -g status-right-length 1000 \\; set -g status-right \"$(_decode_unicode_escapes \"$status_right\")\"\n# }\n#\n# __apply_plugins() {\n# TMUX_PLUGIN_MANAGER_PATH=\"$1\"\n# window_active=\"$2\"\n# tmux_conf_update_plugins_on_launch=\"$3\"\n# tmux_conf_update_plugins_on_reload=\"$4\"\n# tmux_conf_uninstall_plugins_on_reload=\"$5\"\n#\n# if [ -z \"$(tmux display -p '#{session_id}')\" ] || [ \"$(tmux show -sqv '@__apply_plugins')\" = \"true\" ]; then\n# # return early if we don't have a session or if we're already installing/updating tpm\n# return 0\n# fi\n# tmux set -s '@__apply_plugins' true\n#\n# if [ -z \"$TMUX_PLUGIN_MANAGER_PATH\" ]; then\n# return 255\n# fi\n# mkdir -p \"$TMUX_PLUGIN_MANAGER_PATH\"\n#\n# __discover_plugins() (\n# probe_socket=\"$(dirname \"$TMUX_SOCKET\")/tmux-discover-plugins-$$\"\n# TMUX_SOCKET=\"$probe_socket\" tmux -f /dev/null start-server \\; set-option exit-empty off\n# ___discover_plugins() {\n# depth=$((${depth:-0} + 1))\n# IFS=${_IFS:-$IFS}\n# [ \"$depth\" -le 100 ] || return\n# for current_file in \"$@\"; do\n# current_file=\"$(cd \"${current_file%/*}\" 2>/dev/null && pwd)/${current_file##*/}\" || continue\n# while IFS= read -r line; do\n# if plugin=$(printf '%s\\n' \"$line\" | perl -s -n -E 'print if s/^set-option\\s+-g\\s+\\@plugin\\s+//g or die' 2>/dev/null); then\n# discovered_plugins=\"${discovered_plugins}${discovered_plugins:+ }${plugin}\"\n# elif next_files=$(printf '%s\\n' \"$line\" | perl -s -n -E 's/(?<!\\@)current_file/\\@current_file/g ; print if s/^source(?:-file)?(?:\\s+-[qF]+)*\\s*(.+?)$/\\1/g or die' 2>/dev/null); then\n# next_files=$(TMUX_SOCKET=\"$probe_socket\" tmux -f /dev/null \\\n# set -g @current_file \"$current_file\" \\; \\\n# display -pF \"$next_files\")\n#\n# _IFS=\"$IFS\"\n# IFS=$(printf '\\n\\nx')\n# IFS=${IFS%?}\n# # we don't want quoting here as we want wildcard expansion\n# # shellcheck disable=SC2046\n# ___discover_plugins $(printf '%s\\n' \"$next_files\" | xargs printf '%s\\n\\n')\n# fi\n# done << EOF\n# $(TMUX_SOCKET=\"$probe_socket\" tmux -f /dev/null source -nvq \"$current_file\" | perl -s -n -E 'print if s/^$current_file:\\d+:\\s*(set-option\\s+-g\\s+\\@plugin\\s+|source-file)/\\1/g' -- -current_file=\"$current_file\")\n# EOF\n# done\n# }\n# ___discover_plugins \"$@\"\n# TMUX_SOCKET=\"$probe_socket\" tmux -f /dev/null kill-server\n# rm -rf \"$probe_socket\"\n# printf '%s\\n' \"$discovered_plugins\"\n# )\n#\n# tpm_plugins=$(tmux show -gvq '@tpm_plugins' 2>/dev/null)\n# tpm_plugins=$(cat << EOF | tr ' ' '\\n' | awk '/^\\s*$/ {next;}; !seen[$0]++ { gsub(/^[ \\t]+/,\"\",$0); gsub(/[ \\t]+$/,\"\",$0); print $0 }'\n# $(__discover_plugins \"$TMUX_CONF_LOCAL\")\n# EOF\n# )\n# if [ -z \"$tpm_plugins\" ]; then\n# if _is_true \"$tmux_conf_uninstall_plugins_on_reload\" && [ -d \"$TMUX_PLUGIN_MANAGER_PATH/tpm\" ]; then\n# tmux display 'Uninstalling tpm and plugins...'\n# tmux set-environment -gu TMUX_PLUGIN_MANAGER_PATH\n# rm -rf \"$TMUX_PLUGIN_MANAGER_PATH\"\n# tmux display 'Done uninstalling tpm and plugins...'\n# fi\n# else\n# if [ \"$(command tmux display -p '#{pid} #{version} #{socket_path}')\" = \"$(\"$TMUX_PROGRAM\" display -p '#{pid} #{version} #{socket_path}')\" ]; then\n# tmux set-environment -g TMUX_PLUGIN_MANAGER_PATH \"$TMUX_PLUGIN_MANAGER_PATH\"\n# tmux set -g '@tpm_plugins' \"$tpm_plugins\"\n#\n# if [ -d \"$TMUX_PLUGIN_MANAGER_PATH/tpm\" ]; then\n# [ -z \"$(tmux show -gqv '@tpm-install')\" ] && tmux set -g '@tpm-install' 'I'\n# [ -z \"$(tmux show -gqv '@tpm-update')\" ] && tmux set -g '@tpm-update' 'u'\n# [ -z \"$(tmux show -gqv '@tpm-clean')\" ] && tmux set -g '@tpm-clean' 'M-u'\n# \"$TMUX_PLUGIN_MANAGER_PATH/tpm/tpm\" || tmux display \"One or more tpm plugin(s) failed\"\n# fi\n#\n# if git ls-remote -hq https://github.com/gpakosz/.tmux.git master > /dev/null; then\n# if [ ! -d \"$TMUX_PLUGIN_MANAGER_PATH/tpm\" ]; then\n# install_tpm=true\n# tmux display 'Installing tpm and plugins...'\n# git clone --depth 1 https://github.com/tmux-plugins/tpm \"$TMUX_PLUGIN_MANAGER_PATH/tpm\"\n# elif { [ -z \"$window_active\" ] && _is_true \"$tmux_conf_update_plugins_on_launch\"; } || { [ -n \"$window_active\" ] && _is_true \"$tmux_conf_update_plugins_on_reload\"; }; then\n# update_tpm=true\n# tmux display 'Updating tpm and plugins...'\n# (cd \"$TMUX_PLUGIN_MANAGER_PATH/tpm\" && git fetch -q -p && git checkout -q master && git reset -q --hard origin/master)\n# fi\n# if [ \"$install_tpm\" = \"true\" ] || [ \"$update_tpm\" = \"true\" ]; then\n# perl -0777 -p -i -e 's/git clone(?!\\s+--depth\\s+1)/git clone --depth 1/g\n# ;s/(install_plugin(.(?!&))*)\\n(\\s+)done/\\1&\\n\\3done\\n\\3wait/g' \"$TMUX_PLUGIN_MANAGER_PATH/tpm/scripts/install_plugins.sh\"\n# perl -p -i -e 's/git submodule update --init --recursive(?!\\s+--depth\\s+1)/git submodule update --init --recursive --depth 1/g' \"$TMUX_PLUGIN_MANAGER_PATH/tpm/scripts/update_plugin.sh\"\n# perl -p -i -e 's,\\$tmux_file\\s+>/dev/null\\s+2>\\&1,$& || { tmux display \"Plugin \\$(basename \\${plugin_path}) failed\" && false; },' \"$TMUX_PLUGIN_MANAGER_PATH/tpm/scripts/source_plugins.sh\"\n# fi\n# if [ \"$update_tpm\" = \"true\" ]; then\n# {\n# {\n# printf 'List of discovered tpm plugins: %s\\n' \"$(printf '%s\\n' \"$tpm_plugins\" | paste -s -d ' ' -)\" | _timestamp\n# printf '%s\\n' \"Invoking $TMUX_PLUGIN_MANAGER_PATH/tpm/bin/install_plugins\" | _timestamp\n# \"$TMUX_PLUGIN_MANAGER_PATH/tpm/bin/install_plugins\" 2>&1 | _timestamp\n# printf '%s\\n' \"Invoking $TMUX_PLUGIN_MANAGER_PATH/tpm/bin/update_plugins all\" | _timestamp\n# \"$TMUX_PLUGIN_MANAGER_PATH/tpm/bin/update_plugins\" all 2>&1 | _timestamp\n# printf '%s\\n' \"Invoking $TMUX_PLUGIN_MANAGER_PATH/tpm/bin/clean_plugins all\" | _timestamp\n# \"$TMUX_PLUGIN_MANAGER_PATH/tpm/bin/clean_plugins\" all 2>&1 | _timestamp\n# cut -c3- \"$TMUX_CONF\" | sh -s _apply_important\n# printf 'Done.\\n' | _timestamp\n# printf '\\n'\n# } >> \"$TMUX_PLUGIN_MANAGER_PATH/tpm_log.txt\"\n#\n# tmux display 'Done updating tpm and plugins...'\n# } || tmux display 'Failed updating tpm and plugins...'\n# elif [ \"$install_tpm\" = \"true\" ]; then\n# {\n# {\n# printf 'List of discovered tpm plugins: %s\\n' \"$(printf '%s\\n' \"$tpm_plugins\" | paste -s -d ' ' -)\" | _timestamp\n# printf '%s\\n' \"Invoking $TMUX_PLUGIN_MANAGER_PATH/tpm/bin/install_plugins\" | _timestamp\n# \"$TMUX_PLUGIN_MANAGER_PATH/tpm/bin/install_plugins\" 2>&1 | _timestamp\n# cut -c3- \"$TMUX_CONF\" | sh -s _apply_important\n# printf 'Done.\\n' | _timestamp\n# printf '\\n' >> \"$TMUX_PLUGIN_MANAGER_PATH/tpm_log.txt\"\n# } >> \"$TMUX_PLUGIN_MANAGER_PATH/tpm_log.txt\"\n#\n# tmux display 'Done installing tpm and plugins...'\n#\n# [ -z \"$(tmux show -gqv '@tpm-install')\" ] && tmux set -g '@tpm-install' 'I'\n# [ -z \"$(tmux show -gqv '@tpm-update')\" ] && tmux set -g '@tpm-update' 'u'\n# [ -z \"$(tmux show -gqv '@tpm-clean')\" ] && tmux set -g '@tpm-clean' 'M-u'\n# \"$TMUX_PLUGIN_MANAGER_PATH/tpm/tpm\" || tmux display \"One or more tpm plugin(s) failed\"\n# } || tmux display 'Failed installing tpm and plugins...'\n# fi\n# else\n# tmux display \"GitHub doesn't seem to be reachable, skipping installing and/or updating tpm and plugins...\"\n# fi\n# else\n# if [ \"$_tmux_version\" -ge 3200 ]; then\n# tmux run -b \"exec sh -c 'sleep \\$((#{display-time} / 1000)) && \\\"$TMUX_PROGRAM\\\" display -N -d 3000 \\\"Cannot use tpm which assumes a globally installed tmux\\\"'\"\n# else\n# tmux run -b \"exec sh -c 'sleep \\$((#{display-time} / 1000)) && \\\"$TMUX_PROGRAM\\\" set display-time 3000 \\; display \\\"Cannot use tpm which assumes a globally installed tmux\\\" \\; set -u display-time'\"\n# fi\n# fi\n#\n# tmux set -gu '@tpm-install' \\; set -gu '@tpm-update' \\; set -gu '@tpm-clean' \\; set -gu '@plugin'\n# fi\n#\n# tmux set -su '@__apply_plugins'\n# }\n#\n# _apply_plugins() {\n# tmux_conf_update_plugins_on_launch=${tmux_conf_update_plugins_on_launch:-true}\n# tmux_conf_update_plugins_on_reload=${tmux_conf_update_plugins_on_reload:-true}\n# tmux_conf_uninstall_plugins_on_reload=${tmux_conf_uninstall_plugins_on_reload:-true}\n#\n# if [ -z \"$TMUX_PLUGIN_MANAGER_PATH\" ]; then\n# if [ \"$(dirname \"$TMUX_CONF\")\" = \"$HOME\" ]; then\n# TMUX_PLUGIN_MANAGER_PATH=\"$HOME/.tmux/plugins\"\n# else\n# TMUX_PLUGIN_MANAGER_PATH=\"$(dirname \"$TMUX_CONF\")/plugins\"\n# fi\n# fi\n# tmux run -b \"cut -c3- '$TMUX_CONF' | sh -s __apply_plugins '$TMUX_PLUGIN_MANAGER_PATH' '$window_active' '$tmux_conf_update_plugins_on_launch' '$tmux_conf_update_plugins_on_reload' '$tmux_conf_uninstall_plugins_on_reload'\"\n# }\n#\n# _apply_important() {\n# cfg=$(mktemp) && trap 'rm -f $cfg*' EXIT\n#\n# if perl -n -e 'print if /^\\s*(?:set|bind|unbind).+?#!important\\s*$/' \"$TMUX_CONF_LOCAL\" 2>/dev/null > \"$cfg.local\"; then\n# if ! tmux source-file \"$cfg.local\"; then\n# if tmux source-file -v /dev/null 2> /dev/null; then\n# verbose_flag='-v'\n# fi\n# while ! out=$(tmux source-file \"${verbose_flag:+$verbose_flag}\" \"$cfg.local\"); do\n# line=$(printf \"%s\" \"$out\" | tail -1 | cut -d':' -f2)\n# perl -n -i -e \"if ($. != $line) { print }\" \"$cfg.local\"\n# done\n# fi\n# fi\n# }\n#\n# _apply_configuration() {\n# window_active=\"$(tmux display -p '#{window_active}' 2>/dev/null || true)\"\n# if [ -z \"$window_active\" ]; then\n# if [ \"$_tmux_version\" -lt 2600 ]; then\n# tmux run -b 'tmux set display-time 3000 \\; display \"This configuration requires tmux 2.6+\" \\; set -u display-time \\; run \"sleep 3\" \\; kill-server'\n# return\n# fi\n# if [ \"$_tmux_version\" -ge 3200 ]; then\n# for cmd in perl sed awk; do\n# if ! command -v \"$cmd\" > /dev/null 2>&1; then\n# tmux run -b \"tmux display -N -d 3000 'This configuration requires $cmd' \\; run 'sleep 3' \\; kill-server\"\n# return\n# fi\n# done\n# else\n# for cmd in perl sed awk; do\n# if ! command -v \"$cmd\" > /dev/null 2>&1; then\n# tmux run -b \"tmux set display-time 3000 \\; display 'This configuration requires $cmd' \\; set -u display-time \\; run 'sleep 3' \\; kill-server\"\n# return\n# fi\n# done\n# fi\n# fi\n#\n# case \"$_uname_s\" in\n# *CYGWIN*|*MSYS*)\n# # prevent Cygwin and MSYS2 from cd-ing into home directory when evaluating /etc/profile\n# tmux setenv -g CHERE_INVOKING 1\n# ;;\n# esac\n#\n# _apply_tmux_256color\n# _apply_24b&\n# _apply_theme&\n# _apply_bindings&\n# wait\n#\n# _apply_plugins\n# _apply_important\n#\n# # shellcheck disable=SC2046\n# tmux setenv -gu tmux_conf_dummy $(printenv | grep -E -o '^tmux_conf_[^=]+' | awk '{printf \"; setenv -gu %s\", $0}')\n# }\n#\n# _urlview() {\n# pane_id=\"$1\"; shift\n# tmux capture-pane -J -S - -E - -b \"urlview-$pane_id\" -t \"$pane_id\"\n# tmux split-window \"'$TMUX_PROGRAM' ${TMUX_SOCKET:+-S \"$TMUX_SOCKET\"} show-buffer -b 'urlview-$pane_id' | urlview || true; '$TMUX_PROGRAM' ${TMUX_SOCKET:+-S \"$TMUX_SOCKET\"} delete-buffer -b 'urlview-$pane_id'\"\n# }\n#\n# _urlscan() {\n# pane_id=\"$1\"; shift\n# tmux capture-pane -J -S - -E - -b \"urlscan-$pane_id\" -t \"$pane_id\"\n# tmux split-window \"'$TMUX_PROGRAM' ${TMUX_SOCKET:+-S \"$TMUX_SOCKET\"} show-buffer -b 'urlscan-$pane_id' | urlscan $* || true; '$TMUX_PROGRAM' ${TMUX_SOCKET:+-S \"$TMUX_SOCKET\"} delete-buffer -b 'urlscan-$pane_id'\"\n# }\n#\n# _fpp() {\n# tmux capture-pane -J -S - -E - -b \"fpp-$1\" -t \"$1\"\n# tmux split-window -c \"$2\" \"'$TMUX_PROGRAM' ${TMUX_SOCKET:+-S \"$TMUX_SOCKET\"} show-buffer -b 'fpp-$1' | fpp || true; '$TMUX_PROGRAM' ${TMUX_SOCKET:+-S \"$TMUX_SOCKET\"} delete-buffer -b 'fpp-$1'\"\n# }\n#\n# \"$@\"\n",
"sha256": "6807d44735b7b11e64c4488a0c3fdcbd2809cc73efedcc349d098e80a690aeeb"
},
".github/tools/external/tmux/README": {
"mode": "100644",
"encoding": "utf-8",
"data": "Welcome to tmux!\n\ntmux is a terminal multiplexer: it enables a number of terminals to be created,\naccessed, and controlled from a single screen. tmux may be detached from a\nscreen and continue running in the background, then later reattached.\n\nThis release runs on OpenBSD, FreeBSD, NetBSD, Linux, macOS and Solaris.\n\n* Dependencies\n\ntmux depends on libevent 2.x, available from:\n\n\thttps://github.com/libevent/libevent/releases/latest\n\nIt also depends on ncurses, available from:\n\n\thttps://invisible-mirror.net/archives/ncurses/\n\nTo build tmux, a C compiler (for example gcc or clang), make, pkg-config and a\nsuitable yacc (yacc or bison) are needed.\n\n* Installation\n\nTo build and install tmux from a release tarball, use:\n\n\t$ ./configure && make\n\t$ sudo make install\n\ntmux can use the utempter library to update utmp(5), if it is installed - run\nconfigure with --enable-utempter to enable this.\n\nTo get and build the latest from version control - note that this requires\nautoconf, automake and pkg-config:\n\n\t$ git clone https://github.com/tmux/tmux.git\n\t$ cd tmux\n\t$ sh autogen.sh\n\t$ ./configure && make\n\t$ sudo make install\n\n* Contributing\n\nBug reports, feature suggestions and especially code contributions are most\nwelcome. Please send by email to:\n\n\ttmux-users@googlegroups.com\n\nOr open a GitHub issue or pull request.\n\n* Documentation\n\nFor documentation on using tmux, see the tmux.1 manpage. View it from the\nsource tree with:\n\n\t$ nroff -mdoc tmux.1|less\n\nA small example configuration is in example_tmux.conf.\n\nOther documentation is available in the wiki:\n\n\thttps://github.com/tmux/tmux/wiki\n\nAlso see the tmux FAQ at:\n\n\thttps://github.com/tmux/tmux/wiki/FAQ\n\nA bash(1) completion file is at:\n\n\thttps://github.com/scop/bash-completion/blob/main/completions/tmux\n\nFor debugging, run tmux with -v and -vv to generate server and client log files\nin the current directory.\n\n* Support\n\nThe tmux mailing list for general discussion and bug reports is:\n\n\thttps://groups.google.com/forum/#!forum/tmux-users\n\nSubscribe by sending an email to:\n\n\ttmux-users+subscribe@googlegroups.com\n\n* License\n\nThis file and the CHANGES files are licensed under the ISC license. All other\nfiles have a license and copyright notice at their start.\n",
"sha256": "9fb75e6c7f10c25b73e41b8214336d0dc2acfbe4c99984514ccaf7327192d53e"
},
".github/tools/external/tmux/tmux.c": {
"mode": "100644",
"encoding": "utf-8",
"data": "/* $OpenBSD$ */\n\n/*\n * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>\n *\n * Permission to use, copy, modify, and distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER\n * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING\n * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n */\n\n#include <sys/types.h>\n#include <sys/stat.h>\n#include <sys/utsname.h>\n\n#include <errno.h>\n#include <fcntl.h>\n#include <langinfo.h>\n#include <locale.h>\n#include <pwd.h>\n#include <signal.h>\n#include <stdlib.h>\n#include <string.h>\n#include <time.h>\n#include <unistd.h>\n\n#include \"tmux.h\"\n\nstruct options\t*global_options;\t/* server options */\nstruct options\t*global_s_options;\t/* session options */\nstruct options\t*global_w_options;\t/* window options */\nstruct environ\t*global_environ;\n\nstruct timeval\t start_time;\nconst char\t*socket_path;\nint\t\t ptm_fd = -1;\nconst char\t*shell_command;\n\nstatic __dead void\t usage(int);\nstatic char\t\t*make_label(const char *, char **);\n\nstatic int\t\t areshell(const char *);\nstatic const char\t*getshell(void);\n\nstatic __dead void\nusage(int status)\n{\n\tfprintf(status ? stderr : stdout,\n\t \"usage: %s [-2CDhlNuVv] [-c shell-command] [-f file] [-L socket-name]\\n\"\n\t \" [-S socket-path] [-T features] [command [flags]]\\n\",\n\t getprogname());\n\texit(status);\n}\n\nstatic const char *\ngetshell(void)\n{\n\tstruct passwd\t*pw;\n\tconst char\t*shell;\n\n\tshell = getenv(\"SHELL\");\n\tif (checkshell(shell))\n\t\treturn (shell);\n\n\tpw = getpwuid(getuid());\n\tif (pw != NULL && checkshell(pw->pw_shell))\n\t\treturn (pw->pw_shell);\n\n\treturn (_PATH_BSHELL);\n}\n\nint\ncheckshell(const char *shell)\n{\n\tif (shell == NULL || *shell != '/')\n\t\treturn (0);\n\tif (areshell(shell))\n\t\treturn (0);\n\tif (access(shell, X_OK) != 0)\n\t\treturn (0);\n\treturn (1);\n}\n\nstatic int\nareshell(const char *shell)\n{\n\tconst char\t*progname, *ptr;\n\n\tif ((ptr = strrchr(shell, '/')) != NULL)\n\t\tptr++;\n\telse\n\t\tptr = shell;\n\tprogname = getprogname();\n\tif (*progname == '-')\n\t\tprogname++;\n\tif (strcmp(ptr, progname) == 0)\n\t\treturn (1);\n\treturn (0);\n}\n\nstatic char *\nexpand_path(const char *path, const char *home)\n{\n\tchar\t\t\t*expanded, *name;\n\tconst char\t\t*end;\n\tstruct environ_entry\t*value;\n\n\tif (strncmp(path, \"~/\", 2) == 0) {\n\t\tif (home == NULL)\n\t\t\treturn (NULL);\n\t\txasprintf(&expanded, \"%s%s\", home, path + 1);\n\t\treturn (expanded);\n\t}\n\n\tif (*path == '$') {\n\t\tend = strchr(path, '/');\n\t\tif (end == NULL)\n\t\t\tname = xstrdup(path + 1);\n\t\telse\n\t\t\tname = xstrndup(path + 1, end - path - 1);\n\t\tvalue = environ_find(global_environ, name);\n\t\tfree(name);\n\t\tif (value == NULL)\n\t\t\treturn (NULL);\n\t\tif (end == NULL)\n\t\t\tend = \"\";\n\t\txasprintf(&expanded, \"%s%s\", value->value, end);\n\t\treturn (expanded);\n\t}\n\n\treturn (xstrdup(path));\n}\n\nstatic void\nexpand_paths(const char *s, char ***paths, u_int *n, int no_realpath)\n{\n\tconst char\t*home = find_home();\n\tchar\t\t*copy, *next, *tmp, resolved[PATH_MAX], *expanded;\n\tchar\t\t*path;\n\tu_int\t\t i;\n\n\t*paths = NULL;\n\t*n = 0;\n\n\tcopy = tmp = xstrdup(s);\n\twhile ((next = strsep(&tmp, \":\")) != NULL) {\n\t\texpanded = expand_path(next, home);\n\t\tif (expanded == NULL) {\n\t\t\tlog_debug(\"%s: invalid path: %s\", __func__, next);\n\t\t\tcontinue;\n\t\t}\n\t\tif (no_realpath)\n\t\t\tpath = expanded;\n\t\telse {\n\t\t\tif (realpath(expanded, resolved) == NULL) {\n\t\t\t\tlog_debug(\"%s: realpath(\\\"%s\\\") failed: %s\", __func__,\n\t\t\t expanded, strerror(errno));\n\t\t\t\tfree(expanded);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tpath = xstrdup(resolved);\n\t\t\tfree(expanded);\n\t\t}\n\t\tfor (i = 0; i < *n; i++) {\n\t\t\tif (strcmp(path, (*paths)[i]) == 0)\n\t\t\t\tbreak;\n\t\t}\n\t\tif (i != *n) {\n\t\t\tlog_debug(\"%s: duplicate path: %s\", __func__, path);\n\t\t\tfree(path);\n\t\t\tcontinue;\n\t\t}\n\t\t*paths = xreallocarray(*paths, (*n) + 1, sizeof *paths);\n\t\t(*paths)[(*n)++] = path;\n\t}\n\tfree(copy);\n}\n\nstatic char *\nmake_label(const char *label, char **cause)\n{\n\tchar\t\t**paths, *path, *base;\n\tu_int\t\t i, n;\n\tstruct stat\t sb;\n\tuid_t\t\t uid;\n\n\t*cause = NULL;\n\tif (label == NULL)\n\t\tlabel = \"default\";\n\tuid = getuid();\n\n\texpand_paths(TMUX_SOCK, &paths, &n, 0);\n\tif (n == 0) {\n\t\txasprintf(cause, \"no suitable socket path\");\n\t\treturn (NULL);\n\t}\n\tpath = paths[0]; /* can only have one socket! */\n\tfor (i = 1; i < n; i++)\n\t\tfree(paths[i]);\n\tfree(paths);\n\n\txasprintf(&base, \"%s/tmux-%ld\", path, (long)uid);\n\tfree(path);\n\tif (mkdir(base, S_IRWXU) != 0 && errno != EEXIST) {\n\t\txasprintf(cause, \"couldn't create directory %s (%s)\", base,\n\t\t strerror(errno));\n\t\tgoto fail;\n\t}\n\tif (lstat(base, &sb) != 0) {\n\t\txasprintf(cause, \"couldn't read directory %s (%s)\", base,\n\t\t strerror(errno));\n\t\tgoto fail;\n\t}\n\tif (!S_ISDIR(sb.st_mode)) {\n\t\txasprintf(cause, \"%s is not a directory\", base);\n\t\tgoto fail;\n\t}\n\tif (sb.st_uid != uid || (sb.st_mode & TMUX_SOCK_PERM) != 0) {\n\t\txasprintf(cause, \"directory %s has unsafe permissions\", base);\n\t\tgoto fail;\n\t}\n\txasprintf(&path, \"%s/%s\", base, label);\n\tfree(base);\n\treturn (path);\n\nfail:\n\tfree(base);\n\treturn (NULL);\n}\n\nchar *\nshell_argv0(const char *shell, int is_login)\n{\n\tconst char\t*slash, *name;\n\tchar\t\t*argv0;\n\n\tslash = strrchr(shell, '/');\n\tif (slash != NULL && slash[1] != '\\0')\n\t\tname = slash + 1;\n\telse\n\t\tname = shell;\n\tif (is_login)\n\t\txasprintf(&argv0, \"-%s\", name);\n\telse\n\t\txasprintf(&argv0, \"%s\", name);\n\treturn (argv0);\n}\n\nvoid\nsetblocking(int fd, int state)\n{\n\tint mode;\n\n\tif ((mode = fcntl(fd, F_GETFL)) != -1) {\n\t\tif (!state)\n\t\t\tmode |= O_NONBLOCK;\n\t\telse\n\t\t\tmode &= ~O_NONBLOCK;\n\t\tfcntl(fd, F_SETFL, mode);\n\t}\n}\n\nuint64_t\nget_timer(void)\n{\n\tstruct timespec\tts;\n\n\t/*\n\t * We want a timestamp in milliseconds suitable for time measurement,\n\t * so prefer the monotonic clock.\n\t */\n\tif (clock_gettime(CLOCK_MONOTONIC, &ts) != 0)\n\t\tclock_gettime(CLOCK_REALTIME, &ts);\n\treturn ((ts.tv_sec * 1000ULL) + (ts.tv_nsec / 1000000ULL));\n}\n\nconst char *\nsig2name(int signo)\n{\n static char\ts[11];\n\n#ifdef HAVE_SYS_SIGNAME\n if (signo > 0 && signo < NSIG)\n\t return (sys_signame[signo]);\n#endif\n xsnprintf(s, sizeof s, \"%d\", signo);\n return (s);\n}\n\nconst char *\nfind_cwd(void)\n{\n\tchar\t\t resolved1[PATH_MAX], resolved2[PATH_MAX];\n\tstatic char\t cwd[PATH_MAX];\n\tconst char\t*pwd;\n\n\tif (getcwd(cwd, sizeof cwd) == NULL)\n\t\treturn (NULL);\n\tif ((pwd = getenv(\"PWD\")) == NULL || *pwd == '\\0')\n\t\treturn (cwd);\n\n\t/*\n\t * We want to use PWD so that symbolic links are maintained,\n\t * but only if it matches the actual working directory.\n\t */\n\tif (realpath(pwd, resolved1) == NULL)\n\t\treturn (cwd);\n\tif (realpath(cwd, resolved2) == NULL)\n\t\treturn (cwd);\n\tif (strcmp(resolved1, resolved2) != 0)\n\t\treturn (cwd);\n\treturn (pwd);\n}\n\nconst char *\nfind_home(void)\n{\n\tstruct passwd\t\t*pw;\n\tstatic const char\t*home;\n\n\tif (home != NULL)\n\t\treturn (home);\n\n\thome = getenv(\"HOME\");\n\tif (home == NULL || *home == '\\0') {\n\t\tpw = getpwuid(getuid());\n\t\tif (pw != NULL)\n\t\t\thome = pw->pw_dir;\n\t\telse\n\t\t\thome = NULL;\n\t}\n\n\treturn (home);\n}\n\nconst char *\ngetversion(void)\n{\n\treturn (TMUX_VERSION);\n}\n\nint\nmain(int argc, char **argv)\n{\n\tchar\t\t\t\t\t*path = NULL, *label = NULL;\n\tchar\t\t\t\t\t*cause, **var;\n\tconst char\t\t\t\t*s, *cwd;\n\tint\t\t\t\t\t opt, keys, feat = 0, fflag = 0;\n\tuint64_t\t\t\t\t flags = 0;\n\tconst struct options_table_entry\t*oe;\n\tu_int\t\t\t\t\t i;\n\n\tif (setlocale(LC_CTYPE, \"en_US.UTF-8\") == NULL &&\n\t setlocale(LC_CTYPE, \"C.UTF-8\") == NULL) {\n\t\tif (setlocale(LC_CTYPE, \"\") == NULL)\n\t\t\terrx(1, \"invalid LC_ALL, LC_CTYPE or LANG\");\n\t\ts = nl_langinfo(CODESET);\n\t\tif (strcasecmp(s, \"UTF-8\") != 0 && strcasecmp(s, \"UTF8\") != 0)\n\t\t\terrx(1, \"need UTF-8 locale (LC_CTYPE) but have %s\", s);\n\t}\n\n\tsetlocale(LC_TIME, \"\");\n\ttzset();\n\n\tif (**argv == '-')\n\t\tflags = CLIENT_LOGIN;\n\n\tglobal_environ = environ_create();\n\tfor (var = environ; *var != NULL; var++)\n\t\tenviron_put(global_environ, *var, 0);\n\tif ((cwd = find_cwd()) != NULL)\n\t\tenviron_set(global_environ, \"PWD\", 0, \"%s\", cwd);\n\texpand_paths(TMUX_CONF, &cfg_files, &cfg_nfiles, 1);\n\n\twhile ((opt = getopt(argc, argv, \"2c:CDdf:hlL:NqS:T:uUvV\")) != -1) {\n\t\tswitch (opt) {\n\t\tcase '2':\n\t\t\ttty_add_features(&feat, \"256\", \":,\");\n\t\t\tbreak;\n\t\tcase 'c':\n\t\t\tshell_command = optarg;\n\t\t\tbreak;\n\t\tcase 'D':\n\t\t\tflags |= CLIENT_NOFORK;\n\t\t\tbreak;\n\t\tcase 'C':\n\t\t\tif (flags & CLIENT_CONTROL)\n\t\t\t\tflags |= CLIENT_CONTROLCONTROL;\n\t\t\telse\n\t\t\t\tflags |= CLIENT_CONTROL;\n\t\t\tbreak;\n\t\tcase 'f':\n\t\t\tif (!fflag) {\n\t\t\t\tfflag = 1;\n\t\t\t\tfor (i = 0; i < cfg_nfiles; i++)\n\t\t\t\t\tfree(cfg_files[i]);\n\t\t\t\tcfg_nfiles = 0;\n\t\t\t}\n\t\t\tcfg_files = xreallocarray(cfg_files, cfg_nfiles + 1,\n\t\t\t sizeof *cfg_files);\n\t\t\tcfg_files[cfg_nfiles++] = xstrdup(optarg);\n\t\t\tcfg_quiet = 0;\n\t\t\tbreak;\n\t\tcase 'h':\n\t\t\tusage(0);\n\t\tcase 'V':\n\t\t\tprintf(\"tmux %s\\n\", getversion());\n\t\t\texit(0);\n\t\tcase 'l':\n\t\t\tflags |= CLIENT_LOGIN;\n\t\t\tbreak;\n\t\tcase 'L':\n\t\t\tfree(label);\n\t\t\tlabel = xstrdup(optarg);\n\t\t\tbreak;\n\t\tcase 'N':\n\t\t\tflags |= CLIENT_NOSTARTSERVER;\n\t\t\tbreak;\n\t\tcase 'q':\n\t\t\tbreak;\n\t\tcase 'S':\n\t\t\tfree(path);\n\t\t\tpath = xstrdup(optarg);\n\t\t\tbreak;\n\t\tcase 'T':\n\t\t\ttty_add_features(&feat, optarg, \":,\");\n\t\t\tbreak;\n\t\tcase 'u':\n\t\t\tflags |= CLIENT_UTF8;\n\t\t\tbreak;\n\t\tcase 'v':\n\t\t\tlog_add_level();\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tusage(1);\n\t\t}\n\t}\n\targc -= optind;\n\targv += optind;\n\n\tif (shell_command != NULL && argc != 0)\n\t\tusage(1);\n\tif ((flags & CLIENT_NOFORK) && argc != 0)\n\t\tusage(1);\n\n\tif ((ptm_fd = getptmfd()) == -1)\n\t\terr(1, \"getptmfd\");\n\tif (pledge(\"stdio rpath wpath cpath flock fattr unix getpw sendfd \"\n\t \"recvfd proc exec tty ps\", NULL) != 0)\n\t\terr(1, \"pledge\");\n\n\t/*\n\t * tmux is a UTF-8 terminal, so if TMUX is set, assume UTF-8.\n\t * Otherwise, if the user has set LC_ALL, LC_CTYPE or LANG to contain\n\t * UTF-8, it is a safe assumption that either they are using a UTF-8\n\t * terminal, or if not they know that output from UTF-8-capable\n\t * programs may be wrong.\n\t */\n\tif (getenv(\"TMUX\") != NULL)\n\t\tflags |= CLIENT_UTF8;\n\telse {\n\t\ts = getenv(\"LC_ALL\");\n\t\tif (s == NULL || *s == '\\0')\n\t\t\ts = getenv(\"LC_CTYPE\");\n\t\tif (s == NULL || *s == '\\0')\n\t\t\ts = getenv(\"LANG\");\n\t\tif (s == NULL || *s == '\\0')\n\t\t\ts = \"\";\n\t\tif (strcasestr(s, \"UTF-8\") != NULL ||\n\t\t strcasestr(s, \"UTF8\") != NULL)\n\t\t\tflags |= CLIENT_UTF8;\n\t}\n\n\tglobal_options = options_create(NULL);\n\tglobal_s_options = options_create(NULL);\n\tglobal_w_options = options_create(NULL);\n\tfor (oe = options_table; oe->name != NULL; oe++) {\n\t\tif (oe->scope & OPTIONS_TABLE_SERVER)\n\t\t\toptions_default(global_options, oe);\n\t\tif (oe->scope & OPTIONS_TABLE_SESSION)\n\t\t\toptions_default(global_s_options, oe);\n\t\tif (oe->scope & OPTIONS_TABLE_WINDOW)\n\t\t\toptions_default(global_w_options, oe);\n\t}\n\n\t/*\n\t * The default shell comes from SHELL or from the user's passwd entry\n\t * if available.\n\t */\n\toptions_set_string(global_s_options, \"default-shell\", 0, \"%s\",\n\t getshell());\n\n\t/* Override keys to vi if VISUAL or EDITOR are set. */\n\tif ((s = getenv(\"VISUAL\")) != NULL || (s = getenv(\"EDITOR\")) != NULL) {\n\t\toptions_set_string(global_options, \"editor\", 0, \"%s\", s);\n\t\tif (strrchr(s, '/') != NULL)\n\t\t\ts = strrchr(s, '/') + 1;\n\t\tif (strstr(s, \"vi\") != NULL)\n\t\t\tkeys = MODEKEY_VI;\n\t\telse\n\t\t\tkeys = MODEKEY_EMACS;\n\t\toptions_set_number(global_s_options, \"status-keys\", keys);\n\t\toptions_set_number(global_w_options, \"mode-keys\", keys);\n\t}\n\n\t/*\n\t * If socket is specified on the command-line with -S or -L, it is\n\t * used. Otherwise, $TMUX is checked and if that fails \"default\" is\n\t * used.\n\t */\n\tif (path == NULL && label == NULL) {\n\t\ts = getenv(\"TMUX\");\n\t\tif (s != NULL && *s != '\\0' && *s != ',') {\n\t\t\tpath = xstrdup(s);\n\t\t\tpath[strcspn(path, \",\")] = '\\0';\n\t\t}\n\t}\n\tif (path == NULL) {\n\t\tif ((path = make_label(label, &cause)) == NULL) {\n\t\t\tif (cause != NULL) {\n\t\t\t\tfprintf(stderr, \"%s\\n\", cause);\n\t\t\t\tfree(cause);\n\t\t\t}\n\t\t\texit(1);\n\t\t}\n\t\tflags |= CLIENT_DEFAULTSOCKET;\n\t}\n\tsocket_path = path;\n\tfree(label);\n\n\t/* Pass control to the client. */\n\texit(client_main(osdep_event_init(), argc, argv, flags, feat));\n}\n",
"sha256": "58a9bef0d1d424fd2e2a79c6d998dab96aab81ee771b7c2653928451f3bf11a8"
},
".github/tools/external/claude-official-skills/README.md": {
"mode": "100644",
"encoding": "utf-8",
"data": "> **Note:** This repository contains Anthropic's implementation of skills for Claude. For information about the Agent Skills standard, see [agentskills.io](http://agentskills.io).\n\n# Skills\nSkills are folders of instructions, scripts, and resources that Claude loads dynamically to improve performance on specialized tasks. Skills teach Claude how to complete specific tasks in a repeatable way, whether that's creating documents with your company's brand guidelines, analyzing data using your organization's specific workflows, or automating personal tasks.\n\nFor more information, check out:\n- [What are skills?](https://support.claude.com/en/articles/12512176-what-are-skills)\n- [Using skills in Claude](https://support.claude.com/en/articles/12512180-using-skills-in-claude)\n- [How to create custom skills](https://support.claude.com/en/articles/12512198-creating-custom-skills)\n- [Equipping agents for the real world with Agent Skills](https://anthropic.com/engineering/equipping-agents-for-the-real-world-with-agent-skills)\n\n# About This Repository\n\nThis repository contains skills that demonstrate what's possible with Claude's skills system. These skills range from creative applications (art, music, design) to technical tasks (testing web apps, MCP server generation) to enterprise workflows (communications, branding, etc.).\n\nEach skill is self-contained in its own folder with a `SKILL.md` file containing the instructions and metadata that Claude uses. Browse through these skills to get inspiration for your own skills or to understand different patterns and approaches.\n\nMany skills in this repo are open source (Apache 2.0). We've also included the document creation & editing skills that power [Claude's document capabilities](https://www.anthropic.com/news/create-files) under the hood in the [`skills/docx`](./skills/docx), [`skills/pdf`](./skills/pdf), [`skills/pptx`](./skills/pptx), and [`skills/xlsx`](./skills/xlsx) subfolders. These are source-available, not open source, but we wanted to share these with developers as a reference for more complex skills that are actively used in a production AI application.\n\n## Disclaimer\n\n**These skills are provided for demonstration and educational purposes only.** While some of these capabilities may be available in Claude, the implementations and behaviors you receive from Claude may differ from what is shown in these skills. These skills are meant to illustrate patterns and possibilities. Always test skills thoroughly in your own environment before relying on them for critical tasks.\n\n# Skill Sets\n- [./skills](./skills): Skill examples for Creative & Design, Development & Technical, Enterprise & Communication, and Document Skills\n- [./spec](./spec): The Agent Skills specification\n- [./template](./template): Skill template\n\n# Try in Claude Code, Claude.ai, and the API\n\n## Claude Code\nYou can register this repository as a Claude Code Plugin marketplace by running the following command in Claude Code:\n```\n/plugin marketplace add anthropics/skills\n```\n\nThen, to install a specific set of skills:\n1. Select `Browse and install plugins`\n2. Select `anthropic-agent-skills`\n3. Select `document-skills` or `example-skills`\n4. Select `Install now`\n\nAlternatively, directly install either Plugin via:\n```\n/plugin install document-skills@anthropic-agent-skills\n/plugin install example-skills@anthropic-agent-skills\n```\n\nAfter installing the plugin, you can use the skill by just mentioning it. For instance, if you install the `document-skills` plugin from the marketplace, you can ask Claude Code to do something like: \"Use the PDF skill to extract the form fields from `path/to/some-file.pdf`\"\n\n## Claude.ai\n\nThese example skills are all already available to paid plans in Claude.ai. \n\nTo use any skill from this repository or upload custom skills, follow the instructions in [Using skills in Claude](https://support.claude.com/en/articles/12512180-using-skills-in-claude#h_a4222fa77b).\n\n## Claude API\n\nYou can use Anthropic's pre-built skills, and upload custom skills, via the Claude API. See the [Skills API Quickstart](https://docs.claude.com/en/api/skills-guide#creating-a-skill) for more.\n\n# Creating a Basic Skill\n\nSkills are simple to create - just a folder with a `SKILL.md` file containing YAML frontmatter and instructions. You can use the **template-skill** in this repository as a starting point:\n\n```markdown\n---\nname: my-skill-name\ndescription: A clear description of what this skill does and when to use it\n---\n\n# My Skill Name\n\n[Add your instructions here that Claude will follow when this skill is active]\n\n## Examples\n- Example usage 1\n- Example usage 2\n\n## Guidelines\n- Guideline 1\n- Guideline 2\n```\n\nThe frontmatter requires only two fields:\n- `name` - A unique identifier for your skill (lowercase, hyphens for spaces)\n- `description` - A complete description of what the skill does and when to use it\n\nThe markdown content below contains the instructions, examples, and guidelines that Claude will follow. For more details, see [How to create custom skills](https://support.claude.com/en/articles/12512198-creating-custom-skills).\n\n# Partner Skills\n\nSkills are a great way to teach Claude how to get better at using specific pieces of software. As we see awesome example skills from partners, we may highlight some of them here:\n\n- **Notion** - [Notion Skills for Claude](https://www.notion.so/notiondevs/Notion-Skills-for-Claude-28da4445d27180c7af1df7d8615723d0)\n",
"sha256": "d7c5c2f9b248c7c0b31f093cf22b9a7407f5b093c8ca9ebe75a5b6845b02b76e"
},
".github/tools/external/claude-official-skills/skills/skill-creator/scripts/init_skill.py": {
"mode": "100755",
"encoding": "utf-8",
"data": "#!/usr/bin/env python3\n\"\"\"\nSkill Initializer - Creates a new skill from template\n\nUsage:\n init_skill.py <skill-name> --path <path>\n\nExamples:\n init_skill.py my-new-skill --path skills/public\n init_skill.py my-api-helper --path skills/private\n init_skill.py custom-skill --path /custom/location\n\"\"\"\n\nimport sys\nfrom pathlib import Path\n\n\nSKILL_TEMPLATE = \"\"\"---\nname: {skill_name}\ndescription: [TODO: Complete and informative explanation of what the skill does and when to use it. Include WHEN to use this skill - specific scenarios, file types, or tasks that trigger it.]\n---\n\n# {skill_title}\n\n## Overview\n\n[TODO: 1-2 sentences explaining what this skill enables]\n\n## Structuring This Skill\n\n[TODO: Choose the structure that best fits this skill's purpose. Common patterns:\n\n**1. Workflow-Based** (best for sequential processes)\n- Works well when there are clear step-by-step procedures\n- Example: DOCX skill with \"Workflow Decision Tree\" → \"Reading\" → \"Creating\" → \"Editing\"\n- Structure: ## Overview → ## Workflow Decision Tree → ## Step 1 → ## Step 2...\n\n**2. Task-Based** (best for tool collections)\n- Works well when the skill offers different operations/capabilities\n- Example: PDF skill with \"Quick Start\" → \"Merge PDFs\" → \"Split PDFs\" → \"Extract Text\"\n- Structure: ## Overview → ## Quick Start → ## Task Category 1 → ## Task Category 2...\n\n**3. Reference/Guidelines** (best for standards or specifications)\n- Works well for brand guidelines, coding standards, or requirements\n- Example: Brand styling with \"Brand Guidelines\" → \"Colors\" → \"Typography\" → \"Features\"\n- Structure: ## Overview → ## Guidelines → ## Specifications → ## Usage...\n\n**4. Capabilities-Based** (best for integrated systems)\n- Works well when the skill provides multiple interrelated features\n- Example: Product Management with \"Core Capabilities\" → numbered capability list\n- Structure: ## Overview → ## Core Capabilities → ### 1. Feature → ### 2. Feature...\n\nPatterns can be mixed and matched as needed. Most skills combine patterns (e.g., start with task-based, add workflow for complex operations).\n\nDelete this entire \"Structuring This Skill\" section when done - it's just guidance.]\n\n## [TODO: Replace with the first main section based on chosen structure]\n\n[TODO: Add content here. See examples in existing skills:\n- Code samples for technical skills\n- Decision trees for complex workflows\n- Concrete examples with realistic user requests\n- References to scripts/templates/references as needed]\n\n## Resources\n\nThis skill includes example resource directories that demonstrate how to organize different types of bundled resources:\n\n### scripts/\nExecutable code (Python/Bash/etc.) that can be run directly to perform specific operations.\n\n**Examples from other skills:**\n- PDF skill: `fill_fillable_fields.py`, `extract_form_field_info.py` - utilities for PDF manipulation\n- DOCX skill: `document.py`, `utilities.py` - Python modules for document processing\n\n**Appropriate for:** Python scripts, shell scripts, or any executable code that performs automation, data processing, or specific operations.\n\n**Note:** Scripts may be executed without loading into context, but can still be read by Claude for patching or environment adjustments.\n\n### references/\nDocumentation and reference material intended to be loaded into context to inform Claude's process and thinking.\n\n**Examples from other skills:**\n- Product management: `communication.md`, `context_building.md` - detailed workflow guides\n- BigQuery: API reference documentation and query examples\n- Finance: Schema documentation, company policies\n\n**Appropriate for:** In-depth documentation, API references, database schemas, comprehensive guides, or any detailed information that Claude should reference while working.\n\n### assets/\nFiles not intended to be loaded into context, but rather used within the output Claude produces.\n\n**Examples from other skills:**\n- Brand styling: PowerPoint template files (.pptx), logo files\n- Frontend builder: HTML/React boilerplate project directories\n- Typography: Font files (.ttf, .woff2)\n\n**Appropriate for:** Templates, boilerplate code, document templates, images, icons, fonts, or any files meant to be copied or used in the final output.\n\n---\n\n**Any unneeded directories can be deleted.** Not every skill requires all three types of resources.\n\"\"\"\n\nEXAMPLE_SCRIPT = '''#!/usr/bin/env python3\n\"\"\"\nExample helper script for {skill_name}\n\nThis is a placeholder script that can be executed directly.\nReplace with actual implementation or delete if not needed.\n\nExample real scripts from other skills:\n- pdf/scripts/fill_fillable_fields.py - Fills PDF form fields\n- pdf/scripts/convert_pdf_to_images.py - Converts PDF pages to images\n\"\"\"\n\ndef main():\n print(\"This is an example script for {skill_name}\")\n # TODO: Add actual script logic here\n # This could be data processing, file conversion, API calls, etc.\n\nif __name__ == \"__main__\":\n main()\n'''\n\nEXAMPLE_REFERENCE = \"\"\"# Reference Documentation for {skill_title}\n\nThis is a placeholder for detailed reference documentation.\nReplace with actual reference content or delete if not needed.\n\nExample real reference docs from other skills:\n- product-management/references/communication.md - Comprehensive guide for status updates\n- product-management/references/context_building.md - Deep-dive on gathering context\n- bigquery/references/ - API references and query examples\n\n## When Reference Docs Are Useful\n\nReference docs are ideal for:\n- Comprehensive API documentation\n- Detailed workflow guides\n- Complex multi-step processes\n- Information too lengthy for main SKILL.md\n- Content that's only needed for specific use cases\n\n## Structure Suggestions\n\n### API Reference Example\n- Overview\n- Authentication\n- Endpoints with examples\n- Error codes\n- Rate limits\n\n### Workflow Guide Example\n- Prerequisites\n- Step-by-step instructions\n- Common patterns\n- Troubleshooting\n- Best practices\n\"\"\"\n\nEXAMPLE_ASSET = \"\"\"# Example Asset File\n\nThis placeholder represents where asset files would be stored.\nReplace with actual asset files (templates, images, fonts, etc.) or delete if not needed.\n\nAsset files are NOT intended to be loaded into context, but rather used within\nthe output Claude produces.\n\nExample asset files from other skills:\n- Brand guidelines: logo.png, slides_template.pptx\n- Frontend builder: hello-world/ directory with HTML/React boilerplate\n- Typography: custom-font.ttf, font-family.woff2\n- Data: sample_data.csv, test_dataset.json\n\n## Common Asset Types\n\n- Templates: .pptx, .docx, boilerplate directories\n- Images: .png, .jpg, .svg, .gif\n- Fonts: .ttf, .otf, .woff, .woff2\n- Boilerplate code: Project directories, starter files\n- Icons: .ico, .svg\n- Data files: .csv, .json, .xml, .yaml\n\nNote: This is a text placeholder. Actual assets can be any file type.\n\"\"\"\n\n\ndef title_case_skill_name(skill_name):\n \"\"\"Convert hyphenated skill name to Title Case for display.\"\"\"\n return ' '.join(word.capitalize() for word in skill_name.split('-'))\n\n\ndef init_skill(skill_name, path):\n \"\"\"\n Initialize a new skill directory with template SKILL.md.\n\n Args:\n skill_name: Name of the skill\n path: Path where the skill directory should be created\n\n Returns:\n Path to created skill directory, or None if error\n \"\"\"\n # Determine skill directory path\n skill_dir = Path(path).resolve() / skill_name\n\n # Check if directory already exists\n if skill_dir.exists():\n print(f\"❌ Error: Skill directory already exists: {skill_dir}\")\n return None\n\n # Create skill directory\n try:\n skill_dir.mkdir(parents=True, exist_ok=False)\n print(f\"✅ Created skill directory: {skill_dir}\")\n except Exception as e:\n print(f\"❌ Error creating directory: {e}\")\n return None\n\n # Create SKILL.md from template\n skill_title = title_case_skill_name(skill_name)\n skill_content = SKILL_TEMPLATE.format(\n skill_name=skill_name,\n skill_title=skill_title\n )\n\n skill_md_path = skill_dir / 'SKILL.md'\n try:\n skill_md_path.write_text(skill_content)\n print(\"✅ Created SKILL.md\")\n except Exception as e:\n print(f\"❌ Error creating SKILL.md: {e}\")\n return None\n\n # Create resource directories with example files\n try:\n # Create scripts/ directory with example script\n scripts_dir = skill_dir / 'scripts'\n scripts_dir.mkdir(exist_ok=True)\n example_script = scripts_dir / 'example.py'\n example_script.write_text(EXAMPLE_SCRIPT.format(skill_name=skill_name))\n example_script.chmod(0o755)\n print(\"✅ Created scripts/example.py\")\n\n # Create references/ directory with example reference doc\n references_dir = skill_dir / 'references'\n references_dir.mkdir(exist_ok=True)\n example_reference = references_dir / 'api_reference.md'\n example_reference.write_text(EXAMPLE_REFERENCE.format(skill_title=skill_title))\n print(\"✅ Created references/api_reference.md\")\n\n # Create assets/ directory with example asset placeholder\n assets_dir = skill_dir / 'assets'\n assets_dir.mkdir(exist_ok=True)\n example_asset = assets_dir / 'example_asset.txt'\n example_asset.write_text(EXAMPLE_ASSET)\n print(\"✅ Created assets/example_asset.txt\")\n except Exception as e:\n print(f\"❌ Error creating resource directories: {e}\")\n return None\n\n # Print next steps\n print(f\"\\n✅ Skill '{skill_name}' initialized successfully at {skill_dir}\")\n print(\"\\nNext steps:\")\n print(\"1. Edit SKILL.md to complete the TODO items and update the description\")\n print(\"2. Customize or delete the example files in scripts/, references/, and assets/\")\n print(\"3. Run the validator when ready to check the skill structure\")\n\n return skill_dir\n\n\ndef main():\n if len(sys.argv) < 4 or sys.argv[2] != '--path':\n print(\"Usage: init_skill.py <skill-name> --path <path>\")\n print(\"\\nSkill name requirements:\")\n print(\" - Kebab-case identifier (e.g., 'my-data-analyzer')\")\n print(\" - Lowercase letters, digits, and hyphens only\")\n print(\" - Max 64 characters\")\n print(\" - Must match directory name exactly\")\n print(\"\\nExamples:\")\n print(\" init_skill.py my-new-skill --path skills/public\")\n print(\" init_skill.py my-api-helper --path skills/private\")\n print(\" init_skill.py custom-skill --path /custom/location\")\n sys.exit(1)\n\n skill_name = sys.argv[1]\n path = sys.argv[3]\n\n print(f\"🚀 Initializing skill: {skill_name}\")\n print(f\" Location: {path}\")\n print()\n\n result = init_skill(skill_name, path)\n\n if result:\n sys.exit(0)\n else:\n sys.exit(1)\n\n\nif __name__ == \"__main__\":\n main()\n",
"sha256": "cf12790f1d4958799281920d599f56aea38fb5c26e2812a61dd740bf3d4b6b99"
},
".github/tools/external/html-tools-main/README.md": {
"mode": "100644",
"encoding": "utf-8",
"data": "# HTML Tools\n\n**HTML 工具集:集成多种独立 HTML 工具,涵盖单一或多功能设计,致力于一键高效完成任务。**\n\n## 项目简介\n\nHTML Tools 是一个集合各种 HTML 工具的项目,旨在帮助开发者快速、高效地完成 HTML 页面相关的任务。无论是单一功能的小工具,还是集成多种功能的工具,这个项目都能够满足您的需求。\n\n---\n\n## 功能特色\n\n- **多种工具集成**:提供从简单到复杂 HTML 操作的工具。\n- **高效便捷**:一键式操作,快速完成目标任务。\n- **模块化设计**:工具独立,便于扩展和维护。\n- **开源免费**:完全开源,欢迎贡献。\n\n---\n\n## 安装与使用\n\n### 1. 克隆仓库\n```bash\ngit clone https://github.com/fud114514/html-tools.git\ncd html-tools\n```\n\n### 2. 打开工具\n- 将工具直接部署在浏览器中运行,或者在本地 HTML 文件中打开。\n- 无需安装额外依赖。\n\n### 3. 贡献代码\n如果您有兴趣为项目贡献代码,请按照以下步骤进行:\n1. Fork 本仓库。\n2. 创建自己的分支:`git checkout -b feature/your-feature`\n3. 提交更改:`git commit -m 'Add some feature'`\n4. 推送分支到 GitHub:`git push origin feature/your-feature`\n5. 提交 Pull Request。\n\n---\n\n## 文件结构\n\n```plaintext\nhtml-tools/\n├── index.html # 主页面\n├── tools/ # 各种独立工具文件\n├── assets/ # 静态资源 (如图片、样式表)\n└── README.md # 项目文档\n```\n\n---\n\n## 参与贡献\n\n欢迎大家为 HTML Tools 项目贡献自己的力量!无论是修复问题、添加新功能或改进文档,您的每一个贡献都对我们非常重要。\n\n### 提交 Issue\n如果您在使用过程中遇到问题,可以通过 [Issue 页面](https://github.com/fud114514/html-tools/issues) 提交问题。\n\n### 提交 Pull Request\n详细步骤请参考上文的“贡献代码”部分。\n\n---\n\n## 开发者\n\n该项目由 [fud114514](https://github.com/fud114514) 开发和维护。\n\n---\n\n## 许可证\n\n本项目采用 [MIT 许可证](https://opensource.org/licenses/MIT) 开源,详情请参阅 [LICENSE 文件](https://github.com/fud114514/html-tools/blob/main/LICENSE)。\n",
"sha256": "6aeb3fbdd0ad484f15b44b8c0e26caa7228cede0a659292893617d19d99b6df3"
},
".github/tools/external/html-tools-main/clean_epub_css.html": {
"mode": "100644",
"encoding": "utf-8",
"data": "<!DOCTYPE html>\r\n<html lang=\"zh\">\r\n<head>\r\n <meta charset=\"UTF-8\">\r\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\r\n <title>EPUB CSS 清理工具 (Web版)</title>\r\n <style>\r\n body {\r\n font-family: sans-serif;\r\n line-height: 1.6;\r\n padding: 20px;\r\n max-width: 600px;\r\n margin: 20px auto;\r\n background-color: #f4f4f4;\r\n border: 1px solid #ccc;\r\n border-radius: 8px;\r\n }\r\n h1 {\r\n text-align: center;\r\n color: #333;\r\n }\r\n #drop-area {\r\n border: 2px dashed #ccc;\r\n border-radius: 5px;\r\n padding: 30px;\r\n text-align: center;\r\n background-color: #fff;\r\n margin-bottom: 20px;\r\n cursor: pointer;\r\n }\r\n #drop-area.highlight {\r\n border-color: dodgerblue;\r\n }\r\n #drop-area p {\r\n margin: 0;\r\n color: #555;\r\n }\r\n #fileInput {\r\n display: none; /* Hide default input, use drop area or label */\r\n }\r\n label.file-label {\r\n display: inline-block;\r\n padding: 10px 15px;\r\n background-color: dodgerblue;\r\n color: white;\r\n border: none;\r\n border-radius: 4px;\r\n cursor: pointer;\r\n margin-top: 10px;\r\n transition: background-color 0.2s;\r\n }\r\n label.file-label:hover {\r\n background-color: #007ae5;\r\n }\r\n\r\n #status {\r\n margin-top: 15px;\r\n padding: 10px;\r\n background-color: #eee;\r\n border-radius: 4px;\r\n min-height: 40px; /* Ensure space for messages */\r\n text-align: center;\r\n font-weight: bold;\r\n }\r\n .status-details {\r\n font-size: 0.9em;\r\n color: #555;\r\n margin-top: 5px;\r\n }\r\n .warning {\r\n color: #a00;\r\n font-weight: bold;\r\n text-align: center;\r\n margin-top: 20px;\r\n padding: 10px;\r\n background-color: #fdd;\r\n border: 1px solid #fbb;\r\n border-radius: 4px;\r\n }\r\n progress {\r\n width: 100%;\r\n margin-top: 10px;\r\n display: none; /* Hidden by default */\r\n }\r\n </style>\r\n <!-- Include JSZip library -->\r\n <script src=\"https://cdnjs.cloudflare.com/ajax/libs/jszip/3.10.1/jszip.min.js\"></script>\r\n <!-- Include FileSaver.js library -->\r\n <script src=\"https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/2.0.5/FileSaver.min.js\"></script>\r\n</head>\r\n<body>\r\n\r\n <h1>EPUB CSS 清理工具 (Web版)</h1>\r\n\r\n <p>将单个 EPUB 文件或包含多个 EPUB 的 ZIP 文件拖拽到下方区域,或点击按钮选择文件,即可移除指定的 CSS 样式。</p>\r\n\r\n <div id=\"drop-area\">\r\n <!-- Accept both .epub and .zip -->\r\n <input type=\"file\" id=\"fileInput\" accept=\".epub,.zip\">\r\n <p>将 EPUB 或 ZIP 文件拖拽到这里</p>\r\n <label for=\"fileInput\" class=\"file-label\">或者选择文件</label>\r\n </div>\r\n\r\n <progress id=\"progressBar\" value=\"0\" max=\"100\"></progress>\r\n <div id=\"status\">请选择或拖拽一个 EPUB 或 ZIP 文件。</div>\r\n <div id=\"statusDetails\" class=\"status-details\"></div>\r\n\r\n <div class=\"warning\">\r\n <strong>重要提示:</strong> 此工具在你的浏览器中处理文件,不会上传到服务器。处理后的文件需要你手动下载。建议在处理前备份原始文件!处理 ZIP 文件时,会生成一个包含所有处理后(或原始)EPUB 的新 ZIP 文件。\r\n </div>\r\n\r\n <script>\r\n // --- Check if libraries loaded ---\r\n if (typeof JSZip === 'undefined' || typeof saveAs === 'undefined') {\r\n const errorMsg = '错误:无法加载必需的库 (JSZip 或 FileSaver)。请检查您的网络连接,并确保没有浏览器插件(如广告拦截器)阻止从 cdnjs.cloudflare.com 加载脚本。然后请刷新页面重试。';\r\n document.getElementById('status').textContent = errorMsg;\r\n document.getElementById('status').style.color = '#a00';\r\n document.getElementById('drop-area').style.display = 'none';\r\n document.querySelector('.warning').textContent = errorMsg;\r\n } else {\r\n // --- Global Variables & Constants ---\r\n const dropArea = document.getElementById('drop-area');\r\n const fileInput = document.getElementById('fileInput');\r\n const statusDiv = document.getElementById('status');\r\n const statusDetailsDiv = document.getElementById('statusDetails');\r\n const progressBar = document.getElementById('progressBar');\r\n const CSS_REMOVE_PATTERN = /((text-indent|line-height|font-size|height|font-family|color)\\s*:\\s*[^;]*;|display\\s*:\\s*block\\s*;)/ig;\r\n\r\n // --- Event Handlers ---\r\n setupDragDropHandlers();\r\n fileInput.addEventListener('change', handleFileSelect, false);\r\n\r\n function setupDragDropHandlers() {\r\n ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {\r\n dropArea.addEventListener(eventName, preventDefaults, false);\r\n document.body.addEventListener(eventName, preventDefaults, false);\r\n });\r\n ['dragenter', 'dragover'].forEach(eventName => {\r\n dropArea.addEventListener(eventName, () => dropArea.classList.add('highlight'), false);\r\n });\r\n ['dragleave', 'drop'].forEach(eventName => {\r\n dropArea.addEventListener(eventName, () => dropArea.classList.remove('highlight'), false);\r\n });\r\n dropArea.addEventListener('drop', handleDrop, false);\r\n }\r\n\r\n function preventDefaults(e) {\r\n e.preventDefault();\r\n e.stopPropagation();\r\n }\r\n\r\n function handleDrop(e) {\r\n handleFiles(e.dataTransfer.files);\r\n }\r\n\r\n function handleFileSelect(e) {\r\n handleFiles(e.target.files);\r\n }\r\n\r\n // --- Main File Handling Logic ---\r\n function handleFiles(files) {\r\n if (files.length === 0) return;\r\n const file = files[0]; // Process only the first file\r\n\r\n // Check file type\r\n const isEpub = file.name.toLowerCase().endsWith('.epub');\r\n const isZip = file.name.toLowerCase().endsWith('.zip');\r\n\r\n if (!isEpub && !isZip) {\r\n updateStatus('错误:请选择一个 .epub 或 .zip 文件。', true);\r\n resetInput();\r\n return;\r\n }\r\n\r\n updateStatus(`正在读取文件: ${file.name}...`);\r\n clearStatusDetails();\r\n progressBar.style.display = 'block';\r\n progressBar.value = 0;\r\n\r\n const reader = new FileReader();\r\n reader.onload = async (e) => {\r\n const fileContent = e.target.result; // ArrayBuffer\r\n try {\r\n if (isEpub) {\r\n updateStatus(`正在处理 EPUB 文件: ${file.name}...`);\r\n const result = await processEpub(fileContent, file.name);\r\n if (result.blob) {\r\n saveAs(result.blob, result.filename);\r\n updateStatus(`处理完成!已生成 ${result.filename}。`);\r\n } else if (result.modified === false) {\r\n updateStatus('信息:文件无需修改。');\r\n }\r\n resetInput();\r\n } else if (isZip) {\r\n updateStatus(`正在处理 ZIP 压缩包: ${file.name}...`);\r\n await processZipArchive(fileContent, file.name);\r\n }\r\n } catch (error) {\r\n console.error(\"处理失败:\", error);\r\n updateStatus(`处理失败:${error.message}`, true);\r\n resetInput();\r\n }\r\n };\r\n reader.onprogress = updateReadProgress;\r\n reader.onerror = handleReadError;\r\n reader.readAsArrayBuffer(file);\r\n }\r\n\r\n function updateReadProgress(e) {\r\n if (e.lengthComputable) {\r\n progressBar.value = Math.round((e.loaded / e.total) * 10); // Reading is ~10%\r\n }\r\n }\r\n\r\n function handleReadError() {\r\n updateStatus('错误:读取文件时出错。', true);\r\n resetInput();\r\n }\r\n\r\n // --- ZIP Archive Processing ---\r\n async function processZipArchive(zipFileContent, zipFilename) {\r\n let outputZip = new JSZip();\r\n let processedCount = 0;\r\n let failedCount = 0;\r\n let foundCount = 0;\r\n let modifiedCount = 0;\r\n let filePromises = [];\r\n\r\n updateStatus(`正在打开 ZIP 压缩包...`);\r\n progressBar.value = 15;\r\n const inputZip = await JSZip.loadAsync(zipFileContent);\r\n const totalFilesInZip = Object.keys(inputZip.files).length;\r\n\r\n updateStatus(`在 ZIP 中查找 EPUB 文件...`);\r\n\r\n inputZip.forEach((relativePath, zipEntry) => {\r\n if (!zipEntry.dir && relativePath.toLowerCase().endsWith('.epub')) {\r\n foundCount++;\r\n updateStatusDetails(`找到 EPUB: ${relativePath}`);\r\n\r\n // Add a promise to process this EPUB entry\r\n const promise = zipEntry.async('arraybuffer')\r\n .then(async (innerEpubContent) => {\r\n try {\r\n // Process the inner EPUB\r\n const result = await processEpub(innerEpubContent, relativePath);\r\n if (result.blob) {\r\n // Add modified EPUB to output ZIP\r\n outputZip.file(result.filename, result.blob);\r\n modifiedCount++;\r\n console.log(`Added cleaned ${result.filename} to output zip.`);\r\n } else {\r\n // Add original EPUB back if not modified\r\n outputZip.file(relativePath, innerEpubContent);\r\n console.log(`Added original ${relativePath} (no changes needed) to output zip.`);\r\n }\r\n processedCount++;\r\n } catch (epubError) {\r\n // Add original EPUB back if processing failed\r\n console.error(`Error processing inner EPUB ${relativePath}:`, epubError);\r\n updateStatusDetails(`处理 ${relativePath} 时出错,将保留原文件。`);\r\n outputZip.file(relativePath, innerEpubContent); // Add original back\r\n failedCount++;\r\n }\r\n })\r\n .catch(extractError => {\r\n // Handle error extracting the inner EPUB content\r\n console.error(`Error extracting inner EPUB ${relativePath} from zip:`, extractError);\r\n updateStatusDetails(`无法从 ZIP 中提取 ${relativePath},已跳过。`);\r\n failedCount++;\r\n })\r\n .finally(() => {\r\n // Update progress based on entries processed (success or fail)\r\n const progress = 15 + Math.round(((processedCount + failedCount) / foundCount) * 60); // Processing EPUBs is ~60%\r\n progressBar.value = Math.min(progress, 75); // Cap at 75 before final packing\r\n });\r\n filePromises.push(promise);\r\n }\r\n // We are currently NOT adding non-EPUB files from the source ZIP to the output ZIP.\r\n // To do so, handle the 'else' case here and add zipEntry data to outputZip.\r\n });\r\n\r\n // Wait for all inner EPUB processing promises to complete\r\n await Promise.all(filePromises);\r\n\r\n progressBar.value = 80; // Done processing files inside zip\r\n\r\n if (foundCount === 0) {\r\n updateStatus('错误:在 ZIP 文件中未找到任何 EPUB 文件。', true);\r\n resetInput();\r\n return;\r\n }\r\n\r\n updateStatus(`处理了 ${foundCount} 个 EPUB 文件。正在生成输出 ZIP...`);\r\n statusDetailsDiv.innerHTML += `<br>成功: ${processedCount}, 修改: ${modifiedCount}, 失败/跳过: ${failedCount}`;\r\n progressBar.value = 90;\r\n\r\n const outputZipBlob = await outputZip.generateAsync({\r\n type: \"blob\",\r\n compression: \"DEFLATE\",\r\n platform: \"browser\"\r\n }, (metadata) => {\r\n progressBar.value = 90 + Math.round(metadata.percent * 0.1);\r\n });\r\n\r\n progressBar.value = 100;\r\n const baseName = zipFilename.substring(0, zipFilename.lastIndexOf('.')) || zipFilename;\r\n const outputZipFilename = `${baseName}_cleaned.zip`;\r\n saveAs(outputZipBlob, outputZipFilename);\r\n\r\n updateStatus(`处理完成!已生成包含处理后 EPUB 的 ${outputZipFilename}。`);\r\n resetInput();\r\n }\r\n\r\n\r\n // --- Single EPUB Processing (Modified to return result) ---\r\n async function processEpub(fileContent, originalFilename) {\r\n // This function now returns an object:\r\n // { blob: Blob, filename: string } if modified\r\n // { modified: false } if no modification needed\r\n // Throws error if processing fails critically\r\n\r\n console.log(`Processing EPUB: ${originalFilename}`);\r\n // Note: Progress bar updates inside this function are less meaningful now,\r\n // as the overall progress is handled by the caller (handleFiles or processZipArchive).\r\n // We could pass a progress callback if detailed inner progress is needed.\r\n\r\n const zip = await JSZip.loadAsync(fileContent);\r\n const newZip = new JSZip();\r\n let cssFilesFound = false;\r\n let modified = false;\r\n let filePromises = [];\r\n\r\n zip.forEach((relativePath, zipEntry) => {\r\n if (zipEntry.dir) { newZip.folder(relativePath); return; }\r\n\r\n const options = {\r\n date: zipEntry.date,\r\n unixPermissions: zipEntry.unixPermissions,\r\n dosPermissions: zipEntry.dosPermissions,\r\n comment: zipEntry.comment,\r\n dir: zipEntry.dir,\r\n compression: zipEntry.options?.compression === \"STORE\" ? \"STORE\" : \"DEFLATE\"\r\n };\r\n\r\n if (relativePath.toLowerCase() === 'mimetype') {\r\n const promise = zipEntry.async('uint8array').then(data => {\r\n newZip.file(relativePath, data, { ...options, compression: \"STORE\" });\r\n });\r\n filePromises.push(promise);\r\n } else if (relativePath.toLowerCase().endsWith('.css')) {\r\n cssFilesFound = true;\r\n const promise = zipEntry.async('string').then(originalCss => {\r\n const cleanedCss = originalCss.replace(CSS_REMOVE_PATTERN, '');\r\n let contentToAdd = originalCss;\r\n if (cleanedCss !== originalCss) {\r\n modified = true;\r\n contentToAdd = cleanedCss;\r\n console.log(` Cleaned CSS: ${relativePath}`);\r\n }\r\n newZip.file(relativePath, contentToAdd, options);\r\n }).catch(err => {\r\n console.warn(` Could not process CSS ${relativePath} as text, keeping original. Error: ${err}`);\r\n return zipEntry.async('uint8array').then(originalData => {\r\n newZip.file(relativePath, originalData, options);\r\n });\r\n });\r\n filePromises.push(promise);\r\n } else {\r\n const promise = zipEntry.async('uint8array').then(data => {\r\n newZip.file(relativePath, data, options);\r\n });\r\n filePromises.push(promise);\r\n }\r\n });\r\n\r\n await Promise.all(filePromises);\r\n\r\n if (!modified) {\r\n console.log(` EPUB ${originalFilename} - No modifications needed.`);\r\n return { modified: false }; // Indicate no changes were made\r\n }\r\n\r\n console.log(` Repacking modified EPUB: ${originalFilename}`);\r\n const newEpubBlob = await newZip.generateAsync({\r\n type: \"blob\",\r\n mimeType: \"application/epub+zip\",\r\n compression: \"DEFLATE\",\r\n platform: \"browser\"\r\n });\r\n\r\n const baseName = originalFilename.substring(0, originalFilename.lastIndexOf('.')) || originalFilename;\r\n const newFilename = `${baseName}_cleaned.epub`;\r\n\r\n return { blob: newEpubBlob, filename: newFilename }; // Return data for the caller\r\n } // end of processEpub function\r\n\r\n // --- UI Update Functions ---\r\n function updateStatus(message, isError = false) {\r\n statusDiv.textContent = message;\r\n statusDiv.style.color = isError ? '#a00' : '#000';\r\n if (isError) {\r\n progressBar.style.display = 'none';\r\n clearStatusDetails();\r\n }\r\n }\r\n function updateStatusDetails(message) {\r\n statusDetailsDiv.innerHTML += message + \"<br>\";\r\n }\r\n function clearStatusDetails() {\r\n statusDetailsDiv.innerHTML = \"\";\r\n }\r\n\r\n function resetInput() {\r\n fileInput.value = '';\r\n // Hide progress bar after a delay\r\n setTimeout(() => { progressBar.style.display = 'none'; progressBar.value = 0; }, 5000);\r\n }\r\n } // End of the 'else' block for library check\r\n\r\n </script>\r\n\r\n</body>\r\n</html>",
"sha256": "1716a7ea5f4bf4837bc044c9c164e58b3dbb04d492f677b7766b506edd1c0d2a"
},
".github/tools/external/html-tools-main/markdown-bianjiqi.html": {
"mode": "100644",
"encoding": "utf-8",
"data": "<!DOCTYPE html>\n<html lang=\"zh\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>Markdown Editor</title>\n <style>\n :root {\n --border-color: #eee;\n --bg-color: #fafafa;\n --text-color: #333;\n --btn-border: #ddd;\n --code-bg: #f5f5f5;\n --scrollbar-color: #ccc;\n }\n \n * {\n margin: 0;\n padding: 0;\n box-sizing: border-box;\n }\n \n body {\n height: 100vh;\n display: flex;\n flex-direction: column;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n overflow: hidden;\n }\n\n .header {\n padding: 8px 20px;\n background: var(--bg-color);\n border-bottom: 1px solid var(--border-color);\n display: flex;\n justify-content: flex-end;\n align-items: center;\n font-size: 14px;\n color: var(--text-color);\n }\n\n .toolbar {\n display: flex;\n gap: 8px;\n }\n\n .btn {\n border: 1px solid var(--btn-border);\n background: white;\n padding: 4px 12px;\n border-radius: 4px;\n cursor: pointer;\n font-size: 14px;\n color: var(--text-color);\n min-width: 80px;\n text-align: center;\n transition: background-color 0.2s ease;\n }\n\n .btn:hover {\n background: var(--code-bg);\n }\n\n .content {\n display: flex;\n flex: 1;\n overflow: hidden;\n }\n \n #preview, #editor {\n width: 50%;\n height: 100%;\n padding: 20px;\n line-height: 1.6;\n }\n \n #preview {\n color: var(--text-color);\n border-right: 1px solid var(--border-color);\n overflow-y: auto;\n }\n \n #editor {\n font-family: monospace;\n font-size: 14px;\n border: none;\n outline: none;\n resize: none;\n overflow-y: auto;\n scrollbar-width: thin;\n scrollbar-color: var(--scrollbar-color) transparent;\n }\n\n #editor::-webkit-scrollbar {\n width: 8px;\n }\n\n #editor::-webkit-scrollbar-thumb {\n background-color: var(--scrollbar-color);\n border-radius: 4px;\n }\n\n #editor::-webkit-scrollbar-track {\n background-color: transparent;\n }\n\n .preview-content {\n height: auto;\n min-height: 100%;\n padding-right: 8px;\n }\n\n #preview h1, #preview h2, #preview h3 {\n margin: 16px 0;\n font-weight: 500;\n }\n\n #preview h1:first-child {\n margin-top: 0;\n }\n\n #preview p {\n margin: 12px 0;\n }\n\n #preview ul, #preview ol {\n padding-left: 24px;\n margin: 12px 0;\n }\n\n #preview code {\n background-color: var(--code-bg);\n padding: 2px 4px;\n border-radius: 3px;\n font-size: 0.9em;\n }\n\n #preview pre code {\n display: block;\n padding: 12px;\n overflow-x: auto;\n line-height: 1.45;\n }\n\n .toast {\n position: fixed;\n top: 20px;\n right: 20px;\n background: rgba(0, 0, 0, 0.8);\n color: white;\n padding: 8px 16px;\n border-radius: 4px;\n font-size: 14px;\n display: none;\n z-index: 1000;\n animation: fadeIn 0.3s ease;\n }\n\n @keyframes fadeIn {\n from { opacity: 0; transform: translateY(-10px); }\n to { opacity: 1; transform: translateY(0); }\n }\n </style>\n</head>\n<body>\n <div class=\"header\">\n <div class=\"toolbar\">\n <button class=\"btn\" id=\"copyBtn\">一键复制</button>\n <button class=\"btn\" id=\"exportBtn\">导出文本</button>\n </div>\n </div>\n <div class=\"content\">\n <div id=\"preview\">\n <div class=\"preview-content\"></div>\n </div>\n <textarea id=\"editor\" placeholder=\"在这里输入 Markdown 文本...\"></textarea>\n </div>\n <div id=\"toast\" class=\"toast\"></div>\n\n <script src=\"https://cdn.jsdelivr.net/npm/marked/marked.min.js\"></script>\n <script>\n document.addEventListener('DOMContentLoaded', function() {\n const editor = document.getElementById('editor');\n const preview = document.getElementById('preview');\n const previewContent = preview.querySelector('.preview-content');\n const toast = document.getElementById('toast');\n const copyBtn = document.getElementById('copyBtn');\n const exportBtn = document.getElementById('exportBtn');\n\n // Initialize marked with safe options\n marked.setOptions({\n breaks: true,\n gfm: true,\n headerIds: true,\n sanitize: false,\n highlight: function(code, lang) {\n return code;\n }\n });\n\n function showToast(message, duration = 2000) {\n toast.textContent = message;\n toast.style.display = 'block';\n setTimeout(() => {\n toast.style.display = 'none';\n }, duration);\n }\n\n function updatePreview() {\n try {\n const markdownText = editor.value;\n const htmlContent = marked.parse(markdownText);\n previewContent.innerHTML = htmlContent;\n } catch (error) {\n console.error('Markdown parsing error:', error);\n previewContent.innerHTML = '<p style=\"color: red;\">Error parsing markdown</p>';\n }\n }\n\n function debounce(func, wait) {\n let timeout;\n return function(...args) {\n clearTimeout(timeout);\n timeout = setTimeout(() => func.apply(this, args), wait);\n };\n }\n\n const debouncedUpdate = debounce(updatePreview, 150);\n\n async function copyText() {\n try {\n await navigator.clipboard.writeText(editor.value);\n showToast('已复制到剪贴板');\n } catch (err) {\n console.error('Copy failed:', err);\n showToast('复制失败');\n }\n }\n\n function exportTxt() {\n try {\n const text = editor.value;\n const blob = new Blob([text], { type: 'text/plain' });\n const url = URL.createObjectURL(blob);\n const a = document.createElement('a');\n const timestamp = new Date().toISOString().slice(0,19).replace(/[-:]/g, '');\n a.href = url;\n a.download = `markdown_${timestamp}.txt`;\n document.body.appendChild(a);\n a.click();\n document.body.removeChild(a);\n URL.revokeObjectURL(url);\n showToast('已导出为文本文件');\n } catch (err) {\n console.error('Export failed:', err);\n showToast('导出失败');\n }\n }\n\n // Event Listeners\n editor.addEventListener('input', debouncedUpdate);\n copyBtn.addEventListener('click', copyText);\n exportBtn.addEventListener('click', exportTxt);\n\n // Sync scroll\n editor.addEventListener('scroll', () => {\n const percentage = editor.scrollTop / (editor.scrollHeight - editor.clientHeight);\n preview.scrollTop = percentage * (preview.scrollHeight - preview.clientHeight);\n });\n\n // Initial content\n const initialText = `# Markdown 编辑器\n\n## 欢迎使用!\n\n这是一个简单的 Markdown 编辑器。\n\n### 主要功能:\n\n1. 实时预览\n2. 一键复制内容\n3. 导出文本文件\n4. 支持常用 Markdown 语法\n\n### 快速开始:\n\n- 在右侧输入 Markdown 文本\n- 在左侧查看实时预览\n- 使用顶部按钮进行操作\n\n\\`\\`\\`markdown\n# 示例代码\n**粗体** 和 *斜体*\n- 列表项\n- 另一个列表项\n\\`\\`\\``;\n\n editor.value = initialText;\n updatePreview();\n });\n </script>\n</body>\n</html>\n",
"sha256": "e4c76015749bf42e898412ec7b8e1229c847575ef740bcf6900311d7212dc61e"
},
".github/tools/external/html-tools-main/task card generator.html": {
"mode": "100644",
"encoding": "utf-8",
"data": "<!DOCTYPE html>\r\n<html lang=\"zh-CN\">\r\n<head>\r\n <meta charset=\"UTF-8\">\r\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\r\n <title>任务卡片生成器</title>\r\n <style>\r\n body {\r\n display: flex;\r\n flex-direction: column;\r\n justify-content: flex-start; /* 从顶部开始排列 */\r\n align-items: center;\r\n min-height: 100vh;\r\n background: #121212; /* 深色背景,让卡片在预览时效果更一致 */\r\n margin: 0;\r\n font-family: 'Arial', 'Helvetica Neue', Helvetica, sans-serif; /* 更现代的字体栈 */\r\n padding: 30px 20px; /* 给body一些padding */\r\n box-sizing: border-box;\r\n }\r\n .export-container {\r\n background: #282828; /* 图片中外部容器的深灰色 */\r\n padding: 20px; /* 容器内边距 */\r\n border-radius: 8px;\r\n display: inline-block;\r\n box-shadow: 0 8px 20px rgba(0,0,0,0.3); /* 给容器一些阴影 */\r\n }\r\n .card {\r\n width: 370px; /* 调整宽度以适应两列布局和间距 */\r\n background: #000000; /* 卡片纯黑背景 */\r\n padding: 25px;\r\n box-sizing: border-box;\r\n color: #ffffff;\r\n border-radius: 6px; /* 给卡片本身也加一点圆角 */\r\n }\r\n .card-header {\r\n border-bottom: 1px solid #444444; /* 更细、颜色更深的分割线 */\r\n padding-bottom: 15px;\r\n margin-bottom: 20px;\r\n }\r\n .task-id {\r\n font-size: 14px;\r\n color: #888888; /* 灰色ID文字 */\r\n margin-bottom: 8px; /* ID和标题间距 */\r\n min-height: 1.2em; /* 确保空的时候也有高度,placeholder可以显示 */\r\n }\r\n .task-title {\r\n font-size: 24px;\r\n font-weight: bold;\r\n color: #ffffff;\r\n word-wrap: break-word;\r\n min-height: 1.2em;\r\n }\r\n .task-description {\r\n font-size: 15px;\r\n color: #e0e0e0;\r\n line-height: 1.6;\r\n word-wrap: break-word;\r\n margin-top: 15px;\r\n margin-bottom: 25px;\r\n min-height: 45px; /* 描述区域最小高度 */\r\n padding: 5px 2px; /* 轻微内边距 */\r\n }\r\n .task-details {\r\n display: grid;\r\n grid-template-columns: 1fr 1fr; /* 固定两列 */\r\n gap: 15px;\r\n font-size: 14px;\r\n margin-top: 20px;\r\n }\r\n .detail-item {\r\n background-color: #1c1c1c; /* 详情项的背景色,比卡片黑底亮一点 */\r\n padding: 12px;\r\n border-radius: 6px;\r\n }\r\n /* 如果最后一个元素是奇数个中的最后一个(例如第3个),则让它占据整行 */\r\n .detail-item:last-child:nth-child(odd) { \r\n grid-column: 1 / -1; /* 跨越所有列 */\r\n }\r\n .detail-item label {\r\n font-weight: normal;\r\n color: #aaaaaa; /* 标签文字颜色 */\r\n display: block;\r\n margin-bottom: 8px;\r\n font-size: 13px;\r\n }\r\n .detail-item .value.editable,\r\n .detail-item input[type=\"date\"].value {\r\n color: #ffffff;\r\n background-color: #000000; /* 值区域纯黑背景 */\r\n border: 1px solid #333333; /* 值区域的细边框 */\r\n width: 100%;\r\n padding: 8px 10px; /* 值区域内边距 */\r\n min-height: 1.5em; /* 确保有高度 */\r\n border-radius: 4px;\r\n font-size: 15px;\r\n line-height: 1.4;\r\n box-sizing: border-box; /* padding和border不增加额外宽度 */\r\n }\r\n\r\n .detail-item input[type=\"date\"].value {\r\n -webkit-appearance: none;\r\n -moz-appearance: none;\r\n appearance: none;\r\n position: relative; \r\n }\r\n .detail-item input[type=\"date\"].value::-webkit-calendar-picker-indicator {\r\n filter: invert(0.8) brightness(0.8); \r\n cursor: pointer;\r\n opacity: 0.7;\r\n }\r\n .detail-item .value.editable {\r\n position: relative; \r\n }\r\n .detail-item .value.editable:empty::before {\r\n content: attr(data-placeholder);\r\n color: #555555; \r\n position: absolute;\r\n left: 10px; \r\n top: 50%;\r\n transform: translateY(-50%);\r\n pointer-events: none; \r\n width: calc(100% - 20px); \r\n overflow: hidden;\r\n text-overflow: ellipsis;\r\n white-space: nowrap;\r\n }\r\n .editable {\r\n position: relative; \r\n min-height: 1.2em; \r\n }\r\n .editable:empty:not(:focus)::before { \r\n content: attr(data-placeholder);\r\n color: #666666; \r\n position: absolute;\r\n left: 0; \r\n top: 0; \r\n pointer-events: none; \r\n width: 100%;\r\n overflow: hidden;\r\n text-overflow: ellipsis;\r\n white-space: nowrap;\r\n }\r\n .task-id.editable:empty:not(:focus)::before,\r\n .task-title.editable:empty:not(:focus)::before,\r\n .task-description.editable:empty:not(:focus)::before {\r\n left: 2px; \r\n top: 2px;\r\n }\r\n .editable:focus {\r\n outline: 1px dashed #777777;\r\n background-color: #0a0a0a; \r\n }\r\n [contenteditable] {\r\n -webkit-user-select: text;\r\n user-select: text;\r\n }\r\n [contenteditable]:focus {\r\n background-color: #0a0a0a !important;\r\n }\r\n ::selection {\r\n background-color: #444444;\r\n color: #ffffff;\r\n }\r\n .button-container {\r\n margin-top: 25px;\r\n text-align: center;\r\n }\r\n .export-btn {\r\n padding: 12px 25px;\r\n background: #1c1c1c;\r\n color: #ffffff;\r\n border: 1px solid #444444;\r\n cursor: pointer;\r\n font-size: 16px;\r\n border-radius: 6px;\r\n transition: background-color 0.2s ease, border-color 0.2s ease;\r\n }\r\n .export-btn:hover {\r\n background: #282828;\r\n border-color: #555555;\r\n }\r\n </style>\r\n</head>\r\n<body>\r\n <div class=\"export-container\" id=\"export-container\">\r\n <div id=\"taskCard\" class=\"card\">\r\n <div class=\"card-header\">\r\n <div class=\"task-id editable\" contenteditable=\"true\" data-placeholder=\"任务ID (可选)\"></div>\r\n <div class=\"task-title editable\" contenteditable=\"true\" data-placeholder=\"点击输入任务标题\"></div>\r\n </div>\r\n\r\n <div class=\"task-description editable\" contenteditable=\"true\" data-placeholder=\"点击输入任务详细描述...\"></div>\r\n\r\n <div class=\"task-details\">\r\n <div class=\"detail-item\">\r\n <label for=\"assignee-value\">负责人:</label>\r\n <div id=\"assignee-value\" class=\"value editable\" contenteditable=\"true\" data-placeholder=\"未分配\"></div>\r\n </div>\r\n <!-- 标签现在是第二个 -->\r\n <div class=\"detail-item\">\r\n <label for=\"tags-value\">标签:</label>\r\n <div id=\"tags-value\" class=\"value editable\" contenteditable=\"true\" data-placeholder=\"例如: 项目A, Bug\"></div>\r\n </div>\r\n <!-- 截止日期现在是第三个,会自动占据整行 -->\r\n <div class=\"detail-item\"> \r\n <label for=\"dueDate-value\">截止日期:</label>\r\n <input type=\"date\" id=\"dueDate-value\" class=\"value\">\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n <div class=\"button-container\">\r\n <button class=\"export-btn\" onclick=\"exportToPng()\">导出为PNG</button>\r\n </div>\r\n\r\n <script src=\"https://html2canvas.hertzen.com/dist/html2canvas.min.js\"></script>\r\n <script>\r\n function sanitizeFilename(name) {\r\n return name.replace(/[^a-z0-9_\\-.\\u4e00-\\u9fa5\\s]/gi, '').replace(/\\s+/g, '_');\r\n }\r\n\r\n function exportToPng() {\r\n if (window.getSelection) {\r\n if (window.getSelection().empty) { window.getSelection().empty(); }\r\n else if (window.getSelection().removeAllRanges) { window.getSelection().removeAllRanges(); }\r\n } else if (document.selection) { document.selection.empty(); }\r\n \r\n const container = document.getElementById('export-container');\r\n // const card = document.getElementById('taskCard'); // card variable not strictly needed here\r\n const originalDueDate = document.getElementById('dueDate-value').value;\r\n\r\n html2canvas(container, {\r\n backgroundColor: null, \r\n scale: 2,\r\n useCORS: true,\r\n logging: false, // Changed to false to reduce console noise unless debugging\r\n onclone: (documentClone) => {\r\n // const clonedCard = documentClone.getElementById('taskCard'); // clonedCard not strictly needed\r\n \r\n const dueDateInputClone = documentClone.getElementById('dueDate-value');\r\n if (dueDateInputClone) {\r\n dueDateInputClone.value = originalDueDate;\r\n if (!originalDueDate) {\r\n dueDateInputClone.style.color = '#555555'; \r\n } else {\r\n dueDateInputClone.style.color = '#ffffff';\r\n }\r\n }\r\n\r\n const editables = documentClone.querySelectorAll('.editable');\r\n editables.forEach(el => {\r\n // Placeholder handling is mostly done by CSS (:empty::before)\r\n // If specific adjustments needed for clone, add here.\r\n // For example, ensuring text color if content exists:\r\n // if (el.textContent.trim() !== '' && el.classList.contains('value')) {\r\n // el.style.color = '#ffffff';\r\n // }\r\n });\r\n }\r\n }).then(canvas => {\r\n const link = document.createElement('a');\r\n const taskTitleElement = document.getElementById('task-title');\r\n let filename = '任务卡片.png';\r\n if (taskTitleElement && taskTitleElement.textContent.trim() !== '') {\r\n const sanitizedTitle = sanitizeFilename(taskTitleElement.textContent.trim());\r\n if (sanitizedTitle) { // Ensure title isn't just invalid chars\r\n filename = sanitizedTitle + '.png';\r\n }\r\n }\r\n link.download = filename;\r\n link.href = canvas.toDataURL('image/png');\r\n link.click();\r\n }).catch(err => {\r\n console.error(\"导出PNG失败:\", err);\r\n alert(\"导出PNG失败,请查看控制台获取更多信息。\");\r\n });\r\n }\r\n\r\n document.querySelectorAll('.editable').forEach(element => {\r\n element.addEventListener('focus', function() {\r\n // CSS handles placeholder via :not(:focus)::before\r\n });\r\n element.addEventListener('blur', function() {\r\n // CSS handles placeholder\r\n });\r\n });\r\n </script>\r\n</body>\r\n</html>",
"sha256": "0eba89d2f674bb0bc26690c4e406f99b7a2bcd40ecd838c1c19e1f970f7b5670"
},
".github/tools/external/html-tools-main/xhs graphic production.html": {
"mode": "100644",
"encoding": "utf-8",
"data": "<!DOCTYPE html>\r\n<html lang=\"zh-CN\">\r\n<head>\r\n <meta charset=\"UTF-8\">\r\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\r\n <title>小红书内容卡片</title>\r\n <style>\r\n body {\r\n display: flex;\r\n flex-direction: column;\r\n justify-content: center;\r\n align-items: center;\r\n min-height: 100vh;\r\n background: #f0f0f0;\r\n margin: 0;\r\n font-family: 'Arial', sans-serif;\r\n }\r\n .export-container {\r\n background: #333333;\r\n padding: 10px;\r\n border-radius: 8px;\r\n }\r\n .card {\r\n width: 320px;\r\n background: #000000;\r\n border: 2px solid #666666; /* 改为灰色边框 */\r\n box-shadow: 4px 4px 0 #666666; /* 改为灰色阴影 */\r\n padding: 20px;\r\n box-sizing: border-box;\r\n }\r\n .title {\r\n font-size: 24px;\r\n font-weight: bold;\r\n color: #ffffff;\r\n border-bottom: 2px solid #666666; /* 改为灰色边框 */\r\n padding-bottom: 10px;\r\n margin-bottom: 15px;\r\n word-wrap: break-word;\r\n background-color: #000000;\r\n }\r\n .content {\r\n font-size: 16px;\r\n color: #ffffff;\r\n line-height: 1.5;\r\n word-wrap: break-word;\r\n background-color: #000000;\r\n }\r\n .editable {\r\n position: relative;\r\n min-height: 1em;\r\n }\r\n .editable:empty:before {\r\n content: attr(data-placeholder);\r\n color: #666666;\r\n position: absolute;\r\n pointer-events: none;\r\n }\r\n .editable:focus {\r\n outline: none;\r\n background-color: #000000;\r\n }\r\n [contenteditable] {\r\n -webkit-user-select: text;\r\n user-select: text;\r\n background-color: #000000 !important;\r\n }\r\n [contenteditable]:focus {\r\n background-color: #000000 !important;\r\n }\r\n ::selection {\r\n background-color: #333333;\r\n color: #ffffff;\r\n }\r\n .button-container {\r\n margin-top: 20px;\r\n text-align: center;\r\n }\r\n .export-btn {\r\n padding: 10px 20px;\r\n background: #000000;\r\n color: #ffffff;\r\n border: 2px solid #666666; /* 添加灰色边框保持一致性 */\r\n cursor: pointer;\r\n font-size: 16px;\r\n }\r\n .export-btn:hover {\r\n background: #333333;\r\n }\r\n </style>\r\n</head>\r\n<body>\r\n <div class=\"export-container\" id=\"export-container\">\r\n <div id=\"card\" class=\"card\">\r\n <div class=\"title editable\" contenteditable=\"true\" data-placeholder=\"点击输入标题\"></div>\r\n <div class=\"content editable\" contenteditable=\"true\" data-placeholder=\"点击输入内容\"></div>\r\n </div>\r\n </div>\r\n <div class=\"button-container\">\r\n <button class=\"export-btn\" onclick=\"exportToPng()\">导出为PNG</button>\r\n </div>\r\n\r\n <script src=\"https://html2canvas.hertzen.com/dist/html2canvas.min.js\"></script>\r\n <script>\r\n function exportToPng() {\r\n // 清除选中状态\r\n window.getSelection().removeAllRanges();\r\n \r\n const container = document.getElementById('export-container');\r\n html2canvas(container, {\r\n backgroundColor: '#333333',\r\n scale: 2,\r\n useCORS: true,\r\n logging: false,\r\n removeContainer: true,\r\n foreignObjectRendering: false,\r\n onclone: (document) => {\r\n const editables = document.querySelectorAll('.editable');\r\n editables.forEach(el => {\r\n // 确保克隆的元素保持相同的样式\r\n el.style.backgroundColor = '#000000';\r\n if (el.classList.contains('title')) {\r\n el.style.borderBottom = '2px solid #666666';\r\n }\r\n });\r\n // 确保卡片样式在克隆中保持一致\r\n const card = document.querySelector('.card');\r\n card.style.border = '2px solid #666666';\r\n card.style.boxShadow = '4px 4px 0 #666666';\r\n }\r\n }).then(canvas => {\r\n const link = document.createElement('a');\r\n link.download = 'xiaohongshu_card.png';\r\n link.href = canvas.toDataURL('image/png');\r\n link.click();\r\n });\r\n }\r\n\r\n // 监听编辑事件,保持样式一致性\r\n document.querySelectorAll('.editable').forEach(element => {\r\n element.addEventListener('input', function() {\r\n this.style.backgroundColor = '#000000';\r\n });\r\n });\r\n </script>\r\n</body>\r\n</html>",
"sha256": "1835e29563d4cf7f01cb9cf837d3f57d1b2e48304cc202e1061240bccf6e7e0e"
},
".github/tools/external/html-tools-main/xhs graphic production - 1.0.html": {
"mode": "100644",
"encoding": "utf-8",
"data": "<!DOCTYPE html>\r\n<html lang=\"zh-CN\">\r\n<head>\r\n <meta charset=\"UTF-8\">\r\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\r\n <title>Markdown 编辑与预览 (带同步滚动和滑块)</title>\r\n <script src=\"https://cdnjs.cloudflare.com/ajax/libs/showdown/1.9.1/showdown.min.js\"></script>\r\n <script src=\"https://html2canvas.hertzen.com/dist/html2canvas.min.js\"></script>\r\n <style>\r\n body {\r\n display: flex;\r\n flex-direction: column;\r\n align-items: center;\r\n min-height: 100vh;\r\n background: #f0f0f0;\r\n margin: 0;\r\n font-family: 'Arial', sans-serif;\r\n padding-top: 20px;\r\n overflow: hidden; /* Prevent body scrollbars if editor is full height */\r\n }\r\n .editor-container {\r\n display: flex;\r\n width: 90%; /* Use percentage for better responsiveness */\r\n max-width: 1200px; /* Max width for large screens */\r\n height: calc(100vh - 100px); /* Adjust height to fill more of the viewport */\r\n background: #333333;\r\n border-radius: 8px;\r\n overflow: hidden;\r\n box-shadow: 0 4px 8px rgba(0,0,0,0.2);\r\n position: relative; /* For resizer positioning if needed */\r\n }\r\n .markdown-editor, .preview-pane {\r\n padding: 20px;\r\n box-sizing: border-box;\r\n overflow-y: auto;\r\n height: 100%; /* Fill the container height */\r\n }\r\n .markdown-editor {\r\n /* flex: 1; Will be set by JS */\r\n background: #222222;\r\n color: #e0e0e0;\r\n border: none;\r\n resize: none;\r\n font-family: 'Menlo', 'Monaco', 'Courier New', monospace;\r\n font-size: 14px;\r\n line-height: 1.6;\r\n outline: none;\r\n }\r\n .resizer {\r\n flex: 0 0 10px; /* Don't grow, don't shrink, base width 10px */\r\n background: #555555;\r\n cursor: col-resize;\r\n height: 100%;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n user-select: none; /* Prevent text selection during drag */\r\n }\r\n .resizer::before { /* Optional: visual indicator for dragging */\r\n content: '⋮';\r\n color: #aaa;\r\n font-size: 18px;\r\n line-height: 0;\r\n }\r\n .preview-pane {\r\n /* flex: 1; Will be set by JS */\r\n background: #000000;\r\n color: #ffffff;\r\n /* border-left: 2px solid #666666; /* Replaced by resizer */\r\n word-wrap: break-word;\r\n }\r\n\r\n /* Styling for rendered Markdown elements in preview-pane */\r\n .preview-pane h1, .preview-pane h2, .preview-pane h3, .preview-pane h4, .preview-pane h5, .preview-pane h6 {\r\n color: #ffffff;\r\n border-bottom: 1px solid #444444;\r\n padding-bottom: 5px;\r\n margin-top: 1em;\r\n margin-bottom: 0.5em;\r\n }\r\n .preview-pane h1 { font-size: 24px; font-weight: bold; border-bottom: 2px solid #666666; padding-bottom: 10px; margin-bottom: 15px;}\r\n .preview-pane p {\r\n font-size: 16px;\r\n line-height: 1.5;\r\n margin-bottom: 1em;\r\n }\r\n .preview-pane ul, .preview-pane ol {\r\n margin-left: 20px;\r\n margin-bottom: 1em;\r\n }\r\n .preview-pane li {\r\n margin-bottom: 0.5em;\r\n }\r\n .preview-pane blockquote {\r\n border-left: 4px solid #555555;\r\n padding-left: 10px;\r\n color: #aaaaaa;\r\n margin-left: 0;\r\n margin-right: 0;\r\n margin-bottom: 1em;\r\n }\r\n .preview-pane pre {\r\n background-color: #1e1e1e;\r\n padding: 10px;\r\n border-radius: 4px;\r\n overflow-x: auto;\r\n font-family: 'Menlo', 'Monaco', 'Courier New', monospace;\r\n }\r\n .preview-pane code {\r\n font-family: 'Menlo', 'Monaco', 'Courier New', monospace;\r\n background-color: #282c34;\r\n padding: 2px 4px;\r\n border-radius: 3px;\r\n font-size: 0.9em;\r\n }\r\n .preview-pane pre code {\r\n background-color: transparent;\r\n padding: 0;\r\n border-radius: 0;\r\n }\r\n .preview-pane table {\r\n border-collapse: collapse;\r\n width: 100%;\r\n margin-bottom: 1em;\r\n }\r\n .preview-pane th, .preview-pane td {\r\n border: 1px solid #666666;\r\n padding: 8px;\r\n text-align: left;\r\n }\r\n .preview-pane th {\r\n background-color: #1a1a1a;\r\n }\r\n .preview-pane img {\r\n max-width: 100%;\r\n height: auto;\r\n border-radius: 4px;\r\n }\r\n\r\n .button-container {\r\n margin-top: 20px;\r\n text-align: center;\r\n }\r\n .export-btn {\r\n padding: 10px 20px;\r\n background: #000000;\r\n color: #ffffff;\r\n border: 2px solid #666666;\r\n cursor: pointer;\r\n font-size: 16px;\r\n }\r\n .export-btn:hover {\r\n background: #333333;\r\n }\r\n </style>\r\n</head>\r\n<body>\r\n <div class=\"editor-container\">\r\n <textarea id=\"markdown-input\" class=\"markdown-editor\" placeholder=\"在此输入 Markdown... 例如:\\n# 标题\\n\\n- 列表项1\\n- 列表项2\\n\\n**加粗文本**\"></textarea>\r\n <div id=\"resizer\" class=\"resizer\"></div>\r\n <div id=\"preview-output\" class=\"preview-pane\"></div>\r\n </div>\r\n <div class=\"button-container\">\r\n <button class=\"export-btn\" onclick=\"exportToPng()\">导出为PNG</button>\r\n </div>\r\n\r\n <script>\r\n const markdownInput = document.getElementById('markdown-input');\r\n const previewOutput = document.getElementById('preview-output');\r\n const resizer = document.getElementById('resizer');\r\n const editorContainer = document.querySelector('.editor-container');\r\n\r\n // Initial flex distribution\r\n markdownInput.style.flex = '1';\r\n previewOutput.style.flex = '1';\r\n \r\n const converter = new showdown.Converter({\r\n tables: true,\r\n strikethrough: true,\r\n tasklists: true,\r\n ghCompatibleHeaderId: true,\r\n simpleLineBreaks: true\r\n });\r\n converter.setFlavor('github');\r\n\r\n function renderMarkdown() {\r\n const markdownText = markdownInput.value;\r\n const html = converter.makeHtml(markdownText);\r\n previewOutput.innerHTML = html;\r\n }\r\n\r\n markdownInput.addEventListener('input', renderMarkdown);\r\n renderMarkdown(); // Initial render\r\n\r\n // --- Resizer Logic ---\r\n let isResizing = false;\r\n let startX, startEditorWidth, startPreviewWidth;\r\n\r\n resizer.addEventListener('mousedown', (e) => {\r\n e.preventDefault(); // Prevent text selection, etc.\r\n isResizing = true;\r\n startX = e.clientX;\r\n startEditorWidth = markdownInput.offsetWidth;\r\n startPreviewWidth = previewOutput.offsetWidth;\r\n\r\n document.addEventListener('mousemove', handleMouseMove);\r\n document.addEventListener('mouseup', stopResize);\r\n });\r\n\r\n function handleMouseMove(e) {\r\n if (!isResizing) return;\r\n\r\n const dx = e.clientX - startX;\r\n let newEditorWidth = startEditorWidth + dx;\r\n let newPreviewWidth = startPreviewWidth - dx;\r\n\r\n const minWidth = 50; // Minimum width for panes\r\n\r\n if (newEditorWidth < minWidth) {\r\n newEditorWidth = minWidth;\r\n newPreviewWidth = startEditorWidth + startPreviewWidth - minWidth;\r\n } else if (newPreviewWidth < minWidth) {\r\n newPreviewWidth = minWidth;\r\n newEditorWidth = startEditorWidth + startPreviewWidth - minWidth;\r\n }\r\n \r\n const totalWidth = editorContainer.offsetWidth - resizer.offsetWidth;\r\n markdownInput.style.flex = `0 0 ${newEditorWidth}px`;\r\n previewOutput.style.flex = `0 0 ${newPreviewWidth}px`;\r\n }\r\n\r\n function stopResize() {\r\n isResizing = false;\r\n document.removeEventListener('mousemove', handleMouseMove);\r\n document.removeEventListener('mouseup', stopResize);\r\n }\r\n\r\n // --- Synchronized Scrolling ---\r\n let scrollTimeout;\r\n let isSyncingEditor = false;\r\n let isSyncingPreview = false;\r\n\r\n markdownInput.addEventListener('scroll', () => {\r\n if (isSyncingEditor) {\r\n isSyncingEditor = false; // Reset for next manual scroll\r\n return;\r\n }\r\n if (isResizing) return; // Don't sync scroll while resizing\r\n\r\n isSyncingPreview = true; // Prevent preview scroll from triggering editor scroll\r\n \r\n const scrollPercentage = markdownInput.scrollTop / (markdownInput.scrollHeight - markdownInput.clientHeight);\r\n if (isNaN(scrollPercentage)) return; // Avoid NaN if scrollHeight equals clientHeight\r\n\r\n previewOutput.scrollTop = scrollPercentage * (previewOutput.scrollHeight - previewOutput.clientHeight);\r\n \r\n // Clear any existing timeout to avoid race conditions\r\n clearTimeout(scrollTimeout);\r\n scrollTimeout = setTimeout(() => {\r\n isSyncingPreview = false;\r\n }, 100); // Adjust delay as needed\r\n });\r\n\r\n previewOutput.addEventListener('scroll', () => {\r\n if (isSyncingPreview) {\r\n isSyncingPreview = false; // Reset for next manual scroll\r\n return;\r\n }\r\n if (isResizing) return; // Don't sync scroll while resizing\r\n\r\n isSyncingEditor = true; // Prevent editor scroll from triggering preview scroll\r\n\r\n const scrollPercentage = previewOutput.scrollTop / (previewOutput.scrollHeight - previewOutput.clientHeight);\r\n if (isNaN(scrollPercentage)) return;\r\n\r\n markdownInput.scrollTop = scrollPercentage * (markdownInput.scrollHeight - markdownInput.clientHeight);\r\n \r\n clearTimeout(scrollTimeout);\r\n scrollTimeout = setTimeout(() => {\r\n isSyncingEditor = false;\r\n }, 100); // Adjust delay as needed\r\n });\r\n\r\n\r\n function exportToPng() {\r\n const previewPane = document.getElementById('preview-output');\r\n const originalHeight = previewPane.style.height;\r\n const originalOverflowY = previewPane.style.overflowY;\r\n\r\n previewPane.style.height = previewPane.scrollHeight + 'px';\r\n previewPane.style.overflowY = 'visible';\r\n previewPane.style.backgroundColor = '#000000';\r\n\r\n html2canvas(previewPane, {\r\n backgroundColor: '#000000',\r\n scale: 2,\r\n useCORS: true,\r\n logging: false,\r\n onclone: (documentClone) => {\r\n const clonedPreviewPane = documentClone.getElementById('preview-output');\r\n if (clonedPreviewPane) {\r\n clonedPreviewPane.style.backgroundColor = '#000000';\r\n clonedPreviewPane.style.color = '#ffffff';\r\n clonedPreviewPane.style.height = clonedPreviewPane.scrollHeight + 'px';\r\n clonedPreviewPane.style.overflowY = 'visible';\r\n }\r\n }\r\n }).then(canvas => {\r\n const link = document.createElement('a');\r\n link.download = 'markdown_card.png';\r\n link.href = canvas.toDataURL('image/png');\r\n link.click();\r\n }).finally(() => {\r\n previewPane.style.height = originalHeight;\r\n previewPane.style.overflowY = originalOverflowY;\r\n });\r\n }\r\n </script>\r\n</body>\r\n</html>",
"sha256": "14a60fa5cc9fa3b7a8beac146277c1ef15729eb5e18cd7889fbcf498d5d1411a"
},
".github/tools/external/my-nvim/README.md": {
"mode": "100644",
"encoding": "utf-8",
"data": "# 🚀 Perfect Neovim Configuration with LazyVim\n\n## 系统配置文档\n\n### 📋 配置概述\n- **Neovim 版本**: v0.11.5 (最新版)\n- **配置框架**: LazyVim (标准原生方案)\n- **主题**: tokyonight (默认主题)\n- **状态**: 经过全面测试,无任何问题或报错\n\n### 📦 包含内容\n- ✅ LazyVim 配置文件;Neovim 可执行文件需从官方渠道或系统包管理器安装\n- ✅ 标准 LazyVim 配置框架\n- ✅ 修复的 Neotree 配置(无重复问题)\n- ✅ 默认 tokyonight 主题\n- ✅ 自动侧边栏和顶部标签配置\n- ✅ 经过全面测试验证\n\n## 🎯 快速开始\n\n### 1. 克隆仓库\n```bash\ngit clone https://github.com/tukuaiai/vim.git\ncd vim\n```\n\n### 2. 安装配置\n```bash\n# 复制配置文件\ncp -r nvim-config/* ~/.config/\n\n# 安装 Neovim\n# 推荐使用系统包管理器、官方 AppImage 或 GitHub Release。\n# 不再在本仓库跟踪 nvim 二进制运行时。\n```\n\n### 3. 启动使用\n```bash\n# 直接启动\nnvim\n\n# 或使用别名(推荐)\nalias n='nvim'\nn\n```\n\n## 🎨 主题配置\n\n### 当前主题:tokyonight(默认)\n- 深色护眼主题\n- 现代化配色方案\n- 高对比度,适合长时间使用\n\n### 切换主题(可选)\n```vim\n:Telescope colorscheme \" 使用 Telescope 选择主题\n```\n\n## ⚙️ 核心功能\n\n### 1. 文件浏览器(Neotree)\n- **快捷键**:`<leader>e`(空格+e)\n- **功能**:侧边栏文件浏览器\n- **特点**:无重复窗口问题(已修复)\n\n### 2. 顶部标签页(Bufferline)\n- **功能**:显示打开的缓冲区\n- **特点**:始终显示,美观实用\n\n### 3. 模糊查找(Telescope)\n- **快捷键**:`<leader>f`(空格+f)\n- **功能**:快速查找文件、符号等\n\n### 4. Git 集成\n- **快捷键**:`<leader>g`(空格+g)\n- **功能**:Git 状态、提交、差异查看\n\n## ⌨️ 快捷键速查\n\n| 快捷键 | 功能 |\n|--------|------|\n| `<leader>e` | 打开文件浏览器 |\n| `<leader>f` | 模糊查找 |\n| `<leader>g` | Git 相关 |\n| `<leader>b` | 缓冲区管理 |\n| `<leader>w` | 保存文件 |\n| `<leader>q` | 退出 |\n| `<leader>/` | 搜索当前文件 |\n| `<leader>?` | 查看所有快捷键 |\n\n## 🔧 高级配置\n\n### 自动命令(autocmds)\n位于 `~/.config/nvim/lua/config/autocmds.lua`:\n```lua\n-- 自动打开 Neotree(延迟 50ms 确保插件加载)\nvim.api.nvim_create_autocmd(\"VimEnter\", {\n callback = function()\n vim.defer_fn(function()\n vim.cmd(\"Neotree show\")\n end, 50)\n end,\n})\n```\n\n### 插件配置\n位于 `~/.config/nvim/lua/plugins/`:\n- `ui.lua` - UI 相关插件配置\n- `colorscheme.lua` - 主题配置\n- `example.lua` - 示例插件配置\n\n## 🧪 测试验证\n\n### 启动测试\n```bash\n# 基础启动测试\nnvim --headless -c \"echo 'OK'\" -c \"qa\"\n\n# 配置加载测试\nnvim --headless -c \"lua print('Config OK')\" -c \"qa\"\n```\n\n### 健康检查\n```vim\n:checkhealth \" 在 nvim 中运行健康检查\n```\n\n## 📁 文件结构\n```\nnvim-config/\n├── init.lua # 入口文件\n├── lazy-lock.json # 插件锁文件\n├── lazyvim.json # LazyVim 配置\n├── lua/\n│ ├── config/\n│ │ ├── autocmds.lua # 自动命令\n│ │ ├── keymaps.lua # 键位映射\n│ │ ├── lazy.lua # Lazy.nvim 配置\n│ │ └── options.lua # 选项设置\n│ └── plugins/\n│ ├── colorscheme.lua # 主题配置\n│ ├── ui.lua # UI 插件配置\n│ └── example.lua # 示例配置\n└── stylua.toml # 代码格式化配置\n```\n\n## 🚀 高级使用技巧\n\n### 1. 快速文件操作\n```vim\n\" 在当前行下方新建文件\n:enew\n\" 保存文件\n:w\n\" 退出\n:qa\n```\n\n### 2. 窗口管理\n```vim\n\" 水平分割\n:sp filename\n\" 垂直分割\n:vs filename\n\" 在分割间移动\nCtrl+w h/j/k/l\n```\n\n### 3. 搜索和替换\n```vim\n\" 当前文件搜索\n/\n\" 全局搜索\n:Telescope live_grep\n\" 替换\n:%s/old/new/g\n```\n\n## 📚 学习资源\n\n1. **内置教程**:`:Tutor`\n2. **帮助系统**:`:help 主题`\n3. **LazyVim 文档**:按 `<leader>?`\n4. **GitHub 仓库**:https://github.com/tukuaiai/vim\n\n## 🎉 结论\n\n这份配置提供了:\n- ✅ 最新稳定的 Neovim 版本\n- ✅ 标准的 LazyVim 配置框架\n- ✅ 修复的所有已知问题\n- ✅ 美观实用的界面设计\n- ✅ 经过全面测试验证\n\n**确定没有任何问题和报错** - 你可以放心使用这份完美配置!\n",
"sha256": "905c3a248d5208f001f3eb6924beaf768454c70cdbc4c41cf67e906dba7ca8c0"
},
".github/tools/external/my-nvim/nvim-config/init.lua": {
"mode": "100644",
"encoding": "utf-8",
"data": "-- bootstrap lazy.nvim, LazyVim and your plugins\nrequire(\"config.lazy\")\n",
"sha256": "3b2d6e9976a515b7c8df08ed7c7f61a5751e9c08a6ff5579d621b87312c9e2c6"
},
".github/tools/external/my-nvim/nvim-config/lua/config/lazy.lua": {
"mode": "100644",
"encoding": "utf-8",
"data": "local lazypath = vim.fn.stdpath(\"data\") .. \"/lazy/lazy.nvim\"\nif not (vim.uv or vim.loop).fs_stat(lazypath) then\n local lazyrepo = \"https://github.com/folke/lazy.nvim.git\"\n local out = vim.fn.system({ \"git\", \"clone\", \"--filter=blob:none\", \"--branch=stable\", lazyrepo, lazypath })\n if vim.v.shell_error ~= 0 then\n vim.api.nvim_echo({\n { \"Failed to clone lazy.nvim:\\n\", \"ErrorMsg\" },\n { out, \"WarningMsg\" },\n { \"\\nPress any key to exit...\" },\n }, true, {})\n vim.fn.getchar()\n os.exit(1)\n end\nend\nvim.opt.rtp:prepend(lazypath)\n\nrequire(\"lazy\").setup({\n spec = {\n -- add LazyVim and import its plugins\n { \"LazyVim/LazyVim\", import = \"lazyvim.plugins\" },\n -- import/override with your plugins\n { import = \"plugins\" },\n },\n defaults = {\n -- By default, only LazyVim plugins will be lazy-loaded. Your custom plugins will load during startup.\n -- If you know what you're doing, you can set this to `true` to have all your custom plugins lazy-loaded by default.\n lazy = false,\n -- It's recommended to leave version=false for now, since a lot the plugin that support versioning,\n -- have outdated releases, which may break your Neovim install.\n version = false, -- always use the latest git commit\n -- version = \"*\", -- try installing the latest stable version for plugins that support semver\n },\n install = { colorscheme = { \"tokyonight\", \"habamax\" } },\n checker = {\n enabled = true, -- check for plugin updates periodically\n notify = false, -- notify on update\n }, -- automatically check for plugin updates\n performance = {\n rtp = {\n -- disable some rtp plugins\n disabled_plugins = {\n \"gzip\",\n -- \"matchit\",\n -- \"matchparen\",\n -- \"netrwPlugin\",\n \"tarPlugin\",\n \"tohtml\",\n \"tutor\",\n \"zipPlugin\",\n },\n },\n },\n})\n-- 使用默认的tokyonight主题(LazyVim默认主题)\n-- 不需要手动设置,LazyVim会自动加载\n",
"sha256": "5fd03a47dc423a46b7c141149d35ba20cbbd96eb2c90f48f74dbff94c202802e"
},
".github/tools/external/MCPlayerTransfer/README.md": {
"mode": "100644",
"encoding": "utf-8",
"data": "# MC Player Transfer\n\nMinecraft 基岩版角色转移工具 - 像泰拉瑞亚一样转移角色\n\n## 项目结构\n\n```\nMCPlayerTransfer/\n├── main.py # 主入口\n├── requirements.txt # 依赖\n├── README.md\n├── src/\n│ ├── __init__.py\n│ ├── extract_player.py # 提取模块\n│ └── import_player.py # 导入模块\n├── input/ # 放入 .mcworld 文件\n└── output/ # 输出 .dat 角色文件\n```\n\n## 安装\n\n```bash\npip install -r requirements.txt\n```\n\n## 使用\n\n### 提取角色\n```bash\npython main.py extract \"input/World.mcworld\"\n```\n\n### 导入角色\n```bash\npython main.py import \"input/另一个世界.mcworld\" \"output/player.dat\"\n```\n\n## 数据说明\n\n提取的 `.dat` 文件包含角色全部数据:\n- 背包物品\n- 末影箱物品\n- 潜影盒及内容\n- 装备栏\n- 经验等级\n- 生命/饥饿值\n- 位置坐标\n\n## 注意事项\n\n- 操作前备份存档\n- 关闭游戏后操作\n",
"sha256": "f48b3081530011171ee6761115613c5eb7811a9ec3059cdec53e3b50c632f0e3"
},
".github/tools/external/MCPlayerTransfer/main.py": {
"mode": "100644",
"encoding": "utf-8",
"data": "#!/usr/bin/env python3\n\"\"\"\nMinecraft 基岩版角色转移工具\n\"\"\"\n\nimport sys\nimport os\n\nsys.path.insert(0, os.path.join(os.path.dirname(__file__), 'src'))\n\nfrom extract_player import extract_player\nfrom import_player import import_player\n\n\ndef main():\n if len(sys.argv) < 2:\n print(\"\"\"\nMinecraft 基岩版角色转移工具\n============================\n\n用法:\n python main.py extract <.mcworld文件>\n python main.py import <.mcworld文件> <.dat角色文件>\n\n示例:\n python main.py extract \"input/World.mcworld\"\n python main.py import \"input/World.mcworld\" \"output/player.dat\"\n \"\"\")\n return\n \n cmd = sys.argv[1].lower()\n \n if cmd == 'extract':\n if len(sys.argv) < 3:\n print(\"错误: 请提供 .mcworld 文件路径\")\n return\n extract_player(sys.argv[2], \"output\")\n \n elif cmd == 'import':\n if len(sys.argv) < 4:\n print(\"错误: 请提供 .mcworld 文件和 .dat 角色文件\")\n return\n import_player(sys.argv[2], sys.argv[3])\n \n else:\n print(f\"未知命令: {cmd}\")\n\n\nif __name__ == '__main__':\n main()\n",
"sha256": "11bfdb47774247c32ad8cd0de441d56a13a17e9c12bcb3e2d9e81895958e1450"
},
".github/tools/external/XHS-image-to-PDF-conversion/README.md": {
"mode": "100644",
"encoding": "utf-8",
"data": "<div align=\"center\">\n\n# 📚 小红书图文批量转 PDF\n### Batch Convert XHS Images to PDF\n\n**一个智能 Python 脚本,用于将从小红书批量下载的 ZIP 压缩包,按顺序自动拼接为清晰的 PDF 文件。**\n*A smart Python script that automatically converts ZIP archives from Xiaohongshu into well-ordered PDF files.*\n\n---\n\n[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg?style=for-the-badge)](https://opensource.org/licenses/MIT)\n[![Status: Active](https://img.shields.io/badge/Status-Active-success.svg?style=for-the-badge)]()\n[![PRs Welcome](https://img.shields.io/badge/PRs-Welcome-brightgreen.svg?style=for-the-badge)]()\n[![Language: Python](https://img.shields.io/badge/Language-Python-orange.svg?style=for-the-badge)]()\n\n[✨ 功能特性](#-功能特性) • [⚙️ 工作流程](#️-工作流程) • [🚀 快速开始](#-快速开始) • [🗂️ 项目结构](#️-项目结构) • [🤝 参与贡献](#-参与贡献)\n\n</div>\n\n---\n\n## ✨ 功能特性\n\n| 特性 | 描述 |\n|:---:|:---|\n| 📦 **全自动处理** | 无需手动解压,脚本自动处理 `.zip` 压缩包。 |\n| 🔢 **智能自然排序** | 完美处理 `1, 2, ... 10, 11` 这样的文件名排序,确保图片顺序正确。 |\n| 🚀 **批量转换** | 支持一次性转换文件夹内的所有 `.zip` 文件,省时省力。 |\n| 🗑️ **自动清理** | 转换成功后,自动删除原始的 `.zip` 文件和临时文件,保持目录整洁。 |\n| 📖 **PDF 优化** | 生成的 PDF 文件经过优化,保证清晰度的同时控制文件大小。 |\n| 💻 **跨平台兼容** | 依赖的 `Pillow` 库和 Python 脚本可在 Windows, macOS, Linux 上运行。 |\n\n---\n\n## ⚙️ 工作流程\n\n<table>\n<tr>\n<td width=\"50%\">\n\n脚本的核心逻辑非常简单直接:监控并处理文件夹内的 ZIP 文件,通过一系列自动化步骤输出 PDF。\n\n### 核心步骤\n1. **扫描**: 查找当前目录下的所有 `.zip` 文件。\n2. **解压**: 将找到的 `.zip` 文件解压到临时目录。\n3. **排序**: 智能地对所有图片文件进行“自然排序”。\n4. **合并**: 将排序后的图片合并成一个 PDF 文件。\n5. **清理**: 删除原始的 `.zip` 文件和临时文件夹。\n\n</td>\n<td width=\"50%\">\n\n```mermaid\ngraph TD\n A[📁 放置 .zip 文件] --> B{运行 pdf.py 脚本};\n B --> C[🔄 解压到临时目录];\n C --> D[🔢 按文件名自然排序];\n D --> E[🖼️ 合并图片为 PDF];\n E --> F[📄 生成 output.pdf];\n F --> G[🗑️ 删除原 .zip 文件];\n G --> H[✅ 完成];\n```\n\n</td>\n</tr>\n</table>\n\n---\n\n## 🚀 快速开始\n\n### 1. 环境准备\n\n首先,确保你的电脑上安装了 **Python 3**。\n\n然后,将本项目克隆到你的本地:\n```bash\ngit clone https://github.com/tukuaiai/XHS-image-to-PDF-conversion.git\ncd XHS-image-to-PDF-conversion\n```\n\n### 2. 安装依赖\n\n本项目依赖 `Pillow` 库来处理图片。运行以下命令安装它:\n```bash\npip install -r requirements.txt\n```\n或者,你也可以使用 `Makefile` (如果你的系统支持 `make`):\n```bash\nmake install\n```\n\n### 3. 下载图文\n\n使用你喜欢的浏览器扩展(如推荐的 **小地瓜**)从小红书下载图文,并确保它们是 `.zip` 格式。\n\n- **小地瓜 - 小红书图片视频下载助手**: [Firefox 扩展](https://addons.mozilla.org/zh-CN/firefox/addon/%E5%B0%8F%E5%9C%B0%E7%93%9C-%E5%B0%8F%E7%BA%A2%E4%B9%A6%E5%9B%BE%E7%89%87%E8%A7%86%E9%A2%91%E4%B8%8B%E8%BD%BD%E5%8A%A9%E6%89%8B/)\n\n### 4. 运行脚本\n\n<details>\n<summary><b>模式一:批量处理所有 ZIP 文件 (推荐)</b></summary>\n\n1. 将所有下载的 `.zip` 文件移动到本项目文件夹中。\n2. 直接运行 `pdf.bat` (Windows) 或在终端中运行以下命令:\n ```bash\n python pdf.py\n ```\n 或者使用 `make`:\n ```bash\n make run\n ```\n3. 脚本会自动处理文件夹内所有的 `.zip` 文件。\n\n</details>\n\n<details>\n<summary><b>模式二:处理单个 ZIP 文件</b></summary>\n\n如果你只想处理一个文件,可以使用拖放或命令行参数:\n\n1. **拖放 (Windows)**: 将一个 `.zip` 文件直接拖到 `pdf.bat` 图标上。\n2. **命令行**:\n ```bash\n python pdf.py \"你的文件路径.zip\"\n ```\n</details>\n\n---\n\n## 🗂️ 项目结构\n\n```\nXHS-image-to-PDF-conversion/\n├── .git/\n├── docs/ # (未来可能添加的文档)\n├── 📚...pdf # (示例文件)\n├── pdf.bat # Windows 批处理脚本\n├── pdf.py # 核心 Python 脚本\n├── Makefile # 自动化命令\n├── requirements.txt # Python 依赖\n├── README.md # 你正在阅读的这个文件\n├── LICENSE # MIT 许可证\n├── CODE_OF_CONDUCT.md # 社区行为准则\n└── CONTRIBUTING.md # 贡献指南\n```\n\n---\n\n## 🤝 参与贡献\n\n我们欢迎任何形式的贡献!无论是报告 Bug、提出功能建议还是直接贡献代码。\n\n请参考我们的 [**贡献指南 (CONTRIBUTING.md)**](CONTRIBUTING.md) 来了解如何参与。\n\n---\n\n## 📜 许可证\n\n本项目采用 [MIT](https://opensource.org/licenses/MIT) 许可证。\n\n---\n\n<div align=\"center\">\n\n**如果这个项目对你有帮助,请给一个 Star ⭐!**\n\n[![Star History Chart](https://api.star-history.com/svg?repos=tukuaiai/XHS-image-to-PDF-conversion&type=Date)](https://star-history.com/#tukuaiai/XHS-image-to-PDF-conversion&Date)\n\n---\n\n**Made with 🐍 & ❤️ by tukuaiai**\n\n[⬆ 回到顶部](#-小红书图文批量转-pdf)\n\n</div>\n",
"sha256": "19f65c7b6afe56c57789a30d1aed3c214051474fd21ea97f1ec10cc1ec774f13"
},
".github/tools/external/XHS-image-to-PDF-conversion/pdf.py": {
"mode": "100644",
"encoding": "utf-8",
"data": "#!/usr/bin/env python3\n\"\"\"\n图片ZIP转PDF脚本\n将ZIP文件中的图片按序号排序并拼接成PDF文件\n\"\"\"\n\nimport zipfile\nimport os\nimport re\nfrom PIL import Image\nimport shutil\n\ndef 自然排序键(文件名):\n \"\"\"将文件名转换为自然排序键,支持数字排序\"\"\"\n return [int(text) if text.isdigit() else text.lower() for text in re.split(r'(\\d+)', 文件名)]\n\ndef zip转pdf(zip路径):\n \"\"\"\n 将ZIP文件中的图片排序后转换为PDF\n\n Args:\n zip路径: ZIP文件的完整路径\n\n Returns:\n 成功返回PDF路径,失败返回None\n \"\"\"\n try:\n # 获取ZIP文件名(不含扩展名)\n zip目录, zip文件名 = os.path.split(zip路径)\n pdf名称 = os.path.splitext(zip文件名)[0] + '.pdf'\n pdf路径 = os.path.join(zip目录, pdf名称)\n\n print(f\"正在处理: {zip文件名}\")\n\n # 创建临时目录解压文件\n 临时目录 = os.path.join(zip目录, 'temp_extract')\n if os.path.exists(临时目录):\n shutil.rmtree(临时目录)\n os.makedirs(临时目录)\n\n # 解压ZIP文件\n with zipfile.ZipFile(zip路径, 'r') as zip文件:\n zip文件.extractall(临时目录)\n\n # 获取所有图片文件\n 支持的格式 = {'.jpg', '.jpeg', '.png', '.bmp', '.gif', '.tiff', '.webp'}\n 图片文件 = []\n\n for 根目录, 目录, 文件列表 in os.walk(临时目录):\n for 文件 in 文件列表:\n if any(文件.lower().endswith(格式) for 格式 in 支持的格式):\n 完整路径 = os.path.join(根目录, 文件)\n 图片文件.append(完整路径)\n\n if not 图片文件:\n print(\"错误: ZIP文件中没有找到图片文件\")\n shutil.rmtree(临时目录)\n return None\n\n # 按文件名自然排序\n 图片文件.sort(key=lambda x: 自然排序键(os.path.basename(x)))\n\n print(f\"找到 {len(图片文件)} 张图片,开始转换...\")\n\n # 打开第一张图片作为基础\n 图片对象列表 = []\n for 图片路径 in 图片文件:\n try:\n 图片 = Image.open(图片路径)\n # 转换为RGB模式(确保兼容性)\n if 图片.mode != 'RGB':\n 图片 = 图片.convert('RGB')\n 图片对象列表.append(图片)\n except Exception as e:\n print(f\"警告: 无法打开图片 {图片路径}: {e}\")\n continue\n\n if not 图片对象列表:\n print(\"错误: 没有成功加载任何图片\")\n shutil.rmtree(临时目录)\n return None\n\n # 保存为PDF(第一张作为主图,其余附加)\n 图片对象列表[0].save(\n pdf路径,\n \"PDF\",\n quality=95,\n optimize=True,\n save_all=True,\n append_images=图片对象列表[1:]\n )\n\n # 关闭所有图片对象\n for 图片 in 图片对象列表:\n 图片.close()\n\n # 清理临时文件\n shutil.rmtree(临时目录)\n\n # 删除原ZIP文件\n os.remove(zip路径)\n\n print(f\"✓ 成功创建PDF: {pdf名称}\")\n print(f\"✓ 已删除原ZIP文件: {zip文件名}\")\n\n return pdf路径\n\n except zipfile.BadZipFile:\n print(f\"错误: {zip路径} 不是有效的ZIP文件\")\n return None\n except Exception as e:\n print(f\"处理过程中出错: {e}\")\n # 清理临时文件\n if '临时目录' in locals() and os.path.exists(临时目录):\n shutil.rmtree(临时目录)\n return None\n\ndef 批量处理当前目录():\n \"\"\"批量处理当前目录下所有ZIP文件\"\"\"\n 当前目录 = os.getcwd()\n zip文件列表 = []\n\n # 扫描当前目录所有ZIP文件\n for 文件 in os.listdir(当前目录):\n if 文件.lower().endswith('.zip'):\n zip文件列表.append(os.path.join(当前目录, 文件))\n\n if not zip文件列表:\n print(\"当前目录下没有找到ZIP文件\")\n return\n\n print(f\"发现 {len(zip文件列表)} 个ZIP文件,开始批量处理...\")\n print(\"-\" * 50)\n\n 成功计数 = 0\n 失败计数 = 0\n\n for zip路径 in zip文件列表:\n print(f\"\\n[{zip文件列表.index(zip路径) + 1}/{len(zip文件列表)}] 处理: {os.path.basename(zip路径)}\")\n\n # 执行转换\n 结果 = zip转pdf(zip路径)\n\n if 结果:\n 成功计数 += 1\n else:\n 失败计数 += 1\n\n print(\"-\" * 50)\n print(f\"批量处理完成!成功: {成功计数} 个,失败: {失败计数} 个\")\n\ndef 处理指定文件(zip路径):\n \"\"\"处理指定的单个ZIP文件\"\"\"\n if not os.path.exists(zip路径):\n print(f\"错误: 找不到文件 {zip路径}\")\n return False\n\n if not zip路径.lower().endswith('.zip'):\n print(\"错误: 请提供ZIP格式的文件\")\n return False\n\n # 执行转换\n 结果 = zip转pdf(zip路径)\n\n if 结果:\n print(f\"\\n🎉 任务完成!PDF文件已保存为: {结果}\")\n return True\n else:\n print(\"\\n❌ 任务失败,请检查错误信息\")\n return False\n\ndef 主函数():\n \"\"\"主函数:智能处理模式\"\"\"\n import sys\n\n # 优先处理指定文件(如果存在)\n 指定文件路径 = r\"C:\\Users\\lenovo\\Desktop\\新建文件夹\\剥头皮量化策略全拆解:低延迟、高频的底层.zip\"\n\n # 检查是否有命令行参数\n if len(sys.argv) > 1:\n # 命令行指定了ZIP文件路径\n zip路径 = sys.argv[1]\n print(f\"通过命令行参数指定文件: {zip路径}\")\n 处理指定文件(zip路径)\n elif os.path.exists(指定文件路径):\n # 处理默认指定文件\n print(f\"处理默认指定文件: {os.path.basename(指定文件路径)}\")\n 处理指定文件(指定文件路径)\n else:\n # 自动扫描当前目录所有ZIP文件\n print(\"开始扫描当前目录所有ZIP文件...\")\n 批量处理当前目录()\n\nif __name__ == \"__main__\":\n 主函数()",
"sha256": "ee045272a0ba361676c1ee908758e7316e96438774716c79472fb05cc5055539"
},
".github/tools/external/.tmux/LICENSE.MIT": {
"mode": "100644",
"encoding": "utf-8",
"data": "Copyright 2012— Gregory Pakosz\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\nthe Software, and to permit persons to whom the Software is furnished to do so,\nsubject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\nFOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\nCOPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\nIN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n",
"sha256": "f4c34427d3e29630cece9bca418eda48ac298867630cd6698d73e0f04642d1d0"
},
".github/tools/external/.tmux/LICENSE.WTFPLv2": {
"mode": "100644",
"encoding": "utf-8",
"data": " DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE\n Version 2, December 2004\n\n Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>\n\n Everyone is permitted to copy and distribute verbatim or modified\n copies of this license document, and changing it is allowed as long\n as the name is changed.\n\n DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE\n TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\n\n 0. You just DO WHAT THE FUCK YOU WANT TO.\n",
"sha256": "ee820ff0db4ce628569e0975ac27dc926052a9f85d102b101edb104311ef4d90"
},
".github/tools/external/tmux/COPYING": {
"mode": "100644",
"encoding": "utf-8",
"data": "THIS IS FOR INFORMATION ONLY, CODE IS UNDER THE LICENCE AT THE TOP OF ITS FILE.\n\nThe README, CHANGES, FAQ and TODO files are licensed under the ISC license. All\nother files have a license and copyright notice at their start, typically:\n\nCopyright (c) <author>\n\nPermission to use, copy, modify, and distribute this software for any\npurpose with or without fee is hereby granted, provided that the above\ncopyright notice and this permission notice appear in all copies.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\nWITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\nMERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\nANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\nWHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER\nIN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING\nOUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n",
"sha256": "c031bd37f464c534277814f6aa38686fa023d094261d57fd2545ad592bb53ccd"
},
".github/tools/external/Skill_Seekers-development/LICENSE": {
"mode": "100644",
"encoding": "utf-8",
"data": "MIT License\n\nCopyright (c) 2025 [Your Name/Username]\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n",
"sha256": "d131d0e96700cd78f8b3fa7ed79a47b019a0653066500faff376233246b6504d"
},
".github/tools/external/claude-official-skills/skills/skill-creator/LICENSE.txt": {
"mode": "100644",
"encoding": "utf-8",
"data": "\n Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n 1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n 2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n 3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n 4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n 5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n 6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n 7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n 8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n 9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\n END OF TERMS AND CONDITIONS\n\n APPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"[]\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\n Copyright [yyyy] [name of copyright owner]\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.",
"sha256": "58d1e17ffe5109a7ae296caafcadfdbe6a7d176f0bc4ab01e12a689b0499d8bd"
},
".github/tools/external/Skill_Seekers-development/src/skill_seekers/cli/agent_client.py": {
"mode": "100644",
"encoding": "utf-8",
"data": "\"\"\"\nUnified AI Client for Skill Seekers\n\nCentralizes all AI invocations (API and LOCAL mode) so that every enhancer\nuses a single abstraction instead of hardcoding subprocess calls or model names.\n\nSupports:\n- API mode: Anthropic, Moonshot/Kimi, Google Gemini, OpenAI (via adaptor pattern)\n- LOCAL mode: Claude Code, Kimi Code, Codex, Copilot, OpenCode, custom agents\n\nUsage:\n from skill_seekers.cli.agent_client import AgentClient\n\n client = AgentClient(mode=\"auto\")\n response = client.call(\"Analyze this code and return JSON\")\n\n # Or with explicit agent\n client = AgentClient(mode=\"local\", agent=\"kimi\")\n response = client.call(prompt, timeout=300)\n\n # Static helpers\n key, provider = AgentClient.detect_api_key()\n model = AgentClient.get_model()\n\"\"\"\n\nimport logging\nimport os\nimport shutil\nimport subprocess\nimport tempfile\nfrom pathlib import Path\n\nlogger = logging.getLogger(__name__)\n\n# Agent presets for LOCAL mode — reused from enhance_skill_local.py pattern\nAGENT_PRESETS = {\n \"claude\": {\n \"display_name\": \"Claude Code\",\n \"command\": [\"claude\", \"--dangerously-skip-permissions\", \"{prompt_file}\"],\n \"version_check\": [\"claude\", \"--version\"],\n },\n \"codex\": {\n \"display_name\": \"OpenAI Codex CLI\",\n \"command\": [\"codex\", \"exec\", \"--full-auto\", \"--skip-git-repo-check\", \"-\"],\n \"version_check\": [\"codex\", \"--version\"],\n \"uses_stdin\": True,\n },\n \"copilot\": {\n \"display_name\": \"GitHub Copilot CLI\",\n \"command\": [\"gh\", \"copilot\", \"chat\", \"-\"],\n \"version_check\": [\"gh\", \"copilot\", \"--version\"],\n \"uses_stdin\": True,\n },\n \"opencode\": {\n \"display_name\": \"OpenCode CLI\",\n \"command\": [\"opencode\"],\n \"version_check\": [\"opencode\", \"--version\"],\n },\n \"kimi\": {\n \"display_name\": \"Kimi Code CLI\",\n \"command\": [\n \"kimi\",\n \"--print\",\n \"--input-format\",\n \"text\",\n \"--work-dir\",\n \"{cwd}\",\n ],\n \"version_check\": [\"kimi\", \"--version\"],\n \"uses_stdin\": True,\n \"parse_output\": \"kimi\", # Needs special output parsing\n },\n}\n\n# Default models per API provider\nDEFAULT_MODELS = {\n \"anthropic\": \"claude-sonnet-4-20250514\",\n \"moonshot\": \"moonshot-v1-auto\",\n \"google\": \"gemini-2.0-flash\",\n \"openai\": \"gpt-4o\",\n}\n\n# API key env var → provider mapping\nAPI_KEY_MAP = {\n \"ANTHROPIC_API_KEY\": \"anthropic\",\n \"ANTHROPIC_AUTH_TOKEN\": \"anthropic\",\n \"MOONSHOT_API_KEY\": \"moonshot\",\n \"GOOGLE_API_KEY\": \"google\",\n \"OPENAI_API_KEY\": \"openai\",\n}\n\nDEFAULT_ENHANCE_TIMEOUT = 2700 # 45 minutes\nUNLIMITED_TIMEOUT = 86400 # 24 hours (subprocess requires a finite number)\n\n\ndef get_default_timeout() -> int:\n \"\"\"Return default enhancement timeout in seconds.\n\n Priority:\n 1. SKILL_SEEKER_ENHANCE_TIMEOUT environment variable\n 2. DEFAULT_ENHANCE_TIMEOUT (45 minutes)\n\n Supports 'unlimited' or 0/negative values which map to UNLIMITED_TIMEOUT (24h).\n \"\"\"\n env_val = os.environ.get(\"SKILL_SEEKER_ENHANCE_TIMEOUT\", \"\").strip().lower()\n if env_val in (\"unlimited\", \"none\", \"0\"):\n return UNLIMITED_TIMEOUT\n try:\n timeout = int(env_val)\n if timeout <= 0:\n return UNLIMITED_TIMEOUT\n return timeout\n except ValueError:\n return DEFAULT_ENHANCE_TIMEOUT\n\n\n# Provider → target platform mapping (for --target defaults)\nPROVIDER_TARGET_MAP = {\n \"anthropic\": \"claude\",\n \"moonshot\": \"kimi\",\n \"google\": \"gemini\",\n \"openai\": \"openai\",\n}\n\n\ndef normalize_agent_name(agent_name: str) -> str:\n \"\"\"Normalize agent name to canonical form.\"\"\"\n if not agent_name:\n return \"claude\"\n normalized = agent_name.strip().lower()\n aliases = {\n \"claude-code\": \"claude\",\n \"claude_code\": \"claude\",\n \"codex-cli\": \"codex\",\n \"copilot-cli\": \"copilot\",\n \"open-code\": \"opencode\",\n \"open_code\": \"opencode\",\n \"kimi-cli\": \"kimi\",\n \"kimi_code\": \"kimi\",\n \"kimi-code\": \"kimi\",\n }\n return aliases.get(normalized, normalized)\n\n\nclass AgentClient:\n \"\"\"\n Unified AI client that routes to API or LOCAL agent based on configuration.\n\n All enhancers should use this instead of direct subprocess calls or API imports.\n \"\"\"\n\n def __init__(\n self,\n mode: str = \"auto\",\n agent: str | None = None,\n api_key: str | None = None,\n ):\n \"\"\"\n Initialize the agent client.\n\n Args:\n mode: \"auto\" (detect from env), \"api\" (force API), \"local\" (force CLI agent)\n agent: LOCAL mode agent name (\"claude\", \"kimi\", \"codex\", \"copilot\", \"opencode\", \"custom\")\n Resolved from: arg → env SKILL_SEEKER_AGENT → \"claude\"\n api_key: API key override. If None, auto-detected from env vars.\n \"\"\"\n # Resolve agent name: param > ExecutionContext > env var > default\n try:\n from skill_seekers.cli.execution_context import ExecutionContext\n\n ctx = ExecutionContext.get()\n ctx_agent = ctx.enhancement.agent or \"\"\n except Exception:\n ctx_agent = \"\"\n env_agent = os.environ.get(\"SKILL_SEEKER_AGENT\", \"\").strip()\n self.agent = normalize_agent_name(agent or ctx_agent or env_agent or \"claude\")\n self.agent_display = AGENT_PRESETS.get(self.agent, {}).get(\"display_name\", self.agent)\n\n # Detect API key and provider\n if api_key:\n self.api_key = api_key\n # Detect provider from key prefix or env vars\n self.provider = self._detect_provider_from_key(api_key)\n else:\n self.api_key, self.provider = self.detect_api_key()\n\n # Determine mode (keep original for error handling decisions)\n self._requested_mode = mode\n self.mode = mode\n if mode == \"auto\":\n if self.api_key:\n self.mode = \"api\"\n else:\n self.mode = \"local\"\n\n # Initialize API client if needed\n self.client = None\n if self.mode == \"api\" and self.api_key:\n self.client = self._init_api_client()\n\n @staticmethod\n def _detect_provider_from_key(api_key: str) -> str:\n \"\"\"Detect provider from API key prefix or fall back to env var check.\"\"\"\n if api_key.startswith(\"sk-ant-\"):\n return \"anthropic\"\n if api_key.startswith(\"sk-\"):\n # Could be OpenAI or Moonshot — check env vars\n if os.environ.get(\"MOONSHOT_API_KEY\", \"\").strip() == api_key:\n return \"moonshot\"\n return \"openai\"\n if api_key.startswith(\"AIza\"):\n return \"google\"\n # Default: check which env var matches\n for env_var, provider in API_KEY_MAP.items():\n if os.environ.get(env_var, \"\").strip() == api_key:\n return provider\n return \"anthropic\" # Safe fallback\n\n def _init_api_client(self):\n \"\"\"Initialize the API client based on detected provider.\"\"\"\n try:\n if self.provider == \"anthropic\":\n import anthropic\n\n kwargs = {\"api_key\": self.api_key}\n base_url = os.environ.get(\"ANTHROPIC_BASE_URL\")\n if base_url:\n kwargs[\"base_url\"] = base_url\n return anthropic.Anthropic(**kwargs)\n elif self.provider == \"moonshot\":\n import anthropic\n\n return anthropic.Anthropic(\n api_key=self.api_key,\n base_url=\"https://api.moonshot.cn/v1\",\n )\n elif self.provider == \"openai\":\n from openai import OpenAI\n\n return OpenAI(api_key=self.api_key)\n elif self.provider == \"google\":\n import google.generativeai as genai\n\n genai.configure(api_key=self.api_key)\n return genai\n except ImportError as e:\n logger.info(f\"{self.provider} SDK not installed, falling back to LOCAL mode: {e}\")\n self.mode = \"local\"\n except Exception as e:\n if self._requested_mode == \"api\":\n raise RuntimeError(f\"Failed to initialize {self.provider} API client: {e}\") from e\n logger.error(f\"Failed to initialize {self.provider} API client: {e}\")\n self.mode = \"local\"\n return None\n\n def call(\n self,\n prompt: str,\n max_tokens: int = 4096,\n timeout: int | None = None,\n output_file: str | Path | None = None,\n cwd: str | Path | None = None,\n ) -> str | None:\n \"\"\"\n Call the AI agent (API or LOCAL mode).\n\n Args:\n prompt: The prompt to send\n max_tokens: Max response tokens (API mode only)\n timeout: Timeout in seconds (default from SKILL_SEEKER_ENHANCE_TIMEOUT or 2700 = 45m)\n output_file: Path for agent to write output (LOCAL mode, some agents)\n cwd: Working directory for LOCAL mode subprocess\n\n Returns:\n Response text, or None on failure\n \"\"\"\n if timeout is None:\n timeout = get_default_timeout()\n\n if self.mode == \"api\":\n return self._call_api(prompt, max_tokens)\n elif self.mode == \"local\":\n return self._call_local(prompt, timeout, output_file, cwd)\n return None\n\n def _call_api(self, prompt: str, max_tokens: int = 4096) -> str | None:\n \"\"\"Call via API using the detected provider.\"\"\"\n if not self.client:\n return None\n\n model = self.get_model(self.provider)\n\n try:\n if self.provider in (\"anthropic\", \"moonshot\"):\n response = self.client.messages.create(\n model=model,\n max_tokens=max_tokens,\n messages=[{\"role\": \"user\", \"content\": prompt}],\n timeout=120,\n )\n return response.content[0].text\n\n elif self.provider == \"openai\":\n response = self.client.chat.completions.create(\n model=model,\n max_tokens=max_tokens,\n messages=[{\"role\": \"user\", \"content\": prompt}],\n timeout=120,\n )\n return response.choices[0].message.content\n\n elif self.provider == \"google\":\n gmodel = self.client.GenerativeModel(model)\n response = gmodel.generate_content(prompt)\n return response.text\n\n except Exception as e:\n error_type = type(e).__name__\n error_module = type(e).__module__ or \"\"\n\n # Rate limit errors\n if \"rate\" in error_type.lower() or \"ratelimit\" in error_type.lower():\n logger.error(\n f\"{self.provider} API rate limited: {e}. \"\n \"Retry after waiting or reduce request frequency.\"\n )\n return None\n\n # Auth / permission errors\n if \"auth\" in error_type.lower() or \"permission\" in error_type.lower():\n logger.error(\n f\"{self.provider} API authentication failed: {e}. \"\n \"Check your API key is valid and has sufficient permissions.\"\n )\n return None\n\n # Timeout / connection errors\n if (\n any(\n kw in error_type.lower()\n for kw in (\"timeout\", \"connect\", \"connection\", \"network\")\n )\n or \"httpx\" in error_module.lower()\n ):\n logger.error(\n f\"{self.provider} API connection error: {e}. \"\n \"Check your network connectivity and try again.\"\n )\n return None\n\n # All other errors\n logger.error(f\"{self.provider} API call failed: {e}\")\n return None\n\n def _call_local(\n self,\n prompt: str,\n timeout: int | None = None,\n output_file: str | Path | None = None,\n cwd: str | Path | None = None,\n ) -> str | None:\n \"\"\"Call via LOCAL CLI agent using agent presets.\"\"\"\n if timeout is None:\n timeout = get_default_timeout()\n # Handle custom agent from env var\n if self.agent == \"custom\":\n custom_cmd = os.environ.get(\"SKILL_SEEKER_AGENT_CMD\", \"\").strip()\n if not custom_cmd:\n logger.warning(\"⚠️ Custom agent selected but SKILL_SEEKER_AGENT_CMD not set\")\n return None\n preset = {\n \"display_name\": \"Custom Agent\",\n \"command\": custom_cmd.split(),\n \"version_check\": custom_cmd.split()[:1] + [\"--version\"],\n }\n else:\n preset = AGENT_PRESETS.get(self.agent)\n if not preset:\n logger.warning(f\"⚠️ Unknown agent: {self.agent}\")\n return None\n\n try:\n with tempfile.TemporaryDirectory(prefix=\"agent_client_\") as temp_dir:\n temp_path = Path(temp_dir)\n prompt_file = temp_path / \"prompt.md\"\n resp_file = Path(output_file) if output_file else (temp_path / \"response.json\")\n\n # Only append output file instruction when caller explicitly requests it\n full_prompt = prompt\n if output_file:\n full_prompt += f\"\\n\\nWrite your response to: {resp_file}\\n\"\n\n prompt_file.write_text(full_prompt)\n\n # Build command from preset\n cmd = []\n for part in preset[\"command\"]:\n part = part.replace(\"{prompt_file}\", str(prompt_file))\n part = part.replace(\"{cwd}\", str(cwd or temp_path))\n part = part.replace(\"{skill_dir}\", str(cwd or temp_path))\n cmd.append(part)\n\n # Execute — pipe stdin for agents that read from it (e.g., codex)\n stdin_input = full_prompt if preset.get(\"uses_stdin\") else None\n result = subprocess.run(\n cmd,\n capture_output=True,\n text=True,\n timeout=timeout,\n cwd=str(cwd or temp_path),\n input=stdin_input,\n )\n\n if result.returncode != 0:\n logger.error(f\"{self.agent_display} returned error code {result.returncode}\")\n if result.stderr and result.stderr.strip():\n logger.error(f\"{self.agent_display} stderr: {result.stderr.strip()}\")\n\n # Try to read output file first\n resp_path = Path(resp_file)\n if resp_path.exists():\n return resp_path.read_text(encoding=\"utf-8\")\n\n # Try any JSON file in temp dir\n for json_file in temp_path.glob(\"*.json\"):\n if json_file.name != \"prompt.json\":\n return json_file.read_text(encoding=\"utf-8\")\n\n # Fall back to stdout (with agent-specific parsing)\n if result.stdout and result.stdout.strip():\n stdout = result.stdout.strip()\n parser = preset.get(\"parse_output\")\n if parser == \"kimi\":\n stdout = self._parse_kimi_output(stdout)\n return stdout\n\n logger.warning(f\"⚠️ No output from {self.agent_display}\")\n return None\n\n except subprocess.TimeoutExpired:\n logger.warning(f\"⚠️ {self.agent_display} timeout ({timeout}s)\")\n return None\n except FileNotFoundError:\n logger.warning(\n f\"⚠️ {self.agent_display} CLI not found. \"\n f\"Install it or set SKILL_SEEKER_AGENT to a different agent.\"\n )\n return None\n except Exception as e:\n logger.error(f\"{self.agent_display} error: {e}\")\n return None\n\n @staticmethod\n def _parse_kimi_output(raw_output: str) -> str:\n \"\"\"Parse Kimi CLI --print mode output to extract text content.\n\n Kimi's --print mode outputs structured lines like:\n TurnBegin(...)\n StepBegin(...)\n TextPart(type='text', text='actual content')\n ThinkPart(type='think', think='...')\n\n This extracts the text= values from TextPart lines.\n \"\"\"\n import re\n\n text_parts = re.findall(r\"TextPart\\(type='text', text='(.+?)'\\)\", raw_output)\n if text_parts:\n return \"\\n\".join(text_parts)\n # Fallback: return raw if no TextPart found\n return raw_output\n\n def is_available(self) -> bool:\n \"\"\"Check if the configured agent/API is available.\"\"\"\n if self.mode == \"api\":\n return self.client is not None\n\n # LOCAL mode: check if CLI exists\n preset = AGENT_PRESETS.get(self.agent)\n if not preset:\n return False\n\n version_cmd = preset.get(\"version_check\")\n if not version_cmd:\n return shutil.which(preset[\"command\"][0]) is not None\n\n try:\n result = subprocess.run(\n version_cmd,\n capture_output=True,\n text=True,\n timeout=5,\n )\n return result.returncode == 0\n except (FileNotFoundError, subprocess.TimeoutExpired):\n return False\n\n @staticmethod\n def detect_api_key() -> tuple[str | None, str | None]:\n \"\"\"\n Detect API key from environment variables.\n\n Returns:\n (api_key, provider) tuple. Provider is \"anthropic\", \"moonshot\", \"google\", or \"openai\".\n Returns (None, None) if no key found.\n \"\"\"\n for env_var, provider in API_KEY_MAP.items():\n key = os.environ.get(env_var, \"\").strip()\n if key:\n return key, provider\n return None, None\n\n @staticmethod\n def get_model(provider: str = \"anthropic\") -> str:\n \"\"\"\n Get the model name for a provider.\n\n Checks SKILL_SEEKER_MODEL env var first, then provider-specific env vars,\n then falls back to defaults.\n \"\"\"\n # Global override\n global_model = os.environ.get(\"SKILL_SEEKER_MODEL\", \"\").strip()\n if global_model:\n return global_model\n\n # Provider-specific env vars\n provider_env_map = {\n \"anthropic\": \"ANTHROPIC_MODEL\",\n \"moonshot\": \"MOONSHOT_MODEL\",\n \"google\": \"GOOGLE_MODEL\",\n \"openai\": \"OPENAI_MODEL\",\n }\n env_var = provider_env_map.get(provider)\n if env_var:\n model = os.environ.get(env_var, \"\").strip()\n if model:\n return model\n\n return DEFAULT_MODELS.get(provider, \"claude-sonnet-4-20250514\")\n\n @staticmethod\n def detect_default_target() -> str:\n \"\"\"\n Auto-detect the default --target platform from available API keys.\n\n Returns platform name: \"claude\", \"kimi\", \"gemini\", \"openai\", or \"markdown\" (fallback).\n \"\"\"\n _, provider = AgentClient.detect_api_key()\n if provider:\n return PROVIDER_TARGET_MAP.get(provider, \"markdown\")\n return \"markdown\"\n\n def log_mode(self) -> None:\n \"\"\"Log the current mode and agent for UX.\"\"\"\n if self.mode == \"api\":\n logger.info(f\"✅ AI enhancement enabled (using {self.provider} API)\")\n elif self.mode == \"local\":\n logger.info(f\"✅ AI enhancement enabled (using LOCAL mode - {self.agent_display})\")\n else:\n logger.info(\"ℹ️ AI enhancement disabled\")\n",
"sha256": "2fff7e6de630b6c8871db3419661195125c6128ac71d4d76f04e7561f7bdac17"
},
".github/tools/external/Skill_Seekers-development/src/skill_seekers/cli/install_skill.py": {
"mode": "100644",
"encoding": "utf-8",
"data": "#!/usr/bin/env python3\n\"\"\"\nComplete Skill Installation Workflow\nOne-command installation: fetch → scrape → enhance → package → upload\n\nThis CLI tool orchestrates the complete skill installation workflow by calling\nthe install_skill MCP tool.\n\nUsage:\n skill-seekers install --config react\n skill-seekers install --config configs/custom.json --no-upload\n skill-seekers install --config django --unlimited\n skill-seekers install --config react --dry-run\n\nExamples:\n # Install React skill from official configs\n skill-seekers install --config react\n\n # Install from local config file\n skill-seekers install --config configs/custom.json\n\n # Install without uploading\n skill-seekers install --config django --no-upload\n\n # Preview workflow without executing\n skill-seekers install --config react --dry-run\n\"\"\"\n\nimport argparse\nimport asyncio\nimport sys\n\n# Import the MCP tool function (with lazy loading)\ntry:\n from skill_seekers.mcp.server import install_skill_tool\n\n MCP_AVAILABLE = True\nexcept ImportError:\n MCP_AVAILABLE = False\n install_skill_tool = None\n\n\ndef main():\n \"\"\"Main entry point for CLI\"\"\"\n # Check MCP availability first\n if not MCP_AVAILABLE:\n print(\"\\n❌ Error: MCP package not installed\")\n print(\"\\nThe 'install' command requires MCP support.\")\n print(\"Install with:\")\n print(\" pip install skill-seekers[mcp]\")\n print(\"\\nOr use these alternatives:\")\n print(\" skill-seekers scrape --config react\")\n print(\" skill-seekers package output/react/\")\n print()\n sys.exit(1)\n\n parser = argparse.ArgumentParser(\n description=\"Complete skill installation workflow (fetch → scrape → enhance → package → upload)\",\n formatter_class=argparse.RawDescriptionHelpFormatter,\n epilog=\"\"\"\nExamples:\n # Install React skill from official API\n skill-seekers install --config react\n\n # Install from local config file\n skill-seekers install --config configs/custom.json\n\n # Install without uploading\n skill-seekers install --config django --no-upload\n\n # Unlimited scraping (no page limits)\n skill-seekers install --config godot --unlimited\n\n # Preview workflow (dry run)\n skill-seekers install --config react --dry-run\n\n # Install for Gemini instead of default platform\n skill-seekers install --config react --target gemini\n\n # Install for OpenAI ChatGPT\n skill-seekers install --config fastapi --target openai\n\nImportant:\n - Enhancement is MANDATORY (30-60 sec) for quality (3/10→9/10)\n - Total time: 20-45 minutes (mostly scraping)\n - Multi-platform support: claude (default), gemini, openai, markdown\n - Auto-uploads if API key is set (ANTHROPIC_API_KEY, GOOGLE_API_KEY, or OPENAI_API_KEY)\n\nPhases:\n 1. Fetch config (if config name provided)\n 2. Scrape documentation\n 3. AI Enhancement (MANDATORY - no skip option)\n 4. Package for target platform (ZIP or tar.gz)\n 5. Upload to target platform (optional)\n\"\"\",\n )\n\n parser.add_argument(\n \"--config\",\n required=True,\n help=\"Config name (e.g., 'react') or path (e.g., 'configs/custom.json')\",\n )\n\n parser.add_argument(\n \"--destination\",\n default=\"output\",\n help=\"Output directory for skill files (default: output/)\",\n )\n\n parser.add_argument(\n \"--no-upload\", action=\"store_true\", help=\"Skip automatic upload to target platform\"\n )\n\n parser.add_argument(\n \"--unlimited\",\n action=\"store_true\",\n help=\"Remove page limits during scraping (WARNING: Can take hours)\",\n )\n\n parser.add_argument(\"--dry-run\", action=\"store_true\", help=\"Preview workflow without executing\")\n\n parser.add_argument(\n \"--target\",\n choices=[\"claude\", \"gemini\", \"openai\", \"kimi\", \"markdown\"],\n default=None,\n help=\"Target LLM platform (auto-detected from API keys, or 'claude' if none set)\",\n )\n\n args = parser.parse_args()\n\n # Auto-detect target platform if not specified\n if args.target is None:\n from skill_seekers.cli.agent_client import AgentClient\n\n args.target = AgentClient.detect_default_target()\n\n # Determine if config is a name or path\n config_arg = args.config\n if config_arg.endswith(\".json\") or \"/\" in config_arg or \"\\\\\" in config_arg:\n # It's a path\n config_path = config_arg\n config_name = None\n else:\n # It's a name\n config_name = config_arg\n config_path = None\n\n # Build arguments for install_skill_tool\n tool_args = {\n \"config_name\": config_name,\n \"config_path\": config_path,\n \"destination\": args.destination,\n \"auto_upload\": not args.no_upload,\n \"unlimited\": args.unlimited,\n \"dry_run\": args.dry_run,\n \"target\": args.target,\n }\n\n # Run async tool\n try:\n result = asyncio.run(install_skill_tool(tool_args))\n\n # Print output\n for content in result:\n print(content.text)\n\n # Return success/failure based on output\n output_text = result[0].text\n if \"❌\" in output_text and \"WORKFLOW COMPLETE\" not in output_text:\n return 1\n return 0\n\n except KeyboardInterrupt:\n print(\"\\n\\n⚠️ Workflow interrupted by user\")\n return 130 # Standard exit code for SIGINT\n except Exception as e:\n print(f\"\\n\\n❌ Unexpected error: {str(e)}\")\n return 1\n\n\nif __name__ == \"__main__\":\n sys.exit(main())\n",
"sha256": "146be443d3b73b1e5c706b105fd0780831275baa6d0d61424b3c10d03dfa79aa"
},
".github/tools/external/Skill_Seekers-development/src/skill_seekers/cli/upload_skill.py": {
"mode": "100755",
"encoding": "utf-8",
"data": "#!/usr/bin/env python3\n\"\"\"\nAutomatic Skill Uploader\nUploads a skill package to LLM platforms (Claude, Gemini, OpenAI, etc.)\n\nUsage:\n # Anthropic (default)\n export ANTHROPIC_API_KEY=sk-ant-...\n skill-seekers upload output/react.zip\n\n # Gemini\n export GOOGLE_API_KEY=AIzaSy...\n skill-seekers upload output/react-gemini.tar.gz --target gemini\n\n # OpenAI\n export OPENAI_API_KEY=sk-proj-...\n skill-seekers upload output/react-openai.zip --target openai\n\"\"\"\n\nimport argparse\nimport os\nimport sys\nfrom pathlib import Path\n\n# Import utilities\ntry:\n from utils import print_upload_instructions\nexcept ImportError:\n sys.path.insert(0, str(Path(__file__).parent))\n from utils import print_upload_instructions\n\n\ndef upload_skill_api(package_path, target=\"claude\", api_key=None, **kwargs):\n \"\"\"\n Upload skill package to LLM platform\n\n Args:\n package_path: Path to skill package file\n target: Target platform ('claude', 'gemini', 'openai', 'chroma', 'weaviate')\n api_key: Optional API key (otherwise read from environment)\n **kwargs: Platform-specific upload options\n\n Returns:\n tuple: (success, message)\n \"\"\"\n try:\n from skill_seekers.cli.adaptors import get_adaptor\n except ImportError:\n return False, \"Adaptor system not available. Reinstall skill-seekers.\"\n\n # Get platform-specific adaptor\n try:\n adaptor = get_adaptor(target)\n except ValueError as e:\n return False, str(e)\n\n # Get API key\n if not api_key:\n api_key = os.environ.get(adaptor.get_env_var_name(), \"\").strip()\n\n # API key validation only for platforms that require it\n if target in [\"claude\", \"gemini\", \"openai\"]:\n if not api_key:\n return False, f\"{adaptor.get_env_var_name()} not set. Export your API key first.\"\n\n # Validate API key format\n if not adaptor.validate_api_key(api_key):\n return False, f\"Invalid API key format for {adaptor.PLATFORM_NAME}\"\n\n package_path = Path(package_path)\n\n # Basic file validation\n if not package_path.exists():\n return False, f\"File not found: {package_path}\"\n\n skill_name = package_path.stem\n\n print(f\"📤 Uploading skill: {skill_name}\")\n print(f\" Target: {adaptor.PLATFORM_NAME}\")\n print(f\" Source: {package_path}\")\n print(f\" Size: {package_path.stat().st_size:,} bytes\")\n print()\n\n # Upload using adaptor\n print(f\"⏳ Uploading to {adaptor.PLATFORM_NAME}...\")\n\n try:\n result = adaptor.upload(package_path, api_key, **kwargs)\n\n if result[\"success\"]:\n print()\n print(f\"✅ {result['message']}\")\n print()\n if result.get(\"url\"):\n print(\"Your skill is now available at:\")\n print(f\" {result['url']}\")\n if result.get(\"skill_id\"):\n print(f\" Skill ID: {result['skill_id']}\")\n if result.get(\"collection\"):\n print(f\" Collection: {result['collection']}\")\n if result.get(\"class_name\"):\n print(f\" Class: {result['class_name']}\")\n if result.get(\"count\"):\n print(f\" Documents uploaded: {result['count']}\")\n print()\n return True, \"Upload successful\"\n else:\n return False, result[\"message\"]\n\n except Exception as e:\n return False, f\"Unexpected error: {str(e)}\"\n\n\ndef main():\n parser = argparse.ArgumentParser(\n description=\"Upload a skill package to LLM platforms and vector databases\",\n formatter_class=argparse.RawDescriptionHelpFormatter,\n epilog=\"\"\"\nSetup:\n Anthropic (Claude):\n export ANTHROPIC_API_KEY=sk-ant-...\n\n Gemini:\n export GOOGLE_API_KEY=AIzaSy...\n\n OpenAI:\n export OPENAI_API_KEY=sk-proj-...\n\n ChromaDB (local):\n # No API key needed for local instance\n chroma run # Start server\n\n Weaviate (local):\n # No API key needed for local instance\n docker run -p 8080:8080 semitechnologies/weaviate:latest\n\nExamples:\n # Upload to default platform\n skill-seekers upload output/react.zip\n\n # Upload to Gemini\n skill-seekers upload output/react-gemini.tar.gz --target gemini\n\n # Upload to OpenAI\n skill-seekers upload output/react-openai.zip --target openai\n\n # Upload to ChromaDB (local)\n skill-seekers upload output/react-chroma.json --target chroma\n\n # Upload to ChromaDB with OpenAI embeddings\n skill-seekers upload output/react-chroma.json --target chroma --embedding-function openai\n\n # Upload to Weaviate (local)\n skill-seekers upload output/react-weaviate.json --target weaviate\n\n # Upload to Weaviate Cloud\n skill-seekers upload output/react-weaviate.json --target weaviate --use-cloud --cluster-url https://xxx.weaviate.network --api-key YOUR_KEY\n \"\"\",\n )\n\n parser.add_argument(\"package_file\", help=\"Path to skill package file (e.g., output/react.zip)\")\n\n parser.add_argument(\n \"--target\",\n choices=[\"claude\", \"gemini\", \"openai\", \"kimi\", \"chroma\", \"weaviate\"],\n default=None,\n help=\"Target platform (auto-detected from API keys, or 'claude' if none set)\",\n )\n\n parser.add_argument(\"--api-key\", help=\"Platform API key (or set environment variable)\")\n\n # ChromaDB upload options\n parser.add_argument(\n \"--chroma-url\",\n help=\"ChromaDB URL (default: http://localhost:8000 for HTTP, or use --persist-directory for local)\",\n )\n\n parser.add_argument(\n \"--persist-directory\",\n help=\"Local directory for persistent ChromaDB storage (default: ./chroma_db)\",\n )\n\n parser.add_argument(\n \"--embedding-function\",\n choices=[\"openai\", \"sentence-transformers\", \"none\"],\n help=\"Embedding function for ChromaDB/Weaviate (default: platform default)\",\n )\n\n parser.add_argument(\n \"--openai-api-key\", help=\"OpenAI API key for embeddings (or set OPENAI_API_KEY env var)\"\n )\n\n # Weaviate upload options\n parser.add_argument(\n \"--weaviate-url\",\n default=\"http://localhost:8080\",\n help=\"Weaviate URL (default: http://localhost:8080)\",\n )\n\n parser.add_argument(\n \"--use-cloud\",\n action=\"store_true\",\n help=\"Use Weaviate Cloud (requires --api-key and --cluster-url)\",\n )\n\n parser.add_argument(\n \"--cluster-url\", help=\"Weaviate Cloud cluster URL (e.g., https://xxx.weaviate.network)\"\n )\n\n args = parser.parse_args()\n\n # Auto-detect target platform if not specified\n if args.target is None:\n from skill_seekers.cli.agent_client import AgentClient\n\n args.target = AgentClient.detect_default_target()\n\n # Build kwargs for vector DB upload\n upload_kwargs = {}\n\n if args.target == \"chroma\":\n if args.chroma_url:\n upload_kwargs[\"chroma_url\"] = args.chroma_url\n if args.persist_directory:\n upload_kwargs[\"persist_directory\"] = args.persist_directory\n if args.embedding_function:\n upload_kwargs[\"embedding_function\"] = args.embedding_function\n if args.openai_api_key:\n upload_kwargs[\"openai_api_key\"] = args.openai_api_key\n\n elif args.target == \"weaviate\":\n upload_kwargs[\"weaviate_url\"] = args.weaviate_url\n upload_kwargs[\"use_cloud\"] = args.use_cloud\n if args.cluster_url:\n upload_kwargs[\"cluster_url\"] = args.cluster_url\n if args.embedding_function:\n upload_kwargs[\"embedding_function\"] = args.embedding_function\n if args.openai_api_key:\n upload_kwargs[\"openai_api_key\"] = args.openai_api_key\n\n # Upload skill\n success, message = upload_skill_api(\n args.package_file, args.target, args.api_key, **upload_kwargs\n )\n\n if success:\n sys.exit(0)\n else:\n print(f\"\\n❌ Upload failed: {message}\")\n print()\n print(\"📝 Manual upload instructions:\")\n print_upload_instructions(args.package_file)\n sys.exit(1)\n\n\nif __name__ == \"__main__\":\n main()\n",
"sha256": "2967da60c32c2495ea993f9122c6472d76ab86d3bcae878831fbeb07c55b0d1e"
},
".github/tools/external/claude-official-skills/skills/skill-creator/SKILL.md": {
"mode": "100644",
"encoding": "utf-8",
"data": "---\nname: skill-creator\ndescription: Guide for creating effective skills. This skill should be used when users want to create a new skill (or update an existing skill) that extends Claude's capabilities with specialized knowledge, workflows, or tool integrations.\nlicense: Complete terms in LICENSE.txt\n---\n\n# Skill Creator\n\nThis skill provides guidance for creating effective skills.\n\n## About Skills\n\nSkills are modular, self-contained packages that extend Claude's capabilities by providing\nspecialized knowledge, workflows, and tools. Think of them as \"onboarding guides\" for specific\ndomains or tasks—they transform Claude from a general-purpose agent into a specialized agent\nequipped with procedural knowledge that no model can fully possess.\n\n### What Skills Provide\n\n1. Specialized workflows - Multi-step procedures for specific domains\n2. Tool integrations - Instructions for working with specific file formats or APIs\n3. Domain expertise - Company-specific knowledge, schemas, business logic\n4. Bundled resources - Scripts, references, and assets for complex and repetitive tasks\n\n## Core Principles\n\n### Concise is Key\n\nThe context window is a public good. Skills share the context window with everything else Claude needs: system prompt, conversation history, other Skills' metadata, and the actual user request.\n\n**Default assumption: Claude is already very smart.** Only add context Claude doesn't already have. Challenge each piece of information: \"Does Claude really need this explanation?\" and \"Does this paragraph justify its token cost?\"\n\nPrefer concise examples over verbose explanations.\n\n### Set Appropriate Degrees of Freedom\n\nMatch the level of specificity to the task's fragility and variability:\n\n**High freedom (text-based instructions)**: Use when multiple approaches are valid, decisions depend on context, or heuristics guide the approach.\n\n**Medium freedom (pseudocode or scripts with parameters)**: Use when a preferred pattern exists, some variation is acceptable, or configuration affects behavior.\n\n**Low freedom (specific scripts, few parameters)**: Use when operations are fragile and error-prone, consistency is critical, or a specific sequence must be followed.\n\nThink of Claude as exploring a path: a narrow bridge with cliffs needs specific guardrails (low freedom), while an open field allows many routes (high freedom).\n\n### Anatomy of a Skill\n\nEvery skill consists of a required SKILL.md file and optional bundled resources:\n\n```\nskill-name/\n├── SKILL.md (required)\n│ ├── YAML frontmatter metadata (required)\n│ │ ├── name: (required)\n│ │ ├── description: (required)\n│ │ └── compatibility: (optional, rarely needed)\n│ └── Markdown instructions (required)\n└── Bundled Resources (optional)\n ├── scripts/ - Executable code (Python/Bash/etc.)\n ├── references/ - Documentation intended to be loaded into context as needed\n └── assets/ - Files used in output (templates, icons, fonts, etc.)\n```\n\n#### SKILL.md (required)\n\nEvery SKILL.md consists of:\n\n- **Frontmatter** (YAML): Contains `name` and `description` fields (required), plus optional fields like `license`, `metadata`, and `compatibility`. Only `name` and `description` are read by Claude to determine when the skill triggers, so be clear and comprehensive about what the skill is and when it should be used. The `compatibility` field is for noting environment requirements (target product, system packages, etc.) but most skills don't need it.\n- **Body** (Markdown): Instructions and guidance for using the skill. Only loaded AFTER the skill triggers (if at all).\n\n#### Bundled Resources (optional)\n\n##### Scripts (`scripts/`)\n\nExecutable code (Python/Bash/etc.) for tasks that require deterministic reliability or are repeatedly rewritten.\n\n- **When to include**: When the same code is being rewritten repeatedly or deterministic reliability is needed\n- **Example**: `scripts/rotate_pdf.py` for PDF rotation tasks\n- **Benefits**: Token efficient, deterministic, may be executed without loading into context\n- **Note**: Scripts may still need to be read by Claude for patching or environment-specific adjustments\n\n##### References (`references/`)\n\nDocumentation and reference material intended to be loaded as needed into context to inform Claude's process and thinking.\n\n- **When to include**: For documentation that Claude should reference while working\n- **Examples**: `references/finance.md` for financial schemas, `references/mnda.md` for company NDA template, `references/policies.md` for company policies, `references/api_docs.md` for API specifications\n- **Use cases**: Database schemas, API documentation, domain knowledge, company policies, detailed workflow guides\n- **Benefits**: Keeps SKILL.md lean, loaded only when Claude determines it's needed\n- **Best practice**: If files are large (>10k words), include grep search patterns in SKILL.md\n- **Avoid duplication**: Information should live in either SKILL.md or references files, not both. Prefer references files for detailed information unless it's truly core to the skill—this keeps SKILL.md lean while making information discoverable without hogging the context window. Keep only essential procedural instructions and workflow guidance in SKILL.md; move detailed reference material, schemas, and examples to references files.\n\n##### Assets (`assets/`)\n\nFiles not intended to be loaded into context, but rather used within the output Claude produces.\n\n- **When to include**: When the skill needs files that will be used in the final output\n- **Examples**: `assets/logo.png` for brand assets, `assets/slides.pptx` for PowerPoint templates, `assets/frontend-template/` for HTML/React boilerplate, `assets/font.ttf` for typography\n- **Use cases**: Templates, images, icons, boilerplate code, fonts, sample documents that get copied or modified\n- **Benefits**: Separates output resources from documentation, enables Claude to use files without loading them into context\n\n#### What to Not Include in a Skill\n\nA skill should only contain essential files that directly support its functionality. Do NOT create extraneous documentation or auxiliary files, including:\n\n- README.md\n- INSTALLATION_GUIDE.md\n- QUICK_REFERENCE.md\n- CHANGELOG.md\n- etc.\n\nThe skill should only contain the information needed for an AI agent to do the job at hand. It should not contain auxilary context about the process that went into creating it, setup and testing procedures, user-facing documentation, etc. Creating additional documentation files just adds clutter and confusion.\n\n### Progressive Disclosure Design Principle\n\nSkills use a three-level loading system to manage context efficiently:\n\n1. **Metadata (name + description)** - Always in context (~100 words)\n2. **SKILL.md body** - When skill triggers (<5k words)\n3. **Bundled resources** - As needed by Claude (Unlimited because scripts can be executed without reading into context window)\n\n#### Progressive Disclosure Patterns\n\nKeep SKILL.md body to the essentials and under 500 lines to minimize context bloat. Split content into separate files when approaching this limit. When splitting out content into other files, it is very important to reference them from SKILL.md and describe clearly when to read them, to ensure the reader of the skill knows they exist and when to use them.\n\n**Key principle:** When a skill supports multiple variations, frameworks, or options, keep only the core workflow and selection guidance in SKILL.md. Move variant-specific details (patterns, examples, configuration) into separate reference files.\n\n**Pattern 1: High-level guide with references**\n\n```markdown\n# PDF Processing\n\n## Quick start\n\nExtract text with pdfplumber:\n[code example]\n\n## Advanced features\n\n- **Form filling**: See [FORMS.md](FORMS.md) for complete guide\n- **API reference**: See [REFERENCE.md](REFERENCE.md) for all methods\n- **Examples**: See [EXAMPLES.md](EXAMPLES.md) for common patterns\n```\n\nClaude loads FORMS.md, REFERENCE.md, or EXAMPLES.md only when needed.\n\n**Pattern 2: Domain-specific organization**\n\nFor Skills with multiple domains, organize content by domain to avoid loading irrelevant context:\n\n```\nbigquery-skill/\n├── SKILL.md (overview and navigation)\n└── reference/\n ├── finance.md (revenue, billing metrics)\n ├── sales.md (opportunities, pipeline)\n ├── product.md (API usage, features)\n └── marketing.md (campaigns, attribution)\n```\n\nWhen a user asks about sales metrics, Claude only reads sales.md.\n\nSimilarly, for skills supporting multiple frameworks or variants, organize by variant:\n\n```\ncloud-deploy/\n├── SKILL.md (workflow + provider selection)\n└── references/\n ├── aws.md (AWS deployment patterns)\n ├── gcp.md (GCP deployment patterns)\n └── azure.md (Azure deployment patterns)\n```\n\nWhen the user chooses AWS, Claude only reads aws.md.\n\n**Pattern 3: Conditional details**\n\nShow basic content, link to advanced content:\n\n```markdown\n# DOCX Processing\n\n## Creating documents\n\nUse docx-js for new documents. See [DOCX-JS.md](DOCX-JS.md).\n\n## Editing documents\n\nFor simple edits, modify the XML directly.\n\n**For tracked changes**: See [REDLINING.md](REDLINING.md)\n**For OOXML details**: See [OOXML.md](OOXML.md)\n```\n\nClaude reads REDLINING.md or OOXML.md only when the user needs those features.\n\n**Important guidelines:**\n\n- **Avoid deeply nested references** - Keep references one level deep from SKILL.md. All reference files should link directly from SKILL.md.\n- **Structure longer reference files** - For files longer than 100 lines, include a table of contents at the top so Claude can see the full scope when previewing.\n\n## Skill Creation Process\n\nSkill creation involves these steps:\n\n1. Understand the skill with concrete examples\n2. Plan reusable skill contents (scripts, references, assets)\n3. Initialize the skill (run init_skill.py)\n4. Edit the skill (implement resources and write SKILL.md)\n5. Package the skill (run package_skill.py)\n6. Iterate based on real usage\n\nFollow these steps in order, skipping only if there is a clear reason why they are not applicable.\n\n### Step 1: Understanding the Skill with Concrete Examples\n\nSkip this step only when the skill's usage patterns are already clearly understood. It remains valuable even when working with an existing skill.\n\nTo create an effective skill, clearly understand concrete examples of how the skill will be used. This understanding can come from either direct user examples or generated examples that are validated with user feedback.\n\nFor example, when building an image-editor skill, relevant questions include:\n\n- \"What functionality should the image-editor skill support? Editing, rotating, anything else?\"\n- \"Can you give some examples of how this skill would be used?\"\n- \"I can imagine users asking for things like 'Remove the red-eye from this image' or 'Rotate this image'. Are there other ways you imagine this skill being used?\"\n- \"What would a user say that should trigger this skill?\"\n\nTo avoid overwhelming users, avoid asking too many questions in a single message. Start with the most important questions and follow up as needed for better effectiveness.\n\nConclude this step when there is a clear sense of the functionality the skill should support.\n\n### Step 2: Planning the Reusable Skill Contents\n\nTo turn concrete examples into an effective skill, analyze each example by:\n\n1. Considering how to execute on the example from scratch\n2. Identifying what scripts, references, and assets would be helpful when executing these workflows repeatedly\n\nExample: When building a `pdf-editor` skill to handle queries like \"Help me rotate this PDF,\" the analysis shows:\n\n1. Rotating a PDF requires re-writing the same code each time\n2. A `scripts/rotate_pdf.py` script would be helpful to store in the skill\n\nExample: When designing a `frontend-webapp-builder` skill for queries like \"Build me a todo app\" or \"Build me a dashboard to track my steps,\" the analysis shows:\n\n1. Writing a frontend webapp requires the same boilerplate HTML/React each time\n2. An `assets/hello-world/` template containing the boilerplate HTML/React project files would be helpful to store in the skill\n\nExample: When building a `big-query` skill to handle queries like \"How many users have logged in today?\" the analysis shows:\n\n1. Querying BigQuery requires re-discovering the table schemas and relationships each time\n2. A `references/schema.md` file documenting the table schemas would be helpful to store in the skill\n\nTo establish the skill's contents, analyze each concrete example to create a list of the reusable resources to include: scripts, references, and assets.\n\n### Step 3: Initializing the Skill\n\nAt this point, it is time to actually create the skill.\n\nSkip this step only if the skill being developed already exists, and iteration or packaging is needed. In this case, continue to the next step.\n\nWhen creating a new skill from scratch, always run the `init_skill.py` script. The script conveniently generates a new template skill directory that automatically includes everything a skill requires, making the skill creation process much more efficient and reliable.\n\nUsage:\n\n```bash\nscripts/init_skill.py <skill-name> --path <output-directory>\n```\n\nThe script:\n\n- Creates the skill directory at the specified path\n- Generates a SKILL.md template with proper frontmatter and TODO placeholders\n- Creates example resource directories: `scripts/`, `references/`, and `assets/`\n- Adds example files in each directory that can be customized or deleted\n\nAfter initialization, customize or remove the generated SKILL.md and example files as needed.\n\n### Step 4: Edit the Skill\n\nWhen editing the (newly-generated or existing) skill, remember that the skill is being created for another instance of Claude to use. Include information that would be beneficial and non-obvious to Claude. Consider what procedural knowledge, domain-specific details, or reusable assets would help another Claude instance execute these tasks more effectively.\n\n#### Learn Proven Design Patterns\n\nConsult these helpful guides based on your skill's needs:\n\n- **Multi-step processes**: See references/workflows.md for sequential workflows and conditional logic\n- **Specific output formats or quality standards**: See references/output-patterns.md for template and example patterns\n\nThese files contain established best practices for effective skill design.\n\n#### Start with Reusable Skill Contents\n\nTo begin implementation, start with the reusable resources identified above: `scripts/`, `references/`, and `assets/` files. Note that this step may require user input. For example, when implementing a `brand-guidelines` skill, the user may need to provide brand assets or templates to store in `assets/`, or documentation to store in `references/`.\n\nAdded scripts must be tested by actually running them to ensure there are no bugs and that the output matches what is expected. If there are many similar scripts, only a representative sample needs to be tested to ensure confidence that they all work while balancing time to completion.\n\nAny example files and directories not needed for the skill should be deleted. The initialization script creates example files in `scripts/`, `references/`, and `assets/` to demonstrate structure, but most skills won't need all of them.\n\n#### Update SKILL.md\n\n**Writing Guidelines:** Always use imperative/infinitive form.\n\n##### Frontmatter\n\nWrite the YAML frontmatter with `name` and `description`:\n\n- `name`: The skill name\n- `description`: This is the primary triggering mechanism for your skill, and helps Claude understand when to use the skill.\n - Include both what the Skill does and specific triggers/contexts for when to use it.\n - Include all \"when to use\" information here - Not in the body. The body is only loaded after triggering, so \"When to Use This Skill\" sections in the body are not helpful to Claude.\n - Example description for a `docx` skill: \"Comprehensive document creation, editing, and analysis with support for tracked changes, comments, formatting preservation, and text extraction. Use when Claude needs to work with professional documents (.docx files) for: (1) Creating new documents, (2) Modifying or editing content, (3) Working with tracked changes, (4) Adding comments, or any other document tasks\"\n\nDo not include any other fields in YAML frontmatter.\n\n##### Body\n\nWrite instructions for using the skill and its bundled resources.\n\n### Step 5: Packaging a Skill\n\nOnce development of the skill is complete, it must be packaged into a distributable .skill file that gets shared with the user. The packaging process automatically validates the skill first to ensure it meets all requirements:\n\n```bash\nscripts/package_skill.py <path/to/skill-folder>\n```\n\nOptional output directory specification:\n\n```bash\nscripts/package_skill.py <path/to/skill-folder> ./dist\n```\n\nThe packaging script will:\n\n1. **Validate** the skill automatically, checking:\n\n - YAML frontmatter format and required fields\n - Skill naming conventions and directory structure\n - Description completeness and quality\n - File organization and resource references\n\n2. **Package** the skill if validation passes, creating a .skill file named after the skill (e.g., `my-skill.skill`) that includes all files and maintains the proper directory structure for distribution. The .skill file is a zip file with a .skill extension.\n\nIf validation fails, the script will report the errors and exit without creating a package. Fix any validation errors and run the packaging command again.\n\n### Step 6: Iterate\n\nAfter testing the skill, users may request improvements. Often this happens right after using the skill, with fresh context of how the skill performed.\n\n**Iteration workflow:**\n\n1. Use the skill on real tasks\n2. Notice struggles or inefficiencies\n3. Identify how SKILL.md or bundled resources should be updated\n4. Implement changes and test again\n",
"sha256": "d57b6e3a44535b9c0ef454dad5c86f5df78185fc80a65c7092885b4b5e10f81b"
},
".github/tools/external/tmux/compat/explicit_bzero.c": {
"mode": "100644",
"encoding": "utf-8",
"data": "/*\t$OpenBSD: explicit_bzero.c,v 1.4 2015/08/31 02:53:57 guenther Exp $ */\n/*\n * Public domain.\n * Written by Matthew Dempsky.\n */\n\n#include <string.h>\n\n#include \"compat.h\"\n\nvoid\nexplicit_bzero(void *buf, size_t len)\n{\n\tmemset(buf, 0, len);\n}\n",
"sha256": "7e30bc63946093cd6ed7cb4ce01d2f8c6e329ab173a20df250da60bb0a3c757b"
},
".github/tools/external/tmux/compat/getopt_long.c": {
"mode": "100644",
"encoding": "utf-8",
"data": "/* This file is obtained from OpenSSH:\n * Repository: https://github.com/openssh/openssh-portable\n * Commit: b5b405fee7f3e79d44e2d2971a4b6b4cc53f112e\n * File: /openbsd-compat/getopt_long.c */\n\n/*\n * Copyright (c) 2002 Todd C. Miller <Todd.Miller@courtesan.com>\n *\n * Permission to use, copy, modify, and distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n *\n * Sponsored in part by the Defense Advanced Research Projects\n * Agency (DARPA) and Air Force Research Laboratory, Air Force\n * Materiel Command, USAF, under agreement number F39502-99-1-0512.\n */\n/*-\n * Copyright (c) 2000 The NetBSD Foundation, Inc.\n * All rights reserved.\n *\n * This code is derived from software contributed to The NetBSD Foundation\n * by Dieter Baron and Thomas Klausner.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n * notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n * notice, this list of conditions and the following disclaimer in the\n * documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS\n * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED\n * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS\n * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n * POSSIBILITY OF SUCH DAMAGE.\n */\n\n/* OPENBSD ORIGINAL: lib/libc/stdlib/getopt_long.c */\n#include \"compat.h\"\n\n/* The following macro constants are taken from getopt.h of OpenSSH:\n * Repository: https://github.com/openssh/openssh-portable\n * Commit: b5b405fee7f3e79d44e2d2971a4b6b4cc53f112e\n * File: /openbsd-compat/getopt.h\n *\n * ---- BEGIN - Copyright notice and license of getopt.h ----\n * Copyright (c) 2000 The NetBSD Foundation, Inc.\n * All rights reserved.\n *\n * This code is derived from software contributed to The NetBSD Foundation\n * by Dieter Baron and Thomas Klausner.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n * notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n * notice, this list of conditions and the following disclaimer in the\n * documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS\n * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED\n * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS\n * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n * POSSIBILITY OF SUCH DAMAGE.\n * ---- END ----\n */\n#define no_argument 0\n#define required_argument 1\n#define optional_argument 2\n\n#if !defined(HAVE_GETOPT) || !defined(HAVE_GETOPT_OPTRESET)\n\n#if 0\n#include <err.h>\n#include <getopt.h>\n#endif\n#include <errno.h>\n#include <stdlib.h>\n#include <string.h>\n#include <stdarg.h>\n\nstruct option {\n\t/* name of long option */\n\tconst char *name;\n\t/*\n\t * one of no_argument, required_argument, and optional_argument:\n\t * whether option takes an argument\n\t */\n\tint has_arg;\n\t/* if not NULL, set *flag to val when option found */\n\tint *flag;\n\t/* if flag not NULL, value to set *flag to; else return value */\n\tint val;\n};\n\nint\topterr = 1;\t\t/* if error message should be printed */\nint\toptind = 1;\t\t/* index into parent argv vector */\nint\toptopt = '?';\t\t/* character checked for validity */\nint\toptreset;\t\t/* reset getopt */\nchar *optarg;\t\t/* argument associated with option */\n\n#define PRINT_ERROR\t((opterr) && (*options != ':'))\n\n#define FLAG_PERMUTE\t0x01\t/* permute non-options to the end of argv */\n#define FLAG_ALLARGS\t0x02\t/* treat non-options as args to option \"-1\" */\n#define FLAG_LONGONLY\t0x04\t/* operate as getopt_long_only */\n\n/* return values */\n#define\tBADCH\t\t(int)'?'\n#define\tBADARG\t\t((*options == ':') ? (int)':' : (int)'?')\n#define\tINORDER\t\t(int)1\n\n#define\tEMSG\t\t(char *)\"\"\n\nstatic int getopt_internal(int, char * const *, const char *,\n\t\t\t const struct option *, int *, int);\nstatic int parse_long_options(char * const *, const char *,\n\t\t\t const struct option *, int *, int);\nstatic int gcd(int, int);\nstatic void permute_args(int, int, int, char * const *);\n\nstatic char *place = EMSG; /* option letter processing */\n\n/* XXX: set optreset to 1 rather than these two */\nstatic int nonopt_start = -1; /* first non option argument (for permute) */\nstatic int nonopt_end = -1; /* first option after non options (for permute) */\n\n/* Error messages */\nstatic const char recargchar[] = \"option requires an argument -- %c\";\nstatic const char recargstring[] = \"option requires an argument -- %s\";\nstatic const char ambig[] = \"ambiguous option -- %.*s\";\nstatic const char noarg[] = \"option doesn't take an argument -- %.*s\";\nstatic const char illoptchar[] = \"unknown option -- %c\";\nstatic const char illoptstring[] = \"unknown option -- %s\";\n\n/*\n * Compute the greatest common divisor of a and b.\n */\nstatic int\ngcd(int a, int b)\n{\n\tint c;\n\n\tc = a % b;\n\twhile (c != 0) {\n\t\ta = b;\n\t\tb = c;\n\t\tc = a % b;\n\t}\n\n\treturn (b);\n}\n\n/*\n * Exchange the block from nonopt_start to nonopt_end with the block\n * from nonopt_end to opt_end (keeping the same order of arguments\n * in each block).\n */\nstatic void\npermute_args(int panonopt_start, int panonopt_end, int opt_end,\n\tchar * const *nargv)\n{\n\tint cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;\n\tchar *swap;\n\n\t/*\n\t * compute lengths of blocks and number and size of cycles\n\t */\n\tnnonopts = panonopt_end - panonopt_start;\n\tnopts = opt_end - panonopt_end;\n\tncycle = gcd(nnonopts, nopts);\n\tcyclelen = (opt_end - panonopt_start) / ncycle;\n\n\tfor (i = 0; i < ncycle; i++) {\n\t\tcstart = panonopt_end+i;\n\t\tpos = cstart;\n\t\tfor (j = 0; j < cyclelen; j++) {\n\t\t\tif (pos >= panonopt_end)\n\t\t\t\tpos -= nnonopts;\n\t\t\telse\n\t\t\t\tpos += nopts;\n\t\t\tswap = nargv[pos];\n\t\t\t/* LINTED const cast */\n\t\t\t((char **) nargv)[pos] = nargv[cstart];\n\t\t\t/* LINTED const cast */\n\t\t\t((char **)nargv)[cstart] = swap;\n\t\t}\n\t}\n}\n\n/*\n * parse_long_options --\n *\tParse long options in argc/argv argument vector.\n * Returns -1 if short_too is set and the option does not match long_options.\n */\nstatic int\nparse_long_options(char * const *nargv, const char *options,\n\tconst struct option *long_options, int *idx, int short_too)\n{\n\tchar *current_argv, *has_equal;\n\tsize_t current_argv_len;\n\tint i, match;\n\n\tcurrent_argv = place;\n\tmatch = -1;\n\n\toptind++;\n\n\tif ((has_equal = strchr(current_argv, '=')) != NULL) {\n\t\t/* argument found (--option=arg) */\n\t\tcurrent_argv_len = has_equal - current_argv;\n\t\thas_equal++;\n\t} else\n\t\tcurrent_argv_len = strlen(current_argv);\n\n\tfor (i = 0; long_options[i].name; i++) {\n\t\t/* find matching long option */\n\t\tif (strncmp(current_argv, long_options[i].name,\n\t\t current_argv_len))\n\t\t\tcontinue;\n\n\t\tif (strlen(long_options[i].name) == current_argv_len) {\n\t\t\t/* exact match */\n\t\t\tmatch = i;\n\t\t\tbreak;\n\t\t}\n\t\t/*\n\t\t * If this is a known short option, don't allow\n\t\t * a partial match of a single character.\n\t\t */\n\t\tif (short_too && current_argv_len == 1)\n\t\t\tcontinue;\n\n\t\tif (match == -1)\t/* partial match */\n\t\t\tmatch = i;\n\t\telse {\n\t\t\t/* ambiguous abbreviation */\n\t\t\tif (PRINT_ERROR)\n\t\t\t\twarnx(ambig, (int)current_argv_len,\n\t\t\t\t current_argv);\n\t\t\toptopt = 0;\n\t\t\treturn (BADCH);\n\t\t}\n\t}\n\tif (match != -1) {\t\t/* option found */\n\t\tif (long_options[match].has_arg == no_argument\n\t\t && has_equal) {\n\t\t\tif (PRINT_ERROR)\n\t\t\t\twarnx(noarg, (int)current_argv_len,\n\t\t\t\t current_argv);\n\t\t\t/*\n\t\t\t * XXX: GNU sets optopt to val regardless of flag\n\t\t\t */\n\t\t\tif (long_options[match].flag == NULL)\n\t\t\t\toptopt = long_options[match].val;\n\t\t\telse\n\t\t\t\toptopt = 0;\n\t\t\treturn (BADARG);\n\t\t}\n\t\tif (long_options[match].has_arg == required_argument ||\n\t\t long_options[match].has_arg == optional_argument) {\n\t\t\tif (has_equal)\n\t\t\t\toptarg = has_equal;\n\t\t\telse if (long_options[match].has_arg ==\n\t\t\t required_argument) {\n\t\t\t\t/*\n\t\t\t\t * optional argument doesn't use next nargv\n\t\t\t\t */\n\t\t\t\toptarg = nargv[optind++];\n\t\t\t}\n\t\t}\n\t\tif ((long_options[match].has_arg == required_argument)\n\t\t && (optarg == NULL)) {\n\t\t\t/*\n\t\t\t * Missing argument; leading ':' indicates no error\n\t\t\t * should be generated.\n\t\t\t */\n\t\t\tif (PRINT_ERROR)\n\t\t\t\twarnx(recargstring,\n\t\t\t\t current_argv);\n\t\t\t/*\n\t\t\t * XXX: GNU sets optopt to val regardless of flag\n\t\t\t */\n\t\t\tif (long_options[match].flag == NULL)\n\t\t\t\toptopt = long_options[match].val;\n\t\t\telse\n\t\t\t\toptopt = 0;\n\t\t\t--optind;\n\t\t\treturn (BADARG);\n\t\t}\n\t} else {\t\t\t/* unknown option */\n\t\tif (short_too) {\n\t\t\t--optind;\n\t\t\treturn (-1);\n\t\t}\n\t\tif (PRINT_ERROR)\n\t\t\twarnx(illoptstring, current_argv);\n\t\toptopt = 0;\n\t\treturn (BADCH);\n\t}\n\tif (idx)\n\t\t*idx = match;\n\tif (long_options[match].flag) {\n\t\t*long_options[match].flag = long_options[match].val;\n\t\treturn (0);\n\t} else\n\t\treturn (long_options[match].val);\n}\n\n/*\n * getopt_internal --\n *\tParse argc/argv argument vector. Called by user level routines.\n */\nstatic int\ngetopt_internal(int nargc, char * const *nargv, const char *options,\n\tconst struct option *long_options, int *idx, int flags)\n{\n\tchar *oli;\t\t\t\t/* option letter list index */\n\tint optchar, short_too;\n\tstatic int posixly_correct = -1;\n\n\tif (options == NULL)\n\t\treturn (-1);\n\n\t/*\n\t * XXX Some GNU programs (like cvs) set optind to 0 instead of\n\t * XXX using optreset. Work around this braindamage.\n\t */\n\tif (optind == 0)\n\t\toptind = optreset = 1;\n\n\t/*\n\t * Disable GNU extensions if POSIXLY_CORRECT is set or options\n\t * string begins with a '+'.\n\t */\n\tif (posixly_correct == -1 || optreset)\n\t\tposixly_correct = (getenv(\"POSIXLY_CORRECT\") != NULL);\n\tif (*options == '-')\n\t\tflags |= FLAG_ALLARGS;\n\telse if (posixly_correct || *options == '+')\n\t\tflags &= ~FLAG_PERMUTE;\n\tif (*options == '+' || *options == '-')\n\t\toptions++;\n\n\toptarg = NULL;\n\tif (optreset)\n\t\tnonopt_start = nonopt_end = -1;\nstart:\n\tif (optreset || !*place) {\t\t/* update scanning pointer */\n\t\toptreset = 0;\n\t\tif (optind >= nargc) { /* end of argument vector */\n\t\t\tplace = EMSG;\n\t\t\tif (nonopt_end != -1) {\n\t\t\t\t/* do permutation, if we have to */\n\t\t\t\tpermute_args(nonopt_start, nonopt_end,\n\t\t\t\t optind, nargv);\n\t\t\t\toptind -= nonopt_end - nonopt_start;\n\t\t\t}\n\t\t\telse if (nonopt_start != -1) {\n\t\t\t\t/*\n\t\t\t\t * If we skipped non-options, set optind\n\t\t\t\t * to the first of them.\n\t\t\t\t */\n\t\t\t\toptind = nonopt_start;\n\t\t\t}\n\t\t\tnonopt_start = nonopt_end = -1;\n\t\t\treturn (-1);\n\t\t}\n\t\tif (*(place = nargv[optind]) != '-' ||\n\t\t (place[1] == '\\0' && strchr(options, '-') == NULL)) {\n\t\t\tplace = EMSG;\t\t/* found non-option */\n\t\t\tif (flags & FLAG_ALLARGS) {\n\t\t\t\t/*\n\t\t\t\t * GNU extension:\n\t\t\t\t * return non-option as argument to option 1\n\t\t\t\t */\n\t\t\t\toptarg = nargv[optind++];\n\t\t\t\treturn (INORDER);\n\t\t\t}\n\t\t\tif (!(flags & FLAG_PERMUTE)) {\n\t\t\t\t/*\n\t\t\t\t * If no permutation wanted, stop parsing\n\t\t\t\t * at first non-option.\n\t\t\t\t */\n\t\t\t\treturn (-1);\n\t\t\t}\n\t\t\t/* do permutation */\n\t\t\tif (nonopt_start == -1)\n\t\t\t\tnonopt_start = optind;\n\t\t\telse if (nonopt_end != -1) {\n\t\t\t\tpermute_args(nonopt_start, nonopt_end,\n\t\t\t\t optind, nargv);\n\t\t\t\tnonopt_start = optind -\n\t\t\t\t (nonopt_end - nonopt_start);\n\t\t\t\tnonopt_end = -1;\n\t\t\t}\n\t\t\toptind++;\n\t\t\t/* process next argument */\n\t\t\tgoto start;\n\t\t}\n\t\tif (nonopt_start != -1 && nonopt_end == -1)\n\t\t\tnonopt_end = optind;\n\n\t\t/*\n\t\t * If we have \"-\" do nothing, if \"--\" we are done.\n\t\t */\n\t\tif (place[1] != '\\0' && *++place == '-' && place[1] == '\\0') {\n\t\t\toptind++;\n\t\t\tplace = EMSG;\n\t\t\t/*\n\t\t\t * We found an option (--), so if we skipped\n\t\t\t * non-options, we have to permute.\n\t\t\t */\n\t\t\tif (nonopt_end != -1) {\n\t\t\t\tpermute_args(nonopt_start, nonopt_end,\n\t\t\t\t optind, nargv);\n\t\t\t\toptind -= nonopt_end - nonopt_start;\n\t\t\t}\n\t\t\tnonopt_start = nonopt_end = -1;\n\t\t\treturn (-1);\n\t\t}\n\t}\n\n\t/*\n\t * Check long options if:\n\t * 1) we were passed some\n\t * 2) the arg is not just \"-\"\n\t * 3) either the arg starts with -- we are getopt_long_only()\n\t */\n\tif (long_options != NULL && place != nargv[optind] &&\n\t (*place == '-' || (flags & FLAG_LONGONLY))) {\n\t\tshort_too = 0;\n\t\tif (*place == '-')\n\t\t\tplace++;\t\t/* --foo long option */\n\t\telse if (*place != ':' && strchr(options, *place) != NULL)\n\t\t\tshort_too = 1;\t\t/* could be short option too */\n\n\t\toptchar = parse_long_options(nargv, options, long_options,\n\t\t idx, short_too);\n\t\tif (optchar != -1) {\n\t\t\tplace = EMSG;\n\t\t\treturn (optchar);\n\t\t}\n\t}\n\n\tif ((optchar = (int)*place++) == (int)':' ||\n\t (optchar == (int)'-' && *place != '\\0') ||\n\t (oli = strchr(options, optchar)) == NULL) {\n\t\t/*\n\t\t * If the user specified \"-\" and '-' isn't listed in\n\t\t * options, return -1 (non-option) as per POSIX.\n\t\t * Otherwise, it is an unknown option character (or ':').\n\t\t */\n\t\tif (optchar == (int)'-' && *place == '\\0')\n\t\t\treturn (-1);\n\t\tif (!*place)\n\t\t\t++optind;\n\t\tif (PRINT_ERROR)\n\t\t\twarnx(illoptchar, optchar);\n\t\toptopt = optchar;\n\t\treturn (BADCH);\n\t}\n\tif (long_options != NULL && optchar == 'W' && oli[1] == ';') {\n\t\t/* -W long-option */\n\t\tif (*place)\t\t\t/* no space */\n\t\t\t/* NOTHING */;\n\t\telse if (++optind >= nargc) {\t/* no arg */\n\t\t\tplace = EMSG;\n\t\t\tif (PRINT_ERROR)\n\t\t\t\twarnx(recargchar, optchar);\n\t\t\toptopt = optchar;\n\t\t\treturn (BADARG);\n\t\t} else\t\t\t\t/* white space */\n\t\t\tplace = nargv[optind];\n\t\toptchar = parse_long_options(nargv, options, long_options,\n\t\t idx, 0);\n\t\tplace = EMSG;\n\t\treturn (optchar);\n\t}\n\tif (*++oli != ':') {\t\t\t/* doesn't take argument */\n\t\tif (!*place)\n\t\t\t++optind;\n\t} else {\t\t\t\t/* takes (optional) argument */\n\t\toptarg = NULL;\n\t\tif (*place)\t\t\t/* no white space */\n\t\t\toptarg = place;\n\t\telse if (oli[1] != ':') {\t/* arg not optional */\n\t\t\tif (++optind >= nargc) {\t/* no arg */\n\t\t\t\tplace = EMSG;\n\t\t\t\tif (PRINT_ERROR)\n\t\t\t\t\twarnx(recargchar, optchar);\n\t\t\t\toptopt = optchar;\n\t\t\t\treturn (BADARG);\n\t\t\t} else\n\t\t\t\toptarg = nargv[optind];\n\t\t}\n\t\tplace = EMSG;\n\t\t++optind;\n\t}\n\t/* dump back option letter */\n\treturn (optchar);\n}\n\n/*\n * getopt --\n *\tParse argc/argv argument vector.\n *\n * [eventually this will replace the BSD getopt]\n */\nint\ngetopt(int nargc, char * const *nargv, const char *options)\n{\n\n\t/*\n\t * We don't pass FLAG_PERMUTE to getopt_internal() since\n\t * the BSD getopt(3) (unlike GNU) has never done this.\n\t *\n\t * Furthermore, since many privileged programs call getopt()\n\t * before dropping privileges it makes sense to keep things\n\t * as simple (and bug-free) as possible.\n\t */\n\treturn (getopt_internal(nargc, nargv, options, NULL, NULL, 0));\n}\n\n#if 0\n/*\n * getopt_long --\n *\tParse argc/argv argument vector.\n */\nint\ngetopt_long(int nargc, char * const *nargv, const char *options,\n const struct option *long_options, int *idx)\n{\n\n\treturn (getopt_internal(nargc, nargv, options, long_options, idx,\n\t FLAG_PERMUTE));\n}\n\n/*\n * getopt_long_only --\n *\tParse argc/argv argument vector.\n */\nint\ngetopt_long_only(int nargc, char * const *nargv, const char *options,\n const struct option *long_options, int *idx)\n{\n\n\treturn (getopt_internal(nargc, nargv, options, long_options, idx,\n\t FLAG_PERMUTE|FLAG_LONGONLY));\n}\n#endif\n\n#endif /* !defined(HAVE_GETOPT) || !defined(HAVE_OPTRESET) */\n",
"sha256": "0486066fe70fb5a81d79971842f171e3bdcb570dbcab22ce51c1394235b8d21f"
},
".github/tools/external/tmux/xmalloc.c": {
"mode": "100644",
"encoding": "utf-8",
"data": "/* $OpenBSD$ */\n\n/*\n * Author: Tatu Ylonen <ylo@cs.hut.fi>\n * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland\n * All rights reserved\n * Versions of malloc and friends that check their results, and never return\n * failure (they call fatalx if they encounter an error).\n *\n * As far as I am concerned, the code I have written for this software\n * can be used freely for any purpose. Any derived versions of this\n * software must be clearly marked as such, and if the derived work is\n * incompatible with the protocol description in the RFC file, it must be\n * called by a name other than \"ssh\" or \"Secure Shell\".\n */\n\n#include <errno.h>\n#include <limits.h>\n#include <stdint.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include \"tmux.h\"\n\nvoid *\nxmalloc(size_t size)\n{\n\tvoid *ptr;\n\n\tif (size == 0)\n\t\tfatalx(\"xmalloc: zero size\");\n\tptr = malloc(size);\n\tif (ptr == NULL)\n\t\tfatalx(\"xmalloc: allocating %zu bytes: %s\",\n\t\t size, strerror(errno));\n\treturn ptr;\n}\n\nvoid *\nxcalloc(size_t nmemb, size_t size)\n{\n\tvoid *ptr;\n\n\tif (size == 0 || nmemb == 0)\n\t\tfatalx(\"xcalloc: zero size\");\n\tptr = calloc(nmemb, size);\n\tif (ptr == NULL)\n\t\tfatalx(\"xcalloc: allocating %zu * %zu bytes: %s\",\n\t\t nmemb, size, strerror(errno));\n\treturn ptr;\n}\n\nvoid *\nxrealloc(void *ptr, size_t size)\n{\n\treturn xreallocarray(ptr, 1, size);\n}\n\nvoid *\nxreallocarray(void *ptr, size_t nmemb, size_t size)\n{\n\tvoid *new_ptr;\n\n\tif (nmemb == 0 || size == 0)\n\t\tfatalx(\"xreallocarray: zero size\");\n\tnew_ptr = reallocarray(ptr, nmemb, size);\n\tif (new_ptr == NULL)\n\t\tfatalx(\"xreallocarray: allocating %zu * %zu bytes: %s\",\n\t\t nmemb, size, strerror(errno));\n\treturn new_ptr;\n}\n\nvoid *\nxrecallocarray(void *ptr, size_t oldnmemb, size_t nmemb, size_t size)\n{\n\tvoid *new_ptr;\n\n\tif (nmemb == 0 || size == 0)\n\t\tfatalx(\"xrecallocarray: zero size\");\n\tnew_ptr = recallocarray(ptr, oldnmemb, nmemb, size);\n\tif (new_ptr == NULL)\n\t\tfatalx(\"xrecallocarray: allocating %zu * %zu bytes: %s\",\n\t\t nmemb, size, strerror(errno));\n\treturn new_ptr;\n}\n\nchar *\nxstrdup(const char *str)\n{\n\tchar *cp;\n\n\tif ((cp = strdup(str)) == NULL)\n\t\tfatalx(\"xstrdup: %s\", strerror(errno));\n\treturn cp;\n}\n\nchar *\nxstrndup(const char *str, size_t maxlen)\n{\n\tchar *cp;\n\n\tif ((cp = strndup(str, maxlen)) == NULL)\n\t\tfatalx(\"xstrndup: %s\", strerror(errno));\n\treturn cp;\n}\n\nint\nxasprintf(char **ret, const char *fmt, ...)\n{\n\tva_list ap;\n\tint i;\n\n\tva_start(ap, fmt);\n\ti = xvasprintf(ret, fmt, ap);\n\tva_end(ap);\n\n\treturn i;\n}\n\nint\nxvasprintf(char **ret, const char *fmt, va_list ap)\n{\n\tint i;\n\n\ti = vasprintf(ret, fmt, ap);\n\n\tif (i == -1)\n\t\tfatalx(\"xasprintf: %s\", strerror(errno));\n\n\treturn i;\n}\n\nint\nxsnprintf(char *str, size_t len, const char *fmt, ...)\n{\n\tva_list ap;\n\tint i;\n\n\tva_start(ap, fmt);\n\ti = xvsnprintf(str, len, fmt, ap);\n\tva_end(ap);\n\n\treturn i;\n}\n\nint\nxvsnprintf(char *str, size_t len, const char *fmt, va_list ap)\n{\n\tint i;\n\n\tif (len > INT_MAX)\n\t\tfatalx(\"xsnprintf: len > INT_MAX\");\n\n\ti = vsnprintf(str, len, fmt, ap);\n\n\tif (i < 0 || i >= (int)len)\n\t\tfatalx(\"xsnprintf: overflow\");\n\n\treturn i;\n}\n",
"sha256": "8ed468e9903b8abf18d5d5b76d99f030713fc479d02dc107ec3dbaa3a01c702b"
},
".github/tools/external/tmux/logo/LICENSE": {
"mode": "100644",
"encoding": "utf-8",
"data": "Copyright (c) 2015, Jason Long <jason@jasonlong.me>\n\nPermission to use, copy, modify, and/or distribute this software for any\npurpose with or without fee is hereby granted, provided that the above\ncopyright notice and this permission notice appear in all copies.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\nWITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\nMERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\nANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\nWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\nACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\nOR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n",
"sha256": "5fdf604dee98da6f827ea924cf5ae19a9da31555d3814143f2cc6f8e7ee05752"
},
".github/tools/external/tmux/mdoc2man.awk": {
"mode": "100644",
"encoding": "utf-8",
"data": "#!/usr/bin/awk\n#\n# $Id: mdoc2man.awk,v 1.9 2009/10/24 00:52:42 dtucker Exp $\n#\n# Version history:\n# v4+ Adapted for OpenSSH Portable (see cvs Id and history)\n# v3, I put the program under a proper license\n# Dan Nelson <dnelson@allantgroup.com> added .An, .Aq and fixed a typo\n# v2, fixed to work on GNU awk --posix and MacOS X\n# v1, first attempt, didn't work on MacOS X\n#\n# Copyright (c) 2003 Peter Stuge <stuge-mdoc2man@cdy.org>\n#\n# Permission to use, copy, modify, and distribute this software for any\n# purpose with or without fee is hereby granted, provided that the above\n# copyright notice and this permission notice appear in all copies.\n#\n# THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n\n\nBEGIN {\n optlist=0\n oldoptlist=0\n nospace=0\n synopsis=0\n reference=0\n block=0\n ext=0\n extopt=0\n literal=0\n prenl=0\n breakw=0\n line=\"\"\n}\n\nfunction wtail() {\n retval=\"\"\n while(w<nwords) {\n if(length(retval))\n retval=retval OFS\n retval=retval words[++w]\n }\n return retval\n}\n\nfunction add(str) {\n for(;prenl;prenl--)\n line=line \"\\n\"\n line=line str\n}\n\n! /^\\./ {\n for(;prenl;prenl--)\n print \"\"\n print\n if(literal)\n print \".br\"\n next\n}\n\n/^\\.\\\\\"/ { next }\n\n{\n option=0\n parens=0\n angles=0\n sub(\"^\\\\.\",\"\")\n nwords=split($0,words)\n for(w=1;w<=nwords;w++) {\n skip=0\n if(match(words[w],\"^Li|Pf$\")) {\n skip=1\n } else if(match(words[w],\"^Xo$\")) {\n skip=1\n ext=1\n if(length(line)&&!(match(line,\" $\")||prenl))\n\tadd(OFS)\n } else if(match(words[w],\"^Xc$\")) {\n skip=1\n ext=0\n if(!extopt)\n\tprenl++\n w=nwords\n } else if(match(words[w],\"^Bd$\")) {\n skip=1\n if(match(words[w+1],\"-literal\")) {\n\tliteral=1\n\tprenl++\n\tw=nwords\n }\n } else if(match(words[w],\"^Ed$\")) {\n skip=1\n literal=0\n } else if(match(words[w],\"^Ns$\")) {\n skip=1\n if(!nospace)\n\tnospace=1\n sub(\" $\",\"\",line)\n } else if(match(words[w],\"^No$\")) {\n skip=1\n sub(\" $\",\"\",line)\n add(words[++w])\n } else if(match(words[w],\"^Dq$\")) {\n skip=1\n add(\"``\")\n add(words[++w])\n while(w<nwords&&!match(words[w+1],\"^[\\\\.,]\"))\n\tadd(OFS words[++w])\n add(\"''\")\n if(!nospace&&match(words[w+1],\"^[\\\\.,]\"))\n\tnospace=1\n } else if(match(words[w],\"^Sq|Ql$\")) {\n skip=1\n add(\"`\" words[++w] \"'\")\n if(!nospace&&match(words[w+1],\"^[\\\\.,]\"))\n\tnospace=1\n } else if(match(words[w],\"^Oo$\")) {\n skip=1\n extopt=1\n if(!nospace)\n\tnospace=1\n add(\"[\")\n } else if(match(words[w],\"^Oc$\")) {\n skip=1\n extopt=0\n add(\"]\")\n }\n if(!skip) {\n if(!nospace&&length(line)&&!(match(line,\" $\")||prenl))\n\tadd(OFS)\n if(nospace==1)\n\tnospace=0\n }\n if(match(words[w],\"^Dd$\")) {\n if(match(words[w+1],\"^\\\\$Mdocdate:\")) {\n w++;\n if(match(words[w+4],\"^\\\\$$\")) {\n words[w+4] = \"\"\n }\n }\n date=wtail()\n next\n } else if(match(words[w],\"^Dt$\")) {\n id=wtail()\n next\n } else if(match(words[w],\"^Ux$\")) {\n add(\"UNIX\")\n skip=1\n } else if(match(words[w],\"^Ox$\")) {\n add(\"OpenBSD\")\n skip=1\n } else if(match(words[w],\"^Os$\")) {\n add(\".TH \" id \" \\\"\" date \"\\\" \\\"\" wtail() \"\\\"\")\n } else if(match(words[w],\"^Sh$\")) {\n add(\".SH\")\n synopsis=match(words[w+1],\"SYNOPSIS\")\n } else if(match(words[w],\"^Xr$\")) {\n add(\"\\\\fB\" words[++w] \"\\\\fP(\" words[++w] \")\" words[++w])\n } else if(match(words[w],\"^Rs$\")) {\n split(\"\",refauthors)\n nrefauthors=0\n reftitle=\"\"\n refissue=\"\"\n refdate=\"\"\n refopt=\"\"\n refreport=\"\"\n reference=1\n next\n } else if(match(words[w],\"^Re$\")) {\n prenl++\n for(i=nrefauthors-1;i>0;i--) {\n\tadd(refauthors[i])\n\tif(i>1)\n\t add(\", \")\n }\n if(nrefauthors>1)\n\tadd(\" and \")\n if(nrefauthors>0)\n add(refauthors[0] \", \")\n add(\"\\\\fI\" reftitle \"\\\\fP\")\n if(length(refissue))\n\tadd(\", \" refissue)\n if(length(refreport)) {\n\tadd(\", \" refreport)\n }\n if(length(refdate))\n\tadd(\", \" refdate)\n if(length(refopt))\n\tadd(\", \" refopt)\n add(\".\")\n reference=0\n } else if(reference) {\n if(match(words[w],\"^%A$\")) { refauthors[nrefauthors++]=wtail() }\n if(match(words[w],\"^%T$\")) {\n\treftitle=wtail()\n\tsub(\"^\\\"\",\"\",reftitle)\n\tsub(\"\\\"$\",\"\",reftitle)\n }\n if(match(words[w],\"^%N$\")) { refissue=wtail() }\n if(match(words[w],\"^%D$\")) { refdate=wtail() }\n if(match(words[w],\"^%O$\")) { refopt=wtail() }\n if(match(words[w],\"^%R$\")) { refreport=wtail() }\n } else if(match(words[w],\"^Nm$\")) {\n if(synopsis) {\n\tadd(\".br\")\n\tprenl++\n }\n n=words[++w]\n if(!length(name))\n\tname=n\n if(!length(n))\n\tn=name\n add(\"\\\\fB\" n \"\\\\fP\")\n if(!nospace&&match(words[w+1],\"^[\\\\.,]\"))\n\tnospace=1\n } else if(match(words[w],\"^Nd$\")) {\n add(\"\\\\- \" wtail())\n } else if(match(words[w],\"^Fl$\")) {\n add(\"\\\\fB\\\\-\" words[++w] \"\\\\fP\")\n if(!nospace&&match(words[w+1],\"^[\\\\.,]\"))\n\tnospace=1\n } else if(match(words[w],\"^Ar$\")) {\n add(\"\\\\fI\")\n if(w==nwords)\n\tadd(\"file ...\\\\fP\")\n else {\n\tadd(words[++w] \"\\\\fP\")\n\twhile(match(words[w+1],\"^\\\\|$\"))\n\t add(OFS words[++w] \" \\\\fI\" words[++w] \"\\\\fP\")\n }\n if(!nospace&&match(words[w+1],\"^[\\\\.,]\"))\n\tnospace=1\n } else if(match(words[w],\"^Cm$\")) {\n add(\"\\\\fB\" words[++w] \"\\\\fP\")\n while(w<nwords&&match(words[w+1],\"^[\\\\.,:;)]\"))\n\tadd(words[++w])\n } else if(match(words[w],\"^Op$\")) {\n option=1\n if(!nospace)\n\tnospace=1\n add(\"[\")\n } else if(match(words[w],\"^Pp$\")) {\n prenl++\n } else if(match(words[w],\"^An$\")) {\n prenl++\n } else if(match(words[w],\"^Ss$\")) {\n add(\".SS\")\n } else if(match(words[w],\"^Pa$\")&&!option) {\n add(\"\\\\fI\")\n w++\n if(match(words[w],\"^\\\\.\"))\n\tadd(\"\\\\&\")\n add(words[w] \"\\\\fP\")\n while(w<nwords&&match(words[w+1],\"^[\\\\.,:;)]\"))\n\tadd(words[++w])\n } else if(match(words[w],\"^Dv$\")) {\n add(\".BR\")\n } else if(match(words[w],\"^Em|Ev$\")) {\n add(\".IR\")\n } else if(match(words[w],\"^Pq$\")) {\n add(\"(\")\n nospace=1\n parens=1\n } else if(match(words[w],\"^Aq$\")) {\n add(\"<\")\n nospace=1\n angles=1\n } else if(match(words[w],\"^S[xy]$\")) {\n add(\".B \" wtail())\n } else if(match(words[w],\"^Ic$\")) {\n plain=1\n add(\"\\\\fB\")\n while(w<nwords) {\n\tw++\n\tif(match(words[w],\"^Op$\")) {\n\t w++\n\t add(\"[\")\n\t words[nwords]=words[nwords] \"]\"\n\t}\n\tif(match(words[w],\"^Ar$\")) {\n\t add(\"\\\\fI\" words[++w] \"\\\\fP\")\n\t} else if(match(words[w],\"^[\\\\.,]\")) {\n\t sub(\" $\",\"\",line)\n\t if(plain) {\n\t add(\"\\\\fP\")\n\t plain=0\n\t }\n\t add(words[w])\n\t} else {\n\t if(!plain) {\n\t add(\"\\\\fB\")\n\t plain=1\n\t }\n\t add(words[w])\n\t}\n\tif(!nospace)\n\t add(OFS)\n }\n sub(\" $\",\"\",line)\n if(plain)\n\tadd(\"\\\\fP\")\n } else if(match(words[w],\"^Bl$\")) {\n oldoptlist=optlist\n if(match(words[w+1],\"-bullet\"))\n\toptlist=1\n else if(match(words[w+1],\"-enum\")) {\n\toptlist=2\n\tenum=0\n } else if(match(words[w+1],\"-tag\"))\n\toptlist=3\n else if(match(words[w+1],\"-item\"))\n\toptlist=4\n else if(match(words[w+1],\"-bullet\"))\n\toptlist=1\n w=nwords\n } else if(match(words[w],\"^El$\")) {\n optlist=oldoptlist\n } else if(match(words[w],\"^Bk$\")) {\n if(match(words[w+1],\"-words\")) {\n\tw++\n\tbreakw=1\n }\n } else if(match(words[w],\"^Ek$\")) {\n breakw=0\n } else if(match(words[w],\"^It$\")&&optlist) {\n if(optlist==1)\n\tadd(\".IP \\\\(bu\")\n else if(optlist==2)\n\tadd(\".IP \" ++enum \".\")\n else if(optlist==3) {\n\tadd(\".TP\")\n\tprenl++\n\tif(match(words[w+1],\"^Pa$|^Ev$\")) {\n\t add(\".B\")\n\t w++\n\t}\n } else if(optlist==4)\n\tadd(\".IP\")\n } else if(match(words[w],\"^Sm$\")) {\n if(match(words[w+1],\"off\"))\n\tnospace=2\n else if(match(words[w+1],\"on\"))\n\tnospace=0\n w++\n } else if(!skip) {\n add(words[w])\n }\n }\n if(match(line,\"^\\\\.[^a-zA-Z]\"))\n sub(\"^\\\\.\",\"\",line)\n if(parens)\n add(\")\")\n if(angles)\n add(\">\")\n if(option)\n add(\"]\")\n if(ext&&!extopt&&!match(line,\" $\"))\n add(OFS)\n if(!ext&&!extopt&&length(line)) {\n print line\n prenl=0\n line=\"\"\n }\n}\n",
"sha256": "602f3d31ffec414850e697b73f1885e967698ac0cbe8f09efd14800e55abe7ea"
},
".github/tools/external/tmux/tmux.1": {
"mode": "100644",
"encoding": "utf-8",
"data": ".\\\" $OpenBSD$\n.\\\"\n.\\\" Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>\n.\\\"\n.\\\" Permission to use, copy, modify, and distribute this software for any\n.\\\" purpose with or without fee is hereby granted, provided that the above\n.\\\" copyright notice and this permission notice appear in all copies.\n.\\\"\n.\\\" THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n.\\\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n.\\\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n.\\\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n.\\\" WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER\n.\\\" IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING\n.\\\" OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n.\\\"\n.Dd $Mdocdate$\n.Dt TMUX 1\n.Os\n.Sh NAME\n.Nm tmux\n.Nd terminal multiplexer\n.Sh SYNOPSIS\n.Nm tmux\n.Bk -words\n.Op Fl 2CDhlNuVv\n.Op Fl c Ar shell-command\n.Op Fl f Ar file\n.Op Fl L Ar socket-name\n.Op Fl S Ar socket-path\n.Op Fl T Ar features\n.Op Ar command Op Ar flags\n.Ek\n.Sh DESCRIPTION\n.Nm\nis a terminal multiplexer:\nit enables a number of terminals to be created, accessed, and\ncontrolled from a single screen.\n.Nm\nmay be detached from a screen\nand continue running in the background,\nthen later reattached.\n.Pp\nWhen\n.Nm\nis started, it creates a new\n.Em session\nwith a single\n.Em window\nand displays it on screen.\nA status line at the bottom of the screen\nshows information on the current session\nand is used to enter interactive commands.\n.Pp\nA session is a single collection of\n.Em pseudo terminals\nunder the management of\n.Nm .\nEach session has one or more\nwindows linked to it.\nA window occupies the entire screen\nand may be split into rectangular panes,\neach of which is a separate pseudo terminal\n(the\n.Xr pty 4\nmanual page documents the technical details of pseudo terminals).\nAny number of\n.Nm\ninstances may connect to the same session,\nand any number of windows may be present in the same session.\nOnce all sessions are killed,\n.Nm\nexits.\n.Pp\nEach session is persistent and will survive accidental disconnection\n(such as\n.Xr ssh 1\nconnection timeout) or intentional detaching (with the\n.Ql C-b d\nkey strokes).\n.Nm\nmay be reattached using:\n.Pp\n.Dl $ tmux attach\n.Pp\nIn\n.Nm ,\na session is displayed on screen by a\n.Em client\nand all sessions are managed by a single\n.Em server .\nThe server and each client are separate processes which communicate through a\nsocket in\n.Pa /tmp .\n.Pp\nThe options are as follows:\n.Bl -tag -width \"XXXXXXXXXXXX\"\n.It Fl 2\nForce\n.Nm\nto assume the terminal supports 256 colours.\nThis is equivalent to\n.Fl T Ar 256 .\n.It Fl C\nStart in control mode (see the\n.Sx CONTROL MODE\nsection).\nGiven twice\n.Xo ( Fl CC ) Xc\ndisables echo.\n.It Fl c Ar shell-command\nExecute\n.Ar shell-command\nusing the default shell.\nIf necessary, the\n.Nm\nserver will be started to retrieve the\n.Ic default-shell\noption.\nThis option is for compatibility with\n.Xr sh 1\nwhen\n.Nm\nis used as a login shell.\n.It Fl D\nDo not start the\n.Nm\nserver as a daemon.\nThis also turns the\n.Ic exit-empty\noption off.\nWith\n.Fl D ,\n.Ar command\nmay not be specified.\n.It Fl f Ar file\nSpecify an alternative configuration file.\nBy default,\n.Nm\nloads the system configuration file from\n.Pa @SYSCONFDIR@/tmux.conf ,\nif present, then looks for a user configuration file at\n.Pa \\[ti]/.tmux.conf\nor\n.Pa $XDG_CONFIG_HOME/tmux/tmux.conf .\n.Pp\nThe configuration file is a set of\n.Nm\ncommands which are executed in sequence when the server is first started.\n.Nm\nloads configuration files once when the server process has started.\nThe\n.Ic source-file\ncommand may be used to load a file later.\n.Pp\n.Nm\nshows any error messages from commands in configuration files in the first\nsession created, and continues to process the rest of the configuration file.\n.It Fl h\nPrint usage information and exit.\n.It Fl L Ar socket-name\n.Nm\nstores the server socket in a directory under\n.Ev TMUX_TMPDIR\nor\n.Pa /tmp\nif it is unset.\nThe default socket is named\n.Em default .\nThis option allows a different socket name to be specified, allowing several\nindependent\n.Nm\nservers to be run.\nUnlike\n.Fl S\na full path is not necessary: the sockets are all created in a directory\n.Pa tmux-UID\nunder the directory given by\n.Ev TMUX_TMPDIR\nor in\n.Pa /tmp .\nThe\n.Pa tmux-UID\ndirectory is created by\n.Nm\nand must not be world readable, writable or executable.\n.Pp\nIf the socket is accidentally removed, the\n.Dv SIGUSR1\nsignal may be sent to the\n.Nm\nserver process to recreate it (note that this will fail if any parent\ndirectories are missing).\n.It Fl l\nBehave as a login shell.\nThis flag currently has no effect and is for compatibility with other shells\nwhen using tmux as a login shell.\n.It Fl N\nDo not start the server even if the command would normally do so (for example\n.Ic new-session\nor\n.Ic start-server ) .\n.It Fl S Ar socket-path\nSpecify a full alternative path to the server socket.\nIf\n.Fl S\nis specified, the default socket directory is not used and any\n.Fl L\nflag is ignored.\n.It Fl T Ar features\nSet terminal features for the client.\nThis is a comma-separated list of features.\nSee the\n.Ic terminal-features\noption.\n.It Fl u\nWrite UTF-8 output to the terminal even if the first environment\nvariable of\n.Ev LC_ALL ,\n.Ev LC_CTYPE ,\nor\n.Ev LANG\nthat is set does not contain\n.Qq UTF-8\nor\n.Qq UTF8 .\n.It Fl V\nReport the\n.Nm\nversion.\n.It Fl v\nRequest verbose logging.\nLog messages will be saved into\n.Pa tmux-client-PID.log\nand\n.Pa tmux-server-PID.log\nfiles in the current directory, where\n.Em PID\nis the PID of the server or client process.\nIf\n.Fl v\nis specified twice, an additional\n.Pa tmux-out-PID.log\nfile is generated with a copy of everything\n.Nm\nwrites to the terminal.\n.Pp\nThe\n.Dv SIGUSR2\nsignal may be sent to the\n.Nm\nserver process to toggle logging between on (as if\n.Fl v\nwas given) and off.\n.It Ar command Op Ar flags\nThis specifies one of a set of commands used to control\n.Nm ,\nas described in the following sections.\nIf no commands are specified, the command in\n.Ic default-client-command\nis assumed, which defaults to\n.Ic new-session .\n.El\n.Sh DEFAULT KEY BINDINGS\n.Nm\nmay be controlled from an attached client by using a key combination of a\nprefix key,\n.Ql C-b\n(Ctrl-b) by default, followed by a command key.\n.Pp\nThe default command key bindings are:\n.Pp\n.Bl -tag -width \"XXXXXXXXXX\" -offset indent -compact\n.It C-b\nSend the prefix key (C-b) through to the application.\n.It C-o\nRotate the panes in the current window forwards.\n.It C-z\nSuspend the\n.Nm\nclient.\n.It !\nBreak the current pane out of the window.\n.It \\&\"\n.\\\" \"\nSplit the current pane into two, top and bottom.\n.It #\nList all paste buffers.\n.It $\nRename the current session.\n.It %\nSplit the current pane into two, left and right.\n.It &\nKill the current window.\n.It \\[aq]\nPrompt for a window index to select.\n.It \\&(\nSwitch the attached client to the previous session.\n.It \\&)\nSwitch the attached client to the next session.\n.It ,\nRename the current window.\n.It -\nDelete the most recently copied buffer of text.\n.It .\nPrompt for an index to move the current window.\n.It 0 to 9\nSelect windows 0 to 9.\n.It :\nEnter the\n.Nm\ncommand prompt.\n.It ;\nMove to the previously active pane.\n.It =\nChoose which buffer to paste interactively from a list.\n.It \\&?\nList all key bindings.\n.It D\nChoose a client to detach.\n.It L\nSwitch the attached client back to the last session.\n.It \\&[\nEnter copy mode to copy text or view the history.\n.It \\&]\nPaste the most recently copied buffer of text.\n.It c\nCreate a new window.\n.It d\nDetach the current client.\n.It f\nPrompt to search for text in open windows.\n.It i\nDisplay some information about the current window.\n.It l\nMove to the previously selected window.\n.It m\nMark the current pane (see\n.Ic select-pane\n.Fl m ) .\n.It M\nClear the marked pane.\n.It n\nChange to the next window.\n.It o\nSelect the next pane in the current window.\n.It p\nChange to the previous window.\n.It q\nBriefly display pane indexes.\n.It r\nForce redraw of the attached client.\n.It s\nSelect a new session for the attached client interactively.\n.It t\nShow the time.\n.It w\nChoose the current window interactively.\n.It x\nKill the current pane.\n.It z\nToggle zoom state of the current pane.\n.It {\nSwap the current pane with the previous pane.\n.It }\nSwap the current pane with the next pane.\n.It \\[ti]\nShow previous messages from\n.Nm ,\nif any.\n.It Page Up\nEnter copy mode and scroll one page up.\n.It Up, Down\n.It Left, Right\nChange to the pane above, below, to the left, or to the right of the current\npane.\n.It M-1 to M-7\nArrange panes in one of the seven preset layouts:\neven-horizontal, even-vertical,\nmain-horizontal, main-horizontal-mirrored,\nmain-vertical, main-vertical-mirrored,\nor tiled.\n.It Space\nArrange the current window in the next preset layout.\n.It M-n\nMove to the next window with a bell or activity marker.\n.It M-o\nRotate the panes in the current window backwards.\n.It M-p\nMove to the previous window with a bell or activity marker.\n.It C-Up, C-Down\n.It C-Left, C-Right\nResize the current pane in steps of one cell.\n.It M-Up, M-Down\n.It M-Left, M-Right\nResize the current pane in steps of five cells.\n.El\n.Pp\nKey bindings may be changed with the\n.Ic bind-key\nand\n.Ic unbind-key\ncommands.\n.Sh COMMAND PARSING AND EXECUTION\n.Nm\nsupports a large number of commands which can be used to control its\nbehaviour.\nEach command is named and can accept zero or more flags and arguments.\nThey may be bound to a key with the\n.Ic bind-key\ncommand or run from the shell prompt, a shell script, a configuration file or\nthe command prompt.\nFor example, the same\n.Ic set-option\ncommand run from the shell prompt, from\n.Pa \\[ti]/.tmux.conf\nand bound to a key may look like:\n.Bd -literal -offset indent\n$ tmux set-option -g status-style bg=cyan\n\nset-option -g status-style bg=cyan\n\nbind-key C set-option -g status-style bg=cyan\n.Ed\n.Pp\nHere, the command name is\n.Ql set-option ,\n.Ql Fl g\nis a flag and\n.Ql status-style\nand\n.Ql bg=cyan\nare arguments.\n.Pp\n.Nm\ndistinguishes between command parsing and execution.\nIn order to execute a command,\n.Nm\nneeds it to be split up into its name and arguments.\nThis is command parsing.\nIf a command is run from the shell, the shell parses it; from inside\n.Nm\nor from a configuration file,\n.Nm\ndoes.\nExamples of when\n.Nm\nparses commands are:\n.Bl -dash -offset indent\n.It\nin a configuration file;\n.It\ntyped at the command prompt (see\n.Ic command-prompt ) ;\n.It\ngiven to\n.Ic bind-key ;\n.It\npassed as arguments to\n.Ic if-shell\nor\n.Ic confirm-before .\n.El\n.Pp\nTo execute commands, each client has a\n.Ql command queue .\nA global command queue not attached to any client is used on startup\nfor configuration files like\n.Pa \\[ti]/.tmux.conf .\nParsed commands added to the queue are executed in order.\nSome commands, like\n.Ic if-shell\nand\n.Ic confirm-before ,\nparse their argument to create a new command which is inserted immediately\nafter themselves.\nThis means that arguments can be parsed twice or more - once when the parent\ncommand (such as\n.Ic if-shell )\nis parsed and again when it parses and executes its command.\nCommands like\n.Ic if-shell ,\n.Ic run-shell\nand\n.Ic display-panes\nstop execution of subsequent commands on the queue until something happens -\n.Ic if-shell\nand\n.Ic run-shell\nuntil a shell command finishes and\n.Ic display-panes\nuntil a key is pressed.\nFor example, the following commands:\n.Bd -literal -offset indent\nnew-session; new-window\nif-shell \"true\" \"split-window\"\nkill-session\n.Ed\n.Pp\nWill execute\n.Ic new-session ,\n.Ic new-window ,\n.Ic if-shell ,\nthe shell command\n.Xr true 1 ,\n.Ic split-window\nand\n.Ic kill-session\nin that order.\n.Pp\nThe\n.Sx COMMANDS\nsection lists the\n.Nm\ncommands and their arguments.\n.Sh PARSING SYNTAX\nThis section describes the syntax of commands parsed by\n.Nm ,\nfor example in a configuration file or at the command prompt.\nNote that when commands are entered into the shell, they are parsed by the shell\n- see for example\n.Xr ksh 1\nor\n.Xr csh 1 .\n.Pp\nEach command is terminated by a newline or a semicolon (;).\nCommands separated by semicolons together form a\n.Ql command sequence\n- if a command in the sequence encounters an error, no subsequent commands are\nexecuted.\n.Pp\nIt is recommended that a semicolon used as a command separator should be\nwritten as an individual token, for example from\n.Xr sh 1 :\n.Bd -literal -offset indent\n$ tmux neww \\\\; splitw\n.Ed\n.Pp\nOr:\n.Bd -literal -offset indent\n$ tmux neww \\[aq];\\[aq] splitw\n.Ed\n.Pp\nOr from the tmux command prompt:\n.Bd -literal -offset indent\nneww ; splitw\n.Ed\n.Pp\nHowever, a trailing semicolon is also interpreted as a command separator,\nfor example in these\n.Xr sh 1\ncommands:\n.Bd -literal -offset indent\n$ tmux neww\\e; splitw\n.Ed\n.Pp\nOr:\n.Bd -literal -offset indent\n$ tmux \\[aq]neww;\\[aq] splitw\n.Ed\n.Pp\nAs in these examples, when running tmux from the shell extra care must be taken\nto properly quote semicolons:\n.Bl -enum -offset Ds\n.It\nSemicolons that should be interpreted as a command separator\nshould be escaped according to the shell conventions.\nFor\n.Xr sh 1\nthis typically means quoted (such as\n.Ql neww \\[aq];\\[aq] splitw )\nor escaped (such as\n.Ql neww \\e; splitw ) .\n.It\nIndividual semicolons or trailing semicolons that should be interpreted as\narguments should be escaped twice: once according to the shell conventions and\na second time for\n.Nm ;\nfor example:\n.Bd -literal -offset indent\n$ tmux neww \\[aq]foo\\e;\\[aq] bar\n$ tmux neww foo\\e\\e\\e; bar\n.Ed\n.It\nSemicolons that are not individual tokens or trailing another token should only\nbe escaped once according to shell conventions; for example:\n.Bd -literal -offset indent\n$ tmux neww \\[aq]foo-;-bar\\[aq]\n$ tmux neww foo-\\e;-bar\n.Ed\n.El\n.Pp\nComments are marked by the unquoted # character - any remaining text after a\ncomment is ignored until the end of the line.\n.Pp\nIf the last character of a line is \\e, the line is joined with the following\nline (the \\e and the newline are completely removed).\nThis is called line continuation and applies both inside and outside quoted\nstrings and in comments, but not inside braces.\n.Pp\nCommand arguments may be specified as strings surrounded by single (\\[aq])\nquotes or double quotes (\\[dq]), or as command lists surrounded by braces ({}).\n.\\\" \"\nThis is required when the argument contains any special character.\nSingle and double quoted strings cannot span multiple lines except with line\ncontinuation.\nBraces can span multiple lines.\n.Pp\nOutside of quotes and inside double quotes, these replacements are performed:\n.Bl -dash -offset indent\n.It\nEnvironment variables preceded by $ are replaced with their value from the\nglobal environment (see the\n.Sx GLOBAL AND SESSION ENVIRONMENT\nsection).\n.It\nA leading \\[ti] or \\[ti]user is expanded to the home directory of the current or\nspecified user.\n.It\n\\euXXXX or \\euXXXXXXXX is replaced by the Unicode codepoint corresponding to\nthe given four or eight digit hexadecimal number.\n.It\nWhen preceded (escaped) by a \\e, the following characters are replaced: \\ee by\nthe escape character; \\er by a carriage return; \\en by a newline; and \\et by a\ntab.\n.It\n\\eooo is replaced by a character of the octal value ooo.\nThree octal digits are required, for example \\e001.\nThe largest valid character is \\e377.\n.It\nAny other characters preceded by \\e are replaced by themselves (that is, the \\e\nis removed) and are not treated as having any special meaning - so for example\n\\e; will not mark a command sequence and \\e$ will not expand an environment\nvariable.\n.El\n.Pp\nBraces are parsed as a configuration file (so conditions such as\n.Ql %if\nare processed) and then converted into a string.\nThey are designed to avoid the need for additional escaping when passing a\ngroup of\n.Nm\ncommands as an argument (for example to\n.Ic if-shell ) .\nThese two examples produce an identical command - note that no escaping is\nneeded when using {}:\n.Bd -literal -offset indent\nif-shell true {\n display -p \\[aq]brace-dollar-foo: }$foo\\[aq]\n}\n\nif-shell true \"display -p \\[aq]brace-dollar-foo: }\\e$foo\\[aq]\"\n.Ed\n.Pp\nBraces may be enclosed inside braces, for example:\n.Bd -literal -offset indent\nbind x if-shell \"true\" {\n if-shell \"true\" {\n display \"true!\"\n }\n}\n.Ed\n.Pp\nEnvironment variables may be set by using the syntax\n.Ql name=value ,\nfor example\n.Ql HOME=/home/user .\nVariables set during parsing are added to the global environment.\nA hidden variable may be set with\n.Ql %hidden ,\nfor example:\n.Bd -literal -offset indent\n%hidden MYVAR=42\n.Ed\n.Pp\nHidden variables are not passed to the environment of processes created\nby tmux.\nSee the\n.Sx GLOBAL AND SESSION ENVIRONMENT\nsection.\n.Pp\nCommands may be parsed conditionally by surrounding them with\n.Ql %if ,\n.Ql %elif ,\n.Ql %else\nand\n.Ql %endif .\nThe argument to\n.Ql %if\nand\n.Ql %elif\nis expanded as a format (see\n.Sx FORMATS )\nand if it evaluates to false (zero or empty), subsequent text is ignored until\nthe closing\n.Ql %elif ,\n.Ql %else\nor\n.Ql %endif .\nFor example:\n.Bd -literal -offset indent\n%if \"#{==:#{host},myhost}\"\nset -g status-style bg=red\n%elif \"#{==:#{host},myotherhost}\"\nset -g status-style bg=green\n%else\nset -g status-style bg=blue\n%endif\n.Ed\n.Pp\nWill change the status line to red if running on\n.Ql myhost ,\ngreen if running on\n.Ql myotherhost ,\nor blue if running on another host.\nConditionals may be given on one line, for example:\n.Bd -literal -offset indent\n%if #{==:#{host},myhost} set -g status-style bg=red %endif\n.Ed\n.Sh COMMANDS\nThis section describes the commands supported by\n.Nm .\nMost commands accept the optional\n.Fl t\n(and sometimes\n.Fl s )\nargument with one of\n.Ar target-client ,\n.Ar target-session ,\n.Ar target-window ,\nor\n.Ar target-pane .\nThese specify the client, session, window or pane which a command should affect.\n.Pp\n.Ar target-client\nshould be the name of the client,\ntypically the\n.Xr pty 4\nfile to which the client is connected, for example either of\n.Pa /dev/ttyp1\nor\n.Pa ttyp1\nfor the client attached to\n.Pa /dev/ttyp1 .\nIf no client is specified,\n.Nm\nattempts to work out the client currently in use; if that fails, an error is\nreported.\nClients may be listed with the\n.Ic list-clients\ncommand.\n.Pp\n.Ar target-session\nis tried as, in order:\n.Bl -enum -offset Ds\n.It\nA session ID prefixed with a $.\n.It\nAn exact name of a session (as listed by the\n.Ic list-sessions\ncommand).\n.It\nThe start of a session name, for example\n.Ql mysess\nwould match a session named\n.Ql mysession .\n.It\nA\n.Xr glob 7\npattern which is matched against the session name.\n.El\n.Pp\nIf the session name is prefixed with an\n.Ql = ,\nonly an exact match is accepted (so\n.Ql =mysess\nwill only match exactly\n.Ql mysess ,\nnot\n.Ql mysession ) .\n.Pp\nIf a single session is found, it is used as the target session; multiple matches\nproduce an error.\nIf a session is omitted, the current session is used if available; if no\ncurrent session is available, the most recently used is chosen.\n.Pp\n.Ar target-window\n(or\n.Ar src-window\nor\n.Ar dst-window )\nspecifies a window in the form\n.Em session Ns \\&: Ns Em window .\n.Em session\nfollows the same rules as for\n.Ar target-session ,\nand\n.Em window\nis looked for in order as:\n.Bl -enum -offset Ds\n.It\nA special token, listed below.\n.It\nA window index, for example\n.Ql mysession:1\nis window 1 in session\n.Ql mysession .\n.It\nA window ID, such as @1.\n.It\nAn exact window name, such as\n.Ql mysession:mywindow .\n.It\nThe start of a window name, such as\n.Ql mysession:mywin .\n.It\nAs a\n.Xr glob 7\npattern matched against the window name.\n.El\n.Pp\nLike sessions, a\n.Ql =\nprefix will do an exact match only.\nAn empty window name specifies the next unused index if appropriate (for\nexample the\n.Ic new-window\nand\n.Ic link-window\ncommands)\notherwise the current window in\n.Em session\nis chosen.\n.Pp\nThe following special tokens are available to indicate particular windows.\nEach has a single-character alternative form.\n.Bl -column \"XXXXXXXXXX\" \"X\"\n.It Sy \"Token\" Ta Sy \"\" Ta Sy \"Meaning\"\n.It Li \"{start}\" Ta \"^\" Ta \"The lowest-numbered window\"\n.It Li \"{end}\" Ta \"$\" Ta \"The highest-numbered window\"\n.It Li \"{last}\" Ta \"!\" Ta \"The last (previously current) window\"\n.It Li \"{next}\" Ta \"+\" Ta \"The next window by number\"\n.It Li \"{previous}\" Ta \"-\" Ta \"The previous window by number\"\n.It Li \"{current}\" Ta \"@\" Ta \"The current window\"\n.El\n.Pp\n.Ar target-pane\n(or\n.Ar src-pane\nor\n.Ar dst-pane )\nmay be a pane ID or takes a similar form to\n.Ar target-window\nbut with the optional addition of a period followed by a pane index or pane ID,\nfor example:\n.Ql mysession:mywindow.1 .\nIf the pane index is omitted, the currently active pane in the specified\nwindow is used.\nThe following special tokens are available for the pane index:\n.Bl -column \"XXXXXXXXXXXXXX\" \"X\"\n.It Sy \"Token\" Ta Sy \"\" Ta Sy \"Meaning\"\n.It Li \"{last}\" Ta \"!\" Ta \"The last (previously active) pane\"\n.It Li \"{next}\" Ta \"+\" Ta \"The next pane by number\"\n.It Li \"{previous}\" Ta \"-\" Ta \"The previous pane by number\"\n.It Li \"{top}\" Ta \"\" Ta \"The top pane\"\n.It Li \"{bottom}\" Ta \"\" Ta \"The bottom pane\"\n.It Li \"{left}\" Ta \"\" Ta \"The leftmost pane\"\n.It Li \"{right}\" Ta \"\" Ta \"The rightmost pane\"\n.It Li \"{top-left}\" Ta \"\" Ta \"The top-left pane\"\n.It Li \"{top-right}\" Ta \"\" Ta \"The top-right pane\"\n.It Li \"{bottom-left}\" Ta \"\" Ta \"The bottom-left pane\"\n.It Li \"{bottom-right}\" Ta \"\" Ta \"The bottom-right pane\"\n.It Li \"{up-of}\" Ta \"\" Ta \"The pane above the active pane\"\n.It Li \"{down-of}\" Ta \"\" Ta \"The pane below the active pane\"\n.It Li \"{left-of}\" Ta \"\" Ta \"The pane to the left of the active pane\"\n.It Li \"{right-of}\" Ta \"\" Ta \"The pane to the right of the active pane\"\n.It Li \"{active}\" Ta \"@\" Ta \"The active pane\"\n.El\n.Pp\nThe tokens\n.Ql +\nand\n.Ql -\nmay be followed by an offset, for example:\n.Bd -literal -offset indent\nselect-window -t:+2\n.Ed\n.Pp\nIn addition,\n.Em target-session ,\n.Em target-window\nor\n.Em target-pane\nmay consist entirely of the token\n.Ql {mouse}\n(alternative form\n.Ql = )\nto specify the session, window or pane where the most recent mouse event\noccurred (see the\n.Sx MOUSE SUPPORT\nsection)\nor\n.Ql {marked}\n(alternative form\n.Ql \\[ti] )\nto specify the marked pane (see\n.Ic select-pane\n.Fl m ) .\n.Pp\nSessions, window and panes are each numbered with a unique ID; session IDs are\nprefixed with a\n.Ql $ ,\nwindows with a\n.Ql @ ,\nand panes with a\n.Ql % .\nThese are unique and are unchanged for the life of the session, window or pane\nin the\n.Nm\nserver.\nThe pane ID is passed to the child process of the pane in the\n.Ev TMUX_PANE\nenvironment variable.\nIDs may be displayed using the\n.Ql session_id ,\n.Ql window_id ,\nor\n.Ql pane_id\nformats (see the\n.Sx FORMATS\nsection) and the\n.Ic display-message ,\n.Ic list-sessions ,\n.Ic list-windows\nor\n.Ic list-panes\ncommands.\n.Pp\n.Ar shell-command\narguments are\n.Xr sh 1\ncommands.\nThis may be a single argument passed to the shell, for example:\n.Bd -literal -offset indent\nnew-window \\[aq]vi \\[ti]/.tmux.conf\\[aq]\n.Ed\n.Pp\nWill run:\n.Bd -literal -offset indent\n/bin/sh -c \\[aq]vi \\[ti]/.tmux.conf\\[aq]\n.Ed\n.Pp\nAdditionally, the\n.Ic new-window ,\n.Ic new-session ,\n.Ic split-window ,\n.Ic respawn-window\nand\n.Ic respawn-pane\ncommands allow\n.Ar shell-command\nto be given as multiple arguments and executed directly (without\n.Ql sh -c ) .\nThis can avoid issues with shell quoting.\nFor example:\n.Bd -literal -offset indent\n$ tmux new-window vi \\[ti]/.tmux.conf\n.Ed\n.Pp\nWill run\n.Xr vi 1\ndirectly without invoking the shell.\n.Pp\n.Ar command\n.Op Ar argument ...\nrefers to a\n.Nm\ncommand, either passed with the command and arguments separately, for example:\n.Bd -literal -offset indent\nbind-key F1 set-option status off\n.Ed\n.Pp\nOr passed as a single string argument in\n.Pa .tmux.conf ,\nfor example:\n.Bd -literal -offset indent\nbind-key F1 { set-option status off }\n.Ed\n.Pp\nExample\n.Nm\ncommands include:\n.Bd -literal -offset indent\nrefresh-client -t/dev/ttyp2\n\nrename-session -tfirst newname\n\nset-option -wt:0 monitor-activity on\n\nnew-window ; split-window -d\n\nbind-key R source-file \\[ti]/.tmux.conf \\e; \\e\n\tdisplay-message \"source-file done\"\n.Ed\n.Pp\nOr from\n.Xr sh 1 :\n.Bd -literal -offset indent\n$ tmux kill-window -t :1\n\n$ tmux new-window \\e; split-window -d\n\n$ tmux new-session -d \\[aq]vi \\[ti]/.tmux.conf\\[aq] \\e; split-window -d \\e; attach\n.Ed\n.Sh CLIENTS AND SESSIONS\nThe\n.Nm\nserver manages clients, sessions, windows and panes.\nClients are attached to sessions to interact with them, either\nwhen they are created with the\n.Ic new-session\ncommand, or later with the\n.Ic attach-session\ncommand.\nEach session has one or more windows\n.Em linked\ninto it.\nWindows may be linked to multiple sessions and are made up of one or\nmore panes,\neach of which contains a pseudo terminal.\nCommands for creating, linking and otherwise manipulating windows\nare covered\nin the\n.Sx WINDOWS AND PANES\nsection.\n.Pp\nThe following commands are available to manage clients and sessions:\n.Bl -tag -width Ds\n.Tg attach\n.It Xo Ic attach-session\n.Op Fl dErx\n.Op Fl c Ar working-directory\n.Op Fl f Ar flags\n.Op Fl t Ar target-session\n.Xc\n.D1 Pq alias: Ic attach\nIf run from outside\n.Nm ,\nattach to\n.Ar target-session\nin the current terminal.\n.Ar target-session\nmust already exist - to create a new session, see the\n.Ic new-session\ncommand (with\n.Fl A\nto create or attach).\nIf used from inside, switch the currently attached session to\n.Ar target-session .\nIf\n.Fl d\nis specified, any other clients attached to the session are detached.\nIf\n.Fl x\nis given, send\n.Dv SIGHUP\nto the parent process of the client as well as\ndetaching the client, typically causing it to exit.\n.Fl f\nsets a comma-separated list of client flags.\nThe flags are:\n.Bl -tag -width Ds\n.It active-pane\nthe client has an independent active pane\n.It ignore-size\nthe client does not affect the size of other clients\n.It no-detach-on-destroy\ndo not detach the client when the session it is attached to is destroyed if\nthere are any other sessions\n.It no-output\nthe client does not receive pane output in control mode\n.It pause-after=seconds\noutput is paused once the pane is\n.Ar seconds\nbehind in control mode\n.It read-only\nthe client is read-only\n.It wait-exit\nwait for an empty line input before exiting in control mode\n.El\n.Pp\nA leading\n.Ql \\&!\nturns a flag off if the client is already attached.\n.Fl r\nis an alias for\n.Fl f\n.Ar read-only,ignore-size .\nWhen a client is read-only, only keys bound to the\n.Ic detach-client\nor\n.Ic switch-client\ncommands have any effect.\nA client with the\n.Ar active-pane\nflag allows the active pane to be selected independently of the window's active\npane used by clients without the flag.\nThis only affects the cursor position and commands issued from the client;\nother features such as hooks and styles continue to use the window's active\npane.\n.Pp\nIf no server is started,\n.Ic attach-session\nwill attempt to start it; this will fail unless sessions are created in the\nconfiguration file.\n.Pp\nThe\n.Ar target-session\nrules for\n.Ic attach-session\nare slightly adjusted: if\n.Nm\nneeds to select the most recently used session, it will prefer the most\nrecently used\n.Em unattached\nsession.\n.Pp\n.Fl c\nwill set the session working directory (used for new windows) to\n.Ar working-directory .\n.Pp\nIf\n.Fl E\nis used, the\n.Ic update-environment\noption will not be applied.\n.Tg detach\n.It Xo Ic detach-client\n.Op Fl aP\n.Op Fl E Ar shell-command\n.Op Fl s Ar target-session\n.Op Fl t Ar target-client\n.Xc\n.D1 Pq alias: Ic detach\nDetach the current client if bound to a key, the client specified with\n.Fl t ,\nor all clients currently attached to the session specified by\n.Fl s .\nThe\n.Fl a\noption kills all but the client given with\n.Fl t .\nIf\n.Fl P\nis given, send\n.Dv SIGHUP\nto the parent process of the client, typically causing it\nto exit.\nWith\n.Fl E ,\nrun\n.Ar shell-command\nto replace the client.\n.Tg has\n.It Ic has-session Op Fl t Ar target-session\n.D1 Pq alias: Ic has\nReport an error and exit with 1 if the specified session does not exist.\nIf it does exist, exit with 0.\n.It Ic kill-server\nKill the\n.Nm\nserver and clients and destroy all sessions.\n.It Xo Ic kill-session\n.Op Fl aC\n.Op Fl t Ar target-session\n.Xc\nDestroy the given session, closing any windows linked to it and no other\nsessions, and detaching all clients attached to it.\nIf\n.Fl a\nis given, all sessions but the specified one is killed.\nThe\n.Fl C\nflag clears alerts (bell, activity, or silence) in all windows linked to the\nsession.\n.Tg lsc\n.It Xo Ic list-clients\n.Op Fl r\n.Op Fl F Ar format\n.Op Fl f Ar filter\n.Op Fl O Ar sort-order\n.Op Fl t Ar target-session\n.Xc\n.D1 Pq alias: Ic lsc\nList all clients attached to the server.\n.Fl F\nspecifies the format of each line and\n.Fl f\na filter.\nOnly clients for which the filter is true are shown.\nSee the\n.Sx FORMATS\nsection.\n.Fl O\nspecifies the sort order: one of\n.Ql name ,\n.Ql size ,\n.Ql creation\n(time), or\n.Ql activity\n(time).\n.Fl r\nreverses the sort order.\nIf\n.Ar target-session\nis specified, list only clients connected to that session.\n.Tg lscm\n.It Xo Ic list-commands\n.Op Fl F Ar format\n.Op Ar command\n.Xc\n.D1 Pq alias: Ic lscm\nList the syntax of\n.Ar command\nor - if omitted - of all commands supported by\n.Nm .\n.Tg ls\n.It Xo Ic list-sessions\n.Op Fl r\n.Op Fl F Ar format\n.Op Fl f Ar filter\n.Op Fl O Ar sort-order\n.Xc\n.D1 Pq alias: Ic ls\nList all sessions managed by the server.\n.Fl F\nspecifies the format of each line and\n.Fl f\na filter.\nOnly sessions for which the filter is true are shown.\nSee the\n.Sx FORMATS\nsection.\n.Fl O\nspecifies the sort order: one of\n.Ql index ,\n.Ql name ,\n.Ql creation\n(time), or\n.Ql activity\n(time).\n.Fl r\nreverses the sort order.\n.Tg lockc\n.It Ic lock-client Op Fl t Ar target-client\n.D1 Pq alias: Ic lockc\nLock\n.Ar target-client ,\nsee the\n.Ic lock-server\ncommand.\n.Tg locks\n.It Ic lock-session Op Fl t Ar target-session\n.D1 Pq alias: Ic locks\nLock all clients attached to\n.Ar target-session .\n.Tg new\n.It Xo Ic new-session\n.Op Fl AdDEPX\n.Op Fl c Ar start-directory\n.Op Fl e Ar environment\n.Op Fl f Ar flags\n.Op Fl F Ar format\n.Op Fl n Ar window-name\n.Op Fl s Ar session-name\n.Op Fl t Ar group-name\n.Op Fl x Ar width\n.Op Fl y Ar height\n.Op Ar shell-command Op Ar argument ...\n.Xc\n.D1 Pq alias: Ic new\nCreate a new session with name\n.Ar session-name .\n.Pp\nThe new session is attached to the current terminal unless\n.Fl d\nis given.\n.Ar window-name\nand\n.Ar shell-command\nare the name of and shell command to execute in the initial window.\nWith\n.Fl d ,\nthe initial size comes from the global\n.Ic default-size\noption;\n.Fl x\nand\n.Fl y\ncan be used to specify a different size.\n.Ql -\nuses the size of the current client if any.\nIf\n.Fl x\nor\n.Fl y\nis given, the\n.Ic default-size\noption is set for the session.\n.Fl f\nsets a comma-separated list of client flags (see\n.Ic attach-session ) .\n.Pp\nIf run from a terminal, any\n.Xr termios 4\nspecial characters are saved and used for new windows in the new session.\n.Pp\nThe\n.Fl A\nflag makes\n.Ic new-session\nbehave like\n.Ic attach-session\nif\n.Ar session-name\nalready exists;\nif\n.Fl A\nis given,\n.Fl D\nbehaves like\n.Fl d\nto\n.Ic attach-session ,\nand\n.Fl X\nbehaves like\n.Fl x\nto\n.Ic attach-session .\n.Pp\nIf\n.Fl t\nis given, it specifies a\n.Ic session group .\nSessions in the same group share the same set of windows - new windows are\nlinked to all sessions in the group and any windows closed removed from all\nsessions.\nThe current and previous window and any session options remain independent and\nany session in a group may be killed without affecting the others.\nThe\n.Ar group-name\nargument may be:\n.Bl -enum -width Ds\n.It\nthe name of an existing group, in which case the new session is added to that\ngroup;\n.It\nthe name of an existing session - the new session is added to the same group\nas that session, creating a new group if necessary;\n.It\nthe name for a new group containing only the new session.\n.El\n.Pp\n.Fl n\nand\n.Ar shell-command\nare invalid if\n.Fl t\nis used.\n.Pp\nThe\n.Fl P\noption prints information about the new session after it has been created.\nBy default, it uses the format\n.Ql #{session_name}:\\&\nbut a different format may be specified with\n.Fl F .\n.Pp\nIf\n.Fl E\nis used, the\n.Ic update-environment\noption will not be applied.\n.Fl e\ntakes the form\n.Ql VARIABLE=value\nand sets an environment variable for the newly created session; it may be\nspecified multiple times.\n.Tg refresh\n.It Xo Ic refresh-client\n.Op Fl cDlLRSU\n.Op Fl A Ar pane:state\n.Op Fl B Ar name:what:format\n.Op Fl C Ar size\n.Op Fl f Ar flags\n.Op Fl r Ar pane:report\n.Op Fl t Ar target-client\n.Op Ar adjustment\n.Xc\n.D1 Pq alias: Ic refresh\nRefresh the current client if bound to a key, or a single client if one is given\nwith\n.Fl t .\nIf\n.Fl S\nis specified, only update the client's status line.\n.Pp\nThe\n.Fl U ,\n.Fl D ,\n.Fl L\n.Fl R ,\nand\n.Fl c\nflags allow the visible portion of a window which is larger than the client\nto be changed.\n.Fl U\nmoves the visible part up by\n.Ar adjustment\nrows and\n.Fl D\ndown,\n.Fl L\nleft by\n.Ar adjustment\ncolumns and\n.Fl R\nright.\n.Fl c\nreturns to tracking the cursor automatically.\nIf\n.Ar adjustment\nis omitted, 1 is used.\nNote that the visible position is a property of the client not of the\nwindow, changing the current window in the attached session will reset\nit.\n.Pp\n.Fl C\nsets the width and height of a control mode client or of a window for a\ncontrol mode client,\n.Ar size\nmust be one of\n.Ql widthxheight\nor\n.Ql window ID:widthxheight ,\nfor example\n.Ql 80x24\nor\n.Ql @0:80x24 .\n.Fl A\nallows a control mode client to trigger actions on a pane.\nThe argument is a pane ID (with leading\n.Ql % ) ,\na colon, then one of\n.Ql on ,\n.Ql off ,\n.Ql continue\nor\n.Ql pause .\nIf\n.Ql off ,\n.Nm\nwill not send output from the pane to the client and if all clients have turned\nthe pane off, will stop reading from the pane.\nIf\n.Ql continue ,\n.Nm\nwill return to sending output to the pane if it was paused (manually or with the\n.Ar pause-after\nflag).\nIf\n.Ql pause ,\n.Nm\nwill pause the pane.\n.Fl A\nmay be given multiple times for different panes.\n.Pp\n.Fl B\nsets a subscription to a format for a control mode client.\nThe argument is split into three items by colons:\n.Ar name\nis a name for the subscription;\n.Ar what\nis a type of item to subscribe to;\n.Ar format\nis the format.\nAfter a subscription is added, changes to the format are reported with the\n.Ic %subscription-changed\nnotification, at most once a second.\nIf only the name is given, the subscription is removed.\n.Ar what\nmay be empty to check the format only for the attached session, or one of:\na pane ID such as\n.Ql %0 ;\n.Ql %*\nfor all panes in the attached session;\na window ID such as\n.Ql @0 ;\nor\n.Ql @*\nfor all windows in the attached session.\n.Pp\n.Fl f\nsets a comma-separated list of client flags, see\n.Ic attach-session .\n.Fl r\nallows a control mode client to provide information about a pane via a report\n(such as the response to OSC 10).\nThe argument is a pane ID (with a leading\n.Ql % ) ,\na colon, then a report escape sequence.\n.Pp\n.Fl l\nrequests the clipboard from the client using the\n.Xr xterm 1\nescape sequence and stores it in a new paste buffer.\n.Pp\n.Fl L ,\n.Fl R ,\n.Fl U\nand\n.Fl D\nmove the visible portion of the window left, right, up or down\nby\n.Ar adjustment ,\nif the window is larger than the client.\n.Fl c\nresets so that the position follows the cursor.\nSee the\n.Ic window-size\noption.\n.Tg rename\n.It Xo Ic rename-session\n.Op Fl t Ar target-session\n.Ar new-name\n.Xc\n.D1 Pq alias: Ic rename\nRename the session to\n.Ar new-name .\n.It Xo Ic server-access\n.Op Fl adlrw\n.Op Ar user\n.Xc\nChange the access or read/write permission of\n.Ar user .\nThe user running the\n.Nm\nserver (its owner) and the root user cannot be changed and are always\npermitted access.\n.Pp\n.Fl a\nand\n.Fl d\nare used to give or revoke access for the specified user.\nIf the user is already attached, the\n.Fl d\nflag causes their clients to be detached.\n.Pp\n.Fl r\nand\n.Fl w\nchange the permissions for\n.Ar user :\n.Fl r\nmakes their clients read-only and\n.Fl w\nwritable.\n.Fl l\nlists current access permissions.\n.Pp\nBy default, the access list is empty and\n.Nm\ncreates sockets with file system permissions preventing access by any user\nother than the owner (and root).\nThese permissions must be changed manually.\nGreat care should be taken not to allow access to untrusted users even\nread-only.\n.Tg showmsgs\n.It Xo Ic show-messages\n.Op Fl JT\n.Op Fl t Ar target-client\n.Xc\n.D1 Pq alias: Ic showmsgs\nShow server messages or information.\nMessages are stored, up to a maximum of the limit set by the\n.Ar message-limit\nserver option.\n.Fl J\nand\n.Fl T\nshow debugging information about jobs and terminals.\n.Tg source\n.It Xo Ic source-file\n.Op Fl Fnqv\n.Op Fl t Ar target-pane\n.Ar path ...\n.Xc\n.D1 Pq alias: Ic source\nExecute commands from one or more files specified by\n.Ar path\n(which may be\n.Xr glob 7\npatterns).\nIf\n.Fl F\nis present, then\n.Ar path\nis expanded as a format.\nIf\n.Fl q\nis given, no error will be returned if\n.Ar path\ndoes not exist.\nWith\n.Fl n ,\nthe file is parsed but no commands are executed.\n.Fl v\nshows the parsed commands and line numbers if possible.\n.Tg start\n.It Ic start-server\n.D1 Pq alias: Ic start\nStart the\n.Nm\nserver, if not already running, without creating any sessions.\n.Pp\nNote that as by default the\n.Nm\nserver will exit with no sessions, this is only useful if a session is created\nin\n.Pa \\[ti]/.tmux.conf ,\n.Ic exit-empty\nis turned off, or another command is run as part of the same command sequence.\nFor example:\n.Bd -literal -offset indent\n$ tmux start \\\\; show -g\n.Ed\n.Tg suspendc\n.It Xo Ic suspend-client\n.Op Fl t Ar target-client\n.Xc\n.D1 Pq alias: Ic suspendc\nSuspend a client by sending\n.Dv SIGTSTP\n(tty stop).\n.Tg switchc\n.It Xo Ic switch-client\n.Op Fl ElnprZ\n.Op Fl c Ar target-client\n.Op Fl O Ar sort-order\n.Op Fl t Ar target-session\n.Op Fl T Ar key-table\n.Xc\n.D1 Pq alias: Ic switchc\nSwitch the current session for client\n.Ar target-client\nto\n.Ar target-session .\nAs a special case,\n.Fl t\nmay refer to a pane (a target that contains\n.Ql \\&: ,\n.Ql \\&.\nor\n.Ql % ) ,\nto change session, window and pane.\nIn that case,\n.Fl Z\nkeeps the window zoomed if it was zoomed.\nIf\n.Fl l ,\n.Fl n\nor\n.Fl p\nis used, the client is moved to the last, next or previous session\nrespectively.\n.Fl O\nmay be used with\n.Fl n\nand\n.Fl p\nto specify the field to sort on: one of\n.Ql name ,\n.Ql size ,\n.Ql creation\n(time), or\n.Ql activity\n(time).\n.Fl r\ntoggles the client\n.Ic read-only\nand\n.Ic ignore-size\nflags (see the\n.Ic attach-session\ncommand).\n.Pp\nIf\n.Fl E\nis used,\n.Ic update-environment\noption will not be applied.\n.Pp\n.Fl T\nsets the client's key table; the next key will be looked up using\n.Ar key-table .\nAfter that key, the client is returned to its default key table (normally\n.Em root ) .\nThis may be used to configure multiple prefix keys, or to bind commands to\nsequences of keys.\nFor example, to make typing\n.Ql abc\nrun the\n.Ic list-keys\ncommand:\n.Bd -literal -offset indent\nbind-key -Ttable2 c list-keys\nbind-key -Ttable1 b switch-client -Ttable2\nbind-key -Troot a switch-client -Ttable1\n.Ed\n.El\n.Sh WINDOWS AND PANES\nEach window displayed by\n.Nm\nmay be split into one or more\n.Em panes ;\neach pane takes up a certain area of the display and is a separate terminal.\nA window may be split into panes using the\n.Ic split-window\ncommand.\nWindows may be split horizontally (with the\n.Fl h\nflag) or vertically.\nPanes may be resized with the\n.Ic resize-pane\ncommand (bound to\n.Ql C-Up ,\n.Ql C-Down\n.Ql C-Left\nand\n.Ql C-Right\nby default), the current pane may be changed with the\n.Ic select-pane\ncommand and the\n.Ic rotate-window\nand\n.Ic swap-pane\ncommands may be used to swap panes without changing their position.\nPanes are numbered beginning from zero in the order they are created.\n.Pp\nBy default, a\n.Nm\npane permits direct access to the terminal contained in the pane.\nA pane may also be put into one of several modes:\n.Bl -dash -offset indent\n.It\nCopy mode, which permits a section of a window or its\nhistory to be copied to a\n.Em paste buffer\nfor later insertion into another window.\nThis mode is entered with the\n.Ic copy-mode\ncommand, bound to\n.Ql \\&[\nby default.\nCopied text can be pasted with the\n.Ic paste-buffer\ncommand, bound to\n.Ql \\&] .\n.It\nView mode, which is like copy mode but is entered when a command that produces\noutput, such as\n.Ic list-keys ,\nis executed from a key binding.\n.It\nChoose mode, which allows an item to be chosen from a list.\nThis may be a client, a session or window or pane, or a buffer.\nThis mode is entered with the\n.Ic choose-buffer ,\n.Ic choose-client\nand\n.Ic choose-tree\ncommands.\n.El\n.Pp\nIn copy mode an indicator is displayed in the top-right corner of the pane with\nthe current position and the number of lines in the history.\n.Pp\nCommands are sent to copy mode using the\n.Fl X\nflag to the\n.Ic send-keys\ncommand.\nWhen a key is pressed, copy mode automatically uses one of two key tables,\ndepending on the\n.Ic mode-keys\noption:\n.Ic copy-mode\nfor emacs, or\n.Ic copy-mode-vi\nfor vi.\nKey tables may be viewed with the\n.Ic list-keys\ncommand.\n.Pp\nThe following commands are supported in copy mode:\n.Bl -tag -width Ds\n.It Xo\n.Ic append-selection\n.Xc\nAppend the selection to the top paste buffer.\n.It Xo\n.Ic append-selection-and-cancel\n(vi: A)\n.Xc\nAppend the selection to the top paste buffer and exit copy mode.\n.It Xo\n.Ic back-to-indentation\n(vi: ^)\n(emacs: M-m)\n.Xc\nMove the cursor back to the indentation.\n.It Xo\n.Ic begin-selection\n(vi: Space)\n(emacs: C-Space)\n.Xc\nBegin selection.\n.It Xo\n.Ic bottom-line\n(vi: L)\n.Xc\nMove to the bottom line.\n.It Xo\n.Ic cancel\n(vi: q)\n(emacs: Escape)\n.Xc\nExit copy mode.\n.It Xo\n.Ic clear-selection\n(vi: Escape)\n(emacs: C-g)\n.Xc\nClear the current selection.\n.It Xo\n.Ic copy-end-of-line\n.Op Fl CP\n.Op Ar prefix\n.Xc\nCopy from the cursor position to the end of the line.\n.Ar prefix\nis used to name the new paste buffer.\n.It Xo\n.Ic copy-end-of-line-and-cancel\n.Op Fl CP\n.Op Ar prefix\n.Xc\nCopy from the cursor position and exit copy mode.\n.It Xo\n.Ic copy-pipe-end-of-line\n.Op Fl CP\n.Op Ar command\n.Op Ar prefix\n.Xc\nCopy from the cursor position to the end of the line and pipe the text to\n.Ar command .\n.Ar prefix\nis used to name the new paste buffer.\n.It Xo\n.Ic copy-pipe-end-of-line-and-cancel\n.Op Fl CP\n.Op Ar command\n.Op Ar prefix\n.Xc\nSame as\n.Ic copy-pipe-end-of-line\nbut also exit copy mode.\n.It Xo\n.Ic copy-line\n.Op Fl CP\n.Op Ar prefix\n.Xc\nCopy the entire line.\n.It Xo\n.Ic copy-line-and-cancel\n.Op Fl CP\n.Op Ar prefix\n.Xc\nCopy the entire line and exit copy mode.\n.It Xo\n.Ic copy-pipe-line\n.Op Fl CP\n.Op Ar command\n.Op Ar prefix\n.Xc\nCopy the entire line and pipe the text to\n.Ar command .\n.Ar prefix\nis used to name the new paste buffer.\n.It Xo\n.Ic copy-pipe-line-and-cancel\n.Op Fl CP\n.Op Ar command\n.Op Ar prefix\n.Xc\nSame as\n.Ic copy-pipe-line\nbut also exit copy mode.\n.It Xo\n.Ic copy-pipe\n.Op Fl CP\n.Op Ar command\n.Op Ar prefix\n.Xc\nCopy the selection, clear it and pipe its text to\n.Ar command .\n.Ar prefix\nis used to name the new paste buffer.\n.It Xo\n.Ic copy-pipe-no-clear\n.Op Fl CP\n.Op Ar command\n.Op Ar prefix\n.Xc\nSame as\n.Ic copy-pipe\nbut do not clear the selection.\n.It Xo\n.Ic copy-pipe-and-cancel\n.Op Fl CP\n.Op Ar command\n.Op Ar prefix\n.Xc\nSame as\n.Ic copy-pipe\nbut also exit copy mode.\n.It Xo\n.Ic copy-selection\n.Op Fl CP\n.Op Ar prefix\n.Xc\nCopies the current selection.\n.It Xo\n.Ic copy-selection-no-clear\n.Op Fl CP\n.Op Ar prefix\n.Xc\nSame as\n.Ic copy-selection\nbut do not clear the selection.\n.It Xo\n.Ic copy-selection-and-cancel\n.Op Fl CP\n.Op Ar prefix\n(vi: Enter)\n(emacs: M-w)\n.Xc\nCopy the current selection and exit copy mode.\n.It Xo\n.Ic cursor-down\n(vi: j)\n(emacs: Down)\n.Xc\nMove the cursor down.\n.It Xo\n.Ic cursor-down-and-cancel\n.Xc\nSame as\n.Ic cursor-down\nbut also exit copy mode if reaching the bottom.\n.It Xo\n.Ic cursor-left\n(vi: h)\n(emacs: Left)\n.Xc\nMove the cursor left.\n.It Xo\n.Ic cursor-right\n(vi: l)\n(emacs: Right)\n.Xc\nMove the cursor right.\n.It Xo\n.Ic cursor-up\n(vi: k)\n(emacs: Up)\n.Xc\nMove the cursor up.\n.It Xo\n.Ic cursor-centre-vertical\n(emacs: C-l)\n.Xc\nMoves the cursor to the vertical centre of the pane.\n.It Xo\n.Ic cursor-centre-horizontal\n(emacs: M-l)\n.Xc\nMoves the cursor to the horizontal centre of the pane.\n.It Xo\n.Ic end-of-line\n(vi: $)\n(emacs: C-e)\n.Xc\nMove the cursor to the end of the line.\n.It Xo\n.Ic goto-line\n.Ar line\n(vi: :)\n(emacs: g)\n.Xc\nMove the cursor to a specific line.\n.It Xo\n.Ic halfpage-down\n(vi: C-d)\n(emacs: M-Down)\n.Xc\nScroll down by half a page.\n.It Xo\n.Ic halfpage-down-and-cancel\n.Xc\nSame as\n.Ic halfpage-down\nbut also exit copy mode if reaching the bottom.\n.It Xo\n.Ic halfpage-up\n(vi: C-u)\n(emacs: M-Up)\n.Xc\nScroll up by half a page.\n.It Xo\n.Ic history-bottom\n(vi: G)\n(emacs: M->)\n.Xc\nScroll to the bottom of the history.\n.It Xo\n.Ic history-top\n(vi: g)\n(emacs: M-<)\n.Xc\nScroll to the top of the history.\n.It Xo\n.Ic jump-again\n(vi: ;)\n(emacs: ;)\n.Xc\nRepeat the last jump.\n.It Xo\n.Ic jump-backward\n.Ar to\n(vi: F)\n(emacs: F)\n.Xc\nJump backwards to the specified text.\n.It Xo\n.Ic jump-forward\n.Ar to\n(vi: f)\n(emacs: f)\n.Xc\nJump forward to the specified text.\n.It Xo\n.Ic jump-reverse\n(vi: ,)\n(emacs: ,)\n.Xc\nRepeat the last jump in the reverse direction (forward becomes backward and\nbackward becomes forward).\n.It Xo\n.Ic jump-to-backward\n.Ar to\n(vi: T)\n.Xc\nJump backwards, but one character less, placing the cursor on the character\nafter the target.\n.It Xo\n.Ic jump-to-forward\n.Ar to\n(vi: t)\n.Xc\nJump forward, but one character less, placing the cursor on the character\nbefore the target.\n.It Xo\n.Ic jump-to-mark\n(vi: M-x)\n(emacs: M-x)\n.Xc\nJump to the last mark.\n.It Xo\n.Ic middle-line\n(vi: M)\n(emacs: M-r)\n.Xc\nMove to the middle line.\n.It Xo\n.Ic next-matching-bracket\n(vi: %)\n(emacs: M-C-f)\n.Xc\nMove to the next matching bracket.\n.It Xo\n.Ic next-paragraph\n(vi: })\n(emacs: M-})\n.Xc\nMove to the next paragraph.\n.It Xo\n.Ic next-prompt\n.Op Fl o\n.Xc\nMove to the next prompt.\n.It Xo\n.Ic next-word\n(vi: w)\n.Xc\nMove to the next word.\n.It Xo\n.Ic next-word-end\n(vi: e)\n(emacs: M-f)\n.Xc\nMove to the end of the next word.\n.It Xo\n.Ic next-space\n(vi: W)\n.Xc\nSame as\n.Ic next-word\nbut use a space alone as the word separator.\n.It Xo\n.Ic next-space-end\n(vi: E)\n.Xc\nSame as\n.Ic next-word-end\nbut use a space alone as the word separator.\n.It Xo\n.Ic other-end\n(vi: o)\n.Xc\nSwitch at which end of the selection the cursor sits.\n.It Xo\n.Ic page-down\n(vi: C-f)\n(emacs: PageDown)\n.Xc\nScroll down by one page.\n.It Xo\n.Ic page-down-and-cancel\n.Xc\nSame as\n.Ic page-down\nbut also exit copy mode if reaching the bottom.\n.It Xo\n.Ic page-up\n(vi: C-b)\n(emacs: PageUp)\n.Xc\nScroll up by one page.\n.It Xo\n.Ic pipe\n.Op Ar command\n.Xc\nPipe the selected text to\n.Ar command\nand clear the selection.\n.It Xo\n.Ic pipe-no-clear\n.Op Ar command\n.Xc\nSame as\n.Ic pipe\nbut do not clear the selection.\n.It Xo\n.Ic pipe-and-cancel\n.Op Ar command\n.Op Ar prefix\n.Xc\nSame as\n.Ic pipe\nbut also exit copy mode.\n.It Xo\n.Ic previous-matching-bracket\n(emacs: M-C-b)\n.Xc\nMove to the previous matching bracket.\n.It Xo\n.Ic previous-paragraph\n(vi: {)\n(emacs: M-{)\n.Xc\nMove to the previous paragraph.\n.It Xo\n.Ic previous-prompt\n.Op Fl o\n.Xc\nMove to the previous prompt.\n.It Xo\n.Ic previous-word\n(vi: b)\n(emacs: M-b)\n.Xc\nMove to the previous word.\n.It Xo\n.Ic previous-space\n(vi: B)\n.Xc\nSame as\n.Ic previous-word\nbut use a space alone as the word separator.\n.It Xo\n.Ic rectangle-on\n.Xc\nTurn on rectangle selection mode.\n.It Xo\n.Ic rectangle-off\n.Xc\nTurn off rectangle selection mode.\n.It Xo\n.Ic rectangle-toggle\n(vi: v)\n(emacs: R)\n.Xc\nToggle rectangle selection mode.\n.It Xo\n.Ic refresh-from-pane\n(vi: r)\n(emacs: r)\n.Xc\nRefresh the content from the pane.\n.It Xo\n.Ic scroll-bottom\n.Xc\nScroll up until the current line is at the bottom while keeping the cursor on\nthat line.\n.It Xo\n.Ic scroll-down\n(vi: C-e)\n(emacs: C-Down)\n.Xc\nScroll down.\n.It Xo\n.Ic scroll-down-and-cancel\n.Xc\nSame as\n.Ic scroll-down\nbut also exit copy mode if the cursor reaches the bottom.\n.It Xo\n.Ic scroll-middle\n(vi: z)\n.Xc\nScroll so that the current line becomes the middle one while keeping the\ncursor on that line.\n.It Xo\n.Ic scroll-to-mouse\n.Xc\nScroll pane in copy-mode when bound to a mouse drag event.\n.Fl e\ncauses copy mode to exit when at the bottom.\n.Pp\n.It Xo\n.Ic scroll-top\n.Xc\nScroll down until the current line is at the top while keeping the cursor on\nthat line.\n.It Xo\n.Ic scroll-up\n(vi: C-y)\n(emacs: C-Up)\n.Xc\nScroll up.\n.It Xo\n.Ic search-again\n(vi: n)\n(emacs: n)\n.Xc\nRepeat the last search.\n.It Xo\n.Ic search-backward\n.Ar text\n(vi: ?)\n.Xc\nSearch backwards for the specified text.\n.It Xo\n.Ic search-backward-incremental\n.Ar text\n(emacs: C-r)\n.Xc\nSearch backwards incrementally for the specified text.\nIs expected to be used with the\n.Fl i\nflag to the\n.Ic command-prompt\ncommand.\n.It Xo\n.Ic search-backward-text\n.Ar text\n.Xc\nSearch backwards for the specified plain text.\n.It Xo\n.Ic search-forward\n.Ar text\n(vi: /)\n.Xc\nSearch forward for the specified text.\n.It Xo\n.Ic search-forward-incremental\n.Ar text\n(emacs: C-s)\n.Xc\nSearch forward incrementally for the specified text.\nIs expected to be used with the\n.Fl i\nflag to the\n.Ic command-prompt\ncommand.\n.It Xo\n.Ic search-forward-text\n.Ar text\n.Xc\nSearch forward for the specified plain text.\n.It Xo\n.Ic search-reverse\n(vi: N)\n(emacs: N)\n.Xc\nRepeat the last search in the reverse direction (forward becomes backward and\nbackward becomes forward).\n.It Xo\n.Ic select-line\n(vi: V)\n.Xc\nSelect the current line.\n.It Xo\n.Ic select-word\n.Xc\nSelect the current word.\n.It Xo\n.Ic selection-mode\n.Op Ic char | word | line\n.Xc\nChange the selection mode.\n.It Xo\n.Ic set-mark\n(vi: X)\n(emacs: X)\n.Xc\nMark the current line.\n.It Xo\n.Ic start-of-line\n(vi: 0)\n(emacs: C-a)\n.Xc\nMove the cursor to the start of the line.\n.It Xo\n.Ic stop-selection\n.Xc\nStop selecting without clearing the current selection.\n.It Xo\n.Ic toggle-position\n(vi: P)\n(emacs: P)\n.Xc\nToggle the visibility of the position indicator in the top right.\n.It Xo\n.Ic top-line\n(vi: H)\n(emacs: M-R)\n.Xc\nMove to the top line.\n.El\n.Pp\nThe search commands come in several varieties:\n.Ql search-forward\nand\n.Ql search-backward\nsearch for a regular expression;\nthe\n.Ql -text\nvariants search for a plain text string rather than a regular expression;\n.Ql -incremental\nperform an incremental search and expect to be used with the\n.Fl i\nflag to the\n.Ic command-prompt\ncommand.\n.Ql search-again\nrepeats the last search and\n.Ql search-reverse\ndoes the same but reverses the direction (forward becomes backward and backward\nbecomes forward).\n.Pp\nThe default incremental search key bindings,\n.Ql C-r\nand\n.Ql C-s ,\nare designed to emulate\n.Xr emacs 1 .\nWhen first pressed they allow a new search term to be entered; if pressed with\nan empty search term they repeat the previously used search term.\n.Pp\nThe\n.Ql next-prompt\nand\n.Ql previous-prompt\nmove between shell prompts, but require the shell to emit an escape sequence\n(\\e033]133;A\\e033\\e\\e) to tell\n.Nm\nwhere the prompts are located; if the shell does not do this, these commands\nwill do nothing.\nThe\n.Fl o\nflag jumps to the beginning of the command output instead of the shell prompt.\nFinding the beginning of command output requires the shell to emit an escape\nsequence (\\e033]133;C\\e033\\e\\e) to tell tmux where the output begins.\nIf the shell does not send these escape sequences, these commands do nothing.\n.Pp\nCopy commands may take an optional buffer prefix argument which is used\nto generate the buffer name (the default is\n.Ql buffer\nso buffers are named\n.Ql buffer0 ,\n.Ql buffer1\nand so on).\nPipe commands take a command argument which is the command to which the\nselected text is piped.\n.Ql copy-pipe\nvariants also copy the selection.\nThe\n.Ql -and-cancel\nvariants of some commands exit copy mode after they have completed (for copy\ncommands) or when the cursor reaches the bottom (for scrolling commands).\n.Ql -no-clear\nvariants do not clear the selection.\nAll the copy commands can take the\n.Fl C\nand\n.Fl P\nflags.\nThe\n.Fl C\nflag suppresses setting the terminal clipboard when copying, while the\n.Fl P\nflag suppresses adding a paste buffer with the text.\n.Pp\nThe next and previous word keys skip over whitespace and treat consecutive\nruns of either word separators or other letters as words.\nWord separators can be customized with the\n.Em word-separators\nsession option.\nNext word moves to the start of the next word, next word end to the end of the\nnext word and previous word to the start of the previous word.\nThe three next and previous space keys work similarly but use a space alone as\nthe word separator.\nSetting\n.Em word-separators\nto the empty string makes next/previous word equivalent to next/previous space.\n.Pp\nThe jump commands enable quick movement within a line.\nFor instance, typing\n.Ql f\nfollowed by\n.Ql /\nwill move the cursor to the next\n.Ql /\ncharacter on the current line.\nA\n.Ql \\&;\nwill then jump to the next occurrence.\n.Pp\nCommands in copy mode may be prefaced by an optional repeat count.\nWith vi key bindings, a prefix is entered using the number keys; with\nemacs, the Alt (meta) key and a number begins prefix entry.\n.Pp\nThe synopsis for the\n.Ic copy-mode\ncommand is:\n.Bl -tag -width Ds\n.It Xo Ic copy-mode\n.Op Fl deHMqSu\n.Op Fl s Ar src-pane\n.Op Fl t Ar target-pane\n.Xc\nEnter copy mode.\n.Pp\n.Fl u\nenters copy mode and scrolls one page up and\n.Fl d\none page down.\n.Fl H\nhides the position indicator in the top right.\n.Fl q\ncancels copy mode and any other modes.\n.Pp\n.Fl M\nbegins a mouse drag (only valid if bound to a mouse key binding, see\n.Sx MOUSE SUPPORT ) .\n.Pp\n.Fl S\nenters copy-mode and scrolls when bound to a mouse drag event; See\n.Ic scroll-to-mouse .\n.Pp\n.Fl s\ncopies from\n.Ar src-pane\ninstead of\n.Ar target-pane .\n.Pp\n.Fl e\nspecifies that scrolling to the bottom of the history (to the visible screen)\nshould exit copy mode.\nWhile in copy mode, pressing a key other than those used for scrolling will\ndisable this behaviour.\nThis is intended to allow fast scrolling through a pane's history, for\nexample with:\n.Bd -literal -offset indent\nbind PageUp copy-mode -eu\nbind PageDown copy-mode -ed\n.Ed\n.El\n.Pp\nA number of preset arrangements of panes are available, these are called\nlayouts.\nThese may be selected with the\n.Ic select-layout\ncommand or cycled with\n.Ic next-layout\n(bound to\n.Ql Space\nby default); once a layout is chosen, panes within it may be moved and resized\nas normal.\n.Pp\nThe following layouts are supported:\n.Bl -tag -width Ds\n.It Ic even-horizontal\nPanes are spread out evenly from left to right across the window.\n.It Ic even-vertical\nPanes are spread evenly from top to bottom.\n.It Ic main-horizontal\nA large (main) pane is shown at the top of the window and the remaining panes\nare spread from left to right in the leftover space at the bottom.\nUse the\n.Em main-pane-height\nwindow option to specify the height of the top pane.\n.It Ic main-horizontal-mirrored\nThe same as\n.Ic main-horizontal\nbut mirrored so the main pane is at the bottom of the window.\n.It Ic main-vertical\nA large (main) pane is shown on the left of the window and the remaining panes\nare spread from top to bottom in the leftover space on the right.\nUse the\n.Em main-pane-width\nwindow option to specify the width of the left pane.\n.It Ic main-vertical-mirrored\nThe same as\n.Ic main-vertical\nbut mirrored so the main pane is on the right of the window.\n.It Ic tiled\nPanes are spread out as evenly as possible over the window in both rows and\ncolumns.\n.El\n.Pp\nIn addition,\n.Ic select-layout\nmay be used to apply a previously used layout - the\n.Ic list-windows\ncommand displays the layout of each window in a form suitable for use with\n.Ic select-layout .\nFor example:\n.Bd -literal -offset indent\n$ tmux list-windows\n0: ksh [159x48]\n layout: bb62,159x48,0,0{79x48,0,0,79x48,80,0}\n$ tmux select-layout \\[aq]bb62,159x48,0,0{79x48,0,0,79x48,80,0}\\[aq]\n.Ed\n.Pp\n.Nm\nautomatically adjusts the size of the layout for the current window size.\nNote that a layout cannot be applied to a window with more panes than that\nfrom which the layout was originally defined.\n.Pp\nCommands related to windows and panes are as follows:\n.Bl -tag -width Ds\n.Tg breakp\n.It Xo Ic break-pane\n.Op Fl abdP\n.Op Fl F Ar format\n.Op Fl n Ar window-name\n.Op Fl s Ar src-pane\n.Op Fl t Ar dst-window\n.Xc\n.D1 Pq alias: Ic breakp\nBreak\n.Ar src-pane\noff from its containing window to make it the only pane in\n.Ar dst-window .\nWith\n.Fl a\nor\n.Fl b ,\nthe window is moved to the next index after or before (existing windows are\nmoved if necessary).\nIf\n.Fl d\nis given, the new window does not become the current window.\nThe\n.Fl P\noption prints information about the new window after it has been created.\nBy default, it uses the format\n.Ql #{session_name}:#{window_index}.#{pane_index}\nbut a different format may be specified with\n.Fl F .\n.Tg capturep\n.It Xo Ic capture-pane\n.Op Fl aepPqCJMN\n.Op Fl b Ar buffer-name\n.Op Fl E Ar end-line\n.Op Fl S Ar start-line\n.Op Fl t Ar target-pane\n.Xc\n.D1 Pq alias: Ic capturep\nCapture the contents of a pane.\nIf\n.Fl p\nis given, the output goes to stdout, otherwise to the buffer specified with\n.Fl b\nor a new buffer if omitted.\nIf\n.Fl a\nis given, the alternate screen is used, and the history is not accessible.\nIf no alternate screen exists, an error will be returned unless\n.Fl q\nis given.\nSimilarly, if the pane is in a mode,\n.Fl M\nuses the screen for the mode.\nIf\n.Fl e\nis given, the output includes escape sequences for text and background\nattributes.\n.Fl C\nalso escapes non-printable characters as octal \\exxx.\n.Fl T\nignores trailing positions that do not contain a character.\n.Fl N\npreserves trailing spaces at each line's end and\n.Fl J\npreserves trailing spaces and joins any wrapped lines;\n.Fl J\nimplies\n.Fl T .\n.Fl P\ncaptures only any output that the pane has received that is the beginning of an\nas-yet incomplete escape sequence.\n.Pp\n.Fl S\nand\n.Fl E\nspecify the starting and ending line numbers, zero is the first line of the\nvisible pane and negative numbers are lines in the history.\n.Ql -\nto\n.Fl S\nis the start of the history and to\n.Fl E\nthe end of the visible pane.\nThe default is to capture only the visible contents of the pane.\n.It Xo\n.Ic choose-client\n.Op Fl NryZ\n.Op Fl F Ar format\n.Op Fl f Ar filter\n.Op Fl K Ar key-format\n.Op Fl O Ar sort-order\n.Op Fl t Ar target-pane\n.Op Ar template\n.Xc\nPut a pane into client mode, allowing a client to be selected interactively from\na list.\nEach client is shown on one line.\nA shortcut key is shown on the left in brackets allowing for immediate choice,\nor the list may be navigated and an item chosen or otherwise manipulated using\nthe keys below.\n.Fl Z\nzooms the pane.\n.Fl y\ndisables any confirmation prompts.\nThe following keys may be used in client mode:\n.Bl -column \"Key\" \"Function\" -offset indent\n.It Sy \"Key\" Ta Sy \"Function\"\n.It Li \"Enter\" Ta \"Choose selected client\"\n.It Li \"Up\" Ta \"Select previous client\"\n.It Li \"Down\" Ta \"Select next client\"\n.It Li \"C-s\" Ta \"Search by name\"\n.It Li \"n\" Ta \"Repeat last search forwards\"\n.It Li \"N\" Ta \"Repeat last search backwards\"\n.It Li \"t\" Ta \"Toggle if client is tagged\"\n.It Li \"T\" Ta \"Tag no clients\"\n.It Li \"C-t\" Ta \"Tag all clients\"\n.It Li \"d\" Ta \"Detach selected client\"\n.It Li \"D\" Ta \"Detach tagged clients\"\n.It Li \"x\" Ta \"Detach and HUP selected client\"\n.It Li \"X\" Ta \"Detach and HUP tagged clients\"\n.It Li \"z\" Ta \"Suspend selected client\"\n.It Li \"Z\" Ta \"Suspend tagged clients\"\n.It Li \"f\" Ta \"Enter a format to filter items\"\n.It Li \"O\" Ta \"Change sort order\"\n.It Li \"r\" Ta \"Reverse sort order\"\n.It Li \"v\" Ta \"Toggle preview\"\n.It Li \"q\" Ta \"Exit mode\"\n.El\n.Pp\nAfter a client is chosen,\n.Ql %%\nis replaced by the client name in\n.Ar template\nand the result executed as a command.\nIf\n.Ar template\nis not given, \"detach-client -t \\[aq]%%\\[aq]\" is used.\n.Pp\n.Fl O\nspecifies the initial sort order: one of\n.Ql name ,\n.Ql size ,\n.Ql creation\n(time), or\n.Ql activity\n(time).\n.Fl r\nreverses the sort order.\n.Fl f\nspecifies an initial filter: the filter is a format - if it evaluates to zero,\nthe item in the list is not shown, otherwise it is shown.\nIf a filter would lead to an empty list, it is ignored.\n.Fl F\nspecifies the format for each item in the list and\n.Fl K\na format for each shortcut key; both are evaluated once for each line.\n.Fl N\nstarts without the preview or if given twice with the larger preview.\nThis command works only if at least one client is attached.\n.It Xo\n.Ic choose-tree\n.Op Fl GNrswyZ\n.Op Fl F Ar format\n.Op Fl f Ar filter\n.Op Fl K Ar key-format\n.Op Fl O Ar sort-order\n.Op Fl t Ar target-pane\n.Op Ar template\n.Xc\nPut a pane into tree mode, where a session, window or pane may be chosen\ninteractively from a tree.\nEach session, window or pane is shown on one line.\nA shortcut key is shown on the left in brackets allowing for immediate choice,\nor the tree may be navigated and an item chosen or otherwise manipulated using\nthe keys below.\n.Fl s\nstarts with sessions collapsed and\n.Fl w\nwith windows collapsed.\n.Fl Z\nzooms the pane.\n.Fl y\ndisables any confirmation prompts.\nThe following keys may be used in tree mode:\n.Bl -column \"Key\" \"Function\" -offset indent\n.It Sy \"Key\" Ta Sy \"Function\"\n.It Li \"Enter\" Ta \"Choose selected item\"\n.It Li \"Up\" Ta \"Select previous item\"\n.It Li \"Down\" Ta \"Select next item\"\n.It Li \"S-Up\" Ta \"Swap the current window with the previous one\"\n.It Li \"S-Down\" Ta \"Swap the current window with the next one\"\n.It Li \"+\" Ta \"Expand selected item\"\n.It Li \"-\" Ta \"Collapse selected item\"\n.It Li \"M-+\" Ta \"Expand all items\"\n.It Li \"M--\" Ta \"Collapse all items\"\n.It Li \"x\" Ta \"Kill selected item\"\n.It Li \"X\" Ta \"Kill tagged items\"\n.It Li \"<\" Ta \"Scroll list of previews left\"\n.It Li \">\" Ta \"Scroll list of previews right\"\n.It Li \"C-s\" Ta \"Search by name\"\n.It Li \"m\" Ta \"Set the marked pane\"\n.It Li \"M\" Ta \"Clear the marked pane\"\n.It Li \"n\" Ta \"Repeat last search forwards\"\n.It Li \"N\" Ta \"Repeat last search backwards\"\n.It Li \"t\" Ta \"Toggle if item is tagged\"\n.It Li \"T\" Ta \"Tag no items\"\n.It Li \"C-t\" Ta \"Tag all items\"\n.It Li \"\\&:\" Ta \"Run a command for each tagged item\"\n.It Li \"f\" Ta \"Enter a format to filter items\"\n.It Li \"H\" Ta \"Jump to the starting pane\"\n.It Li \"O\" Ta \"Change sort order\"\n.It Li \"r\" Ta \"Reverse sort order\"\n.It Li \"v\" Ta \"Toggle preview\"\n.It Li \"q\" Ta \"Exit mode\"\n.El\n.Pp\nAfter a session, window or pane is chosen, the first instance of\n.Ql %%\nand all instances of\n.Ql %1\nare replaced by the target in\n.Ar template\nand the result executed as a command.\nIf\n.Ar template\nis not given, \"switch-client -t \\[aq]%%\\[aq]\" is used.\n.Pp\n.Fl O\nspecifies the initial sort order: one of\n.Ql index ,\n.Ql name ,\nor\n.Ql activity\n(time).\n.Fl r\nreverses the sort order.\n.Fl f\nspecifies an initial filter: the filter is a format - if it evaluates to zero,\nthe item in the list is not shown, otherwise it is shown.\nIf a filter would lead to an empty list, it is ignored.\n.Fl F\nspecifies the format for each item in the tree and\n.Fl K\na format for each shortcut key; both are evaluated once for each line.\n.Fl N\nstarts without the preview or if given twice with the larger preview.\n.Fl G\nincludes all sessions in any session groups in the tree rather than only the\nfirst.\nThis command works only if at least one client is attached.\n.It Xo\n.Ic customize-mode\n.Op Fl NZ\n.Op Fl F Ar format\n.Op Fl f Ar filter\n.Op Fl t Ar target-pane\n.Op Ar template\n.Xc\nPut a pane into customize mode, where options and key bindings may be browsed\nand modified from a list.\nOption values in the list are shown for the active pane in the current window.\n.Fl Z\nzooms the pane.\nThe following keys may be used in customize mode:\n.Bl -column \"Key\" \"Function\" -offset indent\n.It Sy \"Key\" Ta Sy \"Function\"\n.It Li \"Enter\" Ta \"Set pane, window, session or global option value\"\n.It Li \"Up\" Ta \"Select previous item\"\n.It Li \"Down\" Ta \"Select next item\"\n.It Li \"+\" Ta \"Expand selected item\"\n.It Li \"-\" Ta \"Collapse selected item\"\n.It Li \"M-+\" Ta \"Expand all items\"\n.It Li \"M--\" Ta \"Collapse all items\"\n.It Li \"s\" Ta \"Set option value or key attribute\"\n.It Li \"S\" Ta \"Set global option value\"\n.It Li \"w\" Ta \"Set window option value, if option is for pane and window\"\n.It Li \"d\" Ta \"Set an option or key to the default\"\n.It Li \"D\" Ta \"Set tagged options and tagged keys to the default\"\n.It Li \"u\" Ta \"Unset an option (set to default value if global) or unbind a key\"\n.It Li \"U\" Ta \"Unset tagged options and unbind tagged keys\"\n.It Li \"C-s\" Ta \"Search by name\"\n.It Li \"n\" Ta \"Repeat last search forwards\"\n.It Li \"N\" Ta \"Repeat last search backwards\"\n.It Li \"t\" Ta \"Toggle if item is tagged\"\n.It Li \"T\" Ta \"Tag no items\"\n.It Li \"C-t\" Ta \"Tag all items\"\n.It Li \"f\" Ta \"Enter a format to filter items\"\n.It Li \"v\" Ta \"Toggle option information\"\n.It Li \"q\" Ta \"Exit mode\"\n.El\n.Pp\n.Fl f\nspecifies an initial filter: the filter is a format - if it evaluates to zero,\nthe item in the list is not shown, otherwise it is shown.\nIf a filter would lead to an empty list, it is ignored.\n.Fl F\nspecifies the format for each item in the tree.\n.Fl N\nstarts without the option information.\nThis command works only if at least one client is attached.\n.It Xo\n.Tg displayp\n.Ic display-panes\n.Op Fl bN\n.Op Fl d Ar duration\n.Op Fl t Ar target-client\n.Op Ar template\n.Xc\n.D1 Pq alias: Ic displayp\nDisplay a visible indicator of each pane shown by\n.Ar target-client .\nSee the\n.Ic display-panes-colour\nand\n.Ic display-panes-active-colour\nsession options.\nThe indicator is closed when a key is pressed (unless\n.Fl N\nis given) or\n.Ar duration\nmilliseconds have passed.\nIf\n.Fl d\nis not given,\n.Ic display-panes-time\nis used.\nA duration of zero means the indicator stays until a key is pressed.\nWhile the indicator is on screen, a pane may be chosen with the\n.Ql 0\nto\n.Ql 9\nkeys, which will cause\n.Ar template\nto be executed as a command with\n.Ql %%\nsubstituted by the pane ID.\nThe default\n.Ar template\nis \"select-pane -t \\[aq]%%\\[aq]\".\nWith\n.Fl b ,\nother commands are not blocked from running until the indicator is closed.\n.Tg findw\n.It Xo Ic find-window\n.Op Fl iCNrTZ\n.Op Fl t Ar target-pane\n.Ar match-string\n.Xc\n.D1 Pq alias: Ic findw\nSearch for a\n.Xr glob 7\npattern or, with\n.Fl r ,\nregular expression\n.Ar match-string\nin window names, titles, and visible content (but not history).\nThe flags control matching behavior:\n.Fl C\nmatches only visible window contents,\n.Fl N\nmatches only the window name and\n.Fl T\nmatches only the window title.\n.Fl i\nmakes the search ignore case.\nThe default is\n.Fl CNT .\n.Fl Z\nzooms the pane.\n.Pp\nThis command works only if at least one client is attached.\n.Tg joinp\n.It Xo Ic join-pane\n.Op Fl bdfhv\n.Op Fl l Ar size\n.Op Fl s Ar src-pane\n.Op Fl t Ar dst-pane\n.Xc\n.D1 Pq alias: Ic joinp\nLike\n.Ic split-window ,\nbut instead of splitting\n.Ar dst-pane\nand creating a new pane, split it and move\n.Ar src-pane\ninto the space.\nThis can be used to reverse\n.Ic break-pane .\nThe\n.Fl b\noption causes\n.Ar src-pane\nto be joined to left of or above\n.Ar dst-pane .\n.Pp\nIf\n.Fl s\nis omitted and a marked pane is present (see\n.Ic select-pane\n.Fl m ) ,\nthe marked pane is used rather than the current pane.\n.Tg killp\n.It Xo Ic kill-pane\n.Op Fl a\n.Op Fl t Ar target-pane\n.Xc\n.D1 Pq alias: Ic killp\nDestroy the given pane.\nIf no panes remain in the containing window, it is also destroyed.\nThe\n.Fl a\noption kills all but the pane given with\n.Fl t .\n.Tg killw\n.It Xo Ic kill-window\n.Op Fl a\n.Op Fl t Ar target-window\n.Xc\n.D1 Pq alias: Ic killw\nKill the current window or the window at\n.Ar target-window ,\nremoving it from any sessions to which it is linked.\nThe\n.Fl a\noption kills all but the window given with\n.Fl t .\n.Tg lastp\n.It Xo Ic last-pane\n.Op Fl deZ\n.Op Fl t Ar target-window\n.Xc\n.D1 Pq alias: Ic lastp\nSelect the last (previously selected) pane.\n.Fl Z\nkeeps the window zoomed if it was zoomed.\n.Fl e\nenables or\n.Fl d\ndisables input to the pane.\n.Tg last\n.It Ic last-window Op Fl t Ar target-session\n.D1 Pq alias: Ic last\nSelect the last (previously selected) window.\nIf no\n.Ar target-session\nis specified, select the last window of the current session.\n.Tg link\n.It Xo Ic link-window\n.Op Fl abdk\n.Op Fl s Ar src-window\n.Op Fl t Ar dst-window\n.Xc\n.D1 Pq alias: Ic linkw\nLink the window at\n.Ar src-window\nto the specified\n.Ar dst-window .\nIf\n.Ar dst-window\nis specified and no such window exists, the\n.Ar src-window\nis linked there.\nWith\n.Fl a\nor\n.Fl b\nthe window is moved to the next index after or before\n.Ar dst-window\n(existing windows are moved if necessary).\nIf\n.Fl k\nis given and\n.Ar dst-window\nexists, it is killed, otherwise an error is generated.\nIf\n.Fl d\nis given, the newly linked window is not selected.\n.Tg lsp\n.It Xo Ic list-panes\n.Op Fl ars\n.Op Fl F Ar format\n.Op Fl f Ar filter\n.Op Fl O Ar sort-order\n.Op Fl t Ar target\n.Xc\n.D1 Pq alias: Ic lsp\nIf\n.Fl a\nis given,\n.Ar target\nis ignored and all panes on the server are listed.\nIf\n.Fl s\nis given,\n.Ar target\nis a session (or the current session).\nIf neither is given,\n.Ar target\nis a window (or the current window).\n.Fl F\nspecifies the format of each line and\n.Fl f\na filter.\nOnly panes for which the filter is true are shown.\nSee the\n.Sx FORMATS\nsection.\n.Fl O\nspecifies the sort order: one of\n.Ql name ,\n.Ql creation\n(time), or\n.Ql activity\n(time).\n.Fl r\nreverses the sort order.\n.Tg lsw\n.It Xo Ic list-windows\n.Op Fl ar\n.Op Fl F Ar format\n.Op Fl f Ar filter\n.Op Fl O Ar sort-order\n.Op Fl t Ar target-session\n.Xc\n.D1 Pq alias: Ic lsw\nIf\n.Fl a\nis given, list all windows on the server.\nOtherwise, list windows in the current session or in\n.Ar target-session .\n.Fl F\nspecifies the format of each line and\n.Fl f\na filter.\nOnly windows for which the filter is true are shown.\nSee the\n.Sx FORMATS\nsection.\n.Fl O\nspecifies the sort order: one of\n.Ql index ,\n.Ql name ,\nor\n.Ql activity\n(time).\n.Fl r\nreverses the sort order.\n.Tg movep\n.It Xo Ic move-pane\n.Op Fl bdfhv\n.Op Fl l Ar size\n.Op Fl s Ar src-pane\n.Op Fl t Ar dst-pane\n.Xc\n.D1 Pq alias: Ic movep\nDoes the same as\n.Ic join-pane .\n.Tg movew\n.It Xo Ic move-window\n.Op Fl abrdk\n.Op Fl s Ar src-window\n.Op Fl t Ar dst-window\n.Xc\n.D1 Pq alias: Ic movew\nThis is similar to\n.Ic link-window ,\nexcept the window at\n.Ar src-window\nis moved to\n.Ar dst-window .\nWith\n.Fl r ,\nall windows in the session are renumbered in sequential order, respecting\nthe\n.Ic base-index\noption.\n.Tg neww\n.It Xo Ic new-window\n.Op Fl abdkPS\n.Op Fl c Ar start-directory\n.Op Fl e Ar environment\n.Op Fl F Ar format\n.Op Fl n Ar window-name\n.Op Fl t Ar target-window\n.Op Ar shell-command Op Ar argument ...\n.Xc\n.D1 Pq alias: Ic neww\nCreate a new window.\nWith\n.Fl a\nor\n.Fl b ,\nthe new window is inserted at the next index after or before the specified\n.Ar target-window ,\nmoving windows up if necessary;\notherwise\n.Ar target-window\nis the new window location.\n.Pp\nIf\n.Fl d\nis given, the session does not make the new window the current window.\n.Ar target-window\nrepresents the window to be created; if the target already exists an error is\nshown, unless the\n.Fl k\nflag is used, in which case it is destroyed.\nIf\n.Fl S\nis given and a window named\n.Ar window-name\nalready exists, it is selected (unless\n.Fl d\nis also given in which case the command does nothing).\n.Pp\n.Ar shell-command\nis the command to execute.\nIf\n.Ar shell-command\nis not specified, the value of the\n.Ic default-command\noption is used.\n.Fl c\nspecifies the working directory in which the new window is created.\n.Pp\nWhen the shell command completes, the window closes.\nSee the\n.Ic remain-on-exit\noption to change this behaviour.\n.Pp\n.Fl e\ntakes the form\n.Ql VARIABLE=value\nand sets an environment variable for the newly created window; it may be\nspecified multiple times.\n.Pp\nThe\n.Ev TERM\nenvironment variable must be set to\n.Ql screen\nor\n.Ql tmux\nfor all programs running\n.Em inside\n.Nm .\nNew windows will automatically have\n.Ql TERM=screen\nadded to their environment, but care must be taken not to reset this in shell\nstart-up files or by the\n.Fl e\noption.\n.Pp\nThe\n.Fl P\noption prints information about the new window after it has been created.\nBy default, it uses the format\n.Ql #{session_name}:#{window_index}\nbut a different format may be specified with\n.Fl F .\n.Tg nextl\n.It Ic next-layout Op Fl t Ar target-window\n.D1 Pq alias: Ic nextl\nMove a window to the next layout and rearrange the panes to fit.\n.Tg next\n.It Xo Ic next-window\n.Op Fl a\n.Op Fl t Ar target-session\n.Xc\n.D1 Pq alias: Ic next\nMove to the next window in the session.\nIf\n.Fl a\nis used, move to the next window with an alert.\n.Tg pipep\n.It Xo Ic pipe-pane\n.Op Fl IOo\n.Op Fl t Ar target-pane\n.Op Ar shell-command\n.Xc\n.D1 Pq alias: Ic pipep\nPipe output sent by the program in\n.Ar target-pane\nto a shell command or vice versa.\nA pane may only be connected to one command at a time, any existing pipe is\nclosed before\n.Ar shell-command\nis executed.\nThe\n.Ar shell-command\nstring may contain the special character sequences supported by the\n.Ic status-left\noption.\nIf no\n.Ar shell-command\nis given, the current pipe (if any) is closed.\n.Pp\n.Fl I\nand\n.Fl O\nspecify which of the\n.Ar shell-command\noutput streams are connected to the pane:\nwith\n.Fl I\nstdout is connected (so anything\n.Ar shell-command\nprints is written to the pane as if it were typed);\nwith\n.Fl O\nstdin is connected (so any output in the pane is piped to\n.Ar shell-command ) .\nBoth may be used together and if neither are specified,\n.Fl O\nis used.\n.Pp\nThe\n.Fl o\noption only opens a new pipe if no previous pipe exists, allowing a pipe to\nbe toggled with a single key, for example:\n.Bd -literal -offset indent\nbind-key C-p pipe-pane -o \\[aq]cat >>\\[ti]/output.#I-#P\\[aq]\n.Ed\n.Tg prevl\n.It Xo Ic previous-layout\n.Op Fl t Ar target-window\n.Xc\n.D1 Pq alias: Ic prevl\nMove to the previous layout in the session.\n.Tg prev\n.It Xo Ic previous-window\n.Op Fl a\n.Op Fl t Ar target-session\n.Xc\n.D1 Pq alias: Ic prev\nMove to the previous window in the session.\nWith\n.Fl a ,\nmove to the previous window with an alert.\n.Tg renamew\n.It Xo Ic rename-window\n.Op Fl t Ar target-window\n.Ar new-name\n.Xc\n.D1 Pq alias: Ic renamew\nRename the current window, or the window at\n.Ar target-window\nif specified, to\n.Ar new-name .\n.Tg resizep\n.It Xo Ic resize-pane\n.Op Fl DLMRTUZ\n.Op Fl t Ar target-pane\n.Op Fl x Ar width\n.Op Fl y Ar height\n.Op Ar adjustment\n.Xc\n.D1 Pq alias: Ic resizep\nResize a pane, up, down, left or right by\n.Ar adjustment\nwith\n.Fl U ,\n.Fl D ,\n.Fl L\nor\n.Fl R ,\nor\nto an absolute size\nwith\n.Fl x\nor\n.Fl y .\nThe\n.Ar adjustment\nis given in lines or columns (the default is 1);\n.Fl x\nand\n.Fl y\nmay be a given as a number of lines or columns or followed by\n.Ql %\nfor a percentage of the window size (for example\n.Ql -x 10% ) .\nWith\n.Fl Z ,\nthe active pane is toggled between zoomed (occupying the whole of the window)\nand unzoomed (its normal position in the layout).\n.Pp\n.Fl M\nbegins mouse resizing (only valid if bound to a mouse key binding, see\n.Sx MOUSE SUPPORT ) .\n.Pp\n.Fl T\ntrims all lines below the current cursor position and moves lines out of the\nhistory to replace them.\n.Tg resizew\n.It Xo Ic resize-window\n.Op Fl aADLRU\n.Op Fl t Ar target-window\n.Op Fl x Ar width\n.Op Fl y Ar height\n.Op Ar adjustment\n.Xc\n.D1 Pq alias: Ic resizew\nResize a window, up, down, left or right by\n.Ar adjustment\nwith\n.Fl U ,\n.Fl D ,\n.Fl L\nor\n.Fl R ,\nor\nto an absolute size\nwith\n.Fl x\nor\n.Fl y .\nThe\n.Ar adjustment\nis given in lines or cells (the default is 1).\n.Fl A\nsets the size of the largest session containing the window;\n.Fl a\nthe size of the smallest.\nThis command will automatically set\n.Ic window-size\nto manual in the window options.\n.Tg respawnp\n.It Xo Ic respawn-pane\n.Op Fl k\n.Op Fl c Ar start-directory\n.Op Fl e Ar environment\n.Op Fl t Ar target-pane\n.Op Ar shell-command Op Ar argument ...\n.Xc\n.D1 Pq alias: Ic respawnp\nReactivate a pane in which the command has exited (see the\n.Ic remain-on-exit\nwindow option).\nIf\n.Ar shell-command\nis not given, the command used when the pane was created or last respawned is\nexecuted.\nThe pane must be already inactive, unless\n.Fl k\nis given, in which case any existing command is killed.\n.Fl c\nspecifies a new working directory for the pane.\nThe\n.Fl e\noption has the same meaning as for the\n.Ic new-window\ncommand.\n.Tg respawnw\n.It Xo Ic respawn-window\n.Op Fl k\n.Op Fl c Ar start-directory\n.Op Fl e Ar environment\n.Op Fl t Ar target-window\n.Op Ar shell-command Op Ar argument ...\n.Xc\n.D1 Pq alias: Ic respawnw\nReactivate a window in which the command has exited (see the\n.Ic remain-on-exit\nwindow option).\nIf\n.Ar shell-command\nis not given, the command used when the window was created or last respawned is\nexecuted.\nThe window must be already inactive, unless\n.Fl k\nis given, in which case any existing command is killed.\n.Fl c\nspecifies a new working directory for the window.\nThe\n.Fl e\noption has the same meaning as for the\n.Ic new-window\ncommand.\n.Tg rotatew\n.It Xo Ic rotate-window\n.Op Fl DUZ\n.Op Fl t Ar target-window\n.Xc\n.D1 Pq alias: Ic rotatew\nRotate the positions of the panes within a window, either upward (numerically\nlower) with\n.Fl U\nor downward (numerically higher).\n.Fl Z\nkeeps the window zoomed if it was zoomed.\n.Tg selectl\n.It Xo Ic select-layout\n.Op Fl Enop\n.Op Fl t Ar target-pane\n.Op Ar layout-name\n.Xc\n.D1 Pq alias: Ic selectl\nChoose a specific layout for a window.\nIf\n.Ar layout-name\nis not given, the last preset layout used (if any) is reapplied.\n.Fl n\nand\n.Fl p\nare equivalent to the\n.Ic next-layout\nand\n.Ic previous-layout\ncommands.\n.Fl o\napplies the last set layout if possible (undoes the most recent layout change).\n.Fl E\nspreads the current pane and any panes next to it out evenly.\n.Tg selectp\n.It Xo Ic select-pane\n.Op Fl DdeLlMmRUZ\n.Op Fl T Ar title\n.Op Fl t Ar target-pane\n.Xc\n.D1 Pq alias: Ic selectp\nMake pane\n.Ar target-pane\nthe active pane in its window.\nIf one of\n.Fl D ,\n.Fl L ,\n.Fl R ,\nor\n.Fl U\nis used, respectively the pane below, to the left, to the right, or above the\ntarget pane is used.\n.Fl Z\nkeeps the window zoomed if it was zoomed.\n.Fl l\nis the same as using the\n.Ic last-pane\ncommand.\n.Fl e\nenables or\n.Fl d\ndisables input to the pane.\n.Fl T\nsets the pane title.\n.Pp\n.Fl m\nand\n.Fl M\nare used to set and clear the\n.Em marked pane .\nThere is one marked pane at a time, setting a new marked pane clears the last.\nThe marked pane is the default target for\n.Fl s\nto\n.Ic join-pane ,\n.Ic move-pane ,\n.Ic swap-pane\nand\n.Ic swap-window .\n.Tg selectw\n.It Xo Ic select-window\n.Op Fl lnpT\n.Op Fl t Ar target-window\n.Xc\n.D1 Pq alias: Ic selectw\nSelect the window at\n.Ar target-window .\n.Fl l ,\n.Fl n\nand\n.Fl p\nare equivalent to the\n.Ic last-window ,\n.Ic next-window\nand\n.Ic previous-window\ncommands.\nIf\n.Fl T\nis given and the selected window is already the current window,\nthe command behaves like\n.Ic last-window .\n.Tg splitw\n.It Xo Ic split-window\n.Op Fl bdfhIvPZ\n.Op Fl c Ar start-directory\n.Op Fl e Ar environment\n.Op Fl F Ar format\n.Op Fl l Ar size\n.Op Fl t Ar target-pane\n.Op Ar shell-command Op Ar argument ...\n.Xc\n.D1 Pq alias: Ic splitw\nCreate a new pane by splitting\n.Ar target-pane :\n.Fl h\ndoes a horizontal split and\n.Fl v\na vertical split; if neither is specified,\n.Fl v\nis assumed.\nThe\n.Fl l\noption specifies the size of the new pane in lines (for vertical split) or in\ncolumns (for horizontal split);\n.Ar size\nmay be followed by\n.Ql %\nto specify a percentage of the available space.\nThe\n.Fl b\noption causes the new pane to be created to the left of or above\n.Ar target-pane .\nThe\n.Fl f\noption creates a new pane spanning the full window height (with\n.Fl h )\nor full window width (with\n.Fl v ) ,\ninstead of splitting the active pane.\n.Fl Z\nzooms if the window is not zoomed, or keeps it zoomed if already zoomed.\n.Pp\nAn empty\n.Ar shell-command\n(\\[aq]\\[aq]) will create a pane with no command running in it.\nOutput can be sent to such a pane with the\n.Ic display-message\ncommand.\nThe\n.Fl I\nflag (if\n.Ar shell-command\nis not specified or empty)\nwill create an empty pane and forward any output from stdin to it.\nFor example:\n.Bd -literal -offset indent\n$ make 2>&1|tmux splitw -dI &\n.Ed\n.Pp\nAll other options have the same meaning as for the\n.Ic new-window\ncommand.\n.Tg swapp\n.It Xo Ic swap-pane\n.Op Fl dDUZ\n.Op Fl s Ar src-pane\n.Op Fl t Ar dst-pane\n.Xc\n.D1 Pq alias: Ic swapp\nSwap two panes.\nIf\n.Fl U\nis used and no source pane is specified with\n.Fl s ,\n.Ar dst-pane\nis swapped with the previous pane (before it numerically);\n.Fl D\nswaps with the next pane (after it numerically).\n.Fl d\ninstructs\n.Nm\nnot to change the active pane and\n.Fl Z\nkeeps the window zoomed if it was zoomed.\n.Pp\nIf\n.Fl s\nis omitted and a marked pane is present (see\n.Ic select-pane\n.Fl m ) ,\nthe marked pane is used rather than the current pane.\n.Tg swapw\n.It Xo Ic swap-window\n.Op Fl d\n.Op Fl s Ar src-window\n.Op Fl t Ar dst-window\n.Xc\n.D1 Pq alias: Ic swapw\nThis is similar to\n.Ic link-window ,\nexcept the source and destination windows are swapped.\nIt is an error if no window exists at\n.Ar src-window .\nIf\n.Fl d\nis given, the new window does not become the current window.\n.Pp\nIf\n.Fl s\nis omitted and a marked pane is present (see\n.Ic select-pane\n.Fl m ) ,\nthe window containing the marked pane is used rather than the current window.\n.Tg unlinkw\n.It Xo Ic unlink-window\n.Op Fl k\n.Op Fl t Ar target-window\n.Xc\n.D1 Pq alias: Ic unlinkw\nUnlink\n.Ar target-window .\nUnless\n.Fl k\nis given, a window may be unlinked only if it is linked to multiple sessions -\nwindows may not be linked to no sessions;\nif\n.Fl k\nis specified and the window is linked to only one session, it is unlinked and\ndestroyed.\n.El\n.Sh KEY BINDINGS\n.Nm\nallows a command to be bound to most keys, with or without a prefix key.\nWhen specifying keys, most represent themselves (for example\n.Ql A\nto\n.Ql Z ) .\nCtrl keys may be prefixed with\n.Ql C-\nor\n.Ql ^ ,\nShift keys with\n.Ql S-\nand Alt (meta) with\n.Ql M- .\nIn addition, the following special key names are accepted:\n.Em Up ,\n.Em Down ,\n.Em Left ,\n.Em Right ,\n.Em BSpace ,\n.Em BTab ,\n.Em DC\n(Delete),\n.Em End ,\n.Em Enter ,\n.Em Escape ,\n.Em F1\nto\n.Em F12 ,\n.Em Home ,\n.Em IC\n(Insert),\n.Em NPage/PageDown/PgDn ,\n.Em PPage/PageUp/PgUp ,\n.Em Space ,\nand\n.Em Tab .\nNote that to bind the\n.Ql \\&\"\nor\n.Ql \\[aq]\nkeys, quotation marks are necessary, for example:\n.Bd -literal -offset indent\nbind-key \\[aq]\"\\[aq] split-window\nbind-key \"\\[aq]\" new-window\n.Ed\n.Pp\nA command bound to the\n.Em Any\nkey will execute for all keys which do not have a more specific binding.\n.Pp\nCommands related to key bindings are as follows:\n.Bl -tag -width Ds\n.Tg bind\n.It Xo Ic bind-key\n.Op Fl nr\n.Op Fl N Ar note\n.Op Fl T Ar key-table\n.Ar key\n.Op Ar command Op Ar argument ...\n.Xc\n.D1 Pq alias: Ic bind\nBind key\n.Ar key\nto\n.Ar command .\nKeys are bound in a key table.\nBy default (without -T), the key is bound in\nthe\n.Em prefix\nkey table.\nThis table is used for keys pressed after the prefix key (for example,\nby default\n.Ql c\nis bound to\n.Ic new-window\nin the\n.Em prefix\ntable, so\n.Ql C-b c\ncreates a new window).\nThe\n.Em root\ntable is used for keys pressed without the prefix key: binding\n.Ql c\nto\n.Ic new-window\nin the\n.Em root\ntable (not recommended) means a plain\n.Ql c\nwill create a new window.\n.Fl n\nis an alias\nfor\n.Fl T Ar root .\nKeys may also be bound in custom key tables and the\n.Ic switch-client\n.Fl T\ncommand used to switch to them from a key binding.\nThe\n.Fl r\nflag indicates this key may repeat, see the\n.Ic initial-repeat-time\nand\n.Ic repeat-time\noptions.\n.Fl N\nattaches a note to the key (shown with\n.Ic list-keys\n.Fl N ) ,\nwhich can be cleared by passing an empty string.\nThe\n.Fl r\nand\n.Fl N\nflags can be used without\n.Ar command\nto alter an existing binding.\n.Pp\nTo view the default bindings and possible commands, see the\n.Ic list-keys\ncommand.\n.Tg lsk\n.It Xo Ic list-keys\n.Op Fl 1aN\n.Op Fl P Ar prefix-string\n.Op Fl T Ar key-table\n.Op Ar key\n.Xc\n.D1 Pq alias: Ic lsk\nList key bindings.\nThere are two forms: the default lists keys as\n.Ic bind-key\ncommands;\n.Fl N\nlists only keys with attached notes and shows only the key and note for each\nkey.\n.Pp\nWith the default form, all key tables are listed by default.\n.Fl T\nlists only keys in\n.Ar key-table .\n.Pp\nWith the\n.Fl N\nform, only keys in the\n.Em root\nand\n.Em prefix\nkey tables are listed by default;\n.Fl T\nalso lists only keys in\n.Ar key-table .\n.Fl P\nspecifies a prefix to print before each key and\n.Fl 1\nlists only the first matching key.\n.Fl a\nlists the command for keys that do not have a note rather than skipping them.\n.Tg send\n.It Xo Ic send-keys\n.Op Fl FHKlMRX\n.Op Fl c Ar target-client\n.Op Fl N Ar repeat-count\n.Op Fl t Ar target-pane\n.Op Ar key ...\n.Xc\n.D1 Pq alias: Ic send\nSend a key or keys to a window or client.\nEach argument\n.Ar key\nis the name of the key (such as\n.Ql C-a\nor\n.Ql NPage )\nto send; if the string is not recognised as a key, it is sent as a series of\ncharacters.\nIf\n.Fl K\nis given, keys are sent to\n.Ar target-client ,\nso they are looked up in the client's key table, rather than to\n.Ar target-pane .\nAll arguments are sent sequentially from first to last.\nIf no keys are given and the command is bound to a key, then that key is used.\n.Pp\nThe\n.Fl l\nflag disables key name lookup and processes the keys as literal UTF-8\ncharacters.\nThe\n.Fl H\nflag expects each key to be a hexadecimal number for an ASCII character.\n.Pp\nThe\n.Fl R\nflag causes the terminal state to be reset.\n.Pp\n.Fl M\npasses through a mouse event (only valid if bound to a mouse key binding, see\n.Sx MOUSE SUPPORT ) .\n.Pp\n.Fl X\nis used to send a command into copy mode - see\nthe\n.Sx WINDOWS AND PANES\nsection.\n.Fl N\nspecifies a repeat count and\n.Fl F\nexpands formats in arguments where appropriate.\n.It Xo Ic send-prefix\n.Op Fl 2\n.Op Fl t Ar target-pane\n.Xc\nSend the prefix key, or with\n.Fl 2\nthe secondary prefix key, to a window as if it was pressed.\n.Tg unbind\n.It Xo Ic unbind-key\n.Op Fl anq\n.Op Fl T Ar key-table\n.Ar key\n.Xc\n.D1 Pq alias: Ic unbind\nUnbind the command bound to\n.Ar key .\n.Fl n\nand\n.Fl T\nare the same as for\n.Ic bind-key .\nIf\n.Fl a\nis present, all key bindings are removed.\nThe\n.Fl q\noption prevents errors being returned.\n.El\n.Sh OPTIONS\nThe appearance and behaviour of\n.Nm\nmay be modified by changing the value of various options.\nEach option belongs to one or multiple scopes\n.Po\n.Em server ,\n.Em session ,\n.Em window ,\nand\n.Em pane\n.Pc and has a type\n.Po\n.Em string ,\n.Em number ,\n.Em key ,\n.Em colour ,\n.Em flag ,\n.Em choice ,\nor\n.Em command\n.Pc . Values of\n.Em flag Ns -type\noptions may be one of:\n.Ic 1 ,\n.Ic on ,\n.Ic yes ,\n.Ic 0 ,\n.Ic off ,\nor\n.Ic no ;\nfor possible\n.Em choice\nvalues, see the respective option; for\n.Em key\noptions, the\n.Sx KEY BINDINGS\nsection; and for\n.Em colour\noptions, the\n.Sx STYLES\nsection.\n.Pp\nThe\n.Nm\nserver has a set of global server options which do not apply to any particular\nwindow or session or pane.\nThese are altered with the\n.Ic set-option\n.Fl s\ncommand, or displayed with the\n.Ic show-options\n.Fl s\ncommand.\n.Pp\nIn addition, each individual session may have a set of session options, and\nthere is a separate set of global session options.\nSessions which do not have a particular option configured inherit the value\nfrom the global session options.\nSession options are set or unset with the\n.Ic set-option\ncommand and may be listed with the\n.Ic show-options\ncommand.\nThe available server and session options are listed under the\n.Ic set-option\ncommand.\n.Pp\nSimilarly, a set of window options is attached to each window and a set of pane\noptions to each pane.\nPane options inherit from window options.\nThis means any pane option may be set as a window option to apply the option to\nall panes in the window without the option set, for example these commands will\nset the background colour to red for all panes except pane 0:\n.Bd -literal -offset indent\nset -w window-style bg=red\nset -pt:.0 window-style bg=blue\n.Ed\n.Pp\nThere is also a set of global window options from which any unset window or\npane options are inherited.\nWindow and pane options are altered with\n.Ic set-option\n.Fl w\nand\n.Fl p\ncommands and displayed with\n.Ic show-option\n.Fl w\nand\n.Fl p .\n.Pp\n.Nm\nalso supports user options which are prefixed with a\n.Ql \\&@ .\nUser options may have any name, so long as they are prefixed with\n.Ql \\&@ ,\nand be set to any string.\nFor example:\n.Bd -literal -offset indent\n$ tmux set -wq @foo \"abc123\"\n$ tmux show -wv @foo\nabc123\n.Ed\n.Pp\nOptions are managed with these commands:\n.Bl -tag -width Ds\n.Tg set\n.It Xo Ic set-option\n.Op Fl aFgopqsuUw\n.Op Fl t Ar target-pane\n.Ar option\n.Op Ar value\n.Xc\n.D1 Pq alias: Ic set\nSet a pane option with\n.Fl p ,\na window option with\n.Fl w ,\na server option with\n.Fl s ,\notherwise a session option.\nIf the option is not a user option,\n.Fl w\nor\n.Fl s\nmay be unnecessary -\n.Nm\nwill infer the scope from the option name, assuming\n.Fl w\nfor pane options.\nIf\n.Fl g\nis given, the global session or window option is set.\n.Pp\n.Fl F\nexpands formats in the option value.\nThe\n.Fl u\nflag unsets an option, so a session inherits the option from the global\noptions (or with\n.Fl g ,\nrestores a global option to the default).\n.Fl U\nunsets an option (like\n.Fl u )\nbut if the option is a pane option also unsets the option on any panes in the\nwindow.\n.Ar value\ndepends on the option and its type and can be omitted for flag and choice\noptions to toggle its value (choice options toggle between the first two\nchoices).\n.Pp\nThe\n.Fl o\nflag prevents setting an option that is already set and the\n.Fl q\nflag suppresses errors about unknown or ambiguous options.\n.Pp\nWith\n.Fl a ,\nand if the option expects a string or a style,\n.Ar value\nis appended to the existing setting.\nFor example:\n.Bd -literal -offset indent\nset -g status-left \"foo\"\nset -ag status-left \"bar\"\n.Ed\n.Pp\nWill result in\n.Ql foobar .\nAnd:\n.Bd -literal -offset indent\nset -g status-style \"bg=red\"\nset -ag status-style \"fg=blue\"\n.Ed\n.Pp\nWill result in a red background\n.Em and\nblue foreground.\nWithout\n.Fl a ,\nthe result would be the default background and a blue foreground.\n.Tg show\n.It Xo Ic show-options\n.Op Fl AgHpqsvw\n.Op Fl t Ar target-pane\n.Op Ar option\n.Xc\n.D1 Pq alias: Ic show\nShow the pane options (or a single option if\n.Ar option\nis provided) with\n.Fl p ,\nthe window options with\n.Fl w ,\nthe server options with\n.Fl s ,\notherwise the session options.\nIf the option is not a user option,\n.Fl w\nor\n.Fl s\nmay be unnecessary -\n.Nm\nwill infer the scope from the option name, assuming\n.Fl w\nfor pane options.\nGlobal session or window options are listed if\n.Fl g\nis used.\n.Fl v\nshows only the option value, not the name.\nIf\n.Fl q\nis set, no error will be returned if\n.Ar option\nis unset.\n.Fl H\nincludes hooks (omitted by default).\n.Fl A\nincludes options inherited from a parent set of options, such options are\nmarked with an asterisk.\n.El\n.Pp\nAvailable server options are:\n.Bl -tag -width Ds\n.It Ic backspace Ar key\nSet the key sent by\n.Nm\nfor backspace.\n.It Ic buffer-limit Ar number\nSet the number of buffers; as new buffers are added to the top of the stack,\nold ones are removed from the bottom if necessary to maintain this maximum\nlength.\n.It Xo Ic command-alias[]\n.Ar name=value\n.Xc\nThis is an array of custom aliases for commands.\nIf an unknown command matches\n.Ar name ,\nit is replaced with\n.Ar value .\nFor example, after:\n.Pp\n.Dl set -s command-alias[100] zoom=\\[aq]resize-pane -Z\\[aq]\n.Pp\nUsing:\n.Pp\n.Dl zoom -t:.1\n.Pp\nIs equivalent to:\n.Pp\n.Dl resize-pane -Z -t:.1\n.Pp\nNote that aliases are expanded when a command is parsed rather than when it is\nexecuted, so binding an alias with\n.Ic bind-key\nwill bind the expanded form.\n.It Ic codepoint-widths[] Ar string\nAn array option allowing widths of Unicode codepoints to be overridden.\nNote the new width applies to all clients.\nEach entry is of the form\n.Em codepoint=width ,\nwhere codepoint may be a UTF-8 character or an identifier of the form\n.Ql U+number\nwhere the number is a hexadecimal number.\n.It Ic copy-command Ar shell-command\nGive the command to pipe to if the\n.Ic copy-pipe\ncopy mode command is used without arguments.\n.It Ic default-client-command Ar command\nSet the default command to run when tmux is called without a command.\nThe default is\n.Ic new-session .\n.It Ic default-terminal Ar terminal\nSet the default terminal for new windows created in this session - the\ndefault value of the\n.Ev TERM\nenvironment variable.\nFor\n.Nm\nto work correctly, this\n.Em must\nbe set to\n.Ql screen ,\n.Ql tmux\nor a derivative of them.\n.It Ic escape-time Ar time\nSet the time in milliseconds for which\n.Nm\nwaits after an escape is input to determine if it is part of a function or meta\nkey sequences.\n.It Ic editor Ar shell-command\nSet the command used when\n.Nm\nruns an editor.\n.It Xo Ic exit-empty\n.Op Ic on | off\n.Xc\nIf enabled (the default), the server will exit when there are no active\nsessions.\n.It Xo Ic exit-unattached\n.Op Ic on | off\n.Xc\nIf enabled, the server will exit when there are no attached clients.\n.It Xo Ic extended-keys\n.Op Ic on | off | always\n.Xc\nControls how modified keys (keys pressed together with Control, Meta, or Shift)\nare reported.\nThis is the equivalent of the\n.Ic modifyOtherKeys\n.Xr xterm 1\nresource.\n.Pp\nWhen set to\n.Ic on ,\nthe program inside the pane can request one of two modes: mode 1 which changes\nthe sequence for only keys which lack an existing well-known representation; or\nmode 2 which changes the sequence for all keys.\nWhen set to\n.Ic always ,\nmodes 1 and 2 can still be requested by applications, but mode 1 will be forced\ninstead of the standard mode.\nWhen set to\n.Ic off ,\nthis feature is disabled and only standard keys are reported.\n.Pp\n.Nm\nwill always request extended keys itself if the terminal supports them.\nSee also the\n.Ic extkeys\nfeature for the\n.Ic terminal-features\noption, the\n.Ic extended-keys-format\noption and the\n.Ic pane_key_mode\nvariable.\n.It Xo Ic extended-keys-format\n.Op Ic csi-u | xterm\n.Xc\nSelects one of the two possible formats for reporting modified keys to\napplications.\nThis is the equivalent of the\n.Ic formatOtherKeys\n.Xr xterm 1\nresource.\nFor example, C-S-a will be reported as\n.Ql ^[[27;6;65~\nwhen set to\n.Ic xterm ,\nand as\n.Ql ^[[65;6u\nwhen set to\n.Ic csi-u .\n.It Xo Ic focus-events\n.Op Ic on | off\n.Xc\nWhen enabled, focus events are requested from the terminal if supported and\npassed through to applications running in\n.Nm .\nAttached clients should be detached and attached again after changing this\noption.\n.It Xo Ic focus-follows-mouse\n.Op Ic on | off\n.Xc\nWhen enabled and\n.Ic mouse\nis on, moving the mouse into a pane selects it.\n.It Xo Ic get-clipboard\n.Op Ic both | request | buffer | off\n.Xc\nControls the behaviour when an application requests the clipboard from\n.Nm .\n.Pp\nIf\n.Ic off ,\nthe request is ignored;\nif\n.Ic buffer ,\n.Nm\nresponds with the newest paste buffer;\n.Ic request\ncauses\n.Nm\nto request the clipboard from the most recently used client (if possible) and\nsend the reply (if any) back to the application;\n.Ic buffer\nis the same as\n.Ic request\nbut also creates a paste buffer.\n.Pp\nSee also the\n.Ic set-clipboard\noption.\n.It Ic history-file Ar path\nIf not empty, a file to which\n.Nm\nwill write command prompt history on exit and load it from on start.\n.It Ic input-buffer-size Ar bytes\nMaximum of bytes allowed to read in escape and control sequences.\nOnce reached, the sequence will be discarded.\n.It Ic message-limit Ar number\nSet the number of error or information messages to save in the message log for\neach client.\n.It Ic prompt-history-limit Ar number\nSet the number of history items to save in the history file for each type of\ncommand prompt.\n.It Xo Ic set-clipboard\n.Op Ic on | external | off\n.Xc\nAttempt to set the terminal clipboard content using the\n.Xr xterm 1\nescape sequence, if there is an\n.Em \\&Ms\nentry in the\n.Xr terminfo 5\ndescription (see the\n.Sx TERMINFO EXTENSIONS\nsection).\n.Pp\nIf set to\n.Ic on ,\n.Nm\nwill both accept the escape sequence to create a buffer and attempt to set\nthe terminal clipboard.\nIf set to\n.Ic external ,\n.Nm\nwill attempt to set the terminal clipboard but ignore attempts\nby applications to set\n.Nm\nbuffers.\nIf\n.Ic off ,\n.Nm\nwill neither accept the clipboard escape sequence nor attempt to set the\nclipboard.\n.Pp\nNote that this feature needs to be enabled in\n.Xr xterm 1\nby setting the resource:\n.Bd -literal -offset indent\ndisallowedWindowOps: 20,21,SetXprop\n.Ed\n.Pp\nOr changing this property from the\n.Xr xterm 1\ninteractive menu when required.\n.It Ic terminal-features[] Ar string\nSet terminal features for terminal types read from\n.Xr terminfo 5 .\n.Nm\nhas a set of named terminal features.\nEach will apply appropriate changes to the\n.Xr terminfo 5\nentry in use.\n.Pp\n.Nm\ncan detect features for a few common terminals; this option can be used to\neasily tell tmux about features supported by terminals it cannot detect.\nThe\n.Ic terminal-overrides\noption allows individual\n.Xr terminfo 5\ncapabilities to be set instead,\n.Ic terminal-features\nis intended for classes of functionality supported in a standard way but not\nreported by\n.Xr terminfo 5 .\nCare must be taken to configure this only with features the terminal actually\nsupports.\n.Pp\nThis is an array option where each entry is a colon-separated string made up\nof a terminal type pattern (matched using\n.Xr glob 7\npatterns) followed by a list of terminal features.\nThe available features are:\n.Bl -tag -width Ds\n.It 256\nSupports 256 colours with the SGR escape sequences.\n.It clipboard\nAllows setting the system clipboard.\n.It ccolour\nAllows setting the cursor colour.\n.It cstyle\nAllows setting the cursor style.\n.It extkeys\nSupports extended keys.\n.It focus\nSupports focus reporting.\n.It hyperlinks\nSupports OSC 8 hyperlinks.\n.It ignorefkeys\nIgnore function keys from\n.Xr terminfo 5\nand use the\n.Nm\ninternal set only.\n.It margins\nSupports DECSLRM margins.\n.It mouse\nSupports\n.Xr xterm 1\nmouse sequences.\n.It osc7\nSupports the OSC 7 working directory extension.\n.It overline\nSupports the overline SGR attribute.\n.It rectfill\nSupports the DECFRA rectangle fill escape sequence.\n.It RGB\nSupports RGB colour with the SGR escape sequences.\n.It sixel\nSupports SIXEL graphics.\n.It strikethrough\nSupports the strikethrough SGR escape sequence.\n.It sync\nSupports synchronized updates.\n.It title\nSupports\n.Xr xterm 1\ntitle setting.\n.It usstyle\nAllows underscore style and colour to be set.\n.El\n.It Ic terminal-overrides[] Ar string\nAllow terminal descriptions read using\n.Xr terminfo 5\nto be overridden.\nEach entry is a colon-separated string made up of a terminal type pattern\n(matched using\n.Xr glob 7\npatterns)\nand a set of\n.Em name=value\nentries.\n.Pp\nFor example, to set the\n.Ql clear\n.Xr terminfo 5\nentry to\n.Ql \\ee[H\\ee[2J\nfor all terminal types matching\n.Ql rxvt* :\n.Pp\n.Dl \"rxvt*:clear=\\ee[H\\ee[2J\"\n.Pp\nThe terminal entry value is passed through\n.Xr strunvis 3\nbefore interpretation.\n.It Ic user-keys[] Ar key\nSet list of user-defined key escape sequences.\nEach item is associated with a key named\n.Ql User0 ,\n.Ql User1 ,\nand so on.\n.Pp\nFor example:\n.Bd -literal -offset indent\nset -s user-keys[0] \"\\ee[5;30012\\[ti]\"\nbind User0 resize-pane -L 3\n.Ed\n.It Xo Ic variation-selector-always-wide\n.Op Ic on | off\n.Xc\nAlways treat Unicode variation selector 16 as marking a wide character.\nThis is a feature of some terminals as part of their Unicode 14 support.\n.El\n.Pp\nAvailable session options are:\n.Bl -tag -width Ds\n.It Xo Ic activity-action\n.Op Ic any | none | current | other\n.Xc\nSet action on window activity when\n.Ic monitor-activity\nis on.\n.Ic any\nmeans activity in any window linked to a session causes a bell or message\n(depending on\n.Ic visual-activity )\nin the current window of that session,\n.Ic none\nmeans all activity is ignored (equivalent to\n.Ic monitor-activity\nbeing off),\n.Ic current\nmeans only activity in windows other than the current window are ignored and\n.Ic other\nmeans activity in the current window is ignored but not those in other windows.\n.It Ic assume-paste-time Ar milliseconds\nIf keys are entered faster than one in\n.Ar milliseconds ,\nthey are assumed to have been pasted rather than typed and\n.Nm\nkey bindings are not processed.\nThe default is one millisecond and zero disables.\n.It Ic base-index Ar index\nSet the base index from which an unused index should be searched when a new\nwindow is created.\nThe default is zero.\n.It Xo Ic bell-action\n.Op Ic any | none | current | other\n.Xc\nSet action on a bell in a window when\n.Ic monitor-bell\nis on.\nThe values are the same as those for\n.Ic activity-action .\n.It Ic default-command Ar shell-command\nSet the command used for new windows (if not specified when the window is\ncreated) to\n.Ar shell-command ,\nwhich may be any\n.Xr sh 1\ncommand.\nThe default is an empty string, which instructs\n.Nm\nto create a login shell using the value of the\n.Ic default-shell\noption.\n.It Ic default-shell Ar path\nSpecify the default shell.\nThis is used as the login shell for new windows when the\n.Ic default-command\noption is set to empty, and must be the full path of the executable.\nWhen started\n.Nm\ntries to set a default value from the first suitable of the\n.Ev SHELL\nenvironment variable, the shell returned by\n.Xr getpwuid 3 ,\nor\n.Pa /bin/sh .\nThis option should be configured when\n.Nm\nis used as a login shell.\n.It Ic default-size Ar XxY\nSet the default size of new windows when the\n.Ic window-size\noption is set to manual or when a session is created with\n.Ic new-session\n.Fl d .\nThe value is the width and height separated by an\n.Ql x\ncharacter.\nThe default is 80x24.\n.It Xo Ic destroy-unattached\n.Op Ic off | on | keep-last | keep-group\n.Xc\nIf\n.Ic on ,\ndestroy the session after the last client has detached.\nIf\n.Ic off\n(the default), leave the session orphaned.\nIf\n.Ic keep-last ,\ndestroy the session only if it is in a group and has other sessions in that\ngroup.\nIf\n.Ic keep-group ,\ndestroy the session unless it is in a group and is the only session in that\ngroup.\n.It Xo Ic detach-on-destroy\n.Op Ic off | on | no-detached | previous | next\n.Xc\nIf\n.Ic on\n(the default), the client is detached when the session it is attached to\nis destroyed.\nIf\n.Ic off ,\nthe client is switched to the most recently active of the remaining\nsessions.\nIf\n.Ic no-detached ,\nthe client is detached only if there are no detached sessions; if detached\nsessions exist, the client is switched to the most recently active.\nIf\n.Ic previous\nor\n.Ic next ,\nthe client is switched to the previous or next session in alphabetical order.\n.It Ic display-panes-active-colour Ar colour\nSet the colour used by the\n.Ic display-panes\ncommand to show the indicator for the active pane.\n.It Ic display-panes-colour Ar colour\nSet the colour used by the\n.Ic display-panes\ncommand to show the indicators for inactive panes.\n.It Ic display-panes-time Ar time\nSet the time in milliseconds for which the indicators shown by the\n.Ic display-panes\ncommand appear.\n.It Ic display-time Ar time\nSet the amount of time for which status line messages and other on-screen\nindicators are displayed.\nIf set to 0, messages and indicators are displayed until a key is pressed.\n.Ar time\nis in milliseconds.\n.It Ic history-limit Ar lines\nSet the maximum number of lines held in pane history.\n.It Ic initial-repeat-time Ar time\nSet the time in milliseconds for the initial repeat when a key is bound with the\n.Fl r\nflag.\nThis allows multiple commands to be entered without pressing the prefix key\nagain.\nSee also the\n.Ic repeat-time\noption.\nIf\n.Ic initial-repeat-time\nis zero,\n.Ic repeat-time\nis used for the first key press.\n.It Ic key-table Ar key-table\nSet the default key table to\n.Ar key-table\ninstead of\n.Em root .\n.It Ic lock-after-time Ar number\nLock the session (like the\n.Ic lock-session\ncommand) after\n.Ar number\nseconds of inactivity.\nThe default is not to lock (set to 0).\n.It Ic lock-command Ar shell-command\nCommand to run when locking each client.\nThe default is to run\n.Xr lock 1\nwith\n.Fl np .\n.It Ic menu-style Ar style\nSet the menu style.\nSee the\n.Sx STYLES\nsection on how to specify\n.Ar style .\n.It Ic menu-selected-style Ar style\nSet the selected menu item style.\nSee the\n.Sx STYLES\nsection on how to specify\n.Ar style .\n.It Ic menu-border-style Ar style\nSet the menu border style.\nSee the\n.Sx STYLES\nsection on how to specify\n.Ar style .\n.It Ic menu-border-lines Ar type\nSet the type of characters used for drawing menu borders.\nSee\n.Ic popup-border-lines\nfor possible values for\n.Ar border-lines .\n.It Ic message-command-style Ar style\nSet status line message command style.\nThis is used for the command prompt with\n.Xr vi 1\nkeys when in command mode.\nFor how to specify\n.Ar style ,\nsee the\n.Sx STYLES\nsection.\n.It Xo Ic message-line\n.Op Ic 0 | 1 | 2 | 3 | 4\n.Xc\nSet line on which status line messages and the command prompt are shown.\n.It Ic message-style Ar style\nSet status line message style.\nThis is used for messages and for the command prompt.\nFor how to specify\n.Ar style ,\nsee the\n.Sx STYLES\nsection.\n.It Xo Ic mouse\n.Op Ic on | off\n.Xc\nIf on,\n.Nm\ncaptures the mouse and allows mouse events to be bound as key bindings.\nSee the\n.Sx MOUSE SUPPORT\nsection for details.\n.It Ic prefix Ar key\nSet the key accepted as a prefix key.\nIn addition to the standard keys described under\n.Sx KEY BINDINGS ,\n.Ic prefix\ncan be set to the special key\n.Ql None\nto set no prefix.\n.It Ic prefix2 Ar key\nSet a secondary key accepted as a prefix key.\nLike\n.Ic prefix ,\n.Ic prefix2\ncan be set to\n.Ql None .\n.It Ic prefix-timeout Ar time\nSet the time in milliseconds for which\n.Nm\nwaits after\n.Ic prefix\nis input before dismissing it.\nCan be set to zero to disable any timeout.\n.It Ic prompt-cursor-colour Ar colour\nSet the colour of the cursor in the command prompt.\n.It Ic prompt-cursor-style Ar style\nSet the style of the cursor in the command prompt.\nSee the\n.Ic cursor-style\noptions for available styles.\n.It Ic prompt-command-cursor-style Ar style\nSet the style of the cursor in the command prompt when vi keys are enabled and\nthe prompt is in command mode.\nSee the\n.Ic cursor-style\noptions for available styles.\n.It Xo Ic renumber-windows\n.Op Ic on | off\n.Xc\nIf on, when a window is closed in a session, automatically renumber the other\nwindows in numerical order.\nThis respects the\n.Ic base-index\noption if it has been set.\nIf off, do not renumber the windows.\n.It Ic repeat-time Ar time\nAllow multiple commands to be entered without pressing the prefix key again\nin the specified\n.Ar time\nmilliseconds (the default is 500).\nWhether a key repeats may be set when it is bound using the\n.Fl r\nflag to\n.Ic bind-key .\nRepeat is enabled for the default keys bound to the\n.Ic resize-pane\ncommand.\nSee also the\n.Ic initial-repeat-time\noption.\n.It Xo Ic set-titles\n.Op Ic on | off\n.Xc\nAttempt to set the client terminal title using the\n.Em tsl\nand\n.Em fsl\n.Xr terminfo 5\nentries if they exist.\n.Nm\nautomatically sets these to the \\ee]0;...\\e007 sequence if\nthe terminal appears to be\n.Xr xterm 1 .\nThis option is off by default.\n.It Ic set-titles-string Ar string\nString used to set the client terminal title if\n.Ic set-titles\nis on.\nFormats are expanded, see the\n.Sx FORMATS\nsection.\n.It Xo Ic silence-action\n.Op Ic any | none | current | other\n.Xc\nSet action on window silence when\n.Ic monitor-silence\nis on.\nThe values are the same as those for\n.Ic activity-action .\n.It Xo Ic status\n.Op Ic off | on | 2 | 3 | 4 | 5\n.Xc\nShow or hide the status line or specify its size.\nUsing\n.Ic on\ngives a status line one row in height;\n.Ic 2 ,\n.Ic 3 ,\n.Ic 4\nor\n.Ic 5\nmore rows.\n.It Ic status-format[] Ar format\nSpecify the format to be used for each line of the status line.\nThe default builds the top status line from the various individual status\noptions below.\n.It Ic status-interval Ar interval\nUpdate the status line every\n.Ar interval\nseconds.\nBy default, updates will occur every 15 seconds.\nA setting of zero disables redrawing at interval.\n.It Xo Ic status-justify\n.Op Ic left | centre | right | absolute-centre\n.Xc\nSet the position of the window list in the status line: left, centre or right.\ncentre puts the window list in the relative centre of the available free space;\nabsolute-centre uses the centre of the entire horizontal space.\n.It Xo Ic status-keys\n.Op Ic vi | emacs\n.Xc\nUse vi or emacs-style\nkey bindings in the status line, for example at the command prompt.\nThe default is emacs, unless the\n.Ev VISUAL\nor\n.Ev EDITOR\nenvironment variables are set and contain the string\n.Ql vi .\n.It Ic status-left Ar string\nDisplay\n.Ar string\n(by default the session name) to the left of the status line.\n.Ar string\nwill be passed through\n.Xr strftime 3 .\nAlso see the\n.Sx FORMATS\nand\n.Sx STYLES\nsections.\n.Pp\nFor details on how the names and titles can be set see the\n.Sx \"NAMES AND TITLES\"\nsection.\n.Pp\nExamples are:\n.Bd -literal -offset indent\n#(sysctl vm.loadavg)\n#[fg=yellow,bold]#(apm -l)%%#[default] [#S]\n.Ed\n.Pp\nThe default is\n.Ql \"[#S] \" .\n.It Ic status-left-length Ar length\nSet the maximum\n.Ar length\nof the left component of the status line.\nThe default is 10.\n.It Ic status-left-style Ar style\nSet the style of the left part of the status line.\nFor how to specify\n.Ar style ,\nsee the\n.Sx STYLES\nsection.\n.It Xo Ic status-position\n.Op Ic top | bottom\n.Xc\nSet the position of the status line.\n.It Ic status-right Ar string\nDisplay\n.Ar string\nto the right of the status line.\nBy default, the current pane title in double quotes, the date and the time\nare shown.\nAs with\n.Ic status-left ,\n.Ar string\nwill be passed to\n.Xr strftime 3\nand character pairs are replaced.\n.It Ic status-right-length Ar length\nSet the maximum\n.Ar length\nof the right component of the status line.\nThe default is 40.\n.It Ic status-right-style Ar style\nSet the style of the right part of the status line.\nFor how to specify\n.Ar style ,\nsee the\n.Sx STYLES\nsection.\n.It Ic status-style Ar style\nSet status line style.\nFor how to specify\n.Ar style ,\nsee the\n.Sx STYLES\nsection.\n.It Ic update-environment[] Ar variable\nSet list of environment variables to be copied into the session environment\nwhen a new session is created or an existing session is attached.\nAny variables that do not exist in the source environment are set to be\nremoved from the session environment (as if\n.Fl r\nwas given to the\n.Ic set-environment\ncommand).\n.It Xo Ic visual-activity\n.Op Ic on | off | both\n.Xc\nIf on, display a message instead of sending a bell when activity occurs in a\nwindow for which the\n.Ic monitor-activity\nwindow option is enabled.\nIf set to both, a bell and a message are produced.\n.It Xo Ic visual-bell\n.Op Ic on | off | both\n.Xc\nIf on, a message is shown on a bell in a window for which the\n.Ic monitor-bell\nwindow option is enabled instead of it being passed through to the\nterminal (which normally makes a sound).\nIf set to both, a bell and a message are produced.\nAlso see the\n.Ic bell-action\noption.\n.It Xo Ic visual-silence\n.Op Ic on | off | both\n.Xc\nIf\n.Ic monitor-silence\nis enabled, prints a message after the interval has expired on a given window\ninstead of sending a bell.\nIf set to both, a bell and a message are produced.\n.It Ic word-separators Ar string\nSets the session's conception of what characters are considered word\nseparators, for the purposes of the next and previous word commands in\ncopy mode.\n.El\n.Pp\nAvailable window options are:\n.Pp\n.Bl -tag -width Ds -compact\n.It Xo Ic aggressive-resize\n.Op Ic on | off\n.Xc\nAggressively resize the chosen window.\nThis means that\n.Nm\nwill resize the window to the size of the smallest or largest session\n(see the\n.Ic window-size\noption) for which it is the current window, rather than the session to\nwhich it is attached.\nThe window may resize when the current window is changed on another\nsession; this option is good for full-screen programs which support\n.Dv SIGWINCH\nand poor for interactive programs such as shells.\n.Pp\n.It Xo Ic automatic-rename\n.Op Ic on | off\n.Xc\nControl automatic window renaming.\nWhen this setting is enabled,\n.Nm\nwill rename the window automatically using the format specified by\n.Ic automatic-rename-format .\nThis flag is automatically disabled for an individual window when a name\nis specified at creation with\n.Ic new-window\nor\n.Ic new-session ,\nor later with\n.Ic rename-window ,\nor with a terminal escape sequence.\nIt may be switched off globally with:\n.Bd -literal -offset indent\nset-option -wg automatic-rename off\n.Ed\n.Pp\n.It Ic automatic-rename-format Ar format\nThe format (see\n.Sx FORMATS )\nused when the\n.Ic automatic-rename\noption is enabled.\n.Pp\n.It Ic clock-mode-colour Ar colour\nSet clock colour.\n.Pp\n.It Xo Ic clock-mode-style\n.Op Ic 12 | 24 | 12-with-seconds | 24-with-seconds\n.Xc\nSet clock hour format.\n.Pp\n.It Ic fill-character Ar character\nSet the character used to fill areas of the terminal unused by a window.\n.Pp\n.It Ic main-pane-height Ar height\n.It Ic main-pane-width Ar width\nSet the width or height of the main (left or top) pane in the\n.Ic main-horizontal ,\n.Ic main-horizontal-mirrored ,\n.Ic main-vertical ,\nor\n.Ic main-vertical-mirrored\nlayouts.\nIf suffixed by\n.Ql % ,\nthis is a percentage of the window size.\n.Pp\n.It Ic copy-mode-match-style Ar style\nSet the style of search matches in copy mode.\nFor how to specify\n.Ar style ,\nsee the\n.Sx STYLES\nsection.\n.Pp\n.It Ic copy-mode-mark-style Ar style\nSet the style of the line containing the mark in copy mode.\nFor how to specify\n.Ar style ,\nsee the\n.Sx STYLES\nsection.\n.Pp\n.It Ic copy-mode-current-match-style Ar style\nSet the style of the current search match in copy mode.\nFor how to specify\n.Ar style ,\nsee the\n.Sx STYLES\nsection.\n.Pp\n.It Ic copy-mode-position-format Ar format\nFormat of the position indicator in copy mode.\n.Pp\n.It Xo Ic mode-keys\n.Op Ic vi | emacs\n.Xc\nUse vi or emacs-style key bindings in copy mode.\nThe default is emacs, unless\n.Ev VISUAL\nor\n.Ev EDITOR\ncontains\n.Ql vi .\n.Pp\n.It Ic copy-mode-position-style Ar style\nSet the style of the position indicator in copy mode.\nFor how to specify\n.Ar style ,\nsee the\n.Sx STYLES\nsection.\n.Pp\n.It Ic copy-mode-selection-style Ar style\nSet the style of the selection in copy mode.\nFor how to specify\n.Ar style ,\nsee the\n.Sx STYLES\nsection.\n.Pp\n.It Ic mode-style Ar style\nSet window modes style.\nFor how to specify\n.Ar style ,\nsee the\n.Sx STYLES\nsection.\n.Pp\n.It Xo Ic monitor-activity\n.Op Ic on | off\n.Xc\nMonitor for activity in the window.\nWindows with activity are highlighted in the status line.\n.Pp\n.It Xo Ic monitor-bell\n.Op Ic on | off\n.Xc\nMonitor for a bell in the window.\nWindows with a bell are highlighted in the status line.\n.Pp\n.It Xo Ic monitor-silence\n.Op Ic interval\n.Xc\nMonitor for silence (no activity) in the window within\n.Ic interval\nseconds.\nWindows that have been silent for the interval are highlighted in the\nstatus line.\nAn interval of zero disables the monitoring.\n.Pp\n.It Ic other-pane-height Ar height\nSet the height of the other panes (not the main pane) in the\n.Ic main-horizontal\nand\n.Ic main-horizontal-mirrored\nlayouts.\nIf this option is set to 0 (the default), it will have no effect.\nIf both the\n.Ic main-pane-height\nand\n.Ic other-pane-height\noptions are set, the main pane will grow taller to make the other panes the\nspecified height, but will never shrink to do so.\nIf suffixed by\n.Ql % ,\nthis is a percentage of the window size.\n.Pp\n.It Ic other-pane-width Ar width\nLike\n.Ic other-pane-height ,\nbut set the width of other panes in the\n.Ic main-vertical\nand\n.Ic main-vertical-mirrored\nlayouts.\n.Pp\n.It Ic pane-active-border-style Ar style\nSet the pane border style for the currently active pane.\nFor how to specify\n.Ar style ,\nsee the\n.Sx STYLES\nsection.\nAttributes are ignored.\n.Pp\n.It Ic pane-base-index Ar index\nLike\n.Ic base-index ,\nbut set the starting index for pane numbers.\n.Pp\n.It Ic pane-border-format Ar format\nSet the text shown in pane border status lines.\n.Pp\n.It Xo Ic pane-border-indicators\n.Op Ic off | colour | arrows | both\n.Xc\nIndicate active pane by colouring only half of the border in windows with\nexactly two panes, by displaying arrow markers, by drawing both or neither.\n.Pp\n.It Ic pane-border-lines Ar type\nSet the type of characters used for drawing pane borders.\n.Ar type\nmay be one of:\n.Bl -tag -width Ds\n.It single\nsingle lines using ACS or UTF-8 characters\n.It double\ndouble lines using UTF-8 characters\n.It heavy\nheavy lines using UTF-8 characters\n.It simple\nsimple ASCII characters\n.It number\nthe pane number\n.It spaces\nspace characters\n.El\n.Pp\n.Ql double\nand\n.Ql heavy\nwill fall back to standard ACS line drawing when UTF-8 is not supported.\n.Pp\n.It Xo Ic pane-border-status\n.Op Ic off | top | bottom\n.Xc\nTurn pane border status lines off or set their position.\n.Pp\n.It Ic pane-border-style Ar style\nSet the pane border style for panes aside from the active pane.\nFor how to specify\n.Ar style ,\nsee the\n.Sx STYLES\nsection.\nAttributes are ignored.\n.Pp\n.It Ic popup-style Ar style\nSet the popup style.\nSee the\n.Sx STYLES\nsection on how to specify\n.Ar style .\nAttributes are ignored.\n.Pp\n.It Ic popup-border-style Ar style\nSet the popup border style.\nSee the\n.Sx STYLES\nsection on how to specify\n.Ar style .\nAttributes are ignored.\n.Pp\n.It Ic popup-border-lines Ar type\nSet the type of characters used for drawing popup borders.\n.Ar type\nmay be one of:\n.Bl -tag -width Ds\n.It single\nsingle lines using ACS or UTF-8 characters (default)\n.It rounded\nvariation of single with rounded corners using UTF-8 characters\n.It double\ndouble lines using UTF-8 characters\n.It heavy\nheavy lines using UTF-8 characters\n.It simple\nsimple ASCII characters\n.It padded\nsimple ASCII space character\n.It none\nno border\n.El\n.Pp\n.Ql double\nand\n.Ql heavy\nwill fall back to standard ACS line drawing when UTF-8 is not supported.\n.Pp\n.It Xo Ic pane-scrollbars\n.Op Ic off | modal | on\n.Xc\nWhen enabled, a character based scrollbar appears on the left or right\nof each pane.\nA filled section of the scrollbar, known as the\n.Ql slider ,\nrepresents the position and size of the visible part of the pane content.\n.Pp\nIf set to\n.Ic on\nthe scrollbar is visible all the time.\nIf set to\n.Ic modal\nthe scrollbar only appears when the pane is in copy mode or view mode.\nWhen the scrollbar is visible, the pane is narrowed by the width of the\nscrollbar and the text in the pane is reflowed.\nIf set to\n.Ic modal ,\nthe pane is narrowed only when the scrollbar is visible.\n.Pp\nSee also\n.Ic pane-scrollbars-style .\n.Pp\n.It Ic pane-scrollbars-style Ar style\nSet the scrollbars style.\nFor how to specify\n.Ar style ,\nsee the\n.Sx STYLES\nsection.\nThe foreground colour is used for the slider, the background for the rest of the\nscrollbar.\nThe\n.Ar width\nattribute sets the width of the scrollbar and the\n.Ar pad\nattribute the padding between the scrollbar and the pane.\nOther attributes are ignored.\n.Pp\n.It Xo Ic pane-scrollbars-position\n.Op Ic left | right\n.Xc\nSets which side of the pane to display pane scrollbars on.\n.Pp\n.It Ic pane-status-current-style Ar style\nSet status line style for the currently active pane.\nFor how to specify\n.Ar style ,\nsee the\n.Sx STYLES\nsection.\n.Pp\n.It Ic pane-status-style Ar style\nSet status line style for a single pane.\nFor how to specify\n.Ar style ,\nsee the\n.Sx STYLES\nsection.\n.Pp\n.It Ic session-status-current-style Ar style\nSet status line style for the currently active session.\nFor how to specify\n.Ar style ,\nsee the\n.Sx STYLES\nsection.\n.Pp\n.It Ic session-status-style Ar style\nSet status line style for a single session.\nFor how to specify\n.Ar style ,\nsee the\n.Sx STYLES\nsection.\n.Pp\n.It Ic tiled-layout-max-columns Ar number\nSet the maximum number of columns in the\n.Ic tiled\nlayout.\nA value of 0 (the default) means no limit.\nWhen a limit is set, panes are arranged to not exceed this number of columns,\nwith additional panes stacked in extra rows.\n.Pp\n.It Ic window-status-activity-style Ar style\nSet status line style for windows with an activity alert.\nFor how to specify\n.Ar style ,\nsee the\n.Sx STYLES\nsection.\n.Pp\n.It Ic window-status-bell-style Ar style\nSet status line style for windows with a bell alert.\nFor how to specify\n.Ar style ,\nsee the\n.Sx STYLES\nsection.\n.Pp\n.It Ic window-status-current-format Ar string\nLike\n.Ar window-status-format ,\nbut is the format used when the window is the current window.\n.Pp\n.It Ic window-status-current-style Ar style\nSet status line style for the currently active window.\nFor how to specify\n.Ar style ,\nsee the\n.Sx STYLES\nsection.\n.Pp\n.It Ic window-status-format Ar string\nSet the format in which the window is displayed in the status line window list.\nSee the\n.Sx FORMATS\nand\n.Sx STYLES\nsections.\n.Pp\n.It Ic window-status-last-style Ar style\nSet status line style for the last active window.\nFor how to specify\n.Ar style ,\nsee the\n.Sx STYLES\nsection.\n.Pp\n.It Ic window-status-separator Ar string\nSets the separator drawn between windows in the status line.\nThe default is a single space character.\n.Pp\n.It Ic window-status-style Ar style\nSet status line style for a single window.\nFor how to specify\n.Ar style ,\nsee the\n.Sx STYLES\nsection.\n.Pp\n.It Xo Ic window-size\n.Ar largest | Ar smallest | Ar manual | Ar latest\n.Xc\nConfigure how\n.Nm\ndetermines the window size.\nIf set to\n.Ar largest ,\nthe size of the largest attached session is used; if\n.Ar smallest ,\nthe size of the smallest.\nIf\n.Ar manual ,\nthe size of a new window is set from the\n.Ic default-size\noption and windows are resized automatically.\nWith\n.Ar latest ,\n.Nm\nuses the size of the client that had the most recent activity.\nSee also the\n.Ic resize-window\ncommand and the\n.Ic aggressive-resize\noption.\n.Pp\n.It Xo Ic wrap-search\n.Op Ic on | off\n.Xc\nIf this option is set, searches will wrap around the end of the pane contents.\nThe default is on.\n.El\n.Pp\nAvailable pane options are:\n.Pp\n.Bl -tag -width Ds -compact\n.It Xo Ic allow-passthrough\n.Op Ic on | off | all\n.Xc\nAllow programs in the pane to bypass\n.Nm\nusing a terminal escape sequence (\\eePtmux;...\\ee\\e\\e).\nIf set to\n.Ic on ,\npassthrough sequences will be allowed only if the pane is visible.\nIf set to\n.Ic all ,\nthey will be allowed even if the pane is invisible.\n.Pp\n.It Xo Ic allow-rename\n.Op Ic on | off\n.Xc\nAllow programs in the pane to change the window name using a terminal escape\nsequence (\\eek...\\ee\\e\\e).\n.Pp\n.It Xo Ic allow-set-title\n.Op Ic on | off\n.Xc\nAllow programs in the pane to change the title using the terminal escape\nsequences (\\ee]2;...\\ee\\e\\e or \\ee]0;...\\ee\\e\\e).\n.Pp\n.It Xo Ic alternate-screen\n.Op Ic on | off\n.Xc\nThis option configures whether programs running inside the pane may use the\nterminal alternate screen feature, which allows the\n.Em smcup\nand\n.Em rmcup\n.Xr terminfo 5\ncapabilities.\nThe alternate screen feature preserves the contents of the window when an\ninteractive application starts and restores it on exit, so that any output\nvisible before the application starts reappears unchanged after it exits.\n.Pp\n.It Ic cursor-colour Ar colour\nSet the colour of the cursor.\n.Pp\n.It Ic cursor-style Ar style\nSet the style of the cursor.\nAvailable styles are:\n.Ic default ,\n.Ic blinking-block ,\n.Ic block ,\n.Ic blinking-underline ,\n.Ic underline ,\n.Ic blinking-bar ,\n.Ic bar .\n.Pp\n.It Ic pane-colours[] Ar colour\nThe default colour palette.\nEach entry in the array defines the colour\n.Nm\nuses when the colour with that index is requested.\nThe index may be from zero to 255.\n.Pp\n.It Xo Ic remain-on-exit\n.Op Ic on | off | failed\n.Xc\nA pane with this flag set is not destroyed when the program running in it\nexits.\nIf set to\n.Ic failed ,\nthen only when the program exit status is not zero.\nThe pane may be reactivated with the\n.Ic respawn-pane\ncommand.\n.Pp\n.It Ic remain-on-exit-format Ar string\nSet the text shown at the bottom of exited panes when\n.Ic remain-on-exit\nis enabled.\n.Pp\n.It Xo Ic scroll-on-clear\n.Op Ic on | off\n.Xc\nWhen the entire screen is cleared and this option is on, scroll the contents of\nthe screen into history before clearing it.\n.Pp\n.It Xo Ic synchronize-panes\n.Op Ic on | off\n.Xc\nDuplicate input to all other panes in the same window where this option is also\non (only for panes that are not in any mode).\n.Pp\n.It Ic window-active-style Ar style\nSet the pane style when it is the active pane.\nFor how to specify\n.Ar style ,\nsee the\n.Sx STYLES\nsection.\n.Pp\n.It Ic window-style Ar style\nSet the pane style.\nFor how to specify\n.Ar style ,\nsee the\n.Sx STYLES\nsection.\n.El\n.Sh HOOKS\n.Nm\nallows commands to run on various triggers, called\n.Em hooks .\nMost\n.Nm\ncommands have an\n.Em after\nhook and there are a number of hooks not associated with commands.\n.Pp\nHooks are stored as array options, members of the array are executed in\norder when the hook is triggered.\nLike options different hooks may be global or belong to a session, window or\npane.\nHooks may be configured with the\n.Ic set-hook\nor\n.Ic set-option\ncommands and displayed with\n.Ic show-hooks\nor\n.Ic show-options\n.Fl H .\nThe following two commands are equivalent:\n.Bd -literal -offset indent.\nset-hook -g pane-mode-changed[42] \\[aq]set -g status-left-style bg=red\\[aq]\nset-option -g pane-mode-changed[42] \\[aq]set -g status-left-style bg=red\\[aq]\n.Ed\n.Pp\nSetting a hook without specifying an array index clears the hook and sets the\nfirst member of the array.\n.Pp\nA command's after\nhook is run after it completes, except when the command is run as part of a hook\nitself.\nThey are named with an\n.Ql after-\nprefix.\nFor example, the following command adds a hook to select the even-vertical\nlayout after every\n.Ic split-window :\n.Bd -literal -offset indent\nset-hook -g after-split-window \"selectl even-vertical\"\n.Ed\n.Pp\nIf a command fails, the\n.Ql command-error\nhook will be fired.\nFor example, this could be used to write to a log file:\n.Bd -literal -offset indent\nset-hook -g command-error \"run-shell \\\\\"echo 'a tmux command failed' >>/tmp/log\\\\\"\"\n.Ed\n.Pp\nAll the notifications listed in the\n.Sx CONTROL MODE\nsection are hooks (without any arguments), except\n.Ic %exit .\nThe following additional hooks are available:\n.Bl -tag -width \"XXXXXXXXXXXXXXXXXXXXXX\"\n.It alert-activity\nRun when a window has activity.\nSee\n.Ic monitor-activity .\n.It alert-bell\nRun when a window has received a bell.\nSee\n.Ic monitor-bell .\n.It alert-silence\nRun when a window has been silent.\nSee\n.Ic monitor-silence .\n.It client-active\nRun when a client becomes the latest active client of its session.\n.It client-attached\nRun when a client is attached.\n.It client-detached\nRun when a client is detached\n.It client-focus-in\nRun when focus enters a client\n.It client-focus-out\nRun when focus exits a client\n.It client-resized\nRun when a client is resized.\n.It client-session-changed\nRun when a client's attached session is changed.\n.It client-light-theme\nRun when a client switches to a light theme.\n.It client-dark-theme\nRun when a client switches to a dark theme.\n.It command-error\nRun when a command fails.\n.It pane-died\nRun when the program running in a pane exits, but\n.Ic remain-on-exit\nis on so the pane has not closed.\n.It pane-exited\nRun when the program running in a pane exits.\n.It pane-focus-in\nRun when the focus enters a pane, if the\n.Ic focus-events\noption is on.\n.It pane-focus-out\nRun when the focus exits a pane, if the\n.Ic focus-events\noption is on.\n.It pane-set-clipboard\nRun when the terminal clipboard is set using the\n.Xr xterm 1\nescape sequence.\n.It session-created\nRun when a new session created.\n.It session-closed\nRun when a session closed.\n.It session-renamed\nRun when a session is renamed.\n.It window-layout-changed\nRun when a window layout is changed.\n.It window-linked\nRun when a window is linked into a session.\n.It window-renamed\nRun when a window is renamed.\n.It window-resized\nRun when a window is resized.\nThis may be after the\n.Ar client-resized\nhook is run.\n.It window-unlinked\nRun when a window is unlinked from a session.\n.El\n.Pp\nHooks are managed with these commands:\n.Bl -tag -width Ds\n.It Xo Ic set-hook\n.Op Fl agpRuw\n.Op Fl t Ar target-pane\n.Ar hook-name\n.Op Ar command\n.Xc\nWithout\n.Fl R ,\nsets (or with\n.Fl u\nunsets) hook\n.Ar hook-name\nto\n.Ar command .\nThe flags are the same as for\n.Ic set-option .\n.Pp\nWith\n.Fl R ,\nrun\n.Ar hook-name\nimmediately.\n.It Xo Ic show-hooks\n.Op Fl gpw\n.Op Fl t Ar target-pane\n.Op Ar hook\n.Xc\nShows hooks.\nThe flags are the same as for\n.Ic show-options .\n.El\n.Sh MOUSE SUPPORT\nIf the\n.Ic mouse\noption is on (the default is off),\n.Nm\nallows mouse events to be bound as keys.\nThe name of each key is made up of a mouse event (such as\n.Ql MouseUp1 )\nand a location suffix, one of the following:\n.Bl -column \"XXXXXXXXXXXXX\" -offset indent\n.It Li \"Pane\" Ta \"the contents of a pane\"\n.It Li \"Border\" Ta \"a pane border\"\n.It Li \"Status\" Ta \"the status line window list\"\n.It Li \"StatusLeft\" Ta \"the left part of the status line\"\n.It Li \"StatusRight\" Ta \"the right part of the status line\"\n.It Li \"StatusDefault\" Ta \"any other part of the status line\"\n.It Li \"ScrollbarSlider\" Ta \"the scrollbar slider\"\n.It Li \"ScrollbarUp\" Ta \"above the scrollbar slider\"\n.It Li \"ScrollbarDown\" Ta \"below the scrollbar slider\"\n.El\n.Pp\nThe following mouse events are available:\n.Bl -column \"MouseDown1\" \"MouseDrag1\" \"WheelDown\" -offset indent\n.It Li \"WheelUp\" Ta \"WheelDown\" Ta \"\"\n.It Li \"MouseDown1\" Ta \"MouseUp1\" Ta \"MouseDrag1\" Ta \"MouseDragEnd1\"\n.It Li \"MouseDown2\" Ta \"MouseUp2\" Ta \"MouseDrag2\" Ta \"MouseDragEnd2\"\n.It Li \"MouseDown3\" Ta \"MouseUp3\" Ta \"MouseDrag3\" Ta \"MouseDragEnd3\"\n.It Li \"SecondClick1\" Ta \"SecondClick2\" Ta \"SecondClick3\"\n.It Li \"DoubleClick1\" Ta \"DoubleClick2\" Ta \"DoubleClick3\"\n.It Li \"TripleClick1\" Ta \"TripleClick2\" Ta \"TripleClick3\"\n.El\n.Pp\nThe\n.Ql SecondClick\nevents are fired for the second click of a double click, even if there may be a\nthird click which will fire\n.Ql TripleClick\ninstead of\n.Ql DoubleClick .\n.Pp\nEach should be suffixed with a location, for example\n.Ql MouseDown1Status .\n.Pp\nThe special token\n.Ql {mouse}\nor\n.Ql =\nmay be used as\n.Ar target-window\nor\n.Ar target-pane\nin commands bound to mouse key bindings.\nIt resolves to the window or pane over which the mouse event took place\n(for example, the window in the status line over which button 1 was released\nfor a\n.Ql MouseUp1Status\nbinding, or the pane over which the wheel was scrolled for a\n.Ql WheelDownPane\nbinding).\n.Pp\nThe\n.Ic send-keys\n.Fl M\nflag may be used to forward a mouse event to a pane.\n.Pp\nThe default key bindings allow the mouse to be used to select and resize panes,\nto copy text and to change window using the status line.\nThese take effect if the\n.Ic mouse\noption is turned on.\n.Sh FORMATS\nCertain commands accept the\n.Fl F\nflag with a\n.Ar format\nargument.\nThis is a string which controls the output format of the command.\nFormat variables are enclosed in\n.Ql #{\nand\n.Ql } ,\nfor example\n.Ql #{session_name} .\nThe possible variables are listed in the table below, or the name of a\n.Nm\noption may be used for an option's value, or the name of an environment\nvariable.\nSome variables have a shorter alias such as\n.Ql #S ;\n.Ql ##\nis replaced by a single\n.Ql # ,\n.Ql #,\nby a\n.Ql \\&,\nand\n.Ql #}\nby a\n.Ql } .\n.Pp\nConditionals are available by prefixing with\n.Ql \\&? .\nFor each pair of two arguments, if the variable in the first of the pair exists\nand is not zero, the second of the pair is chosen, otherwise it continues.\nIf no condition from paired arguments matches, the default value is chosen.\nIf there's an unpaired final argument, that is the default.\nIf not, the default is the empty string.\nFor example\n.Ql #{?session_attached,attached,not attached}\nwill include the string\n.Ql attached\nif the session is attached and the string\n.Ql not attached\nif it is unattached, or\n.Ql #{?automatic-rename,yes,no}\nwill include\n.Ql yes\nif\n.Ic automatic-rename\nis enabled, or\n.Ql no\nif not.\n.Ql #{?#{n:window_name},#{window_name} - }\nwill include the window name with a dash separator if there is a window name, or\nthe empty string if the window name is empty.\n.Ql #{?session_format,format1,window_format,format2,format3}\nwill include format1 for a session format, format2 for a window format, or\nformat3 for neither a session nor a window format.\nConditionals can be nested arbitrarily.\nInside a conditional,\n.Ql \\&,\nand\n.Ql }\nmust be escaped as\n.Ql #,\nand\n.Ql #} ,\nunless they are part of a\n.Ql #{...}\nreplacement.\nFor example:\n.Bd -literal -offset indent\n#{?pane_in_mode,#[fg=white#,bg=red],#[fg=red#,bg=white]}#W\n.Ed\n.Pp\nString comparisons may be expressed by prefixing two comma-separated\nalternatives by\n.Ql == ,\n.Ql != ,\n.Ql < ,\n.Ql > ,\n.Ql <=\nor\n.Ql >=\nand a colon.\nFor example\n.Ql #{==:#{host},myhost}\nwill be replaced by\n.Ql 1\nif running on\n.Ql myhost ,\notherwise by\n.Ql 0 .\n.Ql ||\nand\n.Ql &&\nevaluate to true if any or all of the comma-separated alternatives are\ntrue, for example\n.Ql #{||:#{pane_in_mode},#{alternate_on}} .\n.Ql \\&!\nevaluates to true if the value is false and vice versa, for example\n.Ql #{!:#{pane_in_mode}} .\n.Ql !!\nconverts a value to a canonical boolean form, 1 for true and 0 for false, for\nexample\n.Ql #{!!:non-empty string}\nevaluates to 1.\n.Pp\nAn\n.Ql m\nspecifies a\n.Xr glob 7\npattern or regular expression comparison.\nThe first argument is the pattern and the second the string to compare.\nAn optional argument specifies flags:\n.Ql r\nmeans the pattern is a regular expression instead of the default\n.Xr glob 7\npattern, and\n.Ql i\nmeans to ignore case.\nFor example:\n.Ql #{m:*foo*,#{host}}\nor\n.Ql #{m/ri:^A,MYVAR} .\nA\n.Ql C\nperforms a search for a\n.Xr glob 7\npattern or regular expression in the pane content and evaluates to zero if not\nfound, or a line number if found.\nLike\n.Ql m ,\nan\n.Ql r\nflag means search for a regular expression and\n.Ql i\nignores case.\nFor example:\n.Ql #{C/r:^Start}\n.Pp\nNumeric operators may be performed by prefixing two comma-separated alternatives\nwith an\n.Ql e\nand an operator.\nAn optional\n.Ql f\nflag may be given after the operator to use floating point numbers, otherwise\nintegers are used.\nThis may be followed by a number giving the number of decimal places to use for\nthe result.\nThe available operators are:\naddition\n.Ql + ,\nsubtraction\n.Ql - ,\nmultiplication\n.Ql * ,\ndivision\n.Ql / ,\nmodulus\n.Ql m\nor\n.Ql %\n(note that\n.Ql %\nmust be escaped as\n.Ql %%\nin formats which are also expanded by\n.Xr strftime 3 )\nand numeric comparison operators\n.Ql == ,\n.Ql != ,\n.Ql < ,\n.Ql <= ,\n.Ql >\nand\n.Ql >= .\nFor example,\n.Ql #{e|*|f|4:5.5,3}\nmultiplies 5.5 by 3 for a result with four decimal places and\n.Ql #{e|%%:7,3}\nreturns the modulus of 7 and 3.\n.Ql a\nreplaces a numeric argument by its ASCII equivalent, so\n.Ql #{a:98}\nresults in\n.Ql b .\n.Ql c\nreplaces a\n.Nm\ncolour by its six-digit hexadecimal RGB value.\n.Pp\nA limit may be placed on the length of the resultant string by prefixing it\nby an\n.Ql = ,\na number and a colon.\nPositive numbers count from the start of the string and negative from the end,\nso\n.Ql #{=5:pane_title}\nwill include at most the first five characters of the pane title, or\n.Ql #{=-5:pane_title}\nthe last five characters.\nA suffix or prefix may be given as a second argument - if provided then it is\nappended or prepended to the string if the length has been trimmed, for example\n.Ql #{=/5/...:pane_title}\nwill append\n.Ql ...\nif the pane title is more than five characters.\nSimilarly,\n.Ql p\npads the string to a given width, for example\n.Ql #{p10:pane_title}\nwill result in a width of at least 10 characters.\nA positive width pads on the left, a negative on the right.\n.Ql n\nexpands to the length of the variable and\n.Ql w\nto its width when displayed, for example\n.Ql #{n:window_name} .\n.Ql R\nrepeats the first argument by a number of times given by the second argument,\nso\n.Ql #{R:a,3}\nwill result in\n.Ql aaa .\n.Pp\nPrefixing a time variable with\n.Ql t:\\&\nwill convert it to a string, so if\n.Ql #{window_activity}\ngives\n.Ql 1445765102 ,\n.Ql #{t:window_activity}\ngives\n.Ql Sun Oct 25 09:25:02 2015 .\nAdding\n.Ql p (\n.Ql `t/p` )\nwill use shorter but less accurate time format for times in the past.\nA custom format may be given using an\n.Ql f\nsuffix (note that\n.Ql %\nmust be escaped as\n.Ql %%\nif the format is separately being passed through\n.Xr strftime 3 ,\nfor example in the\n.Ic status-left\noption):\n.Ql #{t/f/%%H#:%%M:window_activity} ,\nsee\n.Xr strftime 3 .\n.Pp\nThe\n.Ql b:\\&\nand\n.Ql d:\\&\nprefixes are\n.Xr basename 3\nand\n.Xr dirname 3\nof the variable respectively.\n.Ql q:\\&\nwill escape\n.Xr sh 1\nspecial characters or with a\n.Ql h\nsuffix, escape hash characters (so\n.Ql #\nbecomes\n.Ql ## ) .\n.Ql E:\\&\nwill expand the format twice, for example\n.Ql #{E:status-left}\nis the result of expanding the content of the\n.Ic status-left\noption rather than the option itself.\n.Ql T:\\&\nis like\n.Ql E:\\&\nbut also expands\n.Xr strftime 3\nspecifiers.\n.Ql S:\\& ,\n.Ql W:\\& ,\n.Ql P:\\&\nor\n.Ql L:\\&\nwill loop over each session, window, pane or client and insert the format once\nfor each.\n.Ql L:\\& ,\n.Ql S:\\&\nand\n.Ql W:\\&\ncan take an optional sort argument\n.Ql /i\\& ,\n.Ql /n\\& ,\n.Ql /t\\&\nto sort by index, name, or last activity time; additionally\n.Ql /r\\&\nto sort in reverse order.\n.Ql /r\\&\ncan also be used with\n.Ql P:\\&\nto reverse the sort order by pane index.\nFor example,\n.Ql S/nr:\\&\nto sort sessions by name in reverse order.\nFor each, two comma-separated formats may be given:\nthe second is used for the current window, active pane, or active session.\nFor example, to get a list of windows formatted like the status line:\n.Bd -literal -offset indent\n#{W:#{E:window-status-format} ,#{E:window-status-current-format} }\n.Ed\n.Pp\n.Ql N:\\&\nchecks if a window (without any suffix or with the\n.Ql w\nsuffix) or a session (with the\n.Ql s\nsuffix) name exists, for example\n.Ql `N/w:foo`\nis replaced with 1 if a window named\n.Ql foo\nexists.\n.Pp\nA prefix of the form\n.Ql s/foo/bar/:\\&\nwill substitute\n.Ql foo\nwith\n.Ql bar\nthroughout.\nThe first argument may be an extended regular expression and a final argument\nmay be\n.Ql i\nto ignore case, for example\n.Ql s/a(.)/\\e1x/i:\\&\nwould change\n.Ql abABab\ninto\n.Ql bxBxbx .\nA different delimiter character may also be used, to avoid collisions with\nliteral slashes in the pattern.\nFor example,\n.Ql s|foo/|bar/|:\\&\nwill substitute\n.Ql foo/\nwith\n.Ql bar/\nthroughout.\n.Pp\nMultiple modifiers may be separated with a semicolon (;) as in\n.Ql #{T;=10:status-left} ,\nwhich limits the resulting\n.Xr strftime 3 -expanded\nstring to at most 10 characters.\n.Pp\nIn addition, the last line of a shell command's output may be inserted using\n.Ql #() .\nFor example,\n.Ql #(uptime)\nwill insert the system's uptime.\nWhen constructing formats,\n.Nm\ndoes not wait for\n.Ql #()\ncommands to finish; instead, the previous result from running the same command\nis used, or a placeholder if the command has not been run before.\nIf the command hasn't exited, the most recent line of output will be used, but\nthe status line will not be updated more than once a second.\nCommands are executed using\n.Pa /bin/sh\nand with the\n.Nm\nglobal environment set (see the\n.Sx GLOBAL AND SESSION ENVIRONMENT\nsection).\n.Pp\nAn\n.Ql l\nspecifies that a string should be interpreted literally and not expanded.\nFor example\n.Ql #{l:#{?pane_in_mode,yes,no}}\nwill be replaced by\n.Ql #{?pane_in_mode,yes,no} .\n.Pp\nThe following variables are available, where appropriate:\n.Bl -column \"XXXXXXXXXXXXXXXXXXX\" \"XXXXX\"\n.It Sy \"Variable name\" Ta Sy \"Alias\" Ta Sy \"Replaced with\"\n.It Li \"active_window_index\" Ta \"\" Ta \"Index of active window in session\"\n.It Li \"alternate_on\" Ta \"\" Ta \"1 if pane is in alternate screen\"\n.It Li \"alternate_saved_x\" Ta \"\" Ta \"Saved cursor X in alternate screen\"\n.It Li \"alternate_saved_y\" Ta \"\" Ta \"Saved cursor Y in alternate screen\"\n.It Li \"buffer_created\" Ta \"\" Ta \"Time buffer created\"\n.It Li \"buffer_full\" Ta \"\" Ta \"Full buffer content\"\n.It Li \"buffer_name\" Ta \"\" Ta \"Name of buffer\"\n.It Li \"buffer_sample\" Ta \"\" Ta \"Sample of start of buffer\"\n.It Li \"buffer_size\" Ta \"\" Ta \"Size of the specified buffer in bytes\"\n.It Li \"client_activity\" Ta \"\" Ta \"Time client last had activity\"\n.It Li \"client_cell_height\" Ta \"\" Ta \"Height of each client cell in pixels\"\n.It Li \"client_cell_width\" Ta \"\" Ta \"Width of each client cell in pixels\"\n.It Li \"client_control_mode\" Ta \"\" Ta \"1 if client is in control mode\"\n.It Li \"client_created\" Ta \"\" Ta \"Time client created\"\n.It Li \"client_discarded\" Ta \"\" Ta \"Bytes discarded when client behind\"\n.It Li \"client_flags\" Ta \"\" Ta \"List of client flags\"\n.It Li \"client_height\" Ta \"\" Ta \"Height of client\"\n.It Li \"client_key_table\" Ta \"\" Ta \"Current key table\"\n.It Li \"client_last_session\" Ta \"\" Ta \"Name of the client's last session\"\n.It Li \"client_name\" Ta \"\" Ta \"Name of client\"\n.It Li \"client_pid\" Ta \"\" Ta \"PID of client process\"\n.It Li \"client_prefix\" Ta \"\" Ta \"1 if prefix key has been pressed\"\n.It Li \"client_readonly\" Ta \"\" Ta \"1 if client is read-only\"\n.It Li \"client_session\" Ta \"\" Ta \"Name of the client's session\"\n.It Li \"client_termfeatures\" Ta \"\" Ta \"Terminal features of client, if any\"\n.It Li \"client_termname\" Ta \"\" Ta \"Terminal name of client\"\n.It Li \"client_termtype\" Ta \"\" Ta \"Terminal type of client, if available\"\n.It Li \"client_tty\" Ta \"\" Ta \"Pseudo terminal of client\"\n.It Li \"client_uid\" Ta \"\" Ta \"UID of client process\"\n.It Li \"client_user\" Ta \"\" Ta \"User of client process\"\n.It Li \"client_utf8\" Ta \"\" Ta \"1 if client supports UTF-8\"\n.It Li \"client_width\" Ta \"\" Ta \"Width of client\"\n.It Li \"client_written\" Ta \"\" Ta \"Bytes written to client\"\n.It Li \"command\" Ta \"\" Ta \"Name of command in use, if any\"\n.It Li \"command_list_alias\" Ta \"\" Ta \"Command alias if listing commands\"\n.It Li \"command_list_name\" Ta \"\" Ta \"Command name if listing commands\"\n.It Li \"command_list_usage\" Ta \"\" Ta \"Command usage if listing commands\"\n.It Li \"config_files\" Ta \"\" Ta \"List of configuration files loaded\"\n.It Li \"cursor_blinking\" Ta \"\" Ta \"1 if the cursor is blinking\"\n.It Li \"copy_cursor_hyperlink\" Ta \"\" Ta \"Hyperlink under cursor in copy mode\"\n.It Li \"copy_cursor_line\" Ta \"\" Ta \"Line the cursor is on in copy mode\"\n.It Li \"copy_cursor_word\" Ta \"\" Ta \"Word under cursor in copy mode\"\n.It Li \"copy_cursor_x\" Ta \"\" Ta \"Cursor X position in copy mode\"\n.It Li \"copy_cursor_y\" Ta \"\" Ta \"Cursor Y position in copy mode\"\n.It Li \"current_file\" Ta \"\" Ta \"Current configuration file\"\n.It Li \"cursor_character\" Ta \"\" Ta \"Character at cursor in pane\"\n.It Li \"cursor_colour\" Ta \"\" Ta \"Cursor colour in pane\"\n.It Li \"cursor_flag\" Ta \"\" Ta \"Pane cursor flag\"\n.It Li \"cursor_shape\" Ta \"\" Ta \"Cursor shape in pane\"\n.It Li \"cursor_very_visible\" Ta \"\" Ta \"1 if the cursor is in very visible mode\"\n.It Li \"cursor_x\" Ta \"\" Ta \"Cursor X position in pane\"\n.It Li \"cursor_y\" Ta \"\" Ta \"Cursor Y position in pane\"\n.It Li \"history_bytes\" Ta \"\" Ta \"Number of bytes in window history\"\n.It Li \"history_limit\" Ta \"\" Ta \"Maximum window history lines\"\n.It Li \"history_size\" Ta \"\" Ta \"Size of history in lines\"\n.It Li \"hook\" Ta \"\" Ta \"Name of running hook, if any\"\n.It Li \"hook_client\" Ta \"\" Ta \"Name of client where hook was run, if any\"\n.It Li \"hook_pane\" Ta \"\" Ta \"ID of pane where hook was run, if any\"\n.It Li \"hook_session\" Ta \"\" Ta \"ID of session where hook was run, if any\"\n.It Li \"hook_session_name\" Ta \"\" Ta \"Name of session where hook was run, if any\"\n.It Li \"hook_window\" Ta \"\" Ta \"ID of window where hook was run, if any\"\n.It Li \"hook_window_name\" Ta \"\" Ta \"Name of window where hook was run, if any\"\n.It Li \"host\" Ta \"#H\" Ta \"Hostname of local host\"\n.It Li \"host_short\" Ta \"#h\" Ta \"Hostname of local host (no domain name)\"\n.It Li \"insert_flag\" Ta \"\" Ta \"Pane insert flag\"\n.It Li \"keypad_cursor_flag\" Ta \"\" Ta \"Pane keypad cursor flag\"\n.It Li \"keypad_flag\" Ta \"\" Ta \"Pane keypad flag\"\n.It Li \"last_window_index\" Ta \"\" Ta \"Index of last window in session\"\n.It Li \"line\" Ta \"\" Ta \"Line number in the list\"\n.It Li \"loop_last_flag\" Ta \"\" Ta \"1 if last window, pane, session, client in the W:, P:, S:, or L: loop\"\n.It Li \"mouse_all_flag\" Ta \"\" Ta \"Pane mouse all flag\"\n.It Li \"mouse_any_flag\" Ta \"\" Ta \"Pane mouse any flag\"\n.It Li \"mouse_button_flag\" Ta \"\" Ta \"Pane mouse button flag\"\n.It Li \"mouse_hyperlink\" Ta \"\" Ta \"Hyperlink under mouse, if any\"\n.It Li \"mouse_line\" Ta \"\" Ta \"Line under mouse, if any\"\n.It Li \"mouse_sgr_flag\" Ta \"\" Ta \"Pane mouse SGR flag\"\n.It Li \"mouse_standard_flag\" Ta \"\" Ta \"Pane mouse standard flag\"\n.It Li \"mouse_status_line\" Ta \"\" Ta \"Status line on which mouse event took place\"\n.It Li \"mouse_status_range\" Ta \"\" Ta \"Range type or argument of mouse event on status line\"\n.It Li \"mouse_utf8_flag\" Ta \"\" Ta \"Pane mouse UTF-8 flag\"\n.It Li \"mouse_word\" Ta \"\" Ta \"Word under mouse, if any\"\n.It Li \"mouse_x\" Ta \"\" Ta \"Mouse X position, if any\"\n.It Li \"mouse_y\" Ta \"\" Ta \"Mouse Y position, if any\"\n.It Li \"next_session_id\" Ta \"\" Ta \"Unique session ID for next new session\"\n.It Li \"origin_flag\" Ta \"\" Ta \"Pane origin flag\"\n.It Li \"pane_active\" Ta \"\" Ta \"1 if active pane\"\n.It Li \"pane_at_bottom\" Ta \"\" Ta \"1 if pane is at the bottom of window\"\n.It Li \"pane_at_left\" Ta \"\" Ta \"1 if pane is at the left of window\"\n.It Li \"pane_at_right\" Ta \"\" Ta \"1 if pane is at the right of window\"\n.It Li \"pane_at_top\" Ta \"\" Ta \"1 if pane is at the top of window\"\n.It Li \"pane_bg\" Ta \"\" Ta \"Pane background colour\"\n.It Li \"pane_bottom\" Ta \"\" Ta \"Bottom of pane\"\n.It Li \"pane_current_command\" Ta \"\" Ta \"Current command if available\"\n.It Li \"pane_current_path\" Ta \"\" Ta \"Current path if available\"\n.It Li \"pane_dead\" Ta \"\" Ta \"1 if pane is dead\"\n.It Li \"pane_dead_signal\" Ta \"\" Ta \"Exit signal of process in dead pane\"\n.It Li \"pane_dead_status\" Ta \"\" Ta \"Exit status of process in dead pane\"\n.It Li \"pane_dead_time\" Ta \"\" Ta \"Exit time of process in dead pane\"\n.It Li \"pane_fg\" Ta \"\" Ta \"Pane foreground colour\"\n.It Li \"pane_format\" Ta \"\" Ta \"1 if format is for a pane\"\n.It Li \"pane_height\" Ta \"\" Ta \"Height of pane\"\n.It Li \"pane_id\" Ta \"#D\" Ta \"Unique pane ID\"\n.It Li \"pane_in_mode\" Ta \"\" Ta \"Number of modes pane is in\"\n.It Li \"pane_index\" Ta \"#P\" Ta \"Index of pane\"\n.It Li \"pane_input_off\" Ta \"\" Ta \"1 if input to pane is disabled\"\n.It Li \"pane_key_mode\" Ta \"\" Ta \"Extended key reporting mode in this pane\"\n.It Li \"pane_last\" Ta \"\" Ta \"1 if last pane\"\n.It Li \"pane_left\" Ta \"\" Ta \"Left of pane\"\n.It Li \"pane_marked\" Ta \"\" Ta \"1 if this is the marked pane\"\n.It Li \"pane_marked_set\" Ta \"\" Ta \"1 if a marked pane is set\"\n.It Li \"pane_mode\" Ta \"\" Ta \"Name of pane mode, if any\"\n.It Li \"pane_path\" Ta \"\" Ta \"Path of pane (can be set by application)\"\n.It Li \"pane_pid\" Ta \"\" Ta \"PID of first process in pane\"\n.It Li \"pane_pipe\" Ta \"\" Ta \"1 if pane is being piped\"\n.It Li \"pane_right\" Ta \"\" Ta \"Right of pane\"\n.It Li \"pane_search_string\" Ta \"\" Ta \"Last search string in copy mode\"\n.It Li \"pane_start_command\" Ta \"\" Ta \"Command pane started with\"\n.It Li \"pane_start_path\" Ta \"\" Ta \"Path pane started with\"\n.It Li \"pane_synchronized\" Ta \"\" Ta \"1 if pane is synchronized\"\n.It Li \"pane_tabs\" Ta \"\" Ta \"Pane tab positions\"\n.It Li \"pane_title\" Ta \"#T\" Ta \"Title of pane (can be set by application)\"\n.It Li \"pane_top\" Ta \"\" Ta \"Top of pane\"\n.It Li \"pane_tty\" Ta \"\" Ta \"Pseudo terminal of pane\"\n.It Li \"pane_unseen_changes\" Ta \"\" Ta \"1 if there were changes in pane while in mode\"\n.It Li \"pane_width\" Ta \"\" Ta \"Width of pane\"\n.It Li \"pid\" Ta \"\" Ta \"Server PID\"\n.It Li \"rectangle_toggle\" Ta \"\" Ta \"1 if rectangle selection is activated\"\n.It Li \"scroll_position\" Ta \"\" Ta \"Scroll position in copy mode\"\n.It Li \"scroll_region_lower\" Ta \"\" Ta \"Bottom of scroll region in pane\"\n.It Li \"scroll_region_upper\" Ta \"\" Ta \"Top of scroll region in pane\"\n.It Li \"search_count\" Ta \"\" Ta \"Count of search results\"\n.It Li \"search_count_partial\" Ta \"\" Ta \"1 if search count is partial count\"\n.It Li \"search_match\" Ta \"\" Ta \"Search match if any\"\n.It Li \"search_present\" Ta \"\" Ta \"1 if search started in copy mode\"\n.It Li \"selection_active\" Ta \"\" Ta \"1 if selection started and changes with the cursor in copy mode\"\n.It Li \"selection_end_x\" Ta \"\" Ta \"X position of the end of the selection\"\n.It Li \"selection_end_y\" Ta \"\" Ta \"Y position of the end of the selection\"\n.It Li \"selection_mode\" Ta \"\" Ta \"Selection mode\"\n.It Li \"selection_present\" Ta \"\" Ta \"1 if selection started in copy mode\"\n.It Li \"selection_start_x\" Ta \"\" Ta \"X position of the start of the selection\"\n.It Li \"selection_start_y\" Ta \"\" Ta \"Y position of the start of the selection\"\n.It Li \"server_sessions\" Ta \"\" Ta \"Number of sessions\"\n.It Li \"session_active\" Ta \"\" Ta \"1 if session active\"\n.It Li \"session_activity\" Ta \"\" Ta \"Time of session last activity\"\n.It Li \"session_activity_flag\" Ta \"\" Ta \"1 if any window in session has activity\"\n.It Li \"session_alerts\" Ta \"\" Ta \"List of window indexes with alerts\"\n.It Li \"session_attached\" Ta \"\" Ta \"Number of clients session is attached to\"\n.It Li \"session_attached_list\" Ta \"\" Ta \"List of clients session is attached to\"\n.It Li \"session_bell_flag\" Ta \"\" Ta \"1 if any window in session has bell\"\n.It Li \"session_created\" Ta \"\" Ta \"Time session created\"\n.It Li \"session_format\" Ta \"\" Ta \"1 if format is for a session\"\n.It Li \"session_group\" Ta \"\" Ta \"Name of session group\"\n.It Li \"session_group_attached\" Ta \"\" Ta \"Number of clients sessions in group are attached to\"\n.It Li \"session_group_attached_list\" Ta \"\" Ta \"List of clients sessions in group are attached to\"\n.It Li \"session_group_list\" Ta \"\" Ta \"List of sessions in group\"\n.It Li \"session_group_many_attached\" Ta \"\" Ta \"1 if multiple clients attached to sessions in group\"\n.It Li \"session_group_size\" Ta \"\" Ta \"Size of session group\"\n.It Li \"session_grouped\" Ta \"\" Ta \"1 if session in a group\"\n.It Li \"session_id\" Ta \"\" Ta \"Unique session ID\"\n.It Li \"session_last_attached\" Ta \"\" Ta \"Time session last attached\"\n.It Li \"session_many_attached\" Ta \"\" Ta \"1 if multiple clients attached\"\n.It Li \"session_marked\" Ta \"\" Ta \"1 if this session contains the marked pane\"\n.It Li \"session_name\" Ta \"#S\" Ta \"Name of session\"\n.It Li \"session_path\" Ta \"\" Ta \"Working directory of session\"\n.It Li \"session_silence_flag\" Ta \"\" Ta \"1 if any window in session has silence alert\"\n.It Li \"session_stack\" Ta \"\" Ta \"Window indexes in most recent order\"\n.It Li \"session_windows\" Ta \"\" Ta \"Number of windows in session\"\n.It Li \"socket_path\" Ta \"\" Ta \"Server socket path\"\n.It Li \"sixel_support\" Ta \"\" Ta \"1 if server has support for SIXEL\"\n.It Li \"start_time\" Ta \"\" Ta \"Server start time\"\n.It Li \"synchronized_output_flag\" Ta \"\" Ta \"1 if pane has synchronized output enabled\"\n.It Li \"uid\" Ta \"\" Ta \"Server UID\"\n.It Li \"user\" Ta \"\" Ta \"Server user\"\n.It Li \"version\" Ta \"\" Ta \"Server version\"\n.It Li \"window_active\" Ta \"\" Ta \"1 if window active\"\n.It Li \"window_active_clients\" Ta \"\" Ta \"Number of clients viewing this window\"\n.It Li \"window_active_clients_list\" Ta \"\" Ta \"List of clients viewing this window\"\n.It Li \"window_active_sessions\" Ta \"\" Ta \"Number of sessions on which this window is active\"\n.It Li \"window_active_sessions_list\" Ta \"\" Ta \"List of sessions on which this window is active\"\n.It Li \"window_activity\" Ta \"\" Ta \"Time of window last activity\"\n.It Li \"window_activity_flag\" Ta \"\" Ta \"1 if window has activity\"\n.It Li \"window_bell_flag\" Ta \"\" Ta \"1 if window has bell\"\n.It Li \"window_bigger\" Ta \"\" Ta \"1 if window is larger than client\"\n.It Li \"window_cell_height\" Ta \"\" Ta \"Height of each cell in pixels\"\n.It Li \"window_cell_width\" Ta \"\" Ta \"Width of each cell in pixels\"\n.It Li \"window_end_flag\" Ta \"\" Ta \"1 if window has the highest index\"\n.It Li \"window_flags\" Ta \"#F\" Ta \"Window flags with # escaped as ##\"\n.It Li \"window_format\" Ta \"\" Ta \"1 if format is for a window\"\n.It Li \"window_height\" Ta \"\" Ta \"Height of window\"\n.It Li \"window_id\" Ta \"\" Ta \"Unique window ID\"\n.It Li \"window_index\" Ta \"#I\" Ta \"Index of window\"\n.It Li \"window_last_flag\" Ta \"\" Ta \"1 if window is the last used\"\n.It Li \"window_layout\" Ta \"\" Ta \"Window layout description, ignoring zoomed window panes\"\n.It Li \"window_linked\" Ta \"\" Ta \"1 if window is linked across sessions\"\n.It Li \"window_linked_sessions\" Ta \"\" Ta \"Number of sessions this window is linked to\"\n.It Li \"window_linked_sessions_list\" Ta \"\" Ta \"List of sessions this window is linked to\"\n.It Li \"window_marked_flag\" Ta \"\" Ta \"1 if window contains the marked pane\"\n.It Li \"window_name\" Ta \"#W\" Ta \"Name of window\"\n.It Li \"window_offset_x\" Ta \"\" Ta \"X offset into window if larger than client\"\n.It Li \"window_offset_y\" Ta \"\" Ta \"Y offset into window if larger than client\"\n.It Li \"window_panes\" Ta \"\" Ta \"Number of panes in window\"\n.It Li \"window_raw_flags\" Ta \"\" Ta \"Window flags with nothing escaped\"\n.It Li \"window_silence_flag\" Ta \"\" Ta \"1 if window has silence alert\"\n.It Li \"window_stack_index\" Ta \"\" Ta \"Index in session most recent stack\"\n.It Li \"window_start_flag\" Ta \"\" Ta \"1 if window has the lowest index\"\n.It Li \"window_visible_layout\" Ta \"\" Ta \"Window layout description, respecting zoomed window panes\"\n.It Li \"window_width\" Ta \"\" Ta \"Width of window\"\n.It Li \"window_zoomed_flag\" Ta \"\" Ta \"1 if window is zoomed\"\n.It Li \"wrap_flag\" Ta \"\" Ta \"Pane wrap flag\"\n.El\n.Sh STYLES\n.Nm\noffers various options to specify the colour and attributes of aspects of the\ninterface, for example\n.Ic status-style\nfor the status line.\nIn addition, embedded styles may be specified in format options, such as\n.Ic status-left ,\nby enclosing them in\n.Ql #[\nand\n.Ql \\&] .\n.Pp\nA style may be the single term\n.Ql default\nto specify the default style (which may come from an option, for example\n.Ic status-style\nin the status line) or a space\nor comma separated list of the following:\n.Bl -tag -width Ds\n.It Ic fg=colour\nSet the foreground colour.\nThe colour is one of:\n.Ic black ,\n.Ic red ,\n.Ic green ,\n.Ic yellow ,\n.Ic blue ,\n.Ic magenta ,\n.Ic cyan ,\n.Ic white ;\nif supported the bright variants\n.Ic brightblack ,\n.Ic brightred ,\n.Eo ...;\n.Ec\n.Ic colour0\nto\n.Ic colour255\nfrom the 256-colour set;\n.Ic default\nfor the default colour;\n.Ic terminal\nfor the terminal default colour; or a hexadecimal RGB string such as\n.Ql #ffffff .\n.It Ic bg=colour\nSet the background colour.\n.It Ic us=colour\nSet the underscore colour.\n.It Ic none\nSet no attributes (turn off any active attributes).\n.It Xo Ic acs ,\n.Ic bright\n(or\n.Ic bold ) ,\n.Ic dim ,\n.Ic underscore ,\n.Ic blink ,\n.Ic reverse ,\n.Ic hidden ,\n.Ic italics ,\n.Ic overline ,\n.Ic strikethrough ,\n.Ic double-underscore ,\n.Ic curly-underscore ,\n.Ic dotted-underscore ,\n.Ic dashed-underscore\n.Xc\nSet an attribute.\nAny of the attributes may be prefixed with\n.Ql no\nto unset.\n.Ic acs\nis the terminal alternate character set.\n.It Xo Ic align=left\n(or\n.Ic noalign ) ,\n.Ic align=centre ,\n.Ic align=right\n.Xc\nAlign text to the left, centre or right of the available space if appropriate.\n.It Ic fill=colour\nFill the available space with a background colour if appropriate.\n.It Xo Ic list=on ,\n.Ic list=focus ,\n.Ic list=left-marker ,\n.Ic list=right-marker ,\n.Ic nolist\n.Xc\nMark the position of the various window list components in the\n.Ic status-format\noption:\n.Ic list=on\nmarks the start of the list;\n.Ic list=focus\nis the part of the list that should be kept in focus if the entire list won't\nfit in the available space (typically the current window);\n.Ic list=left-marker\nand\n.Ic list=right-marker\nmark the text to be used to mark that text has been trimmed from the left or\nright of the list if there is not enough space.\n.It Ic noattr\nDo not copy attributes from the default style.\n.It Xo Ic push-default ,\n.Ic pop-default\n.Xc\nStore the current colours and attributes as the default or reset to the previous\ndefault.\nA\n.Ic push-default\naffects any subsequent use of the\n.Ic default\nterm until a\n.Ic pop-default .\nOnly one default may be pushed (each\n.Ic push-default\nreplaces the previous saved default).\n.It Xo Ic range=left ,\n.Ic range=right ,\n.Ic range=session|X ,\n.Ic range=window|X ,\n.Ic range=pane|X ,\n.Ic range=user|X ,\n.Ic norange\n.Xc\nMark a range for mouse events in the\n.Ic status-format\noption.\nWhen a mouse event occurs in the\n.Ic range=left\nor\n.Ic range=right\nrange, the\n.Ql StatusLeft\nand\n.Ql StatusRight\nkey bindings are triggered.\n.Pp\n.Ic range=session|X ,\n.Ic range=window|X\nand\n.Ic range=pane|X\nare ranges for a session, window or pane.\nThese trigger the\n.Ql Status\nmouse key with the target session, window or pane given by the\n.Ql X\nargument.\n.Ql X\nis a session ID, window index in the current session or a pane ID.\nFor these, the\n.Ic mouse_status_range\nformat variable will be set to\n.Ql session ,\n.Ql window\nor\n.Ql pane .\n.Pp\n.Ic range=user|X\nis a user-defined range; it triggers the\n.Ql Status\nmouse key.\nThe argument\n.Ql X\nwill be available in the\n.Ic mouse_status_range\nformat variable.\n.Ql X\nmust be at most 15 bytes in length.\n.It Ic set-default\nSet the current colours and attributes as the default, overwriting any previous\ndefault.\nThe previous default cannot be restored.\n.El\n.Pp\nExamples are:\n.Bd -literal -offset indent\nfg=yellow bold underscore blink\nbg=black,fg=default,noreverse\n.Ed\n.Sh NAMES AND TITLES\n.Nm\ndistinguishes between names and titles.\nWindows and sessions have names, which may be used to specify them in targets\nand are displayed in the status line and various lists: the name is the\n.Nm\nidentifier for a window or session.\nOnly panes have titles.\nA pane's title is typically set by the program running inside the pane using\nan escape sequence (like it would set the\n.Xr xterm 1\nwindow title in\n.Xr X 7 ) .\nWindows themselves do not have titles - a window's title is the title of its\nactive pane.\n.Nm\nitself may set the title of the terminal in which the client is running, see\nthe\n.Ic set-titles\noption.\n.Pp\nA session's name is set with the\n.Ic new-session\nand\n.Ic rename-session\ncommands.\nA window's name is set with one of:\n.Bl -enum -width Ds\n.It\nA command argument (such as\n.Fl n\nfor\n.Ic new-window\nor\n.Ic new-session ) .\n.It\nAn escape sequence (if the\n.Ic allow-rename\noption is turned on):\n.Bd -literal -offset indent\n$ printf \\[aq]\\e033kWINDOW_NAME\\e033\\e\\e\\[aq]\n.Ed\n.It\nAutomatic renaming, which sets the name to the active command in the window's\nactive pane.\nSee the\n.Ic automatic-rename\noption.\n.El\n.Pp\nWhen a pane is first created, its title is the hostname.\nA pane's title can be set via the title setting escape sequence, for example:\n.Bd -literal -offset indent\n$ printf \\[aq]\\e033]2;My Title\\e033\\e\\e\\[aq]\n.Ed\n.Pp\nIt can also be modified with the\n.Ic select-pane\n.Fl T\ncommand.\n.Sh GLOBAL AND SESSION ENVIRONMENT\nWhen the server is started,\n.Nm\ncopies the environment into the\n.Em global environment ;\nin addition, each session has a\n.Em session environment .\nWhen a window is created, the session and global environments are merged.\nIf a variable exists in both, the value from the session environment is used.\nThe result is the initial environment passed to the new process.\n.Pp\nThe\n.Ic update-environment\nsession option may be used to update the session environment from the client\nwhen a new session is created or an old reattached.\n.Nm\nalso initialises the\n.Ev TMUX\nvariable with some internal information to allow commands to be executed\nfrom inside, and the\n.Ev TERM\nvariable with the correct terminal setting of\n.Ql screen .\n.Pp\nVariables in both session and global environments may be marked as hidden.\nHidden variables are not passed into the environment of new processes and\ninstead can only be used by tmux itself (for example in formats, see the\n.Sx FORMATS\nsection).\n.Pp\nCommands to alter and view the environment are:\n.Bl -tag -width Ds\n.Tg setenv\n.It Xo Ic set-environment\n.Op Fl Fhgru\n.Op Fl t Ar target-session\n.Ar variable Op Ar value\n.Xc\n.D1 Pq alias: Ic setenv\nSet or unset an environment variable.\nIf\n.Fl g\nis used, the change is made in the global environment; otherwise, it is applied\nto the session environment for\n.Ar target-session .\nIf\n.Fl F\nis present, then\n.Ar value\nis expanded as a format.\nThe\n.Fl u\nflag unsets a variable.\n.Fl r\nindicates the variable is to be removed from the environment before starting a\nnew process.\n.Fl h\nmarks the variable as hidden.\n.Tg showenv\n.It Xo Ic show-environment\n.Op Fl hgs\n.Op Fl t Ar target-session\n.Op Ar variable\n.Xc\n.D1 Pq alias: Ic showenv\nDisplay the environment for\n.Ar target-session\nor the global environment with\n.Fl g .\nIf\n.Ar variable\nis omitted, all variables are shown.\nVariables removed from the environment are prefixed with\n.Ql - .\nIf\n.Fl s\nis used, the output is formatted as a set of Bourne shell commands.\n.Fl h\nshows hidden variables (omitted by default).\n.El\n.Sh STATUS LINE\n.Nm\nincludes an optional status line which is displayed in the bottom line of each\nterminal.\n.Pp\nBy default, the status line is enabled and one line in height (it may be\ndisabled or made multiple lines with the\n.Ic status\nsession option) and contains, from left-to-right: the name of the current\nsession in square brackets; the window list; the title of the active pane\nin double quotes; and the time and date.\n.Pp\nEach line of the status line is configured with the\n.Ic status-format\noption.\nThe default is made of three parts: configurable left and right sections (which\nmay contain dynamic content such as the time or output from a shell command,\nsee the\n.Ic status-left ,\n.Ic status-left-length ,\n.Ic status-right ,\nand\n.Ic status-right-length\noptions below), and a central window list.\nBy default, the window list shows the index, name and (if any) flag of the\nwindows present in the current session in ascending numerical order.\nIt may be customised with the\n.Ar window-status-format\nand\n.Ar window-status-current-format\noptions.\nThe flag is one of the following symbols appended to the window name:\n.Bl -column \"Symbol\" \"Meaning\" -offset indent\n.It Sy \"Symbol\" Ta Sy \"Meaning\"\n.It Li \"*\" Ta \"Denotes the current window.\"\n.It Li \"-\" Ta \"Marks the last window (previously selected).\"\n.It Li \"#\" Ta \"Window activity is monitored and activity has been detected.\"\n.It Li \"\\&!\" Ta \"Window bells are monitored and a bell has occurred in the window.\"\n.It Li \"\\[ti]\" Ta \"The window has been silent for the monitor-silence interval.\"\n.It Li \"M\" Ta \"The window contains the marked pane.\"\n.It Li \"Z\" Ta \"The window's active pane is zoomed.\"\n.El\n.Pp\nThe # symbol relates to the\n.Ic monitor-activity\nwindow option.\nThe window name is printed in inverted colours if an alert (bell, activity or\nsilence) is present.\n.Pp\nThe colour and attributes of the status line may be configured, the entire\nstatus line using the\n.Ic status-style\nsession option and individual windows using the\n.Ic window-status-style\nwindow option.\n.Pp\nThe status line is automatically refreshed at interval if it has changed, the\ninterval may be controlled with the\n.Ic status-interval\nsession option.\n.Pp\nCommands related to the status line are as follows:\n.Bl -tag -width Ds\n.Tg clearphist\n.It Xo Ic clear-prompt-history\n.Op Fl T Ar prompt-type\n.Xc\n.D1 Pq alias: Ic clearphist\nClear status prompt history for prompt type\n.Ar prompt-type .\nIf\n.Fl T\nis omitted, then clear history for all types.\nSee\n.Ic command-prompt\nfor possible values for\n.Ar prompt-type .\n.It Xo Ic command-prompt\n.Op Fl 1beFiklN\n.Op Fl I Ar inputs\n.Op Fl p Ar prompts\n.Op Fl t Ar target-client\n.Op Fl T Ar prompt-type\n.Op Ar template\n.Xc\nOpen the command prompt in a client.\nThis may be used from inside\n.Nm\nto execute commands interactively.\n.Pp\nIf\n.Ar template\nis specified, it is used as the command.\nWith\n.Fl F ,\n.Ar template\nis expanded as a format.\n.Pp\nIf\n.Fl I\nis present,\n.Ar inputs\nis a comma-separated list of the initial text for each prompt.\nIf\n.Fl p\nis given,\n.Ar prompts\nis a comma-separated list of prompts which are displayed in order; otherwise\na single prompt is displayed, constructed from\n.Ar template\nif it is present, or\n.Ql \\&:\nif not.\n.Fl l\ndisables splitting of\n.Ar inputs\nand\n.Ar prompts\nat commas and treats them literally.\n.Pp\nBefore the command is executed, the first occurrence of the string\n.Ql %%\nand all occurrences of\n.Ql %1\nare replaced by the response to the first prompt, all\n.Ql %2\nare replaced with the response to the second prompt, and so on for further\nprompts.\nUp to nine prompt responses may be replaced\n.Po\n.Ql %1\nto\n.Ql %9\n.Pc .\n.Ql %%%\nis like\n.Ql %%\nbut any quotation marks are escaped.\n.Pp\n.Fl 1\nmakes the prompt only accept one key press, in this case the resulting input\nis a single character.\n.Fl k\nis like\n.Fl 1\nbut the key press is translated to a key name.\n.Fl N\nmakes the prompt only accept numeric key presses.\n.Fl i\nexecutes the command every time the prompt input changes instead of when the\nuser exits the command prompt.\n.Fl e\nmakes\n.Em BSpace\ncancel an empty prompt.\n.Pp\n.Fl T\ntells\n.Nm\nthe prompt type.\nThis affects what completions are offered when\n.Em Tab\nis pressed.\nAvailable types are:\n.Ql command ,\n.Ql search ,\n.Ql target\nand\n.Ql window-target .\n.Pp\nThe following keys have a special meaning in the command prompt, depending\non the value of the\n.Ic status-keys\noption:\n.Bl -column \"FunctionXXXXXXXXXXXXXXXXXXXXXXXXX\" \"viXXXX\" \"emacsX\" -offset indent\n.It Sy \"Function\" Ta Sy \"vi\" Ta Sy \"emacs\"\n.It Li \"Cancel command prompt\" Ta \"q\" Ta \"Escape\"\n.It Li \"Delete from cursor to start of word\" Ta \"\" Ta \"C-w\"\n.It Li \"Delete entire command\" Ta \"d\" Ta \"C-u\"\n.It Li \"Delete from cursor to end\" Ta \"D\" Ta \"C-k\"\n.It Li \"Execute command\" Ta \"Enter\" Ta \"Enter\"\n.It Li \"Get next command from history\" Ta \"\" Ta \"Down\"\n.It Li \"Get previous command from history\" Ta \"\" Ta \"Up\"\n.It Li \"Insert top paste buffer\" Ta \"p\" Ta \"C-y\"\n.It Li \"Look for completions\" Ta \"Tab\" Ta \"Tab\"\n.It Li \"Move cursor left\" Ta \"h\" Ta \"Left\"\n.It Li \"Move cursor right\" Ta \"l\" Ta \"Right\"\n.It Li \"Move cursor to end\" Ta \"$\" Ta \"C-e\"\n.It Li \"Move cursor to next word\" Ta \"w\" Ta \"M-f\"\n.It Li \"Move cursor to previous word\" Ta \"b\" Ta \"M-b\"\n.It Li \"Move cursor to start\" Ta \"0\" Ta \"C-a\"\n.It Li \"Transpose characters\" Ta \"\" Ta \"C-t\"\n.El\n.Pp\nWith\n.Fl b ,\nthe prompt is shown in the background and the invoking client does not exit\nuntil it is dismissed.\n.Tg confirm\n.It Xo Ic confirm-before\n.Op Fl by\n.Op Fl c Ar confirm-key\n.Op Fl p Ar prompt\n.Op Fl t Ar target-client\n.Ar command\n.Xc\n.D1 Pq alias: Ic confirm\nAsk for confirmation before executing\n.Ar command .\nIf\n.Fl p\nis given,\n.Ar prompt\nis the prompt to display; otherwise a prompt is constructed from\n.Ar command .\nIt may contain the special character sequences supported by the\n.Ic status-left\noption.\nWith\n.Fl b ,\nthe prompt is shown in the background and the invoking client does not exit\nuntil it is dismissed.\n.Fl y\nchanges the default behaviour (if Enter alone is pressed) of the prompt to\nrun the command.\n.Fl c\nchanges the confirmation key to\n.Ar confirm-key ;\nthe default is\n.Ql y .\n.Tg menu\n.It Xo Ic display-menu\n.Op Fl OM\n.Op Fl b Ar border-lines\n.Op Fl c Ar target-client\n.Op Fl C Ar starting-choice\n.Op Fl H Ar selected-style\n.Op Fl s Ar style\n.Op Fl S Ar border-style\n.Op Fl t Ar target-pane\n.Op Fl T Ar title\n.Op Fl x Ar position\n.Op Fl y Ar position\n.Ar name\n.Ar key\n.Ar command\n.Op Ar name key command ...\n.Xc\n.D1 Pq alias: Ic menu\nDisplay a menu on\n.Ar target-client .\n.Ar target-pane\ngives the target for any commands run from the menu.\n.Pp\nA menu is passed as a series of arguments: first the menu item name,\nsecond the key shortcut (or empty for none) and third the command\nto run when the menu item is chosen.\nThe name and command are formats, see the\n.Sx FORMATS\nand\n.Sx STYLES\nsections.\nIf the name begins with a hyphen (-), then the item is disabled (shown dim) and\nmay not be chosen.\nThe name may be empty for a separator line, in which case both the key and\ncommand should be omitted.\n.Pp\n.Fl b\nsets the type of characters used for drawing menu borders.\nSee\n.Ic popup-border-lines\nfor possible values for\n.Ar border-lines .\n.Pp\n.Fl H\nsets the style for the selected menu item (see\n.Sx STYLES ) .\n.Pp\n.Fl s\nsets the style for the menu and\n.Fl S\nsets the style for the menu border (see\n.Sx STYLES ) .\n.Pp\n.Fl T\nis a format for the menu title (see\n.Sx FORMATS ) .\n.Pp\n.Fl C\nsets the menu item selected by default, if the menu is not bound to a mouse key\nbinding.\n.Pp\n.Fl x\nand\n.Fl y\ngive the position of the menu.\nBoth may be a row or column number, or one of the following special values:\n.Bl -column \"XXXXX\" \"XXXX\" -offset indent\n.It Sy \"Value\" Ta Sy \"Flag\" Ta Sy \"Meaning\"\n.It Li \"C\" Ta \"Both\" Ta \"The centre of the terminal\"\n.It Li \"R\" Ta Fl x Ta \"The right side of the terminal\"\n.It Li \"P\" Ta \"Both\" Ta \"The bottom left of the pane\"\n.It Li \"M\" Ta \"Both\" Ta \"The mouse position\"\n.It Li \"W\" Ta \"Both\" Ta \"The window position on the status line\"\n.It Li \"S\" Ta Fl y Ta \"The line above or below the status line\"\n.El\n.Pp\nOr a format, which is expanded including the following additional variables:\n.Bl -column \"XXXXXXXXXXXXXXXXXXXXXXXXXX\" -offset indent\n.It Sy \"Variable name\" Ta Sy \"Replaced with\"\n.It Li \"popup_centre_x\" Ta \"Centered in the client\"\n.It Li \"popup_centre_y\" Ta \"Centered in the client\"\n.It Li \"popup_height\" Ta \"Height of menu or popup\"\n.It Li \"popup_mouse_bottom\" Ta \"Bottom of at the mouse\"\n.It Li \"popup_mouse_centre_x\" Ta \"Horizontal centre at the mouse\"\n.It Li \"popup_mouse_centre_y\" Ta \"Vertical centre at the mouse\"\n.It Li \"popup_mouse_top\" Ta \"Top at the mouse\"\n.It Li \"popup_mouse_x\" Ta \"Mouse X position\"\n.It Li \"popup_mouse_y\" Ta \"Mouse Y position\"\n.It Li \"popup_pane_bottom\" Ta \"Bottom of the pane\"\n.It Li \"popup_pane_left\" Ta \"Left of the pane\"\n.It Li \"popup_pane_right\" Ta \"Right of the pane\"\n.It Li \"popup_pane_top\" Ta \"Top of the pane\"\n.It Li \"popup_status_line_y\" Ta \"Above or below the status line\"\n.It Li \"popup_width\" Ta \"Width of menu or popup\"\n.It Li \"popup_window_status_line_x\" Ta \"At the window position in status line\"\n.It Li \"popup_window_status_line_y\" Ta \"At the status line showing the window\"\n.El\n.Pp\nEach menu consists of items followed by a key shortcut shown in brackets.\nIf the menu is too large to fit on the terminal, it is not displayed.\nPressing the key shortcut chooses the corresponding item.\nIf the mouse is enabled and the menu is opened from a mouse key binding,\nreleasing the mouse button with an item selected chooses that item and\nreleasing the mouse button without an item selected closes the menu.\n.Fl O\nchanges this behaviour so that the menu does not close when the mouse button is\nreleased without an item selected the menu is not closed and a mouse button\nmust be clicked to choose an item.\n.Pp\n.Fl M\ntells\n.Nm\nthe menu should handle mouse events; by default only menus opened from mouse\nkey bindings do so.\n.Pp\nThe following keys are available in menus:\n.Bl -column \"Key\" \"Function\" -offset indent\n.It Sy \"Key\" Ta Sy \"Function\"\n.It Li \"Enter\" Ta \"Choose selected item\"\n.It Li \"Up\" Ta \"Select previous item\"\n.It Li \"Down\" Ta \"Select next item\"\n.It Li \"q\" Ta \"Exit menu\"\n.El\n.Tg display\n.It Xo Ic display-message\n.Op Fl aCIlNpv\n.Op Fl c Ar target-client\n.Op Fl d Ar delay\n.Op Fl t Ar target-pane\n.Op Ar message\n.Xc\n.D1 Pq alias: Ic display\nDisplay a message.\nIf\n.Fl p\nis given, the output is printed to stdout, otherwise it is displayed in the\n.Ar target-client\nstatus line for up to\n.Ar delay\nmilliseconds.\nIf\n.Ar delay\nis not given, the\n.Ic display-time\noption is used; a delay of zero waits for a key press.\n.Ql N\nignores key presses and closes only after the delay expires.\nIf\n.Fl C\nis given, the pane will continue to be updated while the message is displayed.\nIf\n.Fl l\nis given,\n.Ar message\nis printed unchanged.\nOtherwise, the format of\n.Ar message\nis described in the\n.Sx FORMATS\nsection; information is taken from\n.Ar target-pane\nif\n.Fl t\nis given, otherwise the active pane.\n.Pp\n.Fl v\nprints verbose logging as the format is parsed and\n.Fl a\nlists the format variables and their values.\n.Pp\n.Fl I\nforwards any input read from stdin to the empty pane given by\n.Ar target-pane .\n.Tg popup\n.It Xo Ic display-popup\n.Op Fl BCEkN\n.Op Fl b Ar border-lines\n.Op Fl c Ar target-client\n.Op Fl d Ar start-directory\n.Op Fl e Ar environment\n.Op Fl h Ar height\n.Op Fl s Ar style\n.Op Fl S Ar border-style\n.Op Fl t Ar target-pane\n.Op Fl T Ar title\n.Op Fl w Ar width\n.Op Fl x Ar position\n.Op Fl y Ar position\n.Op Ar shell-command Op Ar argument ...\n.Xc\n.D1 Pq alias: Ic popup\nDisplay a popup running\n.Ar shell-command\n(or\n.Ar default-command\nwhen omitted) on\n.Ar target-client .\nA popup is a rectangular box drawn over the top of any panes.\nPanes are not updated while a popup is present.\nIf the command is run inside an existing popup, that popup is modified.\nOnly the\n.Fl b ,\n.Fl B ,\n.Fl C ,\n.Fl E ,\n.Fl EE ,\n.Fl K ,\n.Fl N ,\n.Fl s ,\nand\n.Fl S\noptions are accepted in this case;\nall others are ignored.\n.Pp\n.Fl E\ncloses the popup automatically when\n.Ar shell-command\nexits.\nTwo\n.Fl E\ncloses the popup only if\n.Ar shell-command\nexited with success.\n.Fl k\nallows any key to dismiss the popup instead of only\n.Ql Escape\nor\n.Ql C-c .\n.Pp\n.Fl x\nand\n.Fl y\ngive the position of the popup, they have the same meaning as for the\n.Ic display-menu\ncommand.\n.Fl w\nand\n.Fl h\ngive the width and height - both may be a percentage (followed by\n.Ql % ) .\nIf omitted, half of the terminal size is used.\n.Pp\n.Fl B\ndoes not surround the popup by a border.\n.Pp\n.Fl b\nsets the type of characters used for drawing popup borders.\nWhen\n.Fl B\nis specified, the\n.Fl b\noption is ignored.\nSee\n.Ic popup-border-lines\nfor possible values for\n.Ar border-lines .\n.Pp\n.Fl s\nsets the style for the popup and\n.Fl S\nsets the style for the popup border (see\n.Sx STYLES ) .\n.Pp\n.Fl e\ntakes the form\n.Ql VARIABLE=value\nand sets an environment variable for the popup; it may be specified multiple\ntimes.\n.Pp\n.Fl T\nis a format for the popup title (see\n.Sx FORMATS ) .\n.Pp\nThe\n.Fl C\nflag closes any popup on the client.\n.Pp\n.Fl N\ndisables any previously specified -E, -EE, or -k option.\n.Tg showphist\n.It Xo Ic show-prompt-history\n.Op Fl T Ar prompt-type\n.Xc\n.D1 Pq alias: Ic showphist\nDisplay status prompt history for prompt type\n.Ar prompt-type .\nIf\n.Fl T\nis omitted, then show history for all types.\nSee\n.Ic command-prompt\nfor possible values for\n.Ar prompt-type .\n.El\n.Sh BUFFERS\n.Nm\nmaintains a set of named\n.Em paste buffers .\nEach buffer may be either explicitly or automatically named.\nExplicitly named buffers are named when created with the\n.Ic set-buffer\nor\n.Ic load-buffer\ncommands, or by renaming an automatically named buffer with\n.Ic set-buffer\n.Fl n .\nAutomatically named buffers are given a name such as\n.Ql buffer0001 ,\n.Ql buffer0002\nand so on.\nWhen the\n.Ic buffer-limit\noption is reached, the oldest automatically named buffer is deleted.\nExplicitly named buffers are not subject to\n.Ic buffer-limit\nand may be deleted with the\n.Ic delete-buffer\ncommand.\n.Pp\nBuffers may be added using\n.Ic copy-mode\nor the\n.Ic set-buffer\nand\n.Ic load-buffer\ncommands, and pasted into a window using the\n.Ic paste-buffer\ncommand.\nIf a buffer command is used and no buffer is specified, the most\nrecently added automatically named buffer is assumed.\n.Pp\nA configurable history buffer is also maintained for each window.\nBy default, up to 2000 lines are kept; this can be altered with the\n.Ic history-limit\noption (see the\n.Ic set-option\ncommand above).\n.Pp\nThe buffer commands are as follows:\n.Bl -tag -width Ds\n.It Xo\n.Ic choose-buffer\n.Op Fl NryZ\n.Op Fl F Ar format\n.Op Fl f Ar filter\n.Op Fl K Ar key-format\n.Op Fl O Ar sort-order\n.Op Fl t Ar target-pane\n.Op Ar template\n.Xc\nPut a pane into buffer mode, where a buffer may be chosen interactively from\na list.\nEach buffer is shown on one line.\nA shortcut key is shown on the left in brackets allowing for immediate choice,\nor the list may be navigated and an item chosen or otherwise manipulated using\nthe keys below.\n.Fl Z\nzooms the pane.\n.Fl y\ndisables any confirmation prompts.\nThe following keys may be used in buffer mode:\n.Bl -column \"Key\" \"Function\" -offset indent\n.It Sy \"Key\" Ta Sy \"Function\"\n.It Li \"Enter\" Ta \"Paste selected buffer\"\n.It Li \"Up\" Ta \"Select previous buffer\"\n.It Li \"Down\" Ta \"Select next buffer\"\n.It Li \"C-s\" Ta \"Search by name or content\"\n.It Li \"n\" Ta \"Repeat last search forwards\"\n.It Li \"N\" Ta \"Repeat last search backwards\"\n.It Li \"t\" Ta \"Toggle if buffer is tagged\"\n.It Li \"T\" Ta \"Tag no buffers\"\n.It Li \"C-t\" Ta \"Tag all buffers\"\n.It Li \"p\" Ta \"Paste selected buffer\"\n.It Li \"P\" Ta \"Paste tagged buffers\"\n.It Li \"d\" Ta \"Delete selected buffer\"\n.It Li \"D\" Ta \"Delete tagged buffers\"\n.It Li \"e\" Ta \"Open the buffer in an editor\"\n.It Li \"f\" Ta \"Enter a format to filter items\"\n.It Li \"O\" Ta \"Change sort order\"\n.It Li \"r\" Ta \"Reverse sort order\"\n.It Li \"v\" Ta \"Toggle preview\"\n.It Li \"q\" Ta \"Exit mode\"\n.El\n.Pp\nAfter a buffer is chosen,\n.Ql %%\nis replaced by the buffer name in\n.Ar template\nand the result executed as a command.\nIf\n.Ar template\nis not given, \"paste-buffer -p -b \\[aq]%%\\[aq]\" is used.\n.Pp\n.Fl O\nspecifies the initial sort order: one of\n.Ql creation\n(time),\n.Ql name ,\nor\n.Ql size .\n.Fl r\nreverses the sort order.\n.Fl f\nspecifies an initial filter: the filter is a format - if it evaluates to zero,\nthe item in the list is not shown, otherwise it is shown.\nIf a filter would lead to an empty list, it is ignored.\n.Fl F\nspecifies the format for each item in the list and\n.Fl K\na format for each shortcut key; both are evaluated once for each line.\n.Fl N\nstarts without the preview.\nThis command works only if at least one client is attached.\n.Tg clearhist\n.It Xo Ic clear-history\n.Op Fl H\n.Op Fl t Ar target-pane\n.Xc\n.D1 Pq alias: Ic clearhist\nRemove and free the history for the specified pane.\n.Fl H\nalso removes all hyperlinks.\n.Tg deleteb\n.It Ic delete-buffer Op Fl b Ar buffer-name\n.D1 Pq alias: Ic deleteb\nDelete the buffer named\n.Ar buffer-name ,\nor the most recently added automatically named buffer if not specified.\n.Tg lsb\n.It Xo Ic list-buffers\n.Op Fl r\n.Op Fl F Ar format\n.Op Fl f Ar filter\n.Op Fl O Ar sort-order\n.Xc\n.D1 Pq alias: Ic lsb\nList the global buffers.\n.Fl F\nspecifies the format of each line and\n.Fl f\na filter.\nOnly buffers for which the filter is true are shown.\nSee the\n.Sx FORMATS\nsection.\n.Fl O\nspecifies the sort order: one of\n.Ql name ,\n.Ql size ,\nor\n.Ql creation\n(time).\n.Fl r\nreverses the sort order.\n.It Xo Ic load-buffer\n.Op Fl w\n.Op Fl b Ar buffer-name\n.Op Fl t Ar target-client\n.Ar path\n.Xc\n.Tg loadb\n.D1 Pq alias: Ic loadb\nLoad the contents of the specified paste buffer from\n.Ar path .\nIf\n.Fl w\nis given, the buffer is also sent to the clipboard for\n.Ar target-client\nusing the\n.Xr xterm 1\nescape sequence, if possible.\nIf\n.Ar path\nis\n.Ql - ,\nthe contents are read from stdin.\n.Tg pasteb\n.It Xo Ic paste-buffer\n.Op Fl dpr\n.Op Fl b Ar buffer-name\n.Op Fl s Ar separator\n.Op Fl t Ar target-pane\n.Xc\n.D1 Pq alias: Ic pasteb\nInsert the contents of a paste buffer into the specified pane.\nIf not specified, paste into the current one.\nWith\n.Fl d ,\nalso delete the paste buffer.\nWhen output, any linefeed (LF) characters in the paste buffer are replaced with\na separator, by default carriage return (CR).\nA custom separator may be specified using the\n.Fl s\nflag.\nThe\n.Fl r\nflag means to do no replacement (equivalent to a separator of LF).\nIf\n.Fl p\nis specified, paste bracket control codes are inserted around the\nbuffer if the application has requested bracketed paste mode.\n.Tg saveb\n.It Xo Ic save-buffer\n.Op Fl a\n.Op Fl b Ar buffer-name\n.Ar path\n.Xc\n.D1 Pq alias: Ic saveb\nSave the contents of the specified paste buffer to\n.Ar path .\nThe\n.Fl a\noption appends to rather than overwriting the file.\nIf\n.Ar path\nis\n.Ql - ,\nthe contents are written to stdout.\n.It Xo Ic set-buffer\n.Op Fl aw\n.Op Fl b Ar buffer-name\n.Op Fl t Ar target-client\n.Tg setb\n.Op Fl n Ar new-buffer-name\n.Ar data\n.Xc\n.D1 Pq alias: Ic setb\nSet the contents of the specified buffer to\n.Ar data .\nIf\n.Fl w\nis given, the buffer is also sent to the clipboard for\n.Ar target-client\nusing the\n.Xr xterm 1\nescape sequence, if possible.\nThe\n.Fl a\noption appends to rather than overwriting the buffer.\nThe\n.Fl n\noption renames the buffer to\n.Ar new-buffer-name .\n.Tg showb\n.It Xo Ic show-buffer\n.Op Fl b Ar buffer-name\n.Xc\n.D1 Pq alias: Ic showb\nDisplay the contents of the specified buffer.\n.El\n.Sh MISCELLANEOUS\nMiscellaneous commands are as follows:\n.Bl -tag -width Ds\n.It Ic clock-mode Op Fl t Ar target-pane\nDisplay a large clock.\n.Tg if\n.It Xo Ic if-shell\n.Op Fl bF\n.Op Fl t Ar target-pane\n.Ar shell-command command\n.Op Ar command\n.Xc\n.D1 Pq alias: Ic if\nExecute the first\n.Ar command\nif\n.Ar shell-command\n(run with\n.Pa /bin/sh )\nreturns success or the second\n.Ar command\notherwise.\nBefore being executed,\n.Ar shell-command\nis expanded using the rules specified in the\n.Sx FORMATS\nsection, including those relevant to\n.Ar target-pane .\nWith\n.Fl b ,\n.Ar shell-command\nis run in the background.\n.Pp\nIf\n.Fl F\nis given,\n.Ar shell-command\nis not executed but considered success if neither empty nor zero (after formats\nare expanded).\n.Tg lock\n.It Ic lock-server\n.D1 Pq alias: Ic lock\nLock each client individually by running the command specified by the\n.Ic lock-command\noption.\n.Tg run\n.It Xo Ic run-shell\n.Op Fl bCE\n.Op Fl c Ar start-directory\n.Op Fl d Ar delay\n.Op Fl t Ar target-pane\n.Op Ar shell-command\n.Xc\n.D1 Pq alias: Ic run\nExecute\n.Ar shell-command\nusing\n.Pa /bin/sh\nor (with\n.Fl C )\na\n.Nm\ncommand in the background without creating a window.\nBefore being executed,\n.Ar shell-command\nis expanded using the rules specified in the\n.Sx FORMATS\nsection.\nWith\n.Fl b ,\nthe command is run in the background.\n.Fl d\nwaits for\n.Ar delay\nseconds before starting the command.\n.Fl E\nredirects the command's stderr to stdout instead of ignoring it.\nIf\n.Fl c\nis given, the current working directory is set to\n.Ar start-directory .\nIf\n.Fl C\nis not given, any output to stdout is displayed in view mode (in the pane\nspecified by\n.Fl t\nor the current pane if omitted) after the command finishes.\nIf the command fails, the exit status is also displayed.\n.Tg wait\n.It Xo Ic wait-for\n.Op Fl L | S | U\n.Ar channel\n.Xc\n.D1 Pq alias: Ic wait\nWhen used without options, prevents the client from exiting until woken using\n.Ic wait-for\n.Fl S\nwith the same channel.\nWhen\n.Fl L\nis used, the channel is locked and any clients that try to lock the same\nchannel are made to wait until the channel is unlocked with\n.Ic wait-for\n.Fl U .\n.El\n.Sh EXIT MESSAGES\nWhen a\n.Nm\nclient detaches, it prints a message.\nThis may be one of:\n.Bl -tag -width Ds\n.It detached (from session ...)\nThe client was detached normally.\n.It detached and SIGHUP\nThe client was detached and its parent sent the\n.Dv SIGHUP\nsignal (for example with\n.Ic detach-client\n.Fl P ) .\n.It lost tty\nThe client's\n.Xr tty 4\nor\n.Xr pty 4\nwas unexpectedly destroyed.\n.It terminated\nThe client was killed with\n.Dv SIGTERM .\n.It too far behind\nThe client is in control mode and became unable to keep up with the data from\n.Nm .\n.It exited\nThe server exited when it had no sessions.\n.It server exited\nThe server exited when it received\n.Dv SIGTERM .\n.It server exited unexpectedly\nThe server crashed or otherwise exited without telling the client the reason.\n.El\n.Sh TERMINFO EXTENSIONS\n.Nm\nunderstands some unofficial extensions to\n.Xr terminfo 5 .\nIt is not normally necessary to set these manually, instead the\n.Ic terminal-features\noption should be used.\n.Bl -tag -width Ds\n.It Em \\&AX\nAn existing extension that tells\n.Nm\nthe terminal supports default colours.\n.It Em \\&Bidi\nTell\n.Nm\nthat the terminal supports the VTE bidirectional text extensions.\n.It Em \\&Cs , Cr\nSet the cursor colour.\nThe first takes a single string argument and is used to set the colour;\nthe second takes no arguments and restores the default cursor colour.\nIf set, a sequence such as this may be used\nto change the cursor colour from inside\n.Nm :\n.Bd -literal -offset indent\n$ printf \\[aq]\\e033]12;red\\e033\\e\\e\\[aq]\n.Ed\n.Pp\nThe colour is an\n.Xr X 7\ncolour, see\n.Xr XParseColor 3 .\n.It Em \\&Cmg, \\&Clmg, \\&Dsmg , \\&Enmg\nSet, clear, disable or enable DECSLRM margins.\nThese are set automatically if the terminal reports it is\n.Em VT420\ncompatible.\n.It Em \\&Dsbp , \\&Enbp\nDisable and enable bracketed paste.\nThese are set automatically if the\n.Em XT\ncapability is present.\n.It Em \\&Dseks , \\&Eneks\nDisable and enable extended keys.\n.It Em \\&Dsfcs , \\&Enfcs\nDisable and enable focus reporting.\nThese are set automatically if the\n.Em XT\ncapability is present.\n.It Em \\&Hls\nSet or clear a hyperlink annotation.\n.It Em \\&Nobr\nTell\n.Nm\nthat the terminal does not use bright colors for bold display.\n.It Em \\&Rect\nTell\n.Nm\nthat the terminal supports rectangle operations.\n.It Em \\&Smol\nEnable the overline attribute.\n.It Em \\&Smulx\nSet a styled underscore.\nThe single parameter is one of: 0 for no underscore, 1 for normal\nunderscore, 2 for double underscore, 3 for curly underscore, 4 for dotted\nunderscore and 5 for dashed underscore.\n.It Em \\&Setulc , \\&Setulc1, \\&ol\nSet the underscore colour or reset to the default.\n.Em Setulc\nis for RGB colours and\n.Em Setulc1\nfor ANSI or 256 colours.\nThe\n.Em Setulc\nargument is (red * 65536) + (green * 256) + blue where each is between 0\nand 255.\n.It Em \\&Ss , Se\nSet or reset the cursor style.\nIf set, a sequence such as this may be used\nto change the cursor to an underline:\n.Bd -literal -offset indent\n$ printf \\[aq]\\e033[4 q\\[aq]\n.Ed\n.Pp\nIf\n.Em Se\nis not set, \\&Ss with argument 0 will be used to reset the cursor style instead.\n.It Em \\&Swd\nSet the opening sequence for the working directory notification.\nThe sequence is terminated using the standard\n.Em fsl\ncapability.\n.It Em \\&Sxl\nIndicates that the terminal supports SIXEL.\n.It Em \\&Sync\nStart (parameter is 1) or end (parameter is 2) a synchronized update.\n.It Em \\&Tc\nIndicate that the terminal supports the\n.Ql direct colour\nRGB escape sequence (for example, \\ee[38;2;255;255;255m).\n.Pp\nIf supported, this is used for the initialize colour escape sequence (which\nmay be enabled by adding the\n.Ql initc\nand\n.Ql ccc\ncapabilities to the\n.Nm\n.Xr terminfo 5\nentry).\n.Pp\nThis is equivalent to the\n.Em RGB\n.Xr terminfo 5\ncapability.\n.It Em \\&Ms\nStore the current buffer in the host terminal's selection (clipboard).\nSee the\n.Em set-clipboard\noption above and the\n.Xr xterm 1\nman page.\n.It Em \\&XT\nThis is an existing extension capability that tmux uses to mean that the\nterminal supports the\n.Xr xterm 1\ntitle set sequences and to automatically set some of the capabilities above.\n.El\n.Sh CONTROL MODE\n.Nm\noffers a textual interface called\n.Em control mode .\nThis allows applications to communicate with\n.Nm\nusing a simple text-only protocol.\n.Pp\nIn control mode, a client sends\n.Nm\ncommands or command sequences terminated by newlines on standard input.\nEach command will produce one block of output on standard output.\nAn output block consists of a\n.Em %begin\nline followed by the output (which may be empty).\nThe output block ends with a\n.Em %end\nor\n.Em %error .\n.Em %begin\nand matching\n.Em %end\nor\n.Em %error\nhave three arguments: an integer time (as seconds from epoch), command number\nand flags (currently not used).\nFor example:\n.Bd -literal -offset indent\n%begin 1363006971 2 1\n0: ksh* (1 panes) [80x24] [layout b25f,80x24,0,0,2] @2 (active)\n%end 1363006971 2 1\n.Ed\n.Pp\nThe\n.Ic refresh-client\n.Fl C\ncommand may be used to set the size of a client in control mode.\n.Pp\nIn control mode,\n.Nm\noutputs notifications.\nA notification will never occur inside an output block.\n.Pp\nThe following notifications are defined:\n.Bl -tag -width Ds\n.It Ic %client-detached Ar client\nThe client has detached.\n.It Ic %client-session-changed Ar client session-id name\nThe client is now attached to the session with ID\n.Ar session-id ,\nwhich is named\n.Ar name .\n.It Ic %config-error Ar error\nAn error has happened in a configuration file.\n.It Ic %continue Ar pane-id\nThe pane has been continued after being paused (if the\n.Ar pause-after\nflag is set, see\n.Ic refresh-client\n.Fl A ) .\n.It Ic %exit Op Ar reason\nThe\n.Nm\nclient is exiting immediately, either because it is not attached to any session\nor an error occurred.\nIf present,\n.Ar reason\ndescribes why the client exited.\n.It Ic %extended-output Ar pane-id Ar age Ar ... \\& : Ar value\nNew form of\n.Ic %output\nsent when the\n.Ar pause-after\nflag is set.\n.Ar age\nis the time in milliseconds for which tmux had buffered the output before it\nwas sent.\nAny subsequent arguments up until a single\n.Ql \\&:\nare for future use and should be ignored.\n.It Xo Ic %layout-change\n.Ar window-id\n.Ar window-layout\n.Ar window-visible-layout\n.Ar window-flags\n.Xc\nThe layout of a window with ID\n.Ar window-id\nchanged.\nThe new layout is\n.Ar window-layout .\nThe window's visible layout is\n.Ar window-visible-layout\nand the window flags are\n.Ar window-flags .\n.It Ic %message Ar message\nA message sent with the\n.Ic display-message\ncommand.\n.It Ic %output Ar pane-id Ar value\nA window pane produced output.\n.Ar value\nescapes non-printable characters and backslash as octal \\\\xxx.\n.It Ic %pane-mode-changed Ar pane-id\nThe pane with ID\n.Ar pane-id\nhas changed mode.\n.It Ic %paste-buffer-changed Ar name\nPaste buffer\n.Ar name\nhas been changed.\n.It Ic %paste-buffer-deleted Ar name\nPaste buffer\n.Ar name\nhas been deleted.\n.It Ic %pause Ar pane-id\nThe pane has been paused (if the\n.Ar pause-after\nflag is set).\n.It Ic %session-changed Ar session-id Ar name\nThe client is now attached to the session with ID\n.Ar session-id ,\nwhich is named\n.Ar name .\n.It Ic %session-renamed Ar name\nThe current session was renamed to\n.Ar name .\n.It Ic %session-window-changed Ar session-id Ar window-id\nThe session with ID\n.Ar session-id\nchanged its active window to the window with ID\n.Ar window-id .\n.It Ic %sessions-changed\nA session was created or destroyed.\n.It Xo Ic %subscription-changed\n.Ar name\n.Ar session-id\n.Ar window-id\n.Ar window-index\n.Ar pane-id ... \\& :\n.Ar value\n.Xc\nThe value of the format associated with subscription\n.Ar name\nhas changed to\n.Ar value .\nSee\n.Ic refresh-client\n.Fl B .\nAny arguments after\n.Ar pane-id\nup until a single\n.Ql \\&:\nare for future use and should be ignored.\n.It Ic %unlinked-window-add Ar window-id\nThe window with ID\n.Ar window-id\nwas created but is not linked to the current session.\n.It Ic %unlinked-window-close Ar window-id\nThe window with ID\n.Ar window-id ,\nwhich is not linked to the current session, was closed.\n.It Ic %unlinked-window-renamed Ar window-id\nThe window with ID\n.Ar window-id ,\nwhich is not linked to the current session, was renamed.\n.It Ic %window-add Ar window-id\nThe window with ID\n.Ar window-id\nwas linked to the current session.\n.It Ic %window-close Ar window-id\nThe window with ID\n.Ar window-id\nclosed.\n.It Ic %window-pane-changed Ar window-id Ar pane-id\nThe active pane in the window with ID\n.Ar window-id\nchanged to the pane with ID\n.Ar pane-id .\n.It Ic %window-renamed Ar window-id Ar name\nThe window with ID\n.Ar window-id\nwas renamed to\n.Ar name .\n.El\n.Sh ENVIRONMENT\nWhen\n.Nm\nis started, it inspects the following environment variables:\n.Bl -tag -width LC_CTYPE\n.It Ev EDITOR\nIf the command specified in this variable contains the string\n.Ql vi\nand\n.Ev VISUAL\nis unset, use vi-style key bindings.\nOverridden by the\n.Ic mode-keys\nand\n.Ic status-keys\noptions.\n.It Ev HOME\nThe user's login directory.\nIf unset, the\n.Xr passwd 5\ndatabase is consulted.\n.It Ev LC_CTYPE\nThe character encoding\n.Xr locale 1 .\nIt is used for two separate purposes.\nFor output to the terminal, UTF-8 is used if the\n.Fl u\noption is given or if\n.Ev LC_CTYPE\ncontains\n.Qq UTF-8\nor\n.Qq UTF8 .\nOtherwise, only ASCII characters are written and non-ASCII characters\nare replaced with underscores\n.Pq Ql _ .\nFor input,\n.Nm\nalways runs with a UTF-8 locale.\nIf en_US.UTF-8 is provided by the operating system, it is used and\n.Ev LC_CTYPE\nis ignored for input.\nOtherwise,\n.Ev LC_CTYPE\ntells\n.Nm\nwhat the UTF-8 locale is called on the current system.\nIf the locale specified by\n.Ev LC_CTYPE\nis not available or is not a UTF-8 locale,\n.Nm\nexits with an error message.\n.It Ev LC_TIME\nThe date and time format\n.Xr locale 1 .\nIt is used for locale-dependent\n.Xr strftime 3\nformat specifiers.\n.It Ev PWD\nThe current working directory to be set in the global environment.\nThis may be useful if it contains symbolic links.\nIf the value of the variable does not match the current working\ndirectory, the variable is ignored and the result of\n.Xr getcwd 3\nis used instead.\n.It Ev SHELL\nThe absolute path to the default shell for new windows.\nSee the\n.Ic default-shell\noption for details.\n.It Ev TMUX_TMPDIR\nThe parent directory of the directory containing the server sockets.\nSee the\n.Fl L\noption for details.\n.It Ev VISUAL\nIf the command specified in this variable contains the string\n.Ql vi ,\nuse vi-style key bindings.\nOverridden by the\n.Ic mode-keys\nand\n.Ic status-keys\noptions.\n.El\n.Sh FILES\n.Bl -tag -width \"@SYSCONFDIR@/tmux.confXXX\" -compact\n.It Pa \\[ti]/.tmux.conf\n.It Pa $XDG_CONFIG_HOME/tmux/tmux.conf\n.It Pa \\[ti]/.config/tmux/tmux.conf\nDefault\n.Nm\nconfiguration file.\n.It Pa @SYSCONFDIR@/tmux.conf\nSystem-wide configuration file.\n.El\n.Sh EXAMPLES\nTo create a new\n.Nm\nsession running\n.Xr vi 1 :\n.Pp\n.Dl $ tmux new-session vi\n.Pp\nMost commands have a shorter form, known as an alias.\nFor new-session, this is\n.Ic new :\n.Pp\n.Dl $ tmux new vi\n.Pp\nAlternatively, the shortest unambiguous form of a command is accepted.\nIf there are several options, they are listed:\n.Bd -literal -offset indent\n$ tmux n\nambiguous command: n, could be: new-session, new-window, next-window\n.Ed\n.Pp\nWithin an active session, a new window may be created by typing\n.Ql C-b c\n(Ctrl\nfollowed by the\n.Ql b\nkey\nfollowed by the\n.Ql c\nkey).\n.Pp\nWindows may be navigated with:\n.Ql C-b 0\n(to select window 0),\n.Ql C-b 1\n(to select window 1), and so on;\n.Ql C-b n\nto select the next window; and\n.Ql C-b p\nto select the previous window.\n.Pp\nA session may be detached using\n.Ql C-b d\n(or by an external event such as\n.Xr ssh 1\ndisconnection) and reattached with:\n.Pp\n.Dl $ tmux attach-session\n.Pp\nTyping\n.Ql C-b \\&?\nlists the current key bindings in the current window; up and down may be used\nto navigate the list or\n.Ql q\nto exit from it.\n.Pp\nCommands to be run when the\n.Nm\nserver is started may be placed in the\n.Pa \\[ti]/.tmux.conf\nconfiguration file.\nCommon examples include:\n.Pp\nChanging the default prefix key:\n.Bd -literal -offset indent\nset-option -g prefix C-a\nunbind-key C-b\nbind-key C-a send-prefix\n.Ed\n.Pp\nTurning the status line off, or changing its colour:\n.Bd -literal -offset indent\nset-option -g status off\nset-option -g status-style bg=blue\n.Ed\n.Pp\nSetting other options, such as the default command,\nor locking after 30 minutes of inactivity:\n.Bd -literal -offset indent\nset-option -g default-command \"exec /bin/ksh\"\nset-option -g lock-after-time 1800\n.Ed\n.Pp\nCreating new key bindings:\n.Bd -literal -offset indent\nbind-key b set-option status\nbind-key / command-prompt \"split-window \\[aq]exec man %%\\[aq]\"\nbind-key S command-prompt \"new-window -n %1 \\[aq]ssh %1\\[aq]\"\n.Ed\n.Sh SEE ALSO\n.Xr pty 4\n.Sh AUTHORS\n.An Nicholas Marriott Aq Mt nicholas.marriott@gmail.com\n",
"sha256": "f2966da7a8267abc9aaa216a7a7b46d4d914d60114058dc046c4ff1c75ac9422"
},
".github/tools/external/tmux/example_tmux.conf": {
"mode": "100644",
"encoding": "utf-8",
"data": "#\n# Example .tmux.conf\n#\n# By Nicholas Marriott. Public domain.\n#\n\n# Some tweaks to the status line\nset -g status-right \"%H:%M\"\nset -g window-status-current-style \"underscore\"\n\n# If running inside tmux ($TMUX is set), then change the status line to red\n%if #{TMUX}\nset -g status-bg red\n%endif\n\n# Enable RGB colour if running in xterm(1)\nset-option -sa terminal-features \",xterm*:RGB\"\n\n# Change the default $TERM to tmux-256color\nset -g default-terminal \"tmux-256color\"\n\n# No bells at all\nset -g bell-action none\n\n# Keep windows around after they exit\nset -g remain-on-exit on\n\n# Change the prefix key to C-a\nset -g prefix C-a\nunbind C-b\nbind C-a send-prefix\n\n# Turn the mouse on, but without copy mode dragging\nset -g mouse on\nunbind -n MouseDrag1Pane\nunbind -Tcopy-mode MouseDrag1Pane\n\n# Some extra key bindings to select higher numbered windows\nbind F1 selectw -t:10\nbind F2 selectw -t:11\nbind F3 selectw -t:12\nbind F4 selectw -t:13\nbind F5 selectw -t:14\nbind F6 selectw -t:15\nbind F7 selectw -t:16\nbind F8 selectw -t:17\nbind F9 selectw -t:18\nbind F10 selectw -t:19\nbind F11 selectw -t:20\nbind F12 selectw -t:21\n\n# A key to toggle between smallest and largest sizes if a window is visible in\n# multiple places\nbind F set -w window-size\n\n# Keys to toggle monitoring activity in a window and the synchronize-panes option\nbind m set monitor-activity\nbind y set synchronize-panes\\; display 'synchronize-panes #{?synchronize-panes,on,off}'\n\n# Create a single default session - because a session is created here, tmux\n# should be started with \"tmux attach\" rather than \"tmux new\"\nnew -d -s0 -nirssi 'exec irssi'\nset -t0:0 monitor-activity on\nset -t0:0 aggressive-resize on\nneww -d -ntodo 'exec emacs ~/TODO'\nsetw -t0:1 aggressive-resize on\nneww -d -nmutt 'exec mutt'\nsetw -t0:2 aggressive-resize on\nneww -d\nneww -d\nneww -d\n",
"sha256": "0ab7c28342180d485434c3d8e286508a1e1c87ac9a2c8f2dc78bcf477a2de437"
},
".github/tools/external/tmux/tools/24-bit-color.sh": {
"mode": "100644",
"encoding": "utf-8",
"data": "#!/bin/bash\n#\n# This file echoes four gradients with 24-bit color codes\n# to the terminal to demonstrate their functionality.\n# The foreground escape sequence is ^[38;2;<r>;<g>;<b>m\n# The background escape sequence is ^[48;2;<r>;<g>;<b>m\n# <r> <g> <b> range from 0 to 255 inclusive.\n# The escape sequence ^[0m returns output to default\n\n#\n# From\n# https://github.com/gnachman/iTerm2/blob/master/tests/24-bit-color.sh\n# and presumably covered by\n# https://github.com/gnachman/iTerm2/blob/master/LICENSE\n#\n\nSEQ1=\nif which gseq >/dev/null 2>&1; then\n SEQ1=gseq\nelif seq --version|grep -q GNU; then\n SEQ1=seq\nfi\nif [ -n \"$SEQ1\" ]; then\n # GNU seq requires a -ve increment if going backwards\n seq1()\n {\n if [ $1 -gt $2 ]; then\n\t $SEQ1 $1 -1 $2\n\telse\n\t $SEQ1 $1 $2\n\tfi\n }\n SEQ=seq1\nelse\n SEQ=seq\nfi\t\nSEPARATOR=':'\n\nsetBackgroundColor()\n{\n echo -en \"\\033[48${SEPARATOR}2${SEPARATOR}$1${SEPARATOR}$2${SEPARATOR}$3\"\"m\"\n}\n\nresetOutput()\n{\n echo -en \"\\033[0m\\n\"\n}\n\n# Gives a color $1/255 % along HSV\n# Who knows what happens when $1 is outside 0-255\n# Echoes \"$red $green $blue\" where\n# $red $green and $blue are integers\n# ranging between 0 and 255 inclusive\nrainbowColor()\n{ \n let h=$1/43\n let f=$1-43*$h\n let t=$f*255/43\n let q=255-t\n\n if [ $h -eq 0 ]\n then\n echo \"255 $t 0\"\n elif [ $h -eq 1 ]\n then\n echo \"$q 255 0\"\n elif [ $h -eq 2 ]\n then\n echo \"0 255 $t\"\n elif [ $h -eq 3 ]\n then\n echo \"0 $q 255\"\n elif [ $h -eq 4 ]\n then\n echo \"$t 0 255\"\n elif [ $h -eq 5 ]\n then\n echo \"255 0 $q\"\n else\n # execution should never reach here\n echo \"0 0 0\"\n fi\n}\n\nfor i in `$SEQ 0 127`; do\n setBackgroundColor $i 0 0\n echo -en \" \"\ndone\nresetOutput\nfor i in `$SEQ 255 128`; do\n setBackgroundColor $i 0 0\n echo -en \" \"\ndone\nresetOutput\n\nfor i in `$SEQ 0 127`; do\n setBackgroundColor 0 $i 0\n echo -n \" \"\ndone\nresetOutput\nfor i in `$SEQ 255 128`; do\n setBackgroundColor 0 $i 0\n echo -n \" \"\ndone\nresetOutput\n\nfor i in `$SEQ 0 127`; do\n setBackgroundColor 0 0 $i\n echo -n \" \"\ndone\nresetOutput\nfor i in `$SEQ 255 128`; do\n setBackgroundColor 0 0 $i\n echo -n \" \"\ndone\nresetOutput\n\nfor i in `$SEQ 0 127`; do\n setBackgroundColor `rainbowColor $i`\n echo -n \" \"\ndone\nresetOutput\nfor i in `$SEQ 255 128`; do\n setBackgroundColor `rainbowColor $i`\n echo -n \" \"\ndone\nresetOutput\n",
"sha256": "cee34d321461577c2455573ec58537833f5968cebe7df8d53aabf08b0e0d9ccf"
},
".github/tools/external/tmux/README.ja": {
"mode": "100644",
"encoding": "utf-8",
"data": "tmuxへようこそ!\n\ntmuxはターミナルマルチプレクサーです。複数のターミナルを一つのスクリーン内に作成し、操作することができます。\nバックグラウンドで処理を実行中に一度スクリーンから離れて後から復帰することも可能です。\n\nOpenBSD、FreeBSD、NetBSD、Linux、macOS、Solarisで実行できます。\n\ntmuxはlibevent 2.x.に依存します。 下記からダウンロードしてください。\n\n\thttp://libevent.org\n\nまた、ncursesも必要です。こちらからどうぞ。\n\n\thttp://invisible-island.net/ncurses/\n\ntarballでのtmuxのビルドとインストール方法。\n\n\t$ ./configure && make\n\t$ sudo make install\n\ntmuxはutmp(5)をアップデートするためにutempterを使うことができます。もしインストール済みであればオプション「--enable-utempter」をつけて実行してください。\n\nリポジトリから最新バージョンを手に入れるためには下記を実行。\n\n\t$ git clone https://github.com/tmux/tmux.git\n\t$ cd tmux\n\t$ sh autogen.sh\n\t$ ./configure && make\n\n(ビルドのためにはlibevent、ncurses libraries、headersに加えて、C compiler、make、autoconf、automake、pkg-configが必要です。)\n\n詳しい情報はhttp://git-scm.comをご覧ください。修正はメール<tmux-users@googlegroups.com>宛、もしくはhttps://github.com/tmux/tmux/issuesにて受け付けています。\n\ntmuxのドキュメントについてはtmux.1マニュアルをご覧ください。こちらのコマンドで参照可能です。\n\n\t$ nroff -mdoc tmux.1|less\n\nサンプル設定は本リポジトリのexample_tmux.confに\nまた、bash-completionファイルは下記にあります。\n\n\thttps://github.com/scop/bash-completion/blob/main/completions/tmux\n\n「-v」や「-vv」を指定することでデバッグモードでの起動が可能です。カレントディレクトリにサーバーやクライアントのログファイルが生成されます。\n\n議論やバグレポート用のメーリングリストにはこちらから参加可能です。\n\n\thttps://groups.google.com/forum/#!forum/tmux-users\n\ngitコミットについての連絡先\n\n\thttps://groups.google.com/forum/#!forum/tmux-git\n\n購読は<tmux-users+subscribe@googlegroups.com>までメールをお願いします。\n\nバグレポートや機能追加(特にコードへの貢献)は大歓迎です。こちらにご連絡ください。\n\n\ttmux-users@googlegroups.com\n\n本ファイル、CHANGES、 FAQ、SYNCINGそしてTODOはISC licenseで保護されています。\nその他のファイルのライセンスや著作権については、ファイルの上部に明記されています。\n\n-- Nicholas Marriott <nicholas.marriott@gmail.com>\n",
"sha256": "c341a10636227e426a759da4b80b754258ef31f1554a9ac369a79c5afeeadeb6"
},
".github/tools/external/tmux/logo/tmux-logo-1-color.eps": {
"mode": "100644",
"encoding": "utf-8",
"data": "%!PS-Adobe-3.0 EPSF-3.0\n%APL_DSC_Encoding: UTF8\n%APLProducer: (Version 10.10.3 (Build 14D136) Quartz PS Context)\n%%Title: (Unknown)\n%%Creator: (Unknown)\n%%CreationDate: (Unknown)\n%%For: (Unknown)\n%%DocumentData: Clean7Bit\n%%LanguageLevel: 2\n%%Pages: 1\n%%BoundingBox: 0 0 608 160\n%%EndComments\n%%BeginProlog\n%%BeginFile: cg-pdf.ps\n%%Copyright: Copyright 2000-2004 Apple Computer Incorporated.\n%%Copyright: All Rights Reserved.\ncurrentpacking true setpacking\n/cg_md 141 dict def\ncg_md begin\n/L3? languagelevel 3 ge def\n/bd{bind def}bind def\n/ld{load def}bd\n/xs{exch store}bd\n/xd{exch def}bd\n/cmmtx matrix def\nmark\n/sc/setcolor\n/scs/setcolorspace\n/dr/defineresource\n/fr/findresource\n/T/true\n/F/false\n/d/setdash\n/w/setlinewidth\n/J/setlinecap\n/j/setlinejoin\n/M/setmiterlimit\n/i/setflat\n/rc/rectclip\n/rf/rectfill\n/rs/rectstroke\n/f/fill\n/f*/eofill\n/sf/selectfont\n/s/show\n/xS/xshow\n/yS/yshow\n/xyS/xyshow\n/S/stroke\n/m/moveto\n/l/lineto\n/c/curveto\n/h/closepath\n/n/newpath\n/q/gsave\n/Q/grestore\ncounttomark 2 idiv\n{ld}repeat pop\n/SC{\t\n /ColorSpace fr scs\n}bd\n/sopr /setoverprint where{pop/setoverprint}{/pop}ifelse ld\n/soprm /setoverprintmode where{pop/setoverprintmode}{/pop}ifelse ld\n/cgmtx matrix def\n/sdmtx{cgmtx currentmatrix pop}bd\n/CM {cgmtx setmatrix}bd\t\t\n/cm {cmmtx astore CM concat}bd\t\n/W{clip newpath}bd\n/W*{eoclip newpath}bd\nstatusdict begin product end dup (HP) anchorsearch{\n pop pop pop\t\n true\n}{\n pop\t\n (hp) anchorsearch{\n\tpop pop true\n }{\n\tpop false\n }ifelse\n}ifelse\n{\t\n { \n\t{ \n\t pop pop \n\t (0)dup 0 4 -1 roll put\n\t F charpath\n\t}cshow\n }\n}{\n {F charpath}\n}ifelse\n/cply exch bd\n/cps {cply stroke}bd\n/pgsave 0 def\n/bp{/pgsave save store}bd\n/ep{pgsave restore showpage}def\t\t\n/re{4 2 roll m 1 index 0 rlineto 0 exch rlineto neg 0 rlineto h}bd\n/scrdict 10 dict def\n/scrmtx matrix def\n/patarray 0 def\n/createpat{patarray 3 1 roll put}bd\n/makepat{\nscrmtx astore pop\ngsave\ninitgraphics\nCM \npatarray exch get\nscrmtx\nmakepattern\ngrestore\nsetpattern\n}bd\n/cg_BeginEPSF{\n userdict save/cg_b4_Inc_state exch put\n userdict/cg_endepsf/cg_EndEPSF load put\n count userdict/cg_op_count 3 -1 roll put \n countdictstack dup array dictstack userdict/cg_dict_array 3 -1 roll put\n 3 sub{end}repeat\n /showpage {} def\n 0 setgray 0 setlinecap 1 setlinewidth 0 setlinejoin\n 10 setmiterlimit [] 0 setdash newpath\n false setstrokeadjust false setoverprint\t\n}bd\n/cg_EndEPSF{\n countdictstack 3 sub { end } repeat\n cg_dict_array 3 1 index length 3 sub getinterval\n {begin}forall\n count userdict/cg_op_count get sub{pop}repeat\n userdict/cg_b4_Inc_state get restore\n F setpacking\n}bd\n/cg_biproc{currentfile/RunLengthDecode filter}bd\n/cg_aiproc{currentfile/ASCII85Decode filter/RunLengthDecode filter}bd\n/ImageDataSource 0 def\nL3?{\n /cg_mibiproc{pop pop/ImageDataSource{cg_biproc}def}bd\n /cg_miaiproc{pop pop/ImageDataSource{cg_aiproc}def}bd\n}{\n /ImageBandMask 0 def\n /ImageBandData 0 def\n /cg_mibiproc{\n\tstring/ImageBandMask xs\n\tstring/ImageBandData xs\n\t/ImageDataSource{[currentfile/RunLengthDecode filter dup ImageBandMask/readstring cvx\n\t /pop cvx dup ImageBandData/readstring cvx/pop cvx]cvx bind}bd\n }bd\n /cg_miaiproc{\t\n\tstring/ImageBandMask xs\n\tstring/ImageBandData xs\n\t/ImageDataSource{[currentfile/ASCII85Decode filter/RunLengthDecode filter\n\t dup ImageBandMask/readstring cvx\n\t /pop cvx dup ImageBandData/readstring cvx/pop cvx]cvx bind}bd\n }bd\n}ifelse\n/imsave 0 def\n/BI{save/imsave xd mark}bd\n/EI{imsave restore}bd\n/ID{\ncounttomark 2 idiv\ndup 2 add\t\ndict begin\n{def} repeat\npop\t\t\n/ImageType 1 def\n/ImageMatrix[Width 0 0 Height neg 0 Height]def\ncurrentdict dup/ImageMask known{ImageMask}{F}ifelse exch\nL3?{\n dup/MaskedImage known\n { \n\tpop\n\t<<\n\t /ImageType 3\n\t /InterleaveType 2\n\t /DataDict currentdict\n\t /MaskDict\n\t << /ImageType 1\n\t\t/Width Width\n\t\t/Height Height\n\t\t/ImageMatrix ImageMatrix\n\t\t/BitsPerComponent 1\n\t\t/Decode [0 1]\n\t\tcurrentdict/Interpolate known\n\t\t{/Interpolate Interpolate}if\n\t >>\n\t>>\n }if\n}if\nexch\n{imagemask}{image}ifelse\t\nend\t\n}bd\n/cguidfix{statusdict begin mark version end\n{cvr}stopped{cleartomark 0}{exch pop}ifelse\n2012 lt{dup findfont dup length dict begin\n{1 index/FID ne 2 index/UniqueID ne and\n{def} {pop pop} ifelse}forall\ncurrentdict end definefont pop\n}{pop}ifelse\n}bd\n/t_array 0 def\n/t_i 0 def\n/t_c 1 string def\n/x_proc{ \n exch t_array t_i get add exch moveto\n /t_i t_i 1 add store\n}bd\n/y_proc{ \n t_array t_i get add moveto\n /t_i t_i 1 add store\n}bd\n/xy_proc{\n \n\tt_array t_i 2 copy 1 add get 3 1 roll get \n\t4 -1 roll add 3 1 roll add moveto\n\t/t_i t_i 2 add store\n}bd\n/sop 0 def\t\t\n/cp_proc/x_proc ld \t\n/base_charpath\t\t\n{\n /t_array xs\n /t_i 0 def\n { \n\tt_c 0 3 -1 roll put\n currentpoint\n\tt_c cply sop\n cp_proc\n }forall\n /t_array 0 def\n}bd\n/sop/stroke ld\t\t\n/nop{}def\n/xsp/base_charpath ld\n/ysp{/cp_proc/y_proc ld base_charpath/cp_proc/x_proc ld}bd\n/xysp{/cp_proc/xy_proc ld base_charpath/cp_proc/x_proc ld}bd\n/xmp{/sop/nop ld /cp_proc/x_proc ld base_charpath/sop/stroke ld}bd\n/ymp{/sop/nop ld /cp_proc/y_proc ld base_charpath/sop/stroke ld}bd\n/xymp{/sop/nop ld /cp_proc/xy_proc ld base_charpath/sop/stroke ld}bd\n/refnt{ \nfindfont dup length dict copy dup\n/Encoding 4 -1 roll put \ndefinefont pop\n}bd\n/renmfont{ \nfindfont dup length dict copy definefont pop\n}bd\nL3? dup dup{save exch}if\n/Range 0 def\n/DataSource 0 def\n/val 0 def\n/nRange 0 def\n/mulRange 0 def\n/d0 0 def\n/r0 0 def\n/di 0 def\n/ri 0 def\n/a0 0 def\n/a1 0 def\n/r1 0 def\n/r2 0 def\n/dx 0 def\n/Nsteps 0 def\n/sh3tp 0 def\n/ymax 0 def\n/ymin 0 def\n/xmax 0 def\n/xmin 0 def\n/setupFunEval \n{\n begin\n\t/nRange Range length 2 idiv store\n\t/mulRange \n\t\t \n\t[ \n\t 0 1 nRange 1 sub\n\t { \n\t\t 2 mul/nDim2 xd\t\t\n\t\t Range nDim2 get\t\t\n\t\t Range nDim2 1 add get\t\n\t\t 1 index sub\t\t\t\n\t\t\t\t\t\t\n\t\t 255 div\t\t\t\n\t\t exch\t\t\t\n\t }for\n\t]store\n end\n}bd\n/FunEval \n{\n begin\n\t\n\tnRange mul /val xd\t\n\t\t\t\t\n\t0 1 nRange 1 sub\n\t{\n\t dup 2 mul/nDim2 xd \n\t val\t\n\t add DataSource exch get \n\t mulRange nDim2 get mul \t\n\t mulRange nDim2 1 add get \n\t add \n\t}for\t\n end\n}bd\n/max \n{\n\t2 copy lt\n\t{exch pop}{pop}ifelse\n}bd\n/sh2\n{\t\n\t/Coords load aload pop \t\n\t3 index 3 index translate\t\n\t\t\t\t\t\n\t3 -1 roll sub\t\n\t3 1 roll exch \t\n\tsub\t\t\t\t\n\t2 copy\n\tdup mul exch dup mul add sqrt\t\n\tdup\n\tscale \n\tatan\t\n\t\n\trotate\t\t\n\t\n\t/Function load setupFunEval\t\n\t\n\t\n\tclippath {pathbbox}stopped {0 0 0 0}if newpath \t\n\t/ymax xs\n\t/xmax xs\n\t/ymin xs\n\t/xmin xs\n\tcurrentdict/Extend known\n\t{\n\t\t/Extend load 0 get\n\t\t{\t\n\t\t\t0/Function load FunEval sc\t\n\t\t\txmin ymin xmin abs ymax ymin sub rectfill\n\t\t}if\n\t}if\n\t\n\t/Nsteps/Function load/Size get 0 get 1 sub store\n\t/dx 1 Nsteps div store\n\tgsave\n\t\t/di ymax ymin sub store\n\t\t/Function load\n\t\t\n\t\t0 1 Nsteps\n\t\t{\n\t\t\t1 index FunEval sc\n\t\t\t0 ymin dx di rectfill\n\t\t\tdx 0 translate\n\t\t}for\n\t\tpop\t\n\tgrestore\t\n\tcurrentdict/Extend known\n\t{\n\t\t/Extend load 1 get\n\t\t{\t\n\t\t\tNsteps/Function load FunEval sc\t\n\t\t\t1 ymin xmax 1 sub abs ymax ymin sub rectfill\n\t\t}if\n\t}if\n}bd\n/shp\t\n{\t\n\t4 copy\n\t\n\tdup 0 gt{\n\t\t0 exch a1 a0 arc\n\t}{\n\t\tpop 0 moveto\n\t}ifelse\n\tdup 0 gt{\n\t\t0 exch a0 a1 arcn\n\t}{\n\t\tpop 0 lineto\n\t}ifelse\n\t\n\tfill\n\t\n\tdup 0 gt{\n\t\t0 exch a0 a1 arc\n\t}{\n\t\tpop 0 moveto\n\t}ifelse\n\tdup 0 gt{\n\t\t0 exch a1 a0 arcn\n\t}{\n\t\tpop 0 lineto\n\t}ifelse\n\t\n\tfill\n}bd\n/calcmaxs\n{\t\n\t\n\txmin dup mul ymin dup mul add sqrt\t\t\n\txmax dup mul ymin dup mul add sqrt\t\t\n\txmin dup mul ymax dup mul add sqrt\t\t\n\txmax dup mul ymax dup mul add sqrt\t\t\n\tmax max max\t\t\t\t\t\t\t\t\n}bd\n/sh3\n{\t\n\t/Coords load aload pop \t\n\t5 index 5 index translate\t\n\t3 -1 roll 6 -1 roll sub\t\t\n\t3 -1 roll 5 -1 roll sub\t\t\n\t2 copy dup mul exch dup mul add sqrt\n\t/dx xs\t\t\t\t\t\t\n\t2 copy 0 ne exch 0 ne or\n\t{\n\t\t\n\t\texch atan rotate\t\n\t}{\n\t\tpop pop\n\t}ifelse\n\t\n\t/r2 xs\n\t/r1 xs\n\t/Function load \n\tdup/Size get 0 get 1 sub\t\n\t/Nsteps xs\t\t\n\tsetupFunEval\t\t\n\t\n\t\n\t\n\t\n\t\n\tdx r2 add r1 lt{\n\t\t\n\t\t0 \n\t}{\n\t\tdx r1 add r2 le\n\t\t{ \n\t\t\t1\n\t\t}{ \n\t\t\tr1 r2 eq\n\t\t\t{\t\n\t\t\t\t2\n\t\t\t}{ \n\t\t\t\t3\n\t\t\t}ifelse\t\t\n\t\t}ifelse\n\t}ifelse\n\t/sh3tp xs\t\t\n\tclippath {pathbbox}stopped {0 0 0 0}if \n\tnewpath \t\n\t/ymax xs\n\t/xmax xs\n\t/ymin xs\n\t/xmin xs\n\t\n\tdx dup mul r2 r1 sub dup mul sub dup 0 gt\n\t{\n\t\tsqrt r2 r1 sub atan\n\t\t/a0 exch 180 exch sub store \n\t\t/a1 a0 neg store \n\t}{\n\t\tpop\n\t\t/a0 0 store\n\t\t/a1 360 store\t\t\n\t}ifelse\t\t\n\tcurrentdict/Extend known\n\t{\n\t\t/Extend load 0 get r1 0 gt and\t\n\t\t{\t\n\t\t\t0/Function load FunEval sc\t\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\t{ \n\t\t\t\t{\t\n\t\t\t\t\tdx 0 r1 360 0 arcn\n\t\t\t\t\txmin ymin moveto\n\t\t\t\t\txmax ymin lineto\n\t\t\t\t\txmax ymax lineto\n\t\t\t\t\txmin ymax lineto\n\t\t\t\t\txmin ymin lineto\n\t\t\t\t\teofill\t\t\n\t\t\t\t}\n\t\t\t\t{\t\n\t\t\t\t\tr1 0 gt{0 0 r1 0 360 arc fill}if\n\t\t\t\t}\n\t\t\t\t{\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t0 r1 xmin abs r1 add neg r1 shp\n\t\t\t\t}\n\t\t\t\t{\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\tr2 r1 gt{\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t0 r1\n\t\t\t\t\t\tr1 neg r2 r1 sub div dx mul\t\n\t\t\t\t\t\t0\t\n\t\t\t\t\t\tshp\t\n\t\t\t\t\t}{\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t0 r1 calcmaxs\t\n\t\t\t\t\t\tdup\n\t\t\t\t\t\t\n\t\t\t\t\t\tr2 add dx mul dx r1 r2 sub sub div\n\t\t\t\t\t\tneg\t\t\t\t\n\t\t\t\t\t\texch 1 index\t\n\t\t\t\t\t\tabs exch sub\n\t\t\t\t\t\tshp\n\t\t\t\t\t}ifelse\n\t\t\t\t} \n\t\t\t}sh3tp get exec\t\n\t\t}if\n\t}if\n\t\n\t/d0 0 store\n\t/r0 r1 store\n\t/di dx Nsteps div store\n\t/ri r2 r1 sub Nsteps div store \n\t/Function load \n\t0 1 Nsteps\n\t{\t\n\t\t1 index FunEval sc\n\t\td0 di add r0 ri add d0 r0 shp\n\t\t{\n\t\t\n\t\td0 0 r0 a1 a0 arc\n\t\td0 di add 0 r0 ri add a0 a1 arcn\n\t\tfill\n\t\t\n\t\t\n\t\td0 0 r0 a0 a1 arc\n\t\td0 di add 0 r0 ri add a1 a0 arcn\n\t\tfill\n\t\t}pop\n\t\t\n\t\t\n\t\t/d0 d0 di add store\n\t\t/r0 r0 ri add store\n\t}for\n\tpop\t\n\t\n\tcurrentdict/Extend known\n\t{\n\t\t/Extend load 1 get r2 0 gt and\t\n\t\t{\t\n\t\t\tNsteps/Function load FunEval sc\t\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\t{ \n\t\t\t\t{\n\t\t\t\t\tdx 0 r2 0 360 arc fill\n\t\t\t\t} \n\t\t\t\t{\n\t\t\t\t\tdx 0 r2 360 0 arcn\n\t\t\t\t\txmin ymin moveto\n\t\t\t\t\txmax ymin lineto\n\t\t\t\t\txmax ymax lineto\n\t\t\t\t\txmin ymax lineto\n\t\t\t\t\txmin ymin lineto\n\t\t\t\t\teofill\t\t\n\t\t\t\t} \n\t\t\t\t{\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\txmax abs r1 add r1 dx r1 shp\n\t\t\t\t}\t\n\t\t\t\t{\t\n\t\t\t\n\t\t\t\t\tr2 r1 gt{\n\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\tcalcmaxs dup\t\n\t\t\t\t\t\t\n\t\t\t\t\t\tr1 add dx mul dx r2 r1 sub sub div\t\n\t\t\t\t\t\texch 1 index\t\n\t\t\t\t\t\texch sub\n\t\t\t\t\t\tdx r2\n\t\t\t\t\t\tshp\n\t\t\t\t\t}{\t\n\t\t\t\t\t\t\n\t\t\t\t\t\tr1 neg r2 r1 sub div dx mul\t\n\t\t\t\t\t\t0\t\t\n\t\t\t\t\t\tdx \t\t\n\t\t\t\t\t\tr2\t\t\n\t\t\t\t\t\tshp\n\t\t\t\t\t}ifelse\n\t\t\t\t}\n\t\t\t}\t\t\t\n\t\t\tsh3tp get exec\t\n\t\t}if\n\t}if\n}bd\n/sh\t\t\n{\t\n\tbegin\n\t\t/ShadingType load dup dup 2 eq exch 3 eq or\n\t\t{\t\n\t\t\tgsave\n\t\t\t\tnewpath\n\t\t\t\t/ColorSpace load scs\n\t\t\t\tcurrentdict/BBox known\n\t\t\t\t{\n\t\t\t\t\t/BBox load aload pop\t\n\t\t\t\t\t2 index sub\t\t\t\t\n\t\t\t\t\t3 index\t\t\t\t\t\n\t\t\t\t\t3 -1 roll exch sub \n\t\t\t\t\texch rectclip\n\t\t\t\t}if\n\t\t\t\t2 eq\n\t\t\t\t{sh2}{sh3}ifelse\n\t\t\tgrestore\n\t\t}{\n\t\t\t\n\t\t\tpop \n\t\t\t(DEBUG: shading type unimplemented\\n)print flush\n\t\t}ifelse\n\tend\n}bd\n{restore}if not dup{save exch}if\n\tL3?{\t\n\t\t/sh/shfill ld\n\t\t/csq/clipsave ld\n\t\t/csQ/cliprestore ld\n\t}if\n{restore}if\nend\nsetpacking\n%%EndFile\n%%EndProlog\n%%BeginSetup\n%%EndSetup\n%%Page: 1 1\n%%PageBoundingBox: 0 0 608 160\n%%BeginPageSetup\ncg_md begin\nbp\nsdmtx\n[ /CIEBasedABC 4 dict dup begin \n/WhitePoint [ 0.9505 1.0000 1.0891 ] def \n/DecodeABC [ \n{ 1.0 0.0 3 -1 roll 1 index 1 index le { exch pop} { pop } ifelse \n 1 index 1 index ge { exch pop } { pop } ifelse < \n0000000000000000000000000000000000000000000000000000000000000000\n0000000000000000000000000000000000000001010101010101010101010101\n0101010101010101010101010101010101010101010101020202020202020202\n0202020202020202020202020202020202030303030303030303030303030303\n0303030303030304040404040404040404040404040404040404050505050505\n0505050505050505050506060606060606060606060606060607070707070707\n0707070707070708080808080808080808080808090909090909090909090909\n0a0a0a0a0a0a0a0a0a0a0a0b0b0b0b0b0b0b0b0b0b0b0c0c0c0c0c0c0c0c0c0c\n0d0d0d0d0d0d0d0d0d0d0e0e0e0e0e0e0e0e0e0f0f0f0f0f0f0f0f0f10101010\n1010101010111111111111111112121212121212121313131313131313141414\n1414141414151515151515151616161616161616171717171717171818181818\n18181919191919191a1a1a1a1a1a1a1b1b1b1b1b1b1c1c1c1c1c1c1c1d1d1d1d\n1d1d1e1e1e1e1e1e1f1f1f1f1f1f202020202020212121212121222222222223\n2323232323242424242425252525252526262626262727272727282828282829\n292929292a2a2a2a2a2b2b2b2b2b2c2c2c2c2c2d2d2d2d2d2e2e2e2e2e2f2f2f\n2f2f303030303131313131323232323333333333343434343535353535363636\n36373737373838383839393939393a3a3a3a3b3b3b3b3c3c3c3c3d3d3d3d3e3e\n3e3e3f3f3f3f4040404041414141424242424343434444444445454545464646\n4647474748484848494949494a4a4a4b4b4b4b4c4c4c4d4d4d4d4e4e4e4f4f4f\n4f50505051515151525252535353535454545555555656565657575758585859\n59595a5a5a5a5b5b5b5c5c5c5d5d5d5e5e5e5f5f5f6060606061616162626263\n63636464646565656666666767676868686969696a6a6a6b6b6b6c6c6d6d6d6e\n6e6e6f6f6f707070717171727273737374747475757576767677777878787979\n797a7a7b7b7b7c7c7c7d7d7e7e7e7f7f7f808081818182828283838484848585\n86868687878888888989898a8a8b8b8b8c8c8d8d8d8e8e8f8f90909091919292\n9293939494949595969697979798989999999a9a9b9b9c9c9c9d9d9e9e9f9f9f\na0a0a1a1a2a2a3a3a3a4a4a5a5a6a6a6a7a7a8a8a9a9aaaaabababacacadadae\naeafafb0b0b0b1b1b2b2b3b3b4b4b5b5b6b6b6b7b7b8b8b9b9bababbbbbcbcbd\nbdbebebebfbfc0c0c1c1c2c2c3c3c4c4c5c5c6c6c7c7c8c8c9c9cacacbcbcccc\ncdcdcececfcfd0d0d1d1d2d2d3d3d4d4d5d5d6d6d7d7d8d8d9d9dadadbdcdcdd\ndddededfdfe0e0e1e1e2e2e3e3e4e4e5e6e6e7e7e8e8e9e9eaeaebebecededee\neeefeff0f0f1f1f2f3f3f4f4f5f5f6f6f7f8f8f9f9fafafbfcfcfdfdfefeffff\n> dup length 1 sub 3 -1 roll mul dup dup floor cvi exch ceiling \n cvi 3 index exch get 4 -1 roll 3 -1 roll get\n dup 3 1 roll sub 3 -1 roll dup floor cvi sub mul add 255 div } bind \n\n{ 1.0 0.0 3 -1 roll 1 index 1 index le { exch pop} { pop } ifelse \n 1 index 1 index ge { exch pop } { pop } ifelse < \n0000000000000000000000000000000000000000000000000000000000000000\n0000000000000000000000000000000000000001010101010101010101010101\n0101010101010101010101010101010101010101010101020202020202020202\n0202020202020202020202020202020202030303030303030303030303030303\n0303030303030304040404040404040404040404040404040404050505050505\n0505050505050505050506060606060606060606060606060607070707070707\n0707070707070708080808080808080808080808090909090909090909090909\n0a0a0a0a0a0a0a0a0a0a0a0b0b0b0b0b0b0b0b0b0b0b0c0c0c0c0c0c0c0c0c0c\n0d0d0d0d0d0d0d0d0d0d0e0e0e0e0e0e0e0e0e0f0f0f0f0f0f0f0f0f10101010\n1010101010111111111111111112121212121212121313131313131313141414\n1414141414151515151515151616161616161616171717171717171818181818\n18181919191919191a1a1a1a1a1a1a1b1b1b1b1b1b1c1c1c1c1c1c1c1d1d1d1d\n1d1d1e1e1e1e1e1e1f1f1f1f1f1f202020202020212121212121222222222223\n2323232323242424242425252525252526262626262727272727282828282829\n292929292a2a2a2a2a2b2b2b2b2b2c2c2c2c2c2d2d2d2d2d2e2e2e2e2e2f2f2f\n2f2f303030303131313131323232323333333333343434343535353535363636\n36373737373838383839393939393a3a3a3a3b3b3b3b3c3c3c3c3d3d3d3d3e3e\n3e3e3f3f3f3f4040404041414141424242424343434444444445454545464646\n4647474748484848494949494a4a4a4b4b4b4b4c4c4c4d4d4d4d4e4e4e4f4f4f\n4f50505051515151525252535353535454545555555656565657575758585859\n59595a5a5a5a5b5b5b5c5c5c5d5d5d5e5e5e5f5f5f6060606061616162626263\n63636464646565656666666767676868686969696a6a6a6b6b6b6c6c6d6d6d6e\n6e6e6f6f6f707070717171727273737374747475757576767677777878787979\n797a7a7b7b7b7c7c7c7d7d7e7e7e7f7f7f808081818182828283838484848585\n86868687878888888989898a8a8b8b8b8c8c8d8d8d8e8e8f8f90909091919292\n9293939494949595969697979798989999999a9a9b9b9c9c9c9d9d9e9e9f9f9f\na0a0a1a1a2a2a3a3a3a4a4a5a5a6a6a6a7a7a8a8a9a9aaaaabababacacadadae\naeafafb0b0b0b1b1b2b2b3b3b4b4b5b5b6b6b6b7b7b8b8b9b9bababbbbbcbcbd\nbdbebebebfbfc0c0c1c1c2c2c3c3c4c4c5c5c6c6c7c7c8c8c9c9cacacbcbcccc\ncdcdcececfcfd0d0d1d1d2d2d3d3d4d4d5d5d6d6d7d7d8d8d9d9dadadbdcdcdd\ndddededfdfe0e0e1e1e2e2e3e3e4e4e5e6e6e7e7e8e8e9e9eaeaebebecededee\neeefeff0f0f1f1f2f3f3f4f4f5f5f6f6f7f8f8f9f9fafafbfcfcfdfdfefeffff\n> dup length 1 sub 3 -1 roll mul dup dup floor cvi exch ceiling \n cvi 3 index exch get 4 -1 roll 3 -1 roll get\n dup 3 1 roll sub 3 -1 roll dup floor cvi sub mul add 255 div } bind \n\n{ 1.0 0.0 3 -1 roll 1 index 1 index le { exch pop} { pop } ifelse \n 1 index 1 index ge { exch pop } { pop } ifelse < \n0000000000000000000000000000000000000000000000000000000000000000\n0000000000000000000000000000000000000001010101010101010101010101\n0101010101010101010101010101010101010101010101020202020202020202\n0202020202020202020202020202020202030303030303030303030303030303\n0303030303030304040404040404040404040404040404040404050505050505\n0505050505050505050506060606060606060606060606060607070707070707\n0707070707070708080808080808080808080808090909090909090909090909\n0a0a0a0a0a0a0a0a0a0a0a0b0b0b0b0b0b0b0b0b0b0b0c0c0c0c0c0c0c0c0c0c\n0d0d0d0d0d0d0d0d0d0d0e0e0e0e0e0e0e0e0e0f0f0f0f0f0f0f0f0f10101010\n1010101010111111111111111112121212121212121313131313131313141414\n1414141414151515151515151616161616161616171717171717171818181818\n18181919191919191a1a1a1a1a1a1a1b1b1b1b1b1b1c1c1c1c1c1c1c1d1d1d1d\n1d1d1e1e1e1e1e1e1f1f1f1f1f1f202020202020212121212121222222222223\n2323232323242424242425252525252526262626262727272727282828282829\n292929292a2a2a2a2a2b2b2b2b2b2c2c2c2c2c2d2d2d2d2d2e2e2e2e2e2f2f2f\n2f2f303030303131313131323232323333333333343434343535353535363636\n36373737373838383839393939393a3a3a3a3b3b3b3b3c3c3c3c3d3d3d3d3e3e\n3e3e3f3f3f3f4040404041414141424242424343434444444445454545464646\n4647474748484848494949494a4a4a4b4b4b4b4c4c4c4d4d4d4d4e4e4e4f4f4f\n4f50505051515151525252535353535454545555555656565657575758585859\n59595a5a5a5a5b5b5b5c5c5c5d5d5d5e5e5e5f5f5f6060606061616162626263\n63636464646565656666666767676868686969696a6a6a6b6b6b6c6c6d6d6d6e\n6e6e6f6f6f707070717171727273737374747475757576767677777878787979\n797a7a7b7b7b7c7c7c7d7d7e7e7e7f7f7f808081818182828283838484848585\n86868687878888888989898a8a8b8b8b8c8c8d8d8d8e8e8f8f90909091919292\n9293939494949595969697979798989999999a9a9b9b9c9c9c9d9d9e9e9f9f9f\na0a0a1a1a2a2a3a3a3a4a4a5a5a6a6a6a7a7a8a8a9a9aaaaabababacacadadae\naeafafb0b0b0b1b1b2b2b3b3b4b4b5b5b6b6b6b7b7b8b8b9b9bababbbbbcbcbd\nbdbebebebfbfc0c0c1c1c2c2c3c3c4c4c5c5c6c6c7c7c8c8c9c9cacacbcbcccc\ncdcdcececfcfd0d0d1d1d2d2d3d3d4d4d5d5d6d6d7d7d8d8d9d9dadadbdcdcdd\ndddededfdfe0e0e1e1e2e2e3e3e4e4e5e6e6e7e7e8e8e9e9eaeaebebecededee\neeefeff0f0f1f1f2f3f3f4f4f5f5f6f6f7f8f8f9f9fafafbfcfcfdfdfefeffff\n> dup length 1 sub 3 -1 roll mul dup dup floor cvi exch ceiling \n cvi 3 index exch get 4 -1 roll 3 -1 roll get\n dup 3 1 roll sub 3 -1 roll dup floor cvi sub mul add 255 div } bind \n] def \n/MatrixABC [ 0.4124 0.2126 0.0193 0.3576 0.7151 0.1192 0.1805 0.0722 0.9508 ] def \n/RangeLMN [ 0.0 0.9505 0.0 1.0000 0.0 1.0891 ] def \nend ] /Cs1 exch/ColorSpace dr pop\n%%EndPageSetup\n0.60000002 i\n/Cs1 SC\n0.23529412 0.23529412 0.23529412 sc\nq\n2 15.003872 m\n2 7.8149743 7.8157911 2 14.998466 2 c\n145.00154 2 l\n152.17584 2 158 7.8244047 158 15.003872 c\n160 15.003872 m\n160 6.7174625 153.27803 0 145.00154 0 c\n14.998466 0 l\n6.7150416 0 0 6.7065849 0 15.003872 c\n2 14 m\n0 16 l\n160 16 l\n158 14 l\n160 14 m\n0 14 l\nW\n0 0 608 160 rc\n-5 21 m\n165 21 l\n165 -5 l\n-5 -5 l\nh\nf\nQ\nq\n83 90 m\n83 160 l\n77 160 l\n77 14 l\n83 14 l\n83 84 l\n160 84 l\n160 90 l\n83 90 l\nh\n0 144.99352 m\n0 153.28137 6.7219648 160 14.998466 160 c\n145.00154 160 l\n153.28496 160 160 153.27509 160 144.99352 c\n160 14 l\n0 14 l\n0 144.99352 l\nh\n0 144.99352 m\nW*\n0 0 608 160 rc\n-5 165 m\n165 165 l\n165 9 l\n-5 9 l\nh\nf\nQ\nq\n242 12 m\n230.85426 12.165432 222.63789 15.032893 217.12346 20.7679 c\n211.60902 26.502909 208.85185 34.995007 209 46.244446 c\n209 98 l\n189 98 l\n189 113 l\n209 113 l\n209 146 l\n225 146 l\n225 113 l\n262 112.91358 l\n262 98.024689 l\n225 98 l\n225 46.079014 l\n225.39507 39.571983 226.99422 34.802074 230.1926 31.769136 c\n233.39096 28.736198 237.58186 27.219753 242.76543 27.219753 c\n245.19179 27.219753 247.89381 27.49547 250.87161 28.046913 c\n253.8494 28.598356 256.88229 29.425508 259.97037 30.528395 c\n263.27902 15.97037 l\n259.52921 14.646907 255.86215 13.681896 252.27777 13.075309 c\n248.69341 12.468721 245.19179 12.165432 241.77284 12.165432 c\n242 12 l\nh\n295 14 m\n278.15918 14 l\n278 112.91358 l\n295 112.91358 l\n295 96.370369 l\n295 96.370369 304.76617 106.29628 309.67401 109.60493 c\n314.58185 112.9136 320.34436 114.5679 326.96167 114.5679 c\n332.80695 114.5679 337.79745 112.94117 341.93326 109.68765 c\n346.06909 106.43414 349.01926 101.99509 350.78387 96.370369 c\n350.78387 96.370369 361.92294 106.29628 366.99622 109.60493 c\n372.06952 112.9136 378.08014 114.5679 385.02832 114.5679 c\n392.74854 114.5679 398.92459 111.72801 403.55673 106.04815 c\n408.18884 100.36829 410.50488 92.730911 410 83.139999 c\n410 14 l\n394 14 l\n393.96167 80.488892 l\n393.96167 87.106209 392.69336 91.820976 390.15674 94.633331 c\n387.62009 97.445694 383.98062 98.851852 379.23822 98.851852 c\n374.49579 98.851852 369.78104 97.418121 365.09375 94.550621 c\n360.40649 91.683113 356.24316 87.878212 353 83.135803 c\n353 14 l\n336.06042 14 l\n336.06042 80.488892 l\n336.06042 87.106209 334.79211 91.820976 332.25549 94.633331 c\n329.71884 97.445694 326.07938 98.851852 321.33698 98.851852 c\n316.59457 98.851852 311.87979 97.418121 307.19254 94.550621 c\n302.50525 91.683113 298.34192 87.878212 295 83.135803 c\n295 14 l\nh\n438.9505 21.264198 m\n433.10519 27.440361 430.18259 35.656738 430 46 c\n430 113 l\n447 113 l\n447 49.220001 l\n446.7258 42.16375 448.3801 36.814835 451.68875 33.175308 c\n454.99741 29.535784 459.85004 27.716049 466.2468 27.716049 c\n471.32007 27.716049 476.36569 29.177351 481.38382 32.099998 c\n486.40195 35.022648 491.39243 39.35141 496 45.086418 c\n496 112.91358 l\n513 113 l\n512.89862 14 l\n496 14 l\n496 30.197531 l\n496 30.197531 485.13364 20.271622 479.89493 16.962963 c\n474.65622 13.654305 468.78345 12 462.2764 12 c\n452.57101 12 444.79578 15.088035 438.9505 21.264198 c\nh\n588.65784 14 m\n564.50476 51.041977 l\n541.84052 14 l\n523.4776 14 l\n556.56403 63.449383 l\n524.63562 113 l\n543.164 113 l\n566.15906 77.180244 l\n589.48499 113 l\n607.84796 113 l\n574.43066 64.441978 l\n607.18622 14 l\n588.65784 14 l\nh\n588.65784 14 m\nW*\n0 0 608 160 rc\n184 151 m\n612.84796 151 l\n612.84796 7 l\n184 7 l\nh\nf\nep\nend\n%%Trailer\n%%EOF\n",
"sha256": "f4da0cd411ea21140efbb3ebd5fc9a76c87183c8eceb7902e6f08d061c17235b"
},
".github/tools/external/tmux/logo/tmux-logo.eps": {
"mode": "100644",
"encoding": "utf-8",
"data": "%!PS-Adobe-3.0 EPSF-3.0\n%APL_DSC_Encoding: UTF8\n%APLProducer: (Version 10.10.3 (Build 14D136) Quartz PS Context)\n%%Title: (Unknown)\n%%Creator: (Unknown)\n%%CreationDate: (Unknown)\n%%For: (Unknown)\n%%DocumentData: Clean7Bit\n%%LanguageLevel: 2\n%%Pages: 1\n%%BoundingBox: 0 0 608 160\n%%EndComments\n%%BeginProlog\n%%BeginFile: cg-pdf.ps\n%%Copyright: Copyright 2000-2004 Apple Computer Incorporated.\n%%Copyright: All Rights Reserved.\ncurrentpacking true setpacking\n/cg_md 141 dict def\ncg_md begin\n/L3? languagelevel 3 ge def\n/bd{bind def}bind def\n/ld{load def}bd\n/xs{exch store}bd\n/xd{exch def}bd\n/cmmtx matrix def\nmark\n/sc/setcolor\n/scs/setcolorspace\n/dr/defineresource\n/fr/findresource\n/T/true\n/F/false\n/d/setdash\n/w/setlinewidth\n/J/setlinecap\n/j/setlinejoin\n/M/setmiterlimit\n/i/setflat\n/rc/rectclip\n/rf/rectfill\n/rs/rectstroke\n/f/fill\n/f*/eofill\n/sf/selectfont\n/s/show\n/xS/xshow\n/yS/yshow\n/xyS/xyshow\n/S/stroke\n/m/moveto\n/l/lineto\n/c/curveto\n/h/closepath\n/n/newpath\n/q/gsave\n/Q/grestore\ncounttomark 2 idiv\n{ld}repeat pop\n/SC{\t\n /ColorSpace fr scs\n}bd\n/sopr /setoverprint where{pop/setoverprint}{/pop}ifelse ld\n/soprm /setoverprintmode where{pop/setoverprintmode}{/pop}ifelse ld\n/cgmtx matrix def\n/sdmtx{cgmtx currentmatrix pop}bd\n/CM {cgmtx setmatrix}bd\t\t\n/cm {cmmtx astore CM concat}bd\t\n/W{clip newpath}bd\n/W*{eoclip newpath}bd\nstatusdict begin product end dup (HP) anchorsearch{\n pop pop pop\t\n true\n}{\n pop\t\n (hp) anchorsearch{\n\tpop pop true\n }{\n\tpop false\n }ifelse\n}ifelse\n{\t\n { \n\t{ \n\t pop pop \n\t (0)dup 0 4 -1 roll put\n\t F charpath\n\t}cshow\n }\n}{\n {F charpath}\n}ifelse\n/cply exch bd\n/cps {cply stroke}bd\n/pgsave 0 def\n/bp{/pgsave save store}bd\n/ep{pgsave restore showpage}def\t\t\n/re{4 2 roll m 1 index 0 rlineto 0 exch rlineto neg 0 rlineto h}bd\n/scrdict 10 dict def\n/scrmtx matrix def\n/patarray 0 def\n/createpat{patarray 3 1 roll put}bd\n/makepat{\nscrmtx astore pop\ngsave\ninitgraphics\nCM \npatarray exch get\nscrmtx\nmakepattern\ngrestore\nsetpattern\n}bd\n/cg_BeginEPSF{\n userdict save/cg_b4_Inc_state exch put\n userdict/cg_endepsf/cg_EndEPSF load put\n count userdict/cg_op_count 3 -1 roll put \n countdictstack dup array dictstack userdict/cg_dict_array 3 -1 roll put\n 3 sub{end}repeat\n /showpage {} def\n 0 setgray 0 setlinecap 1 setlinewidth 0 setlinejoin\n 10 setmiterlimit [] 0 setdash newpath\n false setstrokeadjust false setoverprint\t\n}bd\n/cg_EndEPSF{\n countdictstack 3 sub { end } repeat\n cg_dict_array 3 1 index length 3 sub getinterval\n {begin}forall\n count userdict/cg_op_count get sub{pop}repeat\n userdict/cg_b4_Inc_state get restore\n F setpacking\n}bd\n/cg_biproc{currentfile/RunLengthDecode filter}bd\n/cg_aiproc{currentfile/ASCII85Decode filter/RunLengthDecode filter}bd\n/ImageDataSource 0 def\nL3?{\n /cg_mibiproc{pop pop/ImageDataSource{cg_biproc}def}bd\n /cg_miaiproc{pop pop/ImageDataSource{cg_aiproc}def}bd\n}{\n /ImageBandMask 0 def\n /ImageBandData 0 def\n /cg_mibiproc{\n\tstring/ImageBandMask xs\n\tstring/ImageBandData xs\n\t/ImageDataSource{[currentfile/RunLengthDecode filter dup ImageBandMask/readstring cvx\n\t /pop cvx dup ImageBandData/readstring cvx/pop cvx]cvx bind}bd\n }bd\n /cg_miaiproc{\t\n\tstring/ImageBandMask xs\n\tstring/ImageBandData xs\n\t/ImageDataSource{[currentfile/ASCII85Decode filter/RunLengthDecode filter\n\t dup ImageBandMask/readstring cvx\n\t /pop cvx dup ImageBandData/readstring cvx/pop cvx]cvx bind}bd\n }bd\n}ifelse\n/imsave 0 def\n/BI{save/imsave xd mark}bd\n/EI{imsave restore}bd\n/ID{\ncounttomark 2 idiv\ndup 2 add\t\ndict begin\n{def} repeat\npop\t\t\n/ImageType 1 def\n/ImageMatrix[Width 0 0 Height neg 0 Height]def\ncurrentdict dup/ImageMask known{ImageMask}{F}ifelse exch\nL3?{\n dup/MaskedImage known\n { \n\tpop\n\t<<\n\t /ImageType 3\n\t /InterleaveType 2\n\t /DataDict currentdict\n\t /MaskDict\n\t << /ImageType 1\n\t\t/Width Width\n\t\t/Height Height\n\t\t/ImageMatrix ImageMatrix\n\t\t/BitsPerComponent 1\n\t\t/Decode [0 1]\n\t\tcurrentdict/Interpolate known\n\t\t{/Interpolate Interpolate}if\n\t >>\n\t>>\n }if\n}if\nexch\n{imagemask}{image}ifelse\t\nend\t\n}bd\n/cguidfix{statusdict begin mark version end\n{cvr}stopped{cleartomark 0}{exch pop}ifelse\n2012 lt{dup findfont dup length dict begin\n{1 index/FID ne 2 index/UniqueID ne and\n{def} {pop pop} ifelse}forall\ncurrentdict end definefont pop\n}{pop}ifelse\n}bd\n/t_array 0 def\n/t_i 0 def\n/t_c 1 string def\n/x_proc{ \n exch t_array t_i get add exch moveto\n /t_i t_i 1 add store\n}bd\n/y_proc{ \n t_array t_i get add moveto\n /t_i t_i 1 add store\n}bd\n/xy_proc{\n \n\tt_array t_i 2 copy 1 add get 3 1 roll get \n\t4 -1 roll add 3 1 roll add moveto\n\t/t_i t_i 2 add store\n}bd\n/sop 0 def\t\t\n/cp_proc/x_proc ld \t\n/base_charpath\t\t\n{\n /t_array xs\n /t_i 0 def\n { \n\tt_c 0 3 -1 roll put\n currentpoint\n\tt_c cply sop\n cp_proc\n }forall\n /t_array 0 def\n}bd\n/sop/stroke ld\t\t\n/nop{}def\n/xsp/base_charpath ld\n/ysp{/cp_proc/y_proc ld base_charpath/cp_proc/x_proc ld}bd\n/xysp{/cp_proc/xy_proc ld base_charpath/cp_proc/x_proc ld}bd\n/xmp{/sop/nop ld /cp_proc/x_proc ld base_charpath/sop/stroke ld}bd\n/ymp{/sop/nop ld /cp_proc/y_proc ld base_charpath/sop/stroke ld}bd\n/xymp{/sop/nop ld /cp_proc/xy_proc ld base_charpath/sop/stroke ld}bd\n/refnt{ \nfindfont dup length dict copy dup\n/Encoding 4 -1 roll put \ndefinefont pop\n}bd\n/renmfont{ \nfindfont dup length dict copy definefont pop\n}bd\nL3? dup dup{save exch}if\n/Range 0 def\n/DataSource 0 def\n/val 0 def\n/nRange 0 def\n/mulRange 0 def\n/d0 0 def\n/r0 0 def\n/di 0 def\n/ri 0 def\n/a0 0 def\n/a1 0 def\n/r1 0 def\n/r2 0 def\n/dx 0 def\n/Nsteps 0 def\n/sh3tp 0 def\n/ymax 0 def\n/ymin 0 def\n/xmax 0 def\n/xmin 0 def\n/setupFunEval \n{\n begin\n\t/nRange Range length 2 idiv store\n\t/mulRange \n\t\t \n\t[ \n\t 0 1 nRange 1 sub\n\t { \n\t\t 2 mul/nDim2 xd\t\t\n\t\t Range nDim2 get\t\t\n\t\t Range nDim2 1 add get\t\n\t\t 1 index sub\t\t\t\n\t\t\t\t\t\t\n\t\t 255 div\t\t\t\n\t\t exch\t\t\t\n\t }for\n\t]store\n end\n}bd\n/FunEval \n{\n begin\n\t\n\tnRange mul /val xd\t\n\t\t\t\t\n\t0 1 nRange 1 sub\n\t{\n\t dup 2 mul/nDim2 xd \n\t val\t\n\t add DataSource exch get \n\t mulRange nDim2 get mul \t\n\t mulRange nDim2 1 add get \n\t add \n\t}for\t\n end\n}bd\n/max \n{\n\t2 copy lt\n\t{exch pop}{pop}ifelse\n}bd\n/sh2\n{\t\n\t/Coords load aload pop \t\n\t3 index 3 index translate\t\n\t\t\t\t\t\n\t3 -1 roll sub\t\n\t3 1 roll exch \t\n\tsub\t\t\t\t\n\t2 copy\n\tdup mul exch dup mul add sqrt\t\n\tdup\n\tscale \n\tatan\t\n\t\n\trotate\t\t\n\t\n\t/Function load setupFunEval\t\n\t\n\t\n\tclippath {pathbbox}stopped {0 0 0 0}if newpath \t\n\t/ymax xs\n\t/xmax xs\n\t/ymin xs\n\t/xmin xs\n\tcurrentdict/Extend known\n\t{\n\t\t/Extend load 0 get\n\t\t{\t\n\t\t\t0/Function load FunEval sc\t\n\t\t\txmin ymin xmin abs ymax ymin sub rectfill\n\t\t}if\n\t}if\n\t\n\t/Nsteps/Function load/Size get 0 get 1 sub store\n\t/dx 1 Nsteps div store\n\tgsave\n\t\t/di ymax ymin sub store\n\t\t/Function load\n\t\t\n\t\t0 1 Nsteps\n\t\t{\n\t\t\t1 index FunEval sc\n\t\t\t0 ymin dx di rectfill\n\t\t\tdx 0 translate\n\t\t}for\n\t\tpop\t\n\tgrestore\t\n\tcurrentdict/Extend known\n\t{\n\t\t/Extend load 1 get\n\t\t{\t\n\t\t\tNsteps/Function load FunEval sc\t\n\t\t\t1 ymin xmax 1 sub abs ymax ymin sub rectfill\n\t\t}if\n\t}if\n}bd\n/shp\t\n{\t\n\t4 copy\n\t\n\tdup 0 gt{\n\t\t0 exch a1 a0 arc\n\t}{\n\t\tpop 0 moveto\n\t}ifelse\n\tdup 0 gt{\n\t\t0 exch a0 a1 arcn\n\t}{\n\t\tpop 0 lineto\n\t}ifelse\n\t\n\tfill\n\t\n\tdup 0 gt{\n\t\t0 exch a0 a1 arc\n\t}{\n\t\tpop 0 moveto\n\t}ifelse\n\tdup 0 gt{\n\t\t0 exch a1 a0 arcn\n\t}{\n\t\tpop 0 lineto\n\t}ifelse\n\t\n\tfill\n}bd\n/calcmaxs\n{\t\n\t\n\txmin dup mul ymin dup mul add sqrt\t\t\n\txmax dup mul ymin dup mul add sqrt\t\t\n\txmin dup mul ymax dup mul add sqrt\t\t\n\txmax dup mul ymax dup mul add sqrt\t\t\n\tmax max max\t\t\t\t\t\t\t\t\n}bd\n/sh3\n{\t\n\t/Coords load aload pop \t\n\t5 index 5 index translate\t\n\t3 -1 roll 6 -1 roll sub\t\t\n\t3 -1 roll 5 -1 roll sub\t\t\n\t2 copy dup mul exch dup mul add sqrt\n\t/dx xs\t\t\t\t\t\t\n\t2 copy 0 ne exch 0 ne or\n\t{\n\t\t\n\t\texch atan rotate\t\n\t}{\n\t\tpop pop\n\t}ifelse\n\t\n\t/r2 xs\n\t/r1 xs\n\t/Function load \n\tdup/Size get 0 get 1 sub\t\n\t/Nsteps xs\t\t\n\tsetupFunEval\t\t\n\t\n\t\n\t\n\t\n\t\n\tdx r2 add r1 lt{\n\t\t\n\t\t0 \n\t}{\n\t\tdx r1 add r2 le\n\t\t{ \n\t\t\t1\n\t\t}{ \n\t\t\tr1 r2 eq\n\t\t\t{\t\n\t\t\t\t2\n\t\t\t}{ \n\t\t\t\t3\n\t\t\t}ifelse\t\t\n\t\t}ifelse\n\t}ifelse\n\t/sh3tp xs\t\t\n\tclippath {pathbbox}stopped {0 0 0 0}if \n\tnewpath \t\n\t/ymax xs\n\t/xmax xs\n\t/ymin xs\n\t/xmin xs\n\t\n\tdx dup mul r2 r1 sub dup mul sub dup 0 gt\n\t{\n\t\tsqrt r2 r1 sub atan\n\t\t/a0 exch 180 exch sub store \n\t\t/a1 a0 neg store \n\t}{\n\t\tpop\n\t\t/a0 0 store\n\t\t/a1 360 store\t\t\n\t}ifelse\t\t\n\tcurrentdict/Extend known\n\t{\n\t\t/Extend load 0 get r1 0 gt and\t\n\t\t{\t\n\t\t\t0/Function load FunEval sc\t\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\t{ \n\t\t\t\t{\t\n\t\t\t\t\tdx 0 r1 360 0 arcn\n\t\t\t\t\txmin ymin moveto\n\t\t\t\t\txmax ymin lineto\n\t\t\t\t\txmax ymax lineto\n\t\t\t\t\txmin ymax lineto\n\t\t\t\t\txmin ymin lineto\n\t\t\t\t\teofill\t\t\n\t\t\t\t}\n\t\t\t\t{\t\n\t\t\t\t\tr1 0 gt{0 0 r1 0 360 arc fill}if\n\t\t\t\t}\n\t\t\t\t{\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t0 r1 xmin abs r1 add neg r1 shp\n\t\t\t\t}\n\t\t\t\t{\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\tr2 r1 gt{\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t0 r1\n\t\t\t\t\t\tr1 neg r2 r1 sub div dx mul\t\n\t\t\t\t\t\t0\t\n\t\t\t\t\t\tshp\t\n\t\t\t\t\t}{\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t0 r1 calcmaxs\t\n\t\t\t\t\t\tdup\n\t\t\t\t\t\t\n\t\t\t\t\t\tr2 add dx mul dx r1 r2 sub sub div\n\t\t\t\t\t\tneg\t\t\t\t\n\t\t\t\t\t\texch 1 index\t\n\t\t\t\t\t\tabs exch sub\n\t\t\t\t\t\tshp\n\t\t\t\t\t}ifelse\n\t\t\t\t} \n\t\t\t}sh3tp get exec\t\n\t\t}if\n\t}if\n\t\n\t/d0 0 store\n\t/r0 r1 store\n\t/di dx Nsteps div store\n\t/ri r2 r1 sub Nsteps div store \n\t/Function load \n\t0 1 Nsteps\n\t{\t\n\t\t1 index FunEval sc\n\t\td0 di add r0 ri add d0 r0 shp\n\t\t{\n\t\t\n\t\td0 0 r0 a1 a0 arc\n\t\td0 di add 0 r0 ri add a0 a1 arcn\n\t\tfill\n\t\t\n\t\t\n\t\td0 0 r0 a0 a1 arc\n\t\td0 di add 0 r0 ri add a1 a0 arcn\n\t\tfill\n\t\t}pop\n\t\t\n\t\t\n\t\t/d0 d0 di add store\n\t\t/r0 r0 ri add store\n\t}for\n\tpop\t\n\t\n\tcurrentdict/Extend known\n\t{\n\t\t/Extend load 1 get r2 0 gt and\t\n\t\t{\t\n\t\t\tNsteps/Function load FunEval sc\t\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\t{ \n\t\t\t\t{\n\t\t\t\t\tdx 0 r2 0 360 arc fill\n\t\t\t\t} \n\t\t\t\t{\n\t\t\t\t\tdx 0 r2 360 0 arcn\n\t\t\t\t\txmin ymin moveto\n\t\t\t\t\txmax ymin lineto\n\t\t\t\t\txmax ymax lineto\n\t\t\t\t\txmin ymax lineto\n\t\t\t\t\txmin ymin lineto\n\t\t\t\t\teofill\t\t\n\t\t\t\t} \n\t\t\t\t{\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\txmax abs r1 add r1 dx r1 shp\n\t\t\t\t}\t\n\t\t\t\t{\t\n\t\t\t\n\t\t\t\t\tr2 r1 gt{\n\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\tcalcmaxs dup\t\n\t\t\t\t\t\t\n\t\t\t\t\t\tr1 add dx mul dx r2 r1 sub sub div\t\n\t\t\t\t\t\texch 1 index\t\n\t\t\t\t\t\texch sub\n\t\t\t\t\t\tdx r2\n\t\t\t\t\t\tshp\n\t\t\t\t\t}{\t\n\t\t\t\t\t\t\n\t\t\t\t\t\tr1 neg r2 r1 sub div dx mul\t\n\t\t\t\t\t\t0\t\t\n\t\t\t\t\t\tdx \t\t\n\t\t\t\t\t\tr2\t\t\n\t\t\t\t\t\tshp\n\t\t\t\t\t}ifelse\n\t\t\t\t}\n\t\t\t}\t\t\t\n\t\t\tsh3tp get exec\t\n\t\t}if\n\t}if\n}bd\n/sh\t\t\n{\t\n\tbegin\n\t\t/ShadingType load dup dup 2 eq exch 3 eq or\n\t\t{\t\n\t\t\tgsave\n\t\t\t\tnewpath\n\t\t\t\t/ColorSpace load scs\n\t\t\t\tcurrentdict/BBox known\n\t\t\t\t{\n\t\t\t\t\t/BBox load aload pop\t\n\t\t\t\t\t2 index sub\t\t\t\t\n\t\t\t\t\t3 index\t\t\t\t\t\n\t\t\t\t\t3 -1 roll exch sub \n\t\t\t\t\texch rectclip\n\t\t\t\t}if\n\t\t\t\t2 eq\n\t\t\t\t{sh2}{sh3}ifelse\n\t\t\tgrestore\n\t\t}{\n\t\t\t\n\t\t\tpop \n\t\t\t(DEBUG: shading type unimplemented\\n)print flush\n\t\t}ifelse\n\tend\n}bd\n{restore}if not dup{save exch}if\n\tL3?{\t\n\t\t/sh/shfill ld\n\t\t/csq/clipsave ld\n\t\t/csQ/cliprestore ld\n\t}if\n{restore}if\nend\nsetpacking\n%%EndFile\n%%EndProlog\n%%BeginSetup\n%%EndSetup\n%%Page: 1 1\n%%PageBoundingBox: 0 0 608 160\n%%BeginPageSetup\ncg_md begin\nbp\nsdmtx\n[ /CIEBasedABC 4 dict dup begin \n/WhitePoint [ 0.9505 1.0000 1.0891 ] def \n/DecodeABC [ \n{ 1.0 0.0 3 -1 roll 1 index 1 index le { exch pop} { pop } ifelse \n 1 index 1 index ge { exch pop } { pop } ifelse < \n0000000000000000000000000000000000000000000000000000000000000000\n0000000000000000000000000000000000000001010101010101010101010101\n0101010101010101010101010101010101010101010101020202020202020202\n0202020202020202020202020202020202030303030303030303030303030303\n0303030303030304040404040404040404040404040404040404050505050505\n0505050505050505050506060606060606060606060606060607070707070707\n0707070707070708080808080808080808080808090909090909090909090909\n0a0a0a0a0a0a0a0a0a0a0a0b0b0b0b0b0b0b0b0b0b0b0c0c0c0c0c0c0c0c0c0c\n0d0d0d0d0d0d0d0d0d0d0e0e0e0e0e0e0e0e0e0f0f0f0f0f0f0f0f0f10101010\n1010101010111111111111111112121212121212121313131313131313141414\n1414141414151515151515151616161616161616171717171717171818181818\n18181919191919191a1a1a1a1a1a1a1b1b1b1b1b1b1c1c1c1c1c1c1c1d1d1d1d\n1d1d1e1e1e1e1e1e1f1f1f1f1f1f202020202020212121212121222222222223\n2323232323242424242425252525252526262626262727272727282828282829\n292929292a2a2a2a2a2b2b2b2b2b2c2c2c2c2c2d2d2d2d2d2e2e2e2e2e2f2f2f\n2f2f303030303131313131323232323333333333343434343535353535363636\n36373737373838383839393939393a3a3a3a3b3b3b3b3c3c3c3c3d3d3d3d3e3e\n3e3e3f3f3f3f4040404041414141424242424343434444444445454545464646\n4647474748484848494949494a4a4a4b4b4b4b4c4c4c4d4d4d4d4e4e4e4f4f4f\n4f50505051515151525252535353535454545555555656565657575758585859\n59595a5a5a5a5b5b5b5c5c5c5d5d5d5e5e5e5f5f5f6060606061616162626263\n63636464646565656666666767676868686969696a6a6a6b6b6b6c6c6d6d6d6e\n6e6e6f6f6f707070717171727273737374747475757576767677777878787979\n797a7a7b7b7b7c7c7c7d7d7e7e7e7f7f7f808081818182828283838484848585\n86868687878888888989898a8a8b8b8b8c8c8d8d8d8e8e8f8f90909091919292\n9293939494949595969697979798989999999a9a9b9b9c9c9c9d9d9e9e9f9f9f\na0a0a1a1a2a2a3a3a3a4a4a5a5a6a6a6a7a7a8a8a9a9aaaaabababacacadadae\naeafafb0b0b0b1b1b2b2b3b3b4b4b5b5b6b6b6b7b7b8b8b9b9bababbbbbcbcbd\nbdbebebebfbfc0c0c1c1c2c2c3c3c4c4c5c5c6c6c7c7c8c8c9c9cacacbcbcccc\ncdcdcececfcfd0d0d1d1d2d2d3d3d4d4d5d5d6d6d7d7d8d8d9d9dadadbdcdcdd\ndddededfdfe0e0e1e1e2e2e3e3e4e4e5e6e6e7e7e8e8e9e9eaeaebebecededee\neeefeff0f0f1f1f2f3f3f4f4f5f5f6f6f7f8f8f9f9fafafbfcfcfdfdfefeffff\n> dup length 1 sub 3 -1 roll mul dup dup floor cvi exch ceiling \n cvi 3 index exch get 4 -1 roll 3 -1 roll get\n dup 3 1 roll sub 3 -1 roll dup floor cvi sub mul add 255 div } bind \n\n{ 1.0 0.0 3 -1 roll 1 index 1 index le { exch pop} { pop } ifelse \n 1 index 1 index ge { exch pop } { pop } ifelse < \n0000000000000000000000000000000000000000000000000000000000000000\n0000000000000000000000000000000000000001010101010101010101010101\n0101010101010101010101010101010101010101010101020202020202020202\n0202020202020202020202020202020202030303030303030303030303030303\n0303030303030304040404040404040404040404040404040404050505050505\n0505050505050505050506060606060606060606060606060607070707070707\n0707070707070708080808080808080808080808090909090909090909090909\n0a0a0a0a0a0a0a0a0a0a0a0b0b0b0b0b0b0b0b0b0b0b0c0c0c0c0c0c0c0c0c0c\n0d0d0d0d0d0d0d0d0d0d0e0e0e0e0e0e0e0e0e0f0f0f0f0f0f0f0f0f10101010\n1010101010111111111111111112121212121212121313131313131313141414\n1414141414151515151515151616161616161616171717171717171818181818\n18181919191919191a1a1a1a1a1a1a1b1b1b1b1b1b1c1c1c1c1c1c1c1d1d1d1d\n1d1d1e1e1e1e1e1e1f1f1f1f1f1f202020202020212121212121222222222223\n2323232323242424242425252525252526262626262727272727282828282829\n292929292a2a2a2a2a2b2b2b2b2b2c2c2c2c2c2d2d2d2d2d2e2e2e2e2e2f2f2f\n2f2f303030303131313131323232323333333333343434343535353535363636\n36373737373838383839393939393a3a3a3a3b3b3b3b3c3c3c3c3d3d3d3d3e3e\n3e3e3f3f3f3f4040404041414141424242424343434444444445454545464646\n4647474748484848494949494a4a4a4b4b4b4b4c4c4c4d4d4d4d4e4e4e4f4f4f\n4f50505051515151525252535353535454545555555656565657575758585859\n59595a5a5a5a5b5b5b5c5c5c5d5d5d5e5e5e5f5f5f6060606061616162626263\n63636464646565656666666767676868686969696a6a6a6b6b6b6c6c6d6d6d6e\n6e6e6f6f6f707070717171727273737374747475757576767677777878787979\n797a7a7b7b7b7c7c7c7d7d7e7e7e7f7f7f808081818182828283838484848585\n86868687878888888989898a8a8b8b8b8c8c8d8d8d8e8e8f8f90909091919292\n9293939494949595969697979798989999999a9a9b9b9c9c9c9d9d9e9e9f9f9f\na0a0a1a1a2a2a3a3a3a4a4a5a5a6a6a6a7a7a8a8a9a9aaaaabababacacadadae\naeafafb0b0b0b1b1b2b2b3b3b4b4b5b5b6b6b6b7b7b8b8b9b9bababbbbbcbcbd\nbdbebebebfbfc0c0c1c1c2c2c3c3c4c4c5c5c6c6c7c7c8c8c9c9cacacbcbcccc\ncdcdcececfcfd0d0d1d1d2d2d3d3d4d4d5d5d6d6d7d7d8d8d9d9dadadbdcdcdd\ndddededfdfe0e0e1e1e2e2e3e3e4e4e5e6e6e7e7e8e8e9e9eaeaebebecededee\neeefeff0f0f1f1f2f3f3f4f4f5f5f6f6f7f8f8f9f9fafafbfcfcfdfdfefeffff\n> dup length 1 sub 3 -1 roll mul dup dup floor cvi exch ceiling \n cvi 3 index exch get 4 -1 roll 3 -1 roll get\n dup 3 1 roll sub 3 -1 roll dup floor cvi sub mul add 255 div } bind \n\n{ 1.0 0.0 3 -1 roll 1 index 1 index le { exch pop} { pop } ifelse \n 1 index 1 index ge { exch pop } { pop } ifelse < \n0000000000000000000000000000000000000000000000000000000000000000\n0000000000000000000000000000000000000001010101010101010101010101\n0101010101010101010101010101010101010101010101020202020202020202\n0202020202020202020202020202020202030303030303030303030303030303\n0303030303030304040404040404040404040404040404040404050505050505\n0505050505050505050506060606060606060606060606060607070707070707\n0707070707070708080808080808080808080808090909090909090909090909\n0a0a0a0a0a0a0a0a0a0a0a0b0b0b0b0b0b0b0b0b0b0b0c0c0c0c0c0c0c0c0c0c\n0d0d0d0d0d0d0d0d0d0d0e0e0e0e0e0e0e0e0e0f0f0f0f0f0f0f0f0f10101010\n1010101010111111111111111112121212121212121313131313131313141414\n1414141414151515151515151616161616161616171717171717171818181818\n18181919191919191a1a1a1a1a1a1a1b1b1b1b1b1b1c1c1c1c1c1c1c1d1d1d1d\n1d1d1e1e1e1e1e1e1f1f1f1f1f1f202020202020212121212121222222222223\n2323232323242424242425252525252526262626262727272727282828282829\n292929292a2a2a2a2a2b2b2b2b2b2c2c2c2c2c2d2d2d2d2d2e2e2e2e2e2f2f2f\n2f2f303030303131313131323232323333333333343434343535353535363636\n36373737373838383839393939393a3a3a3a3b3b3b3b3c3c3c3c3d3d3d3d3e3e\n3e3e3f3f3f3f4040404041414141424242424343434444444445454545464646\n4647474748484848494949494a4a4a4b4b4b4b4c4c4c4d4d4d4d4e4e4e4f4f4f\n4f50505051515151525252535353535454545555555656565657575758585859\n59595a5a5a5a5b5b5b5c5c5c5d5d5d5e5e5e5f5f5f6060606061616162626263\n63636464646565656666666767676868686969696a6a6a6b6b6b6c6c6d6d6d6e\n6e6e6f6f6f707070717171727273737374747475757576767677777878787979\n797a7a7b7b7b7c7c7c7d7d7e7e7e7f7f7f808081818182828283838484848585\n86868687878888888989898a8a8b8b8b8c8c8d8d8d8e8e8f8f90909091919292\n9293939494949595969697979798989999999a9a9b9b9c9c9c9d9d9e9e9f9f9f\na0a0a1a1a2a2a3a3a3a4a4a5a5a6a6a6a7a7a8a8a9a9aaaaabababacacadadae\naeafafb0b0b0b1b1b2b2b3b3b4b4b5b5b6b6b6b7b7b8b8b9b9bababbbbbcbcbd\nbdbebebebfbfc0c0c1c1c2c2c3c3c4c4c5c5c6c6c7c7c8c8c9c9cacacbcbcccc\ncdcdcececfcfd0d0d1d1d2d2d3d3d4d4d5d5d6d6d7d7d8d8d9d9dadadbdcdcdd\ndddededfdfe0e0e1e1e2e2e3e3e4e4e5e6e6e7e7e8e8e9e9eaeaebebecededee\neeefeff0f0f1f1f2f3f3f4f4f5f5f6f6f7f8f8f9f9fafafbfcfcfdfdfefeffff\n> dup length 1 sub 3 -1 roll mul dup dup floor cvi exch ceiling \n cvi 3 index exch get 4 -1 roll 3 -1 roll get\n dup 3 1 roll sub 3 -1 roll dup floor cvi sub mul add 255 div } bind \n] def \n/MatrixABC [ 0.4124 0.2126 0.0193 0.3576 0.7151 0.1192 0.1805 0.0722 0.9508 ] def \n/RangeLMN [ 0.0 0.9505 0.0 1.0000 0.0 1.0891 ] def \nend ] /Cs1 exch/ColorSpace dr pop\n%%EndPageSetup\n0.60000002 i\n/Cs1 SC\n0.10588235 0.72549021 0.12156863 sc\nq\n0 44 m\n160 44 l\n160 15.003872 l\n160 6.7174625 153.27803 0 145.00154 0 c\n14.998466 0 l\n6.7150416 0 0 6.7065849 0 15.003872 c\n0 44 l\nh\n0 44 m\n160 44 l\n160 14 l\n0 14 l\n0 44 l\nh\n0 44 m\nW*\n0 0 608 160 rc\n-5 49 m\n165 49 l\n165 -5 l\n-5 -5 l\nh\nf\nQ\n0.23529412 0.23529412 0.23529412 sc\nq\n83 90 m\n83 160 l\n77 160 l\n77 14 l\n83 14 l\n83 84 l\n160 84 l\n160 90 l\n83 90 l\nh\n0 144.99352 m\n0 153.28137 6.7219648 160 14.998466 160 c\n145.00154 160 l\n153.28496 160 160 153.27509 160 144.99352 c\n160 14 l\n0 14 l\n0 144.99352 l\nh\n0 144.99352 m\nW*\n0 0 608 160 rc\n-5 165 m\n165 165 l\n165 9 l\n-5 9 l\nh\nf\nQ\n0.10588235 0.72549021 0.12156863 sc\nq\n241.77284 12.165432 m\n230.85426 12.165432 222.63789 15.032893 217.12346 20.7679 c\n211.60902 26.502909 208.85185 34.995007 208.85185 46.244446 c\n208.85185 98.024689 l\n189 98.024689 l\n189 112.91358 l\n208.85185 112.91358 l\n208.85185 146 l\n225.39507 146 l\n225.39507 112.91358 l\n261.79013 112.91358 l\n261.79013 98.024689 l\n225.39507 98.024689 l\n225.39507 46.079014 l\n225.39507 39.571983 226.99422 34.802074 230.1926 31.769136 c\n233.39096 28.736198 237.58186 27.219753 242.76543 27.219753 c\n245.19179 27.219753 247.89381 27.49547 250.87161 28.046913 c\n253.8494 28.598356 256.88229 29.425508 259.97037 30.528395 c\n263.27902 15.97037 l\n259.52921 14.646907 255.86215 13.681896 252.27777 13.075309 c\n248.69341 12.468721 245.19179 12.165432 241.77284 12.165432 c\n241.77284 12.165432 l\nh\n294.70239 13.654321 m\n278.15918 13.654321 l\n278.15918 112.91358 l\n294.70239 112.91358 l\n294.70239 96.370369 l\n294.70239 96.370369 304.76617 106.29628 309.67401 109.60493 c\n314.58185 112.9136 320.34436 114.5679 326.96167 114.5679 c\n332.80695 114.5679 337.79745 112.94117 341.93326 109.68765 c\n346.06909 106.43414 349.01926 101.99509 350.78387 96.370369 c\n350.78387 96.370369 361.92294 106.29628 366.99622 109.60493 c\n372.06952 112.9136 378.08014 114.5679 385.02832 114.5679 c\n392.74854 114.5679 398.92459 111.72801 403.55673 106.04815 c\n408.18884 100.36829 410.50488 92.730911 410.50488 83.135803 c\n410.50488 13.654321 l\n393.96167 13.654321 l\n393.96167 80.488892 l\n393.96167 87.106209 392.69336 91.820976 390.15674 94.633331 c\n387.62009 97.445694 383.98062 98.851852 379.23822 98.851852 c\n374.49579 98.851852 369.78104 97.418121 365.09375 94.550621 c\n360.40649 91.683113 356.24316 87.878212 352.60364 83.135803 c\n352.60364 13.654321 l\n336.06042 13.654321 l\n336.06042 80.488892 l\n336.06042 87.106209 334.79211 91.820976 332.25549 94.633331 c\n329.71884 97.445694 326.07938 98.851852 321.33698 98.851852 c\n316.59457 98.851852 311.87979 97.418121 307.19254 94.550621 c\n302.50525 91.683113 298.34192 87.878212 294.70239 83.135803 c\n294.70239 13.654321 l\nh\n438.9505 21.264198 m\n433.10519 27.440361 430.18259 35.656738 430.18259 45.913582 c\n430.18259 112.91358 l\n446.7258 112.91358 l\n446.7258 49.222221 l\n446.7258 42.16375 448.3801 36.814835 451.68875 33.175308 c\n454.99741 29.535784 459.85004 27.716049 466.2468 27.716049 c\n471.32007 27.716049 476.36569 29.177351 481.38382 32.099998 c\n486.40195 35.022648 491.39243 39.35141 496.35544 45.086418 c\n496.35544 112.91358 l\n512.89862 112.91358 l\n512.89862 13.654321 l\n496.35544 13.654321 l\n496.35544 30.197531 l\n496.35544 30.197531 485.13364 20.271622 479.89493 16.962963 c\n474.65622 13.654305 468.78345 12 462.2764 12 c\n452.57101 12 444.79578 15.088035 438.9505 21.264198 c\nh\n588.65784 13.654321 m\n564.50476 51.041977 l\n541.84052 13.654321 l\n523.4776 13.654321 l\n556.56403 63.449383 l\n524.63562 112.91358 l\n543.164 112.91358 l\n566.15906 77.180244 l\n589.48499 112.91358 l\n607.84796 112.91358 l\n574.43066 64.441978 l\n607.18622 13.654321 l\n588.65784 13.654321 l\nh\n588.65784 13.654321 m\nW*\n0 0 608 160 rc\n184 151 m\n612.84796 151 l\n612.84796 7 l\n184 7 l\nh\nf\nep\nend\n%%Trailer\n%%EOF\n",
"sha256": "13ecb5c04f2b40f5dca7dc7e9be3986de3d7641c6494cc3f139669a3e90dd144"
},
".github/tools/external/tmux/logo/tmux-logomark.eps": {
"mode": "100644",
"encoding": "utf-8",
"data": "%!PS-Adobe-3.0 EPSF-3.0\n%APL_DSC_Encoding: UTF8\n%APLProducer: (Version 10.10.3 (Build 14D136) Quartz PS Context)\n%%Title: (Unknown)\n%%Creator: (Unknown)\n%%CreationDate: (Unknown)\n%%For: (Unknown)\n%%DocumentData: Clean7Bit\n%%LanguageLevel: 2\n%%Pages: 1\n%%BoundingBox: 0 0 160 160\n%%EndComments\n%%BeginProlog\n%%BeginFile: cg-pdf.ps\n%%Copyright: Copyright 2000-2004 Apple Computer Incorporated.\n%%Copyright: All Rights Reserved.\ncurrentpacking true setpacking\n/cg_md 141 dict def\ncg_md begin\n/L3? languagelevel 3 ge def\n/bd{bind def}bind def\n/ld{load def}bd\n/xs{exch store}bd\n/xd{exch def}bd\n/cmmtx matrix def\nmark\n/sc/setcolor\n/scs/setcolorspace\n/dr/defineresource\n/fr/findresource\n/T/true\n/F/false\n/d/setdash\n/w/setlinewidth\n/J/setlinecap\n/j/setlinejoin\n/M/setmiterlimit\n/i/setflat\n/rc/rectclip\n/rf/rectfill\n/rs/rectstroke\n/f/fill\n/f*/eofill\n/sf/selectfont\n/s/show\n/xS/xshow\n/yS/yshow\n/xyS/xyshow\n/S/stroke\n/m/moveto\n/l/lineto\n/c/curveto\n/h/closepath\n/n/newpath\n/q/gsave\n/Q/grestore\ncounttomark 2 idiv\n{ld}repeat pop\n/SC{\t\n /ColorSpace fr scs\n}bd\n/sopr /setoverprint where{pop/setoverprint}{/pop}ifelse ld\n/soprm /setoverprintmode where{pop/setoverprintmode}{/pop}ifelse ld\n/cgmtx matrix def\n/sdmtx{cgmtx currentmatrix pop}bd\n/CM {cgmtx setmatrix}bd\t\t\n/cm {cmmtx astore CM concat}bd\t\n/W{clip newpath}bd\n/W*{eoclip newpath}bd\nstatusdict begin product end dup (HP) anchorsearch{\n pop pop pop\t\n true\n}{\n pop\t\n (hp) anchorsearch{\n\tpop pop true\n }{\n\tpop false\n }ifelse\n}ifelse\n{\t\n { \n\t{ \n\t pop pop \n\t (0)dup 0 4 -1 roll put\n\t F charpath\n\t}cshow\n }\n}{\n {F charpath}\n}ifelse\n/cply exch bd\n/cps {cply stroke}bd\n/pgsave 0 def\n/bp{/pgsave save store}bd\n/ep{pgsave restore showpage}def\t\t\n/re{4 2 roll m 1 index 0 rlineto 0 exch rlineto neg 0 rlineto h}bd\n/scrdict 10 dict def\n/scrmtx matrix def\n/patarray 0 def\n/createpat{patarray 3 1 roll put}bd\n/makepat{\nscrmtx astore pop\ngsave\ninitgraphics\nCM \npatarray exch get\nscrmtx\nmakepattern\ngrestore\nsetpattern\n}bd\n/cg_BeginEPSF{\n userdict save/cg_b4_Inc_state exch put\n userdict/cg_endepsf/cg_EndEPSF load put\n count userdict/cg_op_count 3 -1 roll put \n countdictstack dup array dictstack userdict/cg_dict_array 3 -1 roll put\n 3 sub{end}repeat\n /showpage {} def\n 0 setgray 0 setlinecap 1 setlinewidth 0 setlinejoin\n 10 setmiterlimit [] 0 setdash newpath\n false setstrokeadjust false setoverprint\t\n}bd\n/cg_EndEPSF{\n countdictstack 3 sub { end } repeat\n cg_dict_array 3 1 index length 3 sub getinterval\n {begin}forall\n count userdict/cg_op_count get sub{pop}repeat\n userdict/cg_b4_Inc_state get restore\n F setpacking\n}bd\n/cg_biproc{currentfile/RunLengthDecode filter}bd\n/cg_aiproc{currentfile/ASCII85Decode filter/RunLengthDecode filter}bd\n/ImageDataSource 0 def\nL3?{\n /cg_mibiproc{pop pop/ImageDataSource{cg_biproc}def}bd\n /cg_miaiproc{pop pop/ImageDataSource{cg_aiproc}def}bd\n}{\n /ImageBandMask 0 def\n /ImageBandData 0 def\n /cg_mibiproc{\n\tstring/ImageBandMask xs\n\tstring/ImageBandData xs\n\t/ImageDataSource{[currentfile/RunLengthDecode filter dup ImageBandMask/readstring cvx\n\t /pop cvx dup ImageBandData/readstring cvx/pop cvx]cvx bind}bd\n }bd\n /cg_miaiproc{\t\n\tstring/ImageBandMask xs\n\tstring/ImageBandData xs\n\t/ImageDataSource{[currentfile/ASCII85Decode filter/RunLengthDecode filter\n\t dup ImageBandMask/readstring cvx\n\t /pop cvx dup ImageBandData/readstring cvx/pop cvx]cvx bind}bd\n }bd\n}ifelse\n/imsave 0 def\n/BI{save/imsave xd mark}bd\n/EI{imsave restore}bd\n/ID{\ncounttomark 2 idiv\ndup 2 add\t\ndict begin\n{def} repeat\npop\t\t\n/ImageType 1 def\n/ImageMatrix[Width 0 0 Height neg 0 Height]def\ncurrentdict dup/ImageMask known{ImageMask}{F}ifelse exch\nL3?{\n dup/MaskedImage known\n { \n\tpop\n\t<<\n\t /ImageType 3\n\t /InterleaveType 2\n\t /DataDict currentdict\n\t /MaskDict\n\t << /ImageType 1\n\t\t/Width Width\n\t\t/Height Height\n\t\t/ImageMatrix ImageMatrix\n\t\t/BitsPerComponent 1\n\t\t/Decode [0 1]\n\t\tcurrentdict/Interpolate known\n\t\t{/Interpolate Interpolate}if\n\t >>\n\t>>\n }if\n}if\nexch\n{imagemask}{image}ifelse\t\nend\t\n}bd\n/cguidfix{statusdict begin mark version end\n{cvr}stopped{cleartomark 0}{exch pop}ifelse\n2012 lt{dup findfont dup length dict begin\n{1 index/FID ne 2 index/UniqueID ne and\n{def} {pop pop} ifelse}forall\ncurrentdict end definefont pop\n}{pop}ifelse\n}bd\n/t_array 0 def\n/t_i 0 def\n/t_c 1 string def\n/x_proc{ \n exch t_array t_i get add exch moveto\n /t_i t_i 1 add store\n}bd\n/y_proc{ \n t_array t_i get add moveto\n /t_i t_i 1 add store\n}bd\n/xy_proc{\n \n\tt_array t_i 2 copy 1 add get 3 1 roll get \n\t4 -1 roll add 3 1 roll add moveto\n\t/t_i t_i 2 add store\n}bd\n/sop 0 def\t\t\n/cp_proc/x_proc ld \t\n/base_charpath\t\t\n{\n /t_array xs\n /t_i 0 def\n { \n\tt_c 0 3 -1 roll put\n currentpoint\n\tt_c cply sop\n cp_proc\n }forall\n /t_array 0 def\n}bd\n/sop/stroke ld\t\t\n/nop{}def\n/xsp/base_charpath ld\n/ysp{/cp_proc/y_proc ld base_charpath/cp_proc/x_proc ld}bd\n/xysp{/cp_proc/xy_proc ld base_charpath/cp_proc/x_proc ld}bd\n/xmp{/sop/nop ld /cp_proc/x_proc ld base_charpath/sop/stroke ld}bd\n/ymp{/sop/nop ld /cp_proc/y_proc ld base_charpath/sop/stroke ld}bd\n/xymp{/sop/nop ld /cp_proc/xy_proc ld base_charpath/sop/stroke ld}bd\n/refnt{ \nfindfont dup length dict copy dup\n/Encoding 4 -1 roll put \ndefinefont pop\n}bd\n/renmfont{ \nfindfont dup length dict copy definefont pop\n}bd\nL3? dup dup{save exch}if\n/Range 0 def\n/DataSource 0 def\n/val 0 def\n/nRange 0 def\n/mulRange 0 def\n/d0 0 def\n/r0 0 def\n/di 0 def\n/ri 0 def\n/a0 0 def\n/a1 0 def\n/r1 0 def\n/r2 0 def\n/dx 0 def\n/Nsteps 0 def\n/sh3tp 0 def\n/ymax 0 def\n/ymin 0 def\n/xmax 0 def\n/xmin 0 def\n/setupFunEval \n{\n begin\n\t/nRange Range length 2 idiv store\n\t/mulRange \n\t\t \n\t[ \n\t 0 1 nRange 1 sub\n\t { \n\t\t 2 mul/nDim2 xd\t\t\n\t\t Range nDim2 get\t\t\n\t\t Range nDim2 1 add get\t\n\t\t 1 index sub\t\t\t\n\t\t\t\t\t\t\n\t\t 255 div\t\t\t\n\t\t exch\t\t\t\n\t }for\n\t]store\n end\n}bd\n/FunEval \n{\n begin\n\t\n\tnRange mul /val xd\t\n\t\t\t\t\n\t0 1 nRange 1 sub\n\t{\n\t dup 2 mul/nDim2 xd \n\t val\t\n\t add DataSource exch get \n\t mulRange nDim2 get mul \t\n\t mulRange nDim2 1 add get \n\t add \n\t}for\t\n end\n}bd\n/max \n{\n\t2 copy lt\n\t{exch pop}{pop}ifelse\n}bd\n/sh2\n{\t\n\t/Coords load aload pop \t\n\t3 index 3 index translate\t\n\t\t\t\t\t\n\t3 -1 roll sub\t\n\t3 1 roll exch \t\n\tsub\t\t\t\t\n\t2 copy\n\tdup mul exch dup mul add sqrt\t\n\tdup\n\tscale \n\tatan\t\n\t\n\trotate\t\t\n\t\n\t/Function load setupFunEval\t\n\t\n\t\n\tclippath {pathbbox}stopped {0 0 0 0}if newpath \t\n\t/ymax xs\n\t/xmax xs\n\t/ymin xs\n\t/xmin xs\n\tcurrentdict/Extend known\n\t{\n\t\t/Extend load 0 get\n\t\t{\t\n\t\t\t0/Function load FunEval sc\t\n\t\t\txmin ymin xmin abs ymax ymin sub rectfill\n\t\t}if\n\t}if\n\t\n\t/Nsteps/Function load/Size get 0 get 1 sub store\n\t/dx 1 Nsteps div store\n\tgsave\n\t\t/di ymax ymin sub store\n\t\t/Function load\n\t\t\n\t\t0 1 Nsteps\n\t\t{\n\t\t\t1 index FunEval sc\n\t\t\t0 ymin dx di rectfill\n\t\t\tdx 0 translate\n\t\t}for\n\t\tpop\t\n\tgrestore\t\n\tcurrentdict/Extend known\n\t{\n\t\t/Extend load 1 get\n\t\t{\t\n\t\t\tNsteps/Function load FunEval sc\t\n\t\t\t1 ymin xmax 1 sub abs ymax ymin sub rectfill\n\t\t}if\n\t}if\n}bd\n/shp\t\n{\t\n\t4 copy\n\t\n\tdup 0 gt{\n\t\t0 exch a1 a0 arc\n\t}{\n\t\tpop 0 moveto\n\t}ifelse\n\tdup 0 gt{\n\t\t0 exch a0 a1 arcn\n\t}{\n\t\tpop 0 lineto\n\t}ifelse\n\t\n\tfill\n\t\n\tdup 0 gt{\n\t\t0 exch a0 a1 arc\n\t}{\n\t\tpop 0 moveto\n\t}ifelse\n\tdup 0 gt{\n\t\t0 exch a1 a0 arcn\n\t}{\n\t\tpop 0 lineto\n\t}ifelse\n\t\n\tfill\n}bd\n/calcmaxs\n{\t\n\t\n\txmin dup mul ymin dup mul add sqrt\t\t\n\txmax dup mul ymin dup mul add sqrt\t\t\n\txmin dup mul ymax dup mul add sqrt\t\t\n\txmax dup mul ymax dup mul add sqrt\t\t\n\tmax max max\t\t\t\t\t\t\t\t\n}bd\n/sh3\n{\t\n\t/Coords load aload pop \t\n\t5 index 5 index translate\t\n\t3 -1 roll 6 -1 roll sub\t\t\n\t3 -1 roll 5 -1 roll sub\t\t\n\t2 copy dup mul exch dup mul add sqrt\n\t/dx xs\t\t\t\t\t\t\n\t2 copy 0 ne exch 0 ne or\n\t{\n\t\t\n\t\texch atan rotate\t\n\t}{\n\t\tpop pop\n\t}ifelse\n\t\n\t/r2 xs\n\t/r1 xs\n\t/Function load \n\tdup/Size get 0 get 1 sub\t\n\t/Nsteps xs\t\t\n\tsetupFunEval\t\t\n\t\n\t\n\t\n\t\n\t\n\tdx r2 add r1 lt{\n\t\t\n\t\t0 \n\t}{\n\t\tdx r1 add r2 le\n\t\t{ \n\t\t\t1\n\t\t}{ \n\t\t\tr1 r2 eq\n\t\t\t{\t\n\t\t\t\t2\n\t\t\t}{ \n\t\t\t\t3\n\t\t\t}ifelse\t\t\n\t\t}ifelse\n\t}ifelse\n\t/sh3tp xs\t\t\n\tclippath {pathbbox}stopped {0 0 0 0}if \n\tnewpath \t\n\t/ymax xs\n\t/xmax xs\n\t/ymin xs\n\t/xmin xs\n\t\n\tdx dup mul r2 r1 sub dup mul sub dup 0 gt\n\t{\n\t\tsqrt r2 r1 sub atan\n\t\t/a0 exch 180 exch sub store \n\t\t/a1 a0 neg store \n\t}{\n\t\tpop\n\t\t/a0 0 store\n\t\t/a1 360 store\t\t\n\t}ifelse\t\t\n\tcurrentdict/Extend known\n\t{\n\t\t/Extend load 0 get r1 0 gt and\t\n\t\t{\t\n\t\t\t0/Function load FunEval sc\t\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\t{ \n\t\t\t\t{\t\n\t\t\t\t\tdx 0 r1 360 0 arcn\n\t\t\t\t\txmin ymin moveto\n\t\t\t\t\txmax ymin lineto\n\t\t\t\t\txmax ymax lineto\n\t\t\t\t\txmin ymax lineto\n\t\t\t\t\txmin ymin lineto\n\t\t\t\t\teofill\t\t\n\t\t\t\t}\n\t\t\t\t{\t\n\t\t\t\t\tr1 0 gt{0 0 r1 0 360 arc fill}if\n\t\t\t\t}\n\t\t\t\t{\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t0 r1 xmin abs r1 add neg r1 shp\n\t\t\t\t}\n\t\t\t\t{\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\tr2 r1 gt{\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t0 r1\n\t\t\t\t\t\tr1 neg r2 r1 sub div dx mul\t\n\t\t\t\t\t\t0\t\n\t\t\t\t\t\tshp\t\n\t\t\t\t\t}{\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t0 r1 calcmaxs\t\n\t\t\t\t\t\tdup\n\t\t\t\t\t\t\n\t\t\t\t\t\tr2 add dx mul dx r1 r2 sub sub div\n\t\t\t\t\t\tneg\t\t\t\t\n\t\t\t\t\t\texch 1 index\t\n\t\t\t\t\t\tabs exch sub\n\t\t\t\t\t\tshp\n\t\t\t\t\t}ifelse\n\t\t\t\t} \n\t\t\t}sh3tp get exec\t\n\t\t}if\n\t}if\n\t\n\t/d0 0 store\n\t/r0 r1 store\n\t/di dx Nsteps div store\n\t/ri r2 r1 sub Nsteps div store \n\t/Function load \n\t0 1 Nsteps\n\t{\t\n\t\t1 index FunEval sc\n\t\td0 di add r0 ri add d0 r0 shp\n\t\t{\n\t\t\n\t\td0 0 r0 a1 a0 arc\n\t\td0 di add 0 r0 ri add a0 a1 arcn\n\t\tfill\n\t\t\n\t\t\n\t\td0 0 r0 a0 a1 arc\n\t\td0 di add 0 r0 ri add a1 a0 arcn\n\t\tfill\n\t\t}pop\n\t\t\n\t\t\n\t\t/d0 d0 di add store\n\t\t/r0 r0 ri add store\n\t}for\n\tpop\t\n\t\n\tcurrentdict/Extend known\n\t{\n\t\t/Extend load 1 get r2 0 gt and\t\n\t\t{\t\n\t\t\tNsteps/Function load FunEval sc\t\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\t{ \n\t\t\t\t{\n\t\t\t\t\tdx 0 r2 0 360 arc fill\n\t\t\t\t} \n\t\t\t\t{\n\t\t\t\t\tdx 0 r2 360 0 arcn\n\t\t\t\t\txmin ymin moveto\n\t\t\t\t\txmax ymin lineto\n\t\t\t\t\txmax ymax lineto\n\t\t\t\t\txmin ymax lineto\n\t\t\t\t\txmin ymin lineto\n\t\t\t\t\teofill\t\t\n\t\t\t\t} \n\t\t\t\t{\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\txmax abs r1 add r1 dx r1 shp\n\t\t\t\t}\t\n\t\t\t\t{\t\n\t\t\t\n\t\t\t\t\tr2 r1 gt{\n\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\tcalcmaxs dup\t\n\t\t\t\t\t\t\n\t\t\t\t\t\tr1 add dx mul dx r2 r1 sub sub div\t\n\t\t\t\t\t\texch 1 index\t\n\t\t\t\t\t\texch sub\n\t\t\t\t\t\tdx r2\n\t\t\t\t\t\tshp\n\t\t\t\t\t}{\t\n\t\t\t\t\t\t\n\t\t\t\t\t\tr1 neg r2 r1 sub div dx mul\t\n\t\t\t\t\t\t0\t\t\n\t\t\t\t\t\tdx \t\t\n\t\t\t\t\t\tr2\t\t\n\t\t\t\t\t\tshp\n\t\t\t\t\t}ifelse\n\t\t\t\t}\n\t\t\t}\t\t\t\n\t\t\tsh3tp get exec\t\n\t\t}if\n\t}if\n}bd\n/sh\t\t\n{\t\n\tbegin\n\t\t/ShadingType load dup dup 2 eq exch 3 eq or\n\t\t{\t\n\t\t\tgsave\n\t\t\t\tnewpath\n\t\t\t\t/ColorSpace load scs\n\t\t\t\tcurrentdict/BBox known\n\t\t\t\t{\n\t\t\t\t\t/BBox load aload pop\t\n\t\t\t\t\t2 index sub\t\t\t\t\n\t\t\t\t\t3 index\t\t\t\t\t\n\t\t\t\t\t3 -1 roll exch sub \n\t\t\t\t\texch rectclip\n\t\t\t\t}if\n\t\t\t\t2 eq\n\t\t\t\t{sh2}{sh3}ifelse\n\t\t\tgrestore\n\t\t}{\n\t\t\t\n\t\t\tpop \n\t\t\t(DEBUG: shading type unimplemented\\n)print flush\n\t\t}ifelse\n\tend\n}bd\n{restore}if not dup{save exch}if\n\tL3?{\t\n\t\t/sh/shfill ld\n\t\t/csq/clipsave ld\n\t\t/csQ/cliprestore ld\n\t}if\n{restore}if\nend\nsetpacking\n%%EndFile\n%%EndProlog\n%%BeginSetup\n%%EndSetup\n%%Page: 1 1\n%%PageBoundingBox: 0 0 160 160\n%%BeginPageSetup\ncg_md begin\nbp\nsdmtx\n[ /CIEBasedABC 4 dict dup begin \n/WhitePoint [ 0.9505 1.0000 1.0891 ] def \n/DecodeABC [ \n{ 1.0 0.0 3 -1 roll 1 index 1 index le { exch pop} { pop } ifelse \n 1 index 1 index ge { exch pop } { pop } ifelse < \n0000000000000000000000000000000000000000000000000000000000000000\n0000000000000000000000000000000000000001010101010101010101010101\n0101010101010101010101010101010101010101010101020202020202020202\n0202020202020202020202020202020202030303030303030303030303030303\n0303030303030304040404040404040404040404040404040404050505050505\n0505050505050505050506060606060606060606060606060607070707070707\n0707070707070708080808080808080808080808090909090909090909090909\n0a0a0a0a0a0a0a0a0a0a0a0b0b0b0b0b0b0b0b0b0b0b0c0c0c0c0c0c0c0c0c0c\n0d0d0d0d0d0d0d0d0d0d0e0e0e0e0e0e0e0e0e0f0f0f0f0f0f0f0f0f10101010\n1010101010111111111111111112121212121212121313131313131313141414\n1414141414151515151515151616161616161616171717171717171818181818\n18181919191919191a1a1a1a1a1a1a1b1b1b1b1b1b1c1c1c1c1c1c1c1d1d1d1d\n1d1d1e1e1e1e1e1e1f1f1f1f1f1f202020202020212121212121222222222223\n2323232323242424242425252525252526262626262727272727282828282829\n292929292a2a2a2a2a2b2b2b2b2b2c2c2c2c2c2d2d2d2d2d2e2e2e2e2e2f2f2f\n2f2f303030303131313131323232323333333333343434343535353535363636\n36373737373838383839393939393a3a3a3a3b3b3b3b3c3c3c3c3d3d3d3d3e3e\n3e3e3f3f3f3f4040404041414141424242424343434444444445454545464646\n4647474748484848494949494a4a4a4b4b4b4b4c4c4c4d4d4d4d4e4e4e4f4f4f\n4f50505051515151525252535353535454545555555656565657575758585859\n59595a5a5a5a5b5b5b5c5c5c5d5d5d5e5e5e5f5f5f6060606061616162626263\n63636464646565656666666767676868686969696a6a6a6b6b6b6c6c6d6d6d6e\n6e6e6f6f6f707070717171727273737374747475757576767677777878787979\n797a7a7b7b7b7c7c7c7d7d7e7e7e7f7f7f808081818182828283838484848585\n86868687878888888989898a8a8b8b8b8c8c8d8d8d8e8e8f8f90909091919292\n9293939494949595969697979798989999999a9a9b9b9c9c9c9d9d9e9e9f9f9f\na0a0a1a1a2a2a3a3a3a4a4a5a5a6a6a6a7a7a8a8a9a9aaaaabababacacadadae\naeafafb0b0b0b1b1b2b2b3b3b4b4b5b5b6b6b6b7b7b8b8b9b9bababbbbbcbcbd\nbdbebebebfbfc0c0c1c1c2c2c3c3c4c4c5c5c6c6c7c7c8c8c9c9cacacbcbcccc\ncdcdcececfcfd0d0d1d1d2d2d3d3d4d4d5d5d6d6d7d7d8d8d9d9dadadbdcdcdd\ndddededfdfe0e0e1e1e2e2e3e3e4e4e5e6e6e7e7e8e8e9e9eaeaebebecededee\neeefeff0f0f1f1f2f3f3f4f4f5f5f6f6f7f8f8f9f9fafafbfcfcfdfdfefeffff\n> dup length 1 sub 3 -1 roll mul dup dup floor cvi exch ceiling \n cvi 3 index exch get 4 -1 roll 3 -1 roll get\n dup 3 1 roll sub 3 -1 roll dup floor cvi sub mul add 255 div } bind \n\n{ 1.0 0.0 3 -1 roll 1 index 1 index le { exch pop} { pop } ifelse \n 1 index 1 index ge { exch pop } { pop } ifelse < \n0000000000000000000000000000000000000000000000000000000000000000\n0000000000000000000000000000000000000001010101010101010101010101\n0101010101010101010101010101010101010101010101020202020202020202\n0202020202020202020202020202020202030303030303030303030303030303\n0303030303030304040404040404040404040404040404040404050505050505\n0505050505050505050506060606060606060606060606060607070707070707\n0707070707070708080808080808080808080808090909090909090909090909\n0a0a0a0a0a0a0a0a0a0a0a0b0b0b0b0b0b0b0b0b0b0b0c0c0c0c0c0c0c0c0c0c\n0d0d0d0d0d0d0d0d0d0d0e0e0e0e0e0e0e0e0e0f0f0f0f0f0f0f0f0f10101010\n1010101010111111111111111112121212121212121313131313131313141414\n1414141414151515151515151616161616161616171717171717171818181818\n18181919191919191a1a1a1a1a1a1a1b1b1b1b1b1b1c1c1c1c1c1c1c1d1d1d1d\n1d1d1e1e1e1e1e1e1f1f1f1f1f1f202020202020212121212121222222222223\n2323232323242424242425252525252526262626262727272727282828282829\n292929292a2a2a2a2a2b2b2b2b2b2c2c2c2c2c2d2d2d2d2d2e2e2e2e2e2f2f2f\n2f2f303030303131313131323232323333333333343434343535353535363636\n36373737373838383839393939393a3a3a3a3b3b3b3b3c3c3c3c3d3d3d3d3e3e\n3e3e3f3f3f3f4040404041414141424242424343434444444445454545464646\n4647474748484848494949494a4a4a4b4b4b4b4c4c4c4d4d4d4d4e4e4e4f4f4f\n4f50505051515151525252535353535454545555555656565657575758585859\n59595a5a5a5a5b5b5b5c5c5c5d5d5d5e5e5e5f5f5f6060606061616162626263\n63636464646565656666666767676868686969696a6a6a6b6b6b6c6c6d6d6d6e\n6e6e6f6f6f707070717171727273737374747475757576767677777878787979\n797a7a7b7b7b7c7c7c7d7d7e7e7e7f7f7f808081818182828283838484848585\n86868687878888888989898a8a8b8b8b8c8c8d8d8d8e8e8f8f90909091919292\n9293939494949595969697979798989999999a9a9b9b9c9c9c9d9d9e9e9f9f9f\na0a0a1a1a2a2a3a3a3a4a4a5a5a6a6a6a7a7a8a8a9a9aaaaabababacacadadae\naeafafb0b0b0b1b1b2b2b3b3b4b4b5b5b6b6b6b7b7b8b8b9b9bababbbbbcbcbd\nbdbebebebfbfc0c0c1c1c2c2c3c3c4c4c5c5c6c6c7c7c8c8c9c9cacacbcbcccc\ncdcdcececfcfd0d0d1d1d2d2d3d3d4d4d5d5d6d6d7d7d8d8d9d9dadadbdcdcdd\ndddededfdfe0e0e1e1e2e2e3e3e4e4e5e6e6e7e7e8e8e9e9eaeaebebecededee\neeefeff0f0f1f1f2f3f3f4f4f5f5f6f6f7f8f8f9f9fafafbfcfcfdfdfefeffff\n> dup length 1 sub 3 -1 roll mul dup dup floor cvi exch ceiling \n cvi 3 index exch get 4 -1 roll 3 -1 roll get\n dup 3 1 roll sub 3 -1 roll dup floor cvi sub mul add 255 div } bind \n\n{ 1.0 0.0 3 -1 roll 1 index 1 index le { exch pop} { pop } ifelse \n 1 index 1 index ge { exch pop } { pop } ifelse < \n0000000000000000000000000000000000000000000000000000000000000000\n0000000000000000000000000000000000000001010101010101010101010101\n0101010101010101010101010101010101010101010101020202020202020202\n0202020202020202020202020202020202030303030303030303030303030303\n0303030303030304040404040404040404040404040404040404050505050505\n0505050505050505050506060606060606060606060606060607070707070707\n0707070707070708080808080808080808080808090909090909090909090909\n0a0a0a0a0a0a0a0a0a0a0a0b0b0b0b0b0b0b0b0b0b0b0c0c0c0c0c0c0c0c0c0c\n0d0d0d0d0d0d0d0d0d0d0e0e0e0e0e0e0e0e0e0f0f0f0f0f0f0f0f0f10101010\n1010101010111111111111111112121212121212121313131313131313141414\n1414141414151515151515151616161616161616171717171717171818181818\n18181919191919191a1a1a1a1a1a1a1b1b1b1b1b1b1c1c1c1c1c1c1c1d1d1d1d\n1d1d1e1e1e1e1e1e1f1f1f1f1f1f202020202020212121212121222222222223\n2323232323242424242425252525252526262626262727272727282828282829\n292929292a2a2a2a2a2b2b2b2b2b2c2c2c2c2c2d2d2d2d2d2e2e2e2e2e2f2f2f\n2f2f303030303131313131323232323333333333343434343535353535363636\n36373737373838383839393939393a3a3a3a3b3b3b3b3c3c3c3c3d3d3d3d3e3e\n3e3e3f3f3f3f4040404041414141424242424343434444444445454545464646\n4647474748484848494949494a4a4a4b4b4b4b4c4c4c4d4d4d4d4e4e4e4f4f4f\n4f50505051515151525252535353535454545555555656565657575758585859\n59595a5a5a5a5b5b5b5c5c5c5d5d5d5e5e5e5f5f5f6060606061616162626263\n63636464646565656666666767676868686969696a6a6a6b6b6b6c6c6d6d6d6e\n6e6e6f6f6f707070717171727273737374747475757576767677777878787979\n797a7a7b7b7b7c7c7c7d7d7e7e7e7f7f7f808081818182828283838484848585\n86868687878888888989898a8a8b8b8b8c8c8d8d8d8e8e8f8f90909091919292\n9293939494949595969697979798989999999a9a9b9b9c9c9c9d9d9e9e9f9f9f\na0a0a1a1a2a2a3a3a3a4a4a5a5a6a6a6a7a7a8a8a9a9aaaaabababacacadadae\naeafafb0b0b0b1b1b2b2b3b3b4b4b5b5b6b6b6b7b7b8b8b9b9bababbbbbcbcbd\nbdbebebebfbfc0c0c1c1c2c2c3c3c4c4c5c5c6c6c7c7c8c8c9c9cacacbcbcccc\ncdcdcececfcfd0d0d1d1d2d2d3d3d4d4d5d5d6d6d7d7d8d8d9d9dadadbdcdcdd\ndddededfdfe0e0e1e1e2e2e3e3e4e4e5e6e6e7e7e8e8e9e9eaeaebebecededee\neeefeff0f0f1f1f2f3f3f4f4f5f5f6f6f7f8f8f9f9fafafbfcfcfdfdfefeffff\n> dup length 1 sub 3 -1 roll mul dup dup floor cvi exch ceiling \n cvi 3 index exch get 4 -1 roll 3 -1 roll get\n dup 3 1 roll sub 3 -1 roll dup floor cvi sub mul add 255 div } bind \n] def \n/MatrixABC [ 0.4124 0.2126 0.0193 0.3576 0.7151 0.1192 0.1805 0.0722 0.9508 ] def \n/RangeLMN [ 0.0 0.9505 0.0 1.0000 0.0 1.0891 ] def \nend ] /Cs1 exch/ColorSpace dr pop\n%%EndPageSetup\n0.60000002 i\n/Cs1 SC\n0.10588235 0.72549021 0.12156863 sc\nq\n0 44 m\n160 44 l\n160 15.003872 l\n160 6.7174625 153.27803 0 145.00154 0 c\n14.998466 0 l\n6.7150416 0 0 6.7065849 0 15.003872 c\n0 44 l\nh\n0 44 m\n160 44 l\n160 14 l\n0 14 l\n0 44 l\nh\n0 44 m\nW*\n0 0 160 160 rc\n-5 49 m\n165 49 l\n165 -5 l\n-5 -5 l\nh\nf\nQ\n0.23529412 0.23529412 0.23529412 sc\nq\n83 90 m\n83 160 l\n77 160 l\n77 14 l\n83 14 l\n83 84 l\n160 84 l\n160 90 l\n83 90 l\nh\n0 144.99352 m\n0 153.28137 6.7219648 160 14.998466 160 c\n145.00154 160 l\n153.28496 160 160 153.27509 160 144.99352 c\n160 14 l\n0 14 l\n0 144.99352 l\nh\n0 144.99352 m\nW*\n0 0 160 160 rc\n-5 165 m\n165 165 l\n165 9 l\n-5 9 l\nh\nf\nep\nend\n%%Trailer\n%%EOF\n",
"sha256": "f5afbd939a1675b5b1293cd642273d8b0b9555b906683970b5e7a34f802674fd"
},
".github/tools/external/.tmux/.logo/LICENSE": {
"mode": "100644",
"encoding": "utf-8",
"data": "Oh my tmux! logo copyright (c) 2024, Gregory Pakosz <gregory.pakosz@gmail.com>\n\nOriginal tmux logo copyright (c) 2015, Jason Long <jason@jasonlong.me>\nSee https://github.com/tmux/tmux/tree/master/logo\n\nPermission to use, copy, modify, and/or distribute this software for any\npurpose with or without fee is hereby granted, provided that the above\ncopyright notice and this permission notice appear in all copies.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\nWITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\nMERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\nANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\nWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\nACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\nOR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n",
"sha256": "6ae92da1ac8fc251f218491c42048d258d50d57bc685beb871fb09adf0bcea3e"
},
".github/tools/external/Skill_Seekers-development/src/skill_seekers/mcp/server.py": {
"mode": "100644",
"encoding": "utf-8",
"data": "#!/usr/bin/env python3\n\"\"\"\nSkill Seeker MCP Server - Compatibility Shim\n\nThis file provides backward compatibility by delegating to the new server_fastmcp.py implementation.\n\nFor new installations, use server_fastmcp.py directly:\n python -m skill_seekers.mcp.server_fastmcp\n\nThis shim will be deprecated in v3.0.0 (6+ months after v2.4.0 release).\n\"\"\"\n\nimport sys\nimport warnings\n\n# Show deprecation warning (can be disabled with PYTHONWARNINGS=ignore)\nwarnings.warn(\n \"The legacy server.py is deprecated and will be removed in v4.0.0. \"\n \"Please update your MCP configuration to use 'server_fastmcp' instead:\\n\"\n \" OLD: python -m skill_seekers.mcp.server\\n\"\n \" NEW: python -m skill_seekers.mcp.server_fastmcp\\n\"\n \"The new server provides the same functionality with improved performance.\",\n DeprecationWarning,\n stacklevel=2,\n)\n\n# Re-export tool functions for backward compatibility with tests\ntry:\n from skill_seekers.mcp.tools.config_tools import (\n generate_config as generate_config_tool,\n )\n from skill_seekers.mcp.tools.config_tools import (\n list_configs as list_configs_tool,\n )\n from skill_seekers.mcp.tools.config_tools import (\n validate_config as validate_config_tool,\n )\n from skill_seekers.mcp.tools.packaging_tools import (\n install_skill_tool,\n package_skill_tool,\n upload_skill_tool,\n )\n from skill_seekers.mcp.tools.scraping_tools import (\n detect_patterns_tool,\n estimate_pages_tool,\n extract_config_patterns_tool,\n scrape_docs_tool,\n scrape_github_tool,\n scrape_pdf_tool,\n )\n from skill_seekers.mcp.tools.source_tools import (\n add_config_source_tool,\n fetch_config_tool,\n list_config_sources_tool,\n remove_config_source_tool,\n submit_config_tool,\n )\n from skill_seekers.mcp.tools.splitting_tools import (\n generate_router as generate_router_tool,\n )\n from skill_seekers.mcp.tools.splitting_tools import (\n split_config as split_config_tool,\n )\n\n # For test compatibility - create call_tool router function\n async def call_tool(name: str, arguments: dict):\n \"\"\"Route tool calls to appropriate handlers (backward compatibility).\"\"\"\n from mcp.types import TextContent\n\n try:\n if name == \"generate_config\":\n return await generate_config_tool(arguments)\n elif name == \"estimate_pages\":\n return await estimate_pages_tool(arguments)\n elif name == \"scrape_docs\":\n return await scrape_docs_tool(arguments)\n elif name == \"package_skill\":\n return await package_skill_tool(arguments)\n elif name == \"upload_skill\":\n return await upload_skill_tool(arguments)\n elif name == \"list_configs\":\n return await list_configs_tool(arguments)\n elif name == \"validate_config\":\n return await validate_config_tool(arguments)\n elif name == \"split_config\":\n return await split_config_tool(arguments)\n elif name == \"generate_router\":\n return await generate_router_tool(arguments)\n elif name == \"scrape_pdf\":\n return await scrape_pdf_tool(arguments)\n elif name == \"scrape_github\":\n return await scrape_github_tool(arguments)\n elif name == \"fetch_config\":\n return await fetch_config_tool(arguments)\n elif name == \"submit_config\":\n return await submit_config_tool(arguments)\n elif name == \"add_config_source\":\n return await add_config_source_tool(arguments)\n elif name == \"list_config_sources\":\n return await list_config_sources_tool(arguments)\n elif name == \"remove_config_source\":\n return await remove_config_source_tool(arguments)\n elif name == \"install_skill\":\n return await install_skill_tool(arguments)\n elif name == \"detect_patterns\":\n return await detect_patterns_tool(arguments)\n elif name == \"extract_config_patterns\":\n return await extract_config_patterns_tool(arguments)\n else:\n return [TextContent(type=\"text\", text=f\"Unknown tool: {name}\")]\n except Exception as e:\n return [TextContent(type=\"text\", text=f\"Error: {str(e)}\")]\n\n # For test compatibility - create a mock list_tools function\n async def list_tools():\n \"\"\"Mock list_tools for backward compatibility with tests.\"\"\"\n from mcp.types import Tool\n\n tools = [\n Tool(\n name=\"generate_config\",\n description=\"Generate config file\",\n inputSchema={\"type\": \"object\", \"properties\": {}},\n ),\n Tool(\n name=\"list_configs\",\n description=\"List available configs\",\n inputSchema={\"type\": \"object\", \"properties\": {}},\n ),\n Tool(\n name=\"validate_config\",\n description=\"Validate config file\",\n inputSchema={\"type\": \"object\", \"properties\": {}},\n ),\n Tool(\n name=\"estimate_pages\",\n description=\"Estimate page count\",\n inputSchema={\"type\": \"object\", \"properties\": {}},\n ),\n Tool(\n name=\"scrape_docs\",\n description=\"Scrape documentation\",\n inputSchema={\"type\": \"object\", \"properties\": {}},\n ),\n Tool(\n name=\"scrape_github\",\n description=\"Scrape GitHub repository\",\n inputSchema={\"type\": \"object\", \"properties\": {}},\n ),\n Tool(\n name=\"scrape_pdf\",\n description=\"Scrape PDF file\",\n inputSchema={\"type\": \"object\", \"properties\": {}},\n ),\n Tool(\n name=\"package_skill\",\n description=\"Package skill into .zip\",\n inputSchema={\"type\": \"object\", \"properties\": {}},\n ),\n Tool(\n name=\"upload_skill\",\n description=\"Upload skill to Claude\",\n inputSchema={\"type\": \"object\", \"properties\": {}},\n ),\n Tool(\n name=\"install_skill\",\n description=\"Install skill\",\n inputSchema={\"type\": \"object\", \"properties\": {}},\n ),\n Tool(\n name=\"split_config\",\n description=\"Split large config\",\n inputSchema={\"type\": \"object\", \"properties\": {}},\n ),\n Tool(\n name=\"generate_router\",\n description=\"Generate router skill\",\n inputSchema={\"type\": \"object\", \"properties\": {}},\n ),\n Tool(\n name=\"fetch_config\",\n description=\"Fetch config from source\",\n inputSchema={\"type\": \"object\", \"properties\": {}},\n ),\n Tool(\n name=\"submit_config\",\n description=\"Submit config to community\",\n inputSchema={\"type\": \"object\", \"properties\": {}},\n ),\n Tool(\n name=\"add_config_source\",\n description=\"Add config source\",\n inputSchema={\"type\": \"object\", \"properties\": {}},\n ),\n Tool(\n name=\"list_config_sources\",\n description=\"List config sources\",\n inputSchema={\"type\": \"object\", \"properties\": {}},\n ),\n Tool(\n name=\"remove_config_source\",\n description=\"Remove config source\",\n inputSchema={\"type\": \"object\", \"properties\": {}},\n ),\n Tool(\n name=\"extract_config_patterns\",\n description=\"Extract configuration patterns from config files\",\n inputSchema={\"type\": \"object\", \"properties\": {}},\n ),\n ]\n return tools\n\nexcept ImportError:\n # If imports fail, provide empty stubs\n pass\n\n# Delegate to the new FastMCP implementation\nif __name__ == \"__main__\":\n try:\n from skill_seekers.mcp import server_fastmcp\n\n # Run the new server\n server_fastmcp.main()\n except ImportError as e:\n print(f\"❌ Error: Could not import server_fastmcp: {e}\", file=sys.stderr)\n print(\"Ensure the package is installed correctly:\", file=sys.stderr)\n print(\" pip install -e .\", file=sys.stderr)\n sys.exit(1)\n except Exception as e:\n print(f\"❌ Error running server: {e}\", file=sys.stderr)\n sys.exit(1)\n",
"sha256": "cc6c4f24e5b91ab158f2bfbc4ebb27a38ce84d2937473dd85a6c2d035fc3b851"
},
".github/tools/external/Skill_Seekers-development/src/skill_seekers/mcp/server_fastmcp.py": {
"mode": "100644",
"encoding": "utf-8",
"data": "#!/usr/bin/env python3\n\"\"\"\nSkill Seeker MCP Server (FastMCP Implementation)\n\nModern, decorator-based MCP server using FastMCP for simplified tool registration.\nProvides 34 tools for generating LLM skills from documentation.\n\nThis is a streamlined alternative to server.py (2200 lines → 708 lines, 68% reduction).\nAll tool implementations are delegated to modular tool files in tools/ directory.\n\n**Architecture:**\n- FastMCP server with decorator-based tool registration\n- 34 tools organized into 7 categories:\n * Config tools (3): generate_config, list_configs, validate_config\n * Scraping tools (11): estimate_pages, scrape_docs, scrape_github, scrape_pdf, scrape_video, scrape_codebase, detect_patterns, extract_test_examples, build_how_to_guides, extract_config_patterns, scrape_generic\n * Packaging tools (4): package_skill, upload_skill, enhance_skill, install_skill\n * Splitting tools (2): split_config, generate_router\n * Source tools (6): fetch_config, submit_config, push_config, add_config_source, list_config_sources, remove_config_source\n * Marketplace tools (4): add_marketplace, list_marketplaces, remove_marketplace, publish_to_marketplace\n * Vector Database tools (4): export_to_weaviate, export_to_chroma, export_to_faiss, export_to_qdrant\n * Workflow tools (5): list_workflows, get_workflow, create_workflow, update_workflow, delete_workflow\n\n**Usage:**\n # Stdio transport (default, backward compatible)\n python -m skill_seekers.mcp.server_fastmcp\n\n # HTTP transport (new)\n python -m skill_seekers.mcp.server_fastmcp --http\n python -m skill_seekers.mcp.server_fastmcp --http --port 8080\n\n**MCP Integration:**\n Stdio (default):\n {\n \"mcpServers\": {\n \"skill-seeker\": {\n \"command\": \"python\",\n \"args\": [\"-m\", \"skill_seekers.mcp.server_fastmcp\"]\n }\n }\n }\n\n HTTP (alternative):\n {\n \"mcpServers\": {\n \"skill-seeker\": {\n \"url\": \"http://localhost:8000/sse\"\n }\n }\n }\n\"\"\"\n\nimport argparse\nimport logging\nimport sys\n\n# Import FastMCP\nMCP_AVAILABLE = False\nFastMCP = None\n\ntry:\n from mcp.server import FastMCP\n\n MCP_AVAILABLE = True\nexcept ImportError as e:\n # Only exit if running as main module, not when importing for tests\n if __name__ == \"__main__\":\n print(\"❌ Error: mcp package not installed\")\n print(\"Install with: pip install mcp\")\n print(f\"Import error: {e}\")\n sys.exit(1)\n\n# Import all tool implementations\ntry:\n from .tools import (\n add_config_source_impl,\n build_how_to_guides_impl,\n detect_patterns_impl,\n enhance_skill_impl,\n # Scraping tools\n estimate_pages_impl,\n # Vector database tools\n export_to_chroma_impl,\n export_to_faiss_impl,\n export_to_qdrant_impl,\n export_to_weaviate_impl,\n extract_config_patterns_impl,\n extract_test_examples_impl,\n # Source tools\n fetch_config_impl,\n # Marketplace tools\n add_marketplace_impl,\n list_marketplaces_impl,\n remove_marketplace_impl,\n publish_to_marketplace_impl,\n # Config tools\n generate_config_impl,\n generate_router_impl,\n install_skill_impl,\n list_config_sources_impl,\n list_configs_impl,\n # Packaging tools\n package_skill_impl,\n remove_config_source_impl,\n scrape_codebase_impl,\n scrape_docs_impl,\n scrape_generic_impl,\n scrape_github_impl,\n scrape_pdf_impl,\n scrape_video_impl,\n # Splitting tools\n split_config_impl,\n submit_config_impl,\n # Sync config tools\n sync_config_impl,\n upload_skill_impl,\n validate_config_impl,\n # Workflow tools\n list_workflows_impl,\n get_workflow_impl,\n create_workflow_impl,\n update_workflow_impl,\n delete_workflow_impl,\n )\nexcept ImportError:\n # Fallback for direct script execution\n import os\n\n sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))\n from tools import (\n add_config_source_impl,\n build_how_to_guides_impl,\n detect_patterns_impl,\n enhance_skill_impl,\n estimate_pages_impl,\n export_to_chroma_impl,\n export_to_faiss_impl,\n export_to_qdrant_impl,\n export_to_weaviate_impl,\n extract_config_patterns_impl,\n extract_test_examples_impl,\n fetch_config_impl,\n add_marketplace_impl,\n list_marketplaces_impl,\n remove_marketplace_impl,\n publish_to_marketplace_impl,\n generate_config_impl,\n generate_router_impl,\n install_skill_impl,\n list_config_sources_impl,\n list_configs_impl,\n package_skill_impl,\n remove_config_source_impl,\n scrape_codebase_impl,\n scrape_docs_impl,\n scrape_generic_impl,\n scrape_github_impl,\n scrape_pdf_impl,\n scrape_video_impl,\n split_config_impl,\n submit_config_impl,\n sync_config_impl,\n upload_skill_impl,\n validate_config_impl,\n list_workflows_impl,\n get_workflow_impl,\n create_workflow_impl,\n update_workflow_impl,\n delete_workflow_impl,\n )\n\n# Initialize FastMCP server\nmcp = None\nif MCP_AVAILABLE and FastMCP is not None:\n mcp = FastMCP(\n name=\"skill-seeker\",\n instructions=\"Skill Seeker MCP Server - Generate LLM skills from documentation\",\n )\n\n\n# Helper decorator for tests (when MCP is not available)\ndef safe_tool_decorator(*args, **kwargs):\n \"\"\"Decorator that works when mcp is None (for testing)\"\"\"\n if mcp is not None:\n return mcp.tool(*args, **kwargs)\n else:\n # Return a pass-through decorator for testing\n def wrapper(func):\n return func\n\n return wrapper\n\n\n# ============================================================================\n# CONFIG TOOLS (3 tools)\n# ============================================================================\n\n\n@safe_tool_decorator(\n description=\"Generate a config file for documentation scraping. Interactively creates a JSON config for any documentation website.\"\n)\nasync def generate_config(\n name: str,\n url: str,\n description: str,\n max_pages: int = 100,\n unlimited: bool = False,\n rate_limit: float = 0.5,\n) -> str:\n \"\"\"\n Generate a config file for documentation scraping.\n\n Args:\n name: Skill name (lowercase, alphanumeric, hyphens, underscores)\n url: Base documentation URL (must include http:// or https://)\n description: Description of when to use this skill\n max_pages: Maximum pages to scrape (default: 100, use -1 for unlimited)\n unlimited: Remove all limits - scrape all pages (default: false). Overrides max_pages.\n rate_limit: Delay between requests in seconds (default: 0.5)\n\n Returns:\n Success message with config path and next steps, or error message.\n \"\"\"\n args = {\n \"name\": name,\n \"url\": url,\n \"description\": description,\n \"max_pages\": max_pages,\n \"unlimited\": unlimited,\n \"rate_limit\": rate_limit,\n }\n result = await generate_config_impl(args)\n # Extract text from TextContent objects\n if isinstance(result, list) and result:\n return result[0].text if hasattr(result[0], \"text\") else str(result[0])\n return str(result)\n\n\n@safe_tool_decorator(description=\"List all available preset configurations.\")\nasync def list_configs() -> str:\n \"\"\"\n List all available preset configurations.\n\n Returns:\n List of available configs with categories and descriptions.\n \"\"\"\n result = await list_configs_impl({})\n if isinstance(result, list) and result:\n return result[0].text if hasattr(result[0], \"text\") else str(result[0])\n return str(result)\n\n\n@safe_tool_decorator(description=\"Validate a config file for errors.\")\nasync def validate_config(config_path: str) -> str:\n \"\"\"\n Validate a config file for errors.\n\n Args:\n config_path: Path to config JSON file\n\n Returns:\n Validation result with any errors or success message.\n \"\"\"\n result = await validate_config_impl({\"config_path\": config_path})\n if isinstance(result, list) and result:\n return result[0].text if hasattr(result[0], \"text\") else str(result[0])\n return str(result)\n\n\n# ============================================================================\n# SYNC CONFIG TOOLS (1 tool)\n# ============================================================================\n\n\n@safe_tool_decorator(description=\"Sync a config's start_urls against what's live on the docs site.\")\nasync def sync_config(\n config_path: str,\n apply: bool = False,\n depth: int = 2,\n max_pages: int = 500,\n rate_limit: float | None = None,\n source_index: int = 0,\n) -> str:\n \"\"\"\n Sync a config file's start_urls against the live docs site.\n\n Crawls seed/nav pages, discovers internal links, and diffs against the\n config's existing start_urls. Optionally writes the update with apply=True.\n\n Args:\n config_path: Path to the config JSON file.\n apply: Write changes back to the config file (default: False).\n depth: BFS crawl depth from seed pages (default: 2).\n max_pages: Maximum URLs to discover (default: 500).\n rate_limit: Override config rate limit (seconds between requests).\n source_index: Index of the documentation source to sync (default: 0).\n\n Returns:\n Report of added/removed URLs.\n \"\"\"\n result = await sync_config_impl(\n {\n \"config_path\": config_path,\n \"apply\": apply,\n \"depth\": depth,\n \"max_pages\": max_pages,\n \"rate_limit\": rate_limit,\n \"source_index\": source_index,\n }\n )\n if isinstance(result, list) and result:\n return result[0].text if hasattr(result[0], \"text\") else str(result[0])\n return str(result)\n\n\n# ============================================================================\n# SCRAPING TOOLS (11 tools)\n# ============================================================================\n\n\n@safe_tool_decorator(\n description=\"Estimate how many pages will be scraped from a config. Fast preview without downloading content.\"\n)\nasync def estimate_pages(\n config_path: str,\n max_discovery: int = 1000,\n unlimited: bool = False,\n) -> str:\n \"\"\"\n Estimate how many pages will be scraped from a config.\n\n Args:\n config_path: Path to config JSON file (e.g., configs/react.json)\n max_discovery: Maximum pages to discover during estimation (default: 1000, use -1 for unlimited)\n unlimited: Remove discovery limit - estimate all pages (default: false). Overrides max_discovery.\n\n Returns:\n Estimation results with page count and recommendations.\n \"\"\"\n args = {\n \"config_path\": config_path,\n \"max_discovery\": max_discovery,\n \"unlimited\": unlimited,\n }\n result = await estimate_pages_impl(args)\n if isinstance(result, list) and result:\n return result[0].text if hasattr(result[0], \"text\") else str(result[0])\n return str(result)\n\n\n@safe_tool_decorator(\n description=\"Scrape documentation and build LLM skill. Supports both single-source (legacy) and unified multi-source configs. Creates SKILL.md and reference files. Automatically detects llms.txt files for 10x faster processing. Falls back to HTML scraping if not available.\"\n)\nasync def scrape_docs(\n config_path: str,\n unlimited: bool = False,\n enhance_local: bool = False,\n skip_scrape: bool = False,\n dry_run: bool = False,\n merge_mode: str | None = None,\n) -> str:\n \"\"\"\n Scrape documentation and build LLM skill.\n\n Args:\n config_path: Path to config JSON file (e.g., configs/react.json or configs/godot_unified.json)\n unlimited: Remove page limit - scrape all pages (default: false). Overrides max_pages in config.\n enhance_local: Open terminal for local enhancement with AI coding agent (default: false)\n skip_scrape: Skip scraping, use cached data (default: false)\n dry_run: Preview what will be scraped without saving (default: false)\n merge_mode: Override merge mode for unified configs: 'rule-based' or 'claude-enhanced' (default: from config)\n\n Returns:\n Scraping results with file paths and statistics.\n \"\"\"\n args = {\n \"config_path\": config_path,\n \"unlimited\": unlimited,\n \"enhance_local\": enhance_local,\n \"skip_scrape\": skip_scrape,\n \"dry_run\": dry_run,\n }\n if merge_mode:\n args[\"merge_mode\"] = merge_mode\n result = await scrape_docs_impl(args)\n if isinstance(result, list) and result:\n return result[0].text if hasattr(result[0], \"text\") else str(result[0])\n return str(result)\n\n\n@safe_tool_decorator(\n description=\"Scrape GitHub repository and build Claude skill. Extracts README, Issues, Changelog, Releases, and code structure.\"\n)\nasync def scrape_github(\n repo: str | None = None,\n config_path: str | None = None,\n name: str | None = None,\n description: str | None = None,\n token: str | None = None,\n no_issues: bool = False,\n no_changelog: bool = False,\n no_releases: bool = False,\n max_issues: int = 100,\n scrape_only: bool = False,\n) -> str:\n \"\"\"\n Scrape GitHub repository and build Claude skill.\n\n Args:\n repo: GitHub repository (owner/repo, e.g., facebook/react)\n config_path: Path to GitHub config JSON file (e.g., configs/react_github.json)\n name: Skill name (default: repo name)\n description: Skill description\n token: GitHub personal access token (or use GITHUB_TOKEN env var)\n no_issues: Skip GitHub issues extraction (default: false)\n no_changelog: Skip CHANGELOG extraction (default: false)\n no_releases: Skip releases extraction (default: false)\n max_issues: Maximum issues to fetch (default: 100)\n scrape_only: Only scrape, don't build skill (default: false)\n\n Returns:\n GitHub scraping results with file paths.\n \"\"\"\n args = {}\n if repo:\n args[\"repo\"] = repo\n if config_path:\n args[\"config_path\"] = config_path\n if name:\n args[\"name\"] = name\n if description:\n args[\"description\"] = description\n if token:\n args[\"token\"] = token\n args[\"no_issues\"] = no_issues\n args[\"no_changelog\"] = no_changelog\n args[\"no_releases\"] = no_releases\n args[\"max_issues\"] = max_issues\n args[\"scrape_only\"] = scrape_only\n\n result = await scrape_github_impl(args)\n if isinstance(result, list) and result:\n return result[0].text if hasattr(result[0], \"text\") else str(result[0])\n return str(result)\n\n\n@safe_tool_decorator(\n description=\"Scrape PDF documentation and build Claude skill. Extracts text, code, and images from PDF files.\"\n)\nasync def scrape_pdf(\n config_path: str | None = None,\n pdf_path: str | None = None,\n name: str | None = None,\n description: str | None = None,\n from_json: str | None = None,\n) -> str:\n \"\"\"\n Scrape PDF documentation and build Claude skill.\n\n Args:\n config_path: Path to PDF config JSON file (e.g., configs/manual_pdf.json)\n pdf_path: Direct PDF path (alternative to config_path)\n name: Skill name (required with pdf_path)\n description: Skill description (optional)\n from_json: Build from extracted JSON file (e.g., output/manual_extracted.json)\n\n Returns:\n PDF scraping results with file paths.\n \"\"\"\n args = {}\n if config_path:\n args[\"config_path\"] = config_path\n if pdf_path:\n args[\"pdf_path\"] = pdf_path\n if name:\n args[\"name\"] = name\n if description:\n args[\"description\"] = description\n if from_json:\n args[\"from_json\"] = from_json\n\n result = await scrape_pdf_impl(args)\n if isinstance(result, list) and result:\n return result[0].text if hasattr(result[0], \"text\") else str(result[0])\n return str(result)\n\n\n@safe_tool_decorator(\n description=\"Extract transcripts and metadata from videos (YouTube, Vimeo, local files) and build Claude skill.\"\n)\nasync def scrape_video(\n url: str | None = None,\n video_file: str | None = None,\n playlist: str | None = None,\n name: str | None = None,\n description: str | None = None,\n languages: str | None = None,\n from_json: str | None = None,\n visual: bool = False,\n whisper_model: str | None = None,\n visual_interval: float | None = None,\n visual_min_gap: float | None = None,\n visual_similarity: float | None = None,\n vision_ocr: bool = False,\n start_time: str | None = None,\n end_time: str | None = None,\n setup: bool = False,\n) -> str:\n \"\"\"\n Scrape video content and build Claude skill.\n\n Args:\n url: Video URL (YouTube, Vimeo)\n video_file: Local video file path\n playlist: Playlist URL\n name: Skill name\n description: Skill description\n languages: Transcript language preferences (comma-separated)\n from_json: Build from extracted JSON file\n visual: Enable visual frame extraction (requires video-full extras)\n whisper_model: Whisper model size for local transcription (e.g., base, small, medium, large)\n visual_interval: Seconds between frame captures (default: 5.0)\n visual_min_gap: Minimum seconds between kept frames (default: 2.0)\n visual_similarity: Similarity threshold to skip duplicate frames 0.0-1.0 (default: 0.95)\n vision_ocr: Use vision model for OCR on extracted frames\n start_time: Start time for extraction (seconds, MM:SS, or HH:MM:SS). Single video only.\n end_time: End time for extraction (seconds, MM:SS, or HH:MM:SS). Single video only.\n setup: Auto-detect GPU and install visual extraction deps (PyTorch, easyocr, etc.)\n\n Returns:\n Video scraping results with file paths.\n \"\"\"\n if setup:\n from skill_seekers.cli.video_setup import run_setup\n\n rc = run_setup(interactive=False)\n return \"Setup completed successfully.\" if rc == 0 else \"Setup failed. Check logs.\"\n\n args = {}\n if url:\n args[\"url\"] = url\n if video_file:\n args[\"video_file\"] = video_file\n if playlist:\n args[\"playlist\"] = playlist\n if name:\n args[\"name\"] = name\n if description:\n args[\"description\"] = description\n if languages:\n args[\"languages\"] = languages\n if from_json:\n args[\"from_json\"] = from_json\n if start_time:\n args[\"start_time\"] = start_time\n if end_time:\n args[\"end_time\"] = end_time\n if visual:\n args[\"visual\"] = visual\n if whisper_model:\n args[\"whisper_model\"] = whisper_model\n if visual_interval is not None:\n args[\"visual_interval\"] = visual_interval\n if visual_min_gap is not None:\n args[\"visual_min_gap\"] = visual_min_gap\n if visual_similarity is not None:\n args[\"visual_similarity\"] = visual_similarity\n if vision_ocr:\n args[\"vision_ocr\"] = vision_ocr\n\n result = await scrape_video_impl(args)\n if isinstance(result, list) and result:\n return result[0].text if hasattr(result[0], \"text\") else str(result[0])\n return str(result)\n\n\n@safe_tool_decorator(\n description=\"Analyze local codebase and extract code knowledge. Walks directory tree, analyzes code files, extracts signatures, docstrings, and optionally generates API reference documentation and dependency graphs.\"\n)\nasync def scrape_codebase(\n directory: str,\n output: str = \"output/codebase/\",\n depth: str = \"deep\",\n languages: str = \"\",\n file_patterns: str = \"\",\n build_api_reference: bool = False,\n build_dependency_graph: bool = False,\n) -> str:\n \"\"\"\n Analyze local codebase and extract code knowledge.\n\n Args:\n directory: Directory to analyze (required)\n output: Output directory for results (default: output/codebase/)\n depth: Analysis depth - surface, deep, full (default: deep)\n languages: Comma-separated languages to analyze (e.g., \"Python,JavaScript,C++\")\n file_patterns: Comma-separated file patterns (e.g., \"*.py,src/**/*.js\")\n build_api_reference: Generate API reference markdown (default: false)\n build_dependency_graph: Generate dependency graph and detect circular dependencies (default: false)\n\n Returns:\n Codebase analysis results with file paths.\n \"\"\"\n args = {\n \"directory\": directory,\n \"output\": output,\n \"depth\": depth,\n \"languages\": languages,\n \"file_patterns\": file_patterns,\n \"build_api_reference\": build_api_reference,\n \"build_dependency_graph\": build_dependency_graph,\n }\n\n result = await scrape_codebase_impl(args)\n if isinstance(result, list) and result:\n return result[0].text if hasattr(result[0], \"text\") else str(result[0])\n return str(result)\n\n\n@safe_tool_decorator(\n description=\"Detect design patterns in source code (Singleton, Factory, Observer, Strategy, Decorator, Builder, Adapter, Command, Template Method, Chain of Responsibility). Supports 9 languages: Python, JavaScript, TypeScript, C++, C, C#, Go, Rust, Java, Ruby, PHP.\"\n)\nasync def detect_patterns(\n file: str = \"\",\n directory: str = \"\",\n output: str = \"\",\n depth: str = \"deep\",\n json: bool = False,\n) -> str:\n \"\"\"\n Detect design patterns in source code.\n\n Analyzes source files or directories to identify common design patterns.\n Provides confidence scores and evidence for each detected pattern.\n\n Args:\n file: Single file to analyze (optional)\n directory: Directory to analyze all source files (optional)\n output: Output directory for JSON results (optional)\n depth: Detection depth - surface (fast), deep (balanced), full (thorough). Default: deep\n json: Output JSON format instead of human-readable (default: false)\n\n Returns:\n Pattern detection results with confidence scores and evidence.\n\n Example:\n detect_patterns(file=\"src/database.py\", depth=\"deep\")\n detect_patterns(directory=\"src/\", output=\"patterns/\", json=true)\n \"\"\"\n args = {\n \"file\": file,\n \"directory\": directory,\n \"output\": output,\n \"depth\": depth,\n \"json\": json,\n }\n\n result = await detect_patterns_impl(args)\n if isinstance(result, list) and result:\n return result[0].text if hasattr(result[0], \"text\") else str(result[0])\n return str(result)\n\n\n@safe_tool_decorator(\n description=\"Extract usage examples from test files. Analyzes test files to extract real API usage patterns including instantiation, method calls, configs, setup patterns, and workflows. Supports 9 languages (Python AST-based, others regex-based).\"\n)\nasync def extract_test_examples(\n file: str = \"\",\n directory: str = \"\",\n language: str = \"\",\n min_confidence: float = 0.5,\n max_per_file: int = 10,\n json: bool = False,\n markdown: bool = False,\n) -> str:\n \"\"\"\n Extract usage examples from test files.\n\n Analyzes test files to extract real API usage patterns including:\n - Object instantiation with real parameters\n - Method calls with expected behaviors\n - Configuration examples\n - Setup patterns from fixtures/setUp()\n - Multi-step workflows from integration tests\n\n Supports 9 languages: Python (AST-based), JavaScript, TypeScript, Go, Rust, Java, C#, PHP, Ruby.\n\n Args:\n file: Single test file to analyze (optional)\n directory: Directory containing test files (optional)\n language: Filter by language (python, javascript, etc.)\n min_confidence: Minimum confidence threshold 0.0-1.0 (default: 0.5)\n max_per_file: Maximum examples per file (default: 10)\n json: Output JSON format (default: false)\n markdown: Output Markdown format (default: false)\n\n Examples:\n extract_test_examples(directory=\"tests/\", language=\"python\")\n extract_test_examples(file=\"tests/test_scraper.py\", json=true)\n \"\"\"\n args = {\n \"file\": file,\n \"directory\": directory,\n \"language\": language,\n \"min_confidence\": min_confidence,\n \"max_per_file\": max_per_file,\n \"json\": json,\n \"markdown\": markdown,\n }\n\n result = await extract_test_examples_impl(args)\n if isinstance(result, list) and result:\n return result[0].text if hasattr(result[0], \"text\") else str(result[0])\n return str(result)\n\n\n@safe_tool_decorator(\n description=\"Build how-to guides from workflow test examples. Transforms workflow examples extracted from test files into step-by-step educational guides with prerequisites, verification points, and troubleshooting tips.\"\n)\nasync def build_how_to_guides(\n input: str,\n output: str = \"output/codebase/tutorials\",\n group_by: str = \"ai-tutorial-group\",\n no_ai: bool = False,\n json_output: bool = False,\n) -> str:\n \"\"\"\n Build how-to guides from workflow test examples.\n\n Transforms workflow examples extracted from test files into step-by-step\n educational guides. Automatically groups related workflows, extracts steps,\n and generates comprehensive markdown guides.\n\n Features:\n - Python AST-based step extraction (heuristic for other languages)\n - 4 grouping strategies: ai-tutorial-group, file-path, test-name, complexity\n - Detects prerequisites, setup code, and verification points\n - Generates troubleshooting tips and next steps\n\n Args:\n input: Path to test_examples.json from extract_test_examples\n output: Output directory for guides (default: output/codebase/tutorials)\n group_by: Grouping strategy - ai-tutorial-group, file-path, test-name, complexity (default: ai-tutorial-group)\n no_ai: Disable AI enhancement for grouping (default: false)\n json_output: Output JSON format alongside markdown (default: false)\n\n Examples:\n build_how_to_guides(input=\"output/codebase/test_examples/test_examples.json\")\n build_how_to_guides(input=\"examples.json\", group_by=\"file-path\", no_ai=true)\n \"\"\"\n args = {\n \"input\": input,\n \"output\": output,\n \"group_by\": group_by,\n \"no_ai\": no_ai,\n \"json_output\": json_output,\n }\n\n result = await build_how_to_guides_impl(args)\n if isinstance(result, list) and result:\n return result[0].text if hasattr(result[0], \"text\") else str(result[0])\n return str(result)\n\n\n@safe_tool_decorator(\n description=\"Extract configuration patterns from config files (C3.4) with optional AI enhancement. Analyzes config files, detects patterns (database, API, logging, etc.), generates documentation, and optionally enhances with AI insights (security analysis, best practices, migration suggestions). Supports 9 formats.\"\n)\nasync def extract_config_patterns(\n directory: str,\n output: str = \"output/codebase/config_patterns\",\n max_files: int = 100,\n enhance: bool = False,\n enhance_local: bool = False,\n ai_mode: str = \"none\",\n json: bool = True,\n markdown: bool = True,\n) -> str:\n \"\"\"\n Extract configuration patterns from config files with optional AI enhancement.\n\n Analyzes configuration files in the codebase to extract settings,\n detect common patterns, and generate comprehensive documentation.\n\n **AI Enhancement (NEW)**: Optional AI-powered insights including:\n - Explanations of what each config does\n - Best practice suggestions\n - Security analysis (hardcoded secrets, exposed credentials)\n - Migration suggestions (consolidation opportunities)\n - Context-aware documentation\n\n Supports 9 config formats: JSON, YAML, TOML, ENV, INI, Python modules,\n JavaScript/TypeScript configs, Dockerfile, Docker Compose.\n\n Detects 7 common patterns:\n - Database configuration (host, port, credentials)\n - API configuration (endpoints, keys, timeouts)\n - Logging configuration (level, format, handlers)\n - Cache configuration (backend, TTL, keys)\n - Email configuration (SMTP, credentials)\n - Authentication configuration (providers, secrets)\n - Server configuration (host, port, workers)\n\n Args:\n directory: Directory to analyze (required)\n output: Output directory for results (default: output/codebase/config_patterns)\n max_files: Maximum config files to process (default: 100)\n enhance: Enable AI enhancement - API mode (default: false, requires ANTHROPIC_API_KEY)\n enhance_local: Enable AI enhancement - LOCAL mode (default: false, uses Claude Code CLI)\n ai_mode: AI enhancement mode - auto, api, local, none (default: none)\n json: Output JSON format (default: true)\n markdown: Output Markdown format (default: true)\n\n Returns:\n Config extraction results with patterns, settings, and optional AI insights.\n\n Examples:\n extract_config_patterns(directory=\".\")\n extract_config_patterns(directory=\"/path/to/repo\", max_files=50)\n extract_config_patterns(directory=\".\", enhance_local=true) # With AI enhancement (LOCAL mode)\n extract_config_patterns(directory=\".\", ai_mode=\"api\") # With AI enhancement (API mode)\n \"\"\"\n args = {\n \"directory\": directory,\n \"output\": output,\n \"max_files\": max_files,\n \"enhance\": enhance,\n \"enhance_local\": enhance_local,\n \"ai_mode\": ai_mode,\n \"json\": json,\n \"markdown\": markdown,\n }\n\n result = await extract_config_patterns_impl(args)\n if isinstance(result, list) and result:\n return result[0].text if hasattr(result[0], \"text\") else str(result[0])\n return str(result)\n\n\n@safe_tool_decorator(\n description=\"Scrape content from new source types: jupyter, html, openapi, asciidoc, pptx, confluence, notion, rss, manpage, chat. A generic entry point that delegates to the appropriate CLI scraper module.\"\n)\nasync def scrape_generic(\n source_type: str,\n name: str,\n path: str | None = None,\n url: str | None = None,\n) -> str:\n \"\"\"\n Scrape content from various source types and build a skill.\n\n A generic scraper that supports 10 new source types. It delegates to the\n corresponding CLI scraper module (e.g., skill_seekers.cli.jupyter_scraper).\n\n File-based types (jupyter, html, openapi, asciidoc, pptx, manpage, chat)\n typically use the 'path' parameter. URL-based types (confluence, notion, rss)\n typically use the 'url' parameter.\n\n Args:\n source_type: Source type to scrape. One of: jupyter, html, openapi,\n asciidoc, pptx, confluence, notion, rss, manpage, chat.\n name: Skill name for the output\n path: File or directory path (for file-based sources like jupyter, html, pptx)\n url: URL (for URL-based sources like confluence, notion, rss)\n\n Returns:\n Scraping results with file paths and statistics.\n \"\"\"\n args = {\n \"source_type\": source_type,\n \"name\": name,\n }\n if path:\n args[\"path\"] = path\n if url:\n args[\"url\"] = url\n\n result = await scrape_generic_impl(args)\n if isinstance(result, list) and result:\n return result[0].text if hasattr(result[0], \"text\") else str(result[0])\n return str(result)\n\n\n# ============================================================================\n# PACKAGING TOOLS (4 tools)\n# ============================================================================\n\n\n@safe_tool_decorator(\n description=\"Package skill directory into platform-specific format (ZIP for Claude/OpenAI/Markdown, tar.gz for Gemini). Supports all platforms: claude, gemini, openai, markdown. Automatically uploads if platform API key is set.\"\n)\nasync def package_skill(\n skill_dir: str,\n target: str = \"auto\",\n auto_upload: bool = True,\n) -> str:\n \"\"\"\n Package skill directory for target LLM platform.\n\n Args:\n skill_dir: Path to skill directory to package (e.g., output/react/)\n target: Target platform (default: 'auto'). Options: auto, claude, gemini, openai, markdown\n auto_upload: Auto-upload after packaging if API key is available (default: true). Requires platform-specific API key: ANTHROPIC_API_KEY, GOOGLE_API_KEY, or OPENAI_API_KEY.\n\n Returns:\n Packaging results with file path and platform info.\n \"\"\"\n if target == \"auto\":\n from skill_seekers.cli.agent_client import AgentClient\n\n target = AgentClient.detect_default_target()\n args = {\n \"skill_dir\": skill_dir,\n \"target\": target,\n \"auto_upload\": auto_upload,\n }\n result = await package_skill_impl(args)\n if isinstance(result, list) and result:\n return result[0].text if hasattr(result[0], \"text\") else str(result[0])\n return str(result)\n\n\n@safe_tool_decorator(\n description=\"Upload skill package to target LLM platform API. Requires platform-specific API key. Supports: claude (Anthropic Skills API), gemini (Google Files API), openai (Assistants API). Does NOT support markdown.\"\n)\nasync def upload_skill(\n skill_zip: str,\n target: str = \"auto\",\n api_key: str | None = None,\n) -> str:\n \"\"\"\n Upload skill package to target platform.\n\n Args:\n skill_zip: Path to skill package (.zip or .tar.gz, e.g., output/react.zip)\n target: Target platform (default: 'auto'). Options: auto, claude, gemini, openai\n api_key: Optional API key (uses env var if not provided: ANTHROPIC_API_KEY, GOOGLE_API_KEY, or OPENAI_API_KEY)\n\n Returns:\n Upload results with skill ID and platform URL.\n \"\"\"\n if target == \"auto\":\n from skill_seekers.cli.agent_client import AgentClient\n\n target = AgentClient.detect_default_target()\n args = {\n \"skill_zip\": skill_zip,\n \"target\": target,\n }\n if api_key:\n args[\"api_key\"] = api_key\n\n result = await upload_skill_impl(args)\n if isinstance(result, list) and result:\n return result[0].text if hasattr(result[0], \"text\") else str(result[0])\n return str(result)\n\n\n@safe_tool_decorator(\n description=\"Enhance SKILL.md with AI using target platform's model. Local mode uses AI coding agent (no API key). API mode uses platform API (requires key). Transforms basic templates into comprehensive 500+ line guides with examples.\"\n)\nasync def enhance_skill(\n skill_dir: str,\n target: str = \"auto\",\n mode: str = \"local\",\n api_key: str | None = None,\n) -> str:\n \"\"\"\n Enhance SKILL.md with AI.\n\n Args:\n skill_dir: Path to skill directory containing SKILL.md (e.g., output/react/)\n target: Target platform (default: 'auto'). Options: auto, claude, gemini, openai\n mode: Enhancement mode (default: 'local'). Options: local (AI coding agent, no API), api (uses platform API)\n api_key: Optional API key for 'api' mode (uses env var if not provided: ANTHROPIC_API_KEY, GOOGLE_API_KEY, or OPENAI_API_KEY)\n\n Returns:\n Enhancement results with backup location.\n \"\"\"\n if target == \"auto\":\n from skill_seekers.cli.agent_client import AgentClient\n\n target = AgentClient.detect_default_target()\n args = {\n \"skill_dir\": skill_dir,\n \"target\": target,\n \"mode\": mode,\n }\n if api_key:\n args[\"api_key\"] = api_key\n\n result = await enhance_skill_impl(args)\n if isinstance(result, list) and result:\n return result[0].text if hasattr(result[0], \"text\") else str(result[0])\n return str(result)\n\n\n@safe_tool_decorator(\n description=\"Complete one-command workflow: fetch config → scrape docs → AI enhance (MANDATORY) → package → upload. Enhancement required for quality (3/10→9/10). Takes 20-45 min depending on config size. Supports multiple LLM platforms: auto (detects from environment), claude, gemini, openai, markdown. Auto-uploads if platform API key is set.\"\n)\nasync def install_skill(\n config_name: str | None = None,\n config_path: str | None = None,\n destination: str = \"output\",\n auto_upload: bool = True,\n unlimited: bool = False,\n dry_run: bool = False,\n target: str = \"auto\",\n) -> str:\n \"\"\"\n Complete one-command workflow to install a skill.\n\n Args:\n config_name: Config name from API (e.g., 'react', 'django'). Mutually exclusive with config_path. Tool will fetch this config from the official API before scraping.\n config_path: Path to existing config JSON file (e.g., 'configs/custom.json'). Mutually exclusive with config_name. Use this if you already have a config file.\n destination: Output directory for skill files (default: 'output')\n auto_upload: Auto-upload after packaging (requires platform API key). Default: true. Set to false to skip upload.\n unlimited: Remove page limits during scraping (default: false). WARNING: Can take hours for large sites.\n dry_run: Preview workflow without executing (default: false). Shows all phases that would run.\n target: Target LLM platform (default: 'auto'). Options: auto, claude, gemini, openai, markdown. Requires corresponding API key: ANTHROPIC_API_KEY, GOOGLE_API_KEY, or OPENAI_API_KEY.\n\n Returns:\n Workflow results with all phase statuses.\n \"\"\"\n if target == \"auto\":\n from skill_seekers.cli.agent_client import AgentClient\n\n target = AgentClient.detect_default_target()\n args = {\n \"destination\": destination,\n \"auto_upload\": auto_upload,\n \"unlimited\": unlimited,\n \"dry_run\": dry_run,\n \"target\": target,\n }\n if config_name:\n args[\"config_name\"] = config_name\n if config_path:\n args[\"config_path\"] = config_path\n\n result = await install_skill_impl(args)\n if isinstance(result, list) and result:\n return result[0].text if hasattr(result[0], \"text\") else str(result[0])\n return str(result)\n\n\n# ============================================================================\n# SPLITTING TOOLS (2 tools)\n# ============================================================================\n\n\n@safe_tool_decorator(\n description=\"Split large configs into multiple focused skills. Supports documentation (10K+ pages) and unified multi-source configs. Auto-detects config type and recommends best strategy.\"\n)\nasync def split_config(\n config_path: str,\n strategy: str = \"auto\",\n target_pages: int = 5000,\n dry_run: bool = False,\n) -> str:\n \"\"\"\n Split large configs into multiple skills.\n\n Supports:\n - Documentation configs: Split by categories, size, or create router skills\n - Unified configs: Split by source type (documentation, github, pdf)\n\n Args:\n config_path: Path to config JSON file (e.g., configs/godot.json or configs/react_unified.json)\n strategy: Split strategy: auto, none, source, category, router, size (default: auto). 'source' is for unified configs.\n target_pages: Target pages per skill for doc configs (default: 5000)\n dry_run: Preview without saving files (default: false)\n\n Returns:\n Splitting results with generated config paths.\n \"\"\"\n args = {\n \"config_path\": config_path,\n \"strategy\": strategy,\n \"target_pages\": target_pages,\n \"dry_run\": dry_run,\n }\n result = await split_config_impl(args)\n if isinstance(result, list) and result:\n return result[0].text if hasattr(result[0], \"text\") else str(result[0])\n return str(result)\n\n\n@safe_tool_decorator(\n description=\"Generate router/hub skill for split documentation. Creates intelligent routing to sub-skills.\"\n)\nasync def generate_router(\n config_pattern: str,\n router_name: str | None = None,\n) -> str:\n \"\"\"\n Generate router/hub skill for split documentation.\n\n Args:\n config_pattern: Config pattern for sub-skills (e.g., 'configs/godot-*.json')\n router_name: Router skill name (optional, inferred from configs)\n\n Returns:\n Router generation results with file paths.\n \"\"\"\n args = {\"config_pattern\": config_pattern}\n if router_name:\n args[\"router_name\"] = router_name\n\n result = await generate_router_impl(args)\n if isinstance(result, list) and result:\n return result[0].text if hasattr(result[0], \"text\") else str(result[0])\n return str(result)\n\n\n# ============================================================================\n# SOURCE TOOLS (5 tools)\n# ============================================================================\n\n\n@safe_tool_decorator(\n description=\"Fetch config from API, git URL, or registered source. Supports three modes: (1) Named source from registry, (2) Direct git URL, (3) API (default). List available configs or download a specific one by name.\"\n)\nasync def fetch_config(\n config_name: str | None = None,\n destination: str = \"configs\",\n list_available: bool = False,\n category: str | None = None,\n git_url: str | None = None,\n source: str | None = None,\n branch: str = \"main\",\n token: str | None = None,\n refresh: bool = False,\n) -> str:\n \"\"\"\n Fetch config from API, git URL, or registered source.\n\n Args:\n config_name: Name of the config to download (e.g., 'react', 'django', 'godot'). Required for git modes. Omit to list all available configs in API mode.\n destination: Directory to save the config file (default: 'configs/')\n list_available: List all available configs from the API (only works in API mode, default: false)\n category: Filter configs by category when listing in API mode (e.g., 'web-frameworks', 'game-engines', 'devops')\n git_url: Git repository URL containing configs. If provided, fetches from git instead of API. Supports HTTPS and SSH URLs. Example: 'https://github.com/myorg/configs.git'\n source: Named source from registry (highest priority). Use add_config_source to register sources first. Example: 'team', 'company'\n branch: Git branch to use (default: 'main'). Only used with git_url or source.\n token: Authentication token for private repos (optional). Prefer using environment variables (GITHUB_TOKEN, GITLAB_TOKEN, etc.).\n refresh: Force refresh cached git repository (default: false). Deletes cache and re-clones. Only used with git modes.\n\n Returns:\n Fetch results with config path or list of available configs.\n \"\"\"\n args = {\n \"destination\": destination,\n \"list_available\": list_available,\n \"branch\": branch,\n \"refresh\": refresh,\n }\n if config_name:\n args[\"config_name\"] = config_name\n if category:\n args[\"category\"] = category\n if git_url:\n args[\"git_url\"] = git_url\n if source:\n args[\"source\"] = source\n if token:\n args[\"token\"] = token\n\n result = await fetch_config_impl(args)\n if isinstance(result, list) and result:\n return result[0].text if hasattr(result[0], \"text\") else str(result[0])\n return str(result)\n\n\n@safe_tool_decorator(\n description=\"Submit a custom config file to the community. Validates config (legacy or unified format) and creates a GitHub issue in skill-seekers-configs repo for review.\"\n)\nasync def submit_config(\n config_path: str | None = None,\n config_json: str | None = None,\n testing_notes: str | None = None,\n github_token: str | None = None,\n) -> str:\n \"\"\"\n Submit a custom config file to the community.\n\n Args:\n config_path: Path to config JSON file to submit (e.g., 'configs/myframework.json')\n config_json: Config JSON as string (alternative to config_path)\n testing_notes: Notes about testing (e.g., 'Tested with 20 pages, works well')\n github_token: GitHub personal access token (or use GITHUB_TOKEN env var)\n\n Returns:\n Submission results with GitHub issue URL.\n \"\"\"\n args = {}\n if config_path:\n args[\"config_path\"] = config_path\n if config_json:\n args[\"config_json\"] = config_json\n if testing_notes:\n args[\"testing_notes\"] = testing_notes\n if github_token:\n args[\"github_token\"] = github_token\n\n result = await submit_config_impl(args)\n if isinstance(result, list) and result:\n return result[0].text if hasattr(result[0], \"text\") else str(result[0])\n return str(result)\n\n\n@safe_tool_decorator(\n description=\"Register a git repository as a config source. Allows fetching configs from private/team repos. Use this to set up named sources that can be referenced by fetch_config. Supports GitHub, GitLab, Gitea, Bitbucket, and custom git servers.\"\n)\nasync def add_config_source(\n name: str,\n git_url: str,\n source_type: str = \"github\",\n token_env: str | None = None,\n branch: str = \"main\",\n priority: int = 100,\n enabled: bool = True,\n) -> str:\n \"\"\"\n Register a git repository as a config source.\n\n Args:\n name: Source identifier (lowercase, alphanumeric, hyphens/underscores allowed). Example: 'team', 'company-internal', 'my_configs'\n git_url: Git repository URL (HTTPS or SSH). Example: 'https://github.com/myorg/configs.git' or 'git@github.com:myorg/configs.git'\n source_type: Source type (default: 'github'). Options: 'github', 'gitlab', 'gitea', 'bitbucket', 'custom'\n token_env: Environment variable name for auth token (optional). Auto-detected if not provided. Example: 'GITHUB_TOKEN', 'GITLAB_TOKEN', 'MY_CUSTOM_TOKEN'\n branch: Git branch to use (default: 'main'). Example: 'main', 'master', 'develop'\n priority: Source priority (lower = higher priority, default: 100). Used for conflict resolution when same config exists in multiple sources.\n enabled: Whether source is enabled (default: true)\n\n Returns:\n Registration results with source details.\n \"\"\"\n args = {\n \"name\": name,\n \"git_url\": git_url,\n \"source_type\": source_type,\n \"branch\": branch,\n \"priority\": priority,\n \"enabled\": enabled,\n }\n if token_env:\n args[\"token_env\"] = token_env\n\n result = await add_config_source_impl(args)\n if isinstance(result, list) and result:\n return result[0].text if hasattr(result[0], \"text\") else str(result[0])\n return str(result)\n\n\n@safe_tool_decorator(\n description=\"List all registered config sources. Shows git repositories that have been registered with add_config_source. Use this to see available sources for fetch_config.\"\n)\nasync def list_config_sources(enabled_only: bool = False) -> str:\n \"\"\"\n List all registered config sources.\n\n Args:\n enabled_only: Only show enabled sources (default: false)\n\n Returns:\n List of registered sources with details.\n \"\"\"\n result = await list_config_sources_impl({\"enabled_only\": enabled_only})\n if isinstance(result, list) and result:\n return result[0].text if hasattr(result[0], \"text\") else str(result[0])\n return str(result)\n\n\n@safe_tool_decorator(\n description=\"Remove a registered config source. Deletes the source from the registry. Does not delete cached git repository data.\"\n)\nasync def remove_config_source(name: str) -> str:\n \"\"\"\n Remove a registered config source.\n\n Args:\n name: Source identifier to remove. Example: 'team', 'company-internal'\n\n Returns:\n Removal results with success/error message.\n \"\"\"\n result = await remove_config_source_impl({\"name\": name})\n if isinstance(result, list) and result:\n return result[0].text if hasattr(result[0], \"text\") else str(result[0])\n return str(result)\n\n\n@safe_tool_decorator(\n description=\"Push a config to a registered config source repository. Validates, places in category directory, commits, and pushes.\"\n)\nasync def push_config(\n config_path: str,\n source_name: str,\n category: str = \"auto\",\n create_branch: bool = False,\n force: bool = False,\n) -> str:\n \"\"\"\n Push a config to a registered config source repository.\n\n Args:\n config_path: Path to config JSON file. Example: 'configs/unity-spine.json'\n source_name: Registered source name. Example: 'spyke'\n category: Category directory (e.g., 'game-engines'). Auto-detected if 'auto'.\n create_branch: Create feature branch instead of pushing to main. Default: false\n force: Overwrite existing config if it exists. Default: false\n\n Returns:\n Push results with commit SHA and config location.\n \"\"\"\n from skill_seekers.mcp.tools.source_tools import push_config_tool\n\n result = await push_config_tool(\n {\n \"config_path\": config_path,\n \"source_name\": source_name,\n \"category\": category,\n \"create_branch\": create_branch,\n \"force\": force,\n }\n )\n if isinstance(result, list) and result:\n return result[0].text if hasattr(result[0], \"text\") else str(result[0])\n return str(result)\n\n\n# ============================================================================\n# MARKETPLACE TOOLS (4 tools)\n# ============================================================================\n\n\n@safe_tool_decorator(\n description=\"Register a plugin marketplace repository. Allows publishing skills to private/team plugin repos. Supports GitHub, GitLab, Bitbucket with per-repo authentication.\"\n)\nasync def add_marketplace(\n name: str,\n git_url: str,\n token_env: str = None,\n branch: str = \"main\",\n author_name: str = \"\",\n author_email: str = \"\",\n enabled: bool = True,\n) -> str:\n \"\"\"\n Register a plugin marketplace repository.\n\n Args:\n name: Marketplace identifier (lowercase, alphanumeric + hyphens/underscores). Example: 'spyke'\n git_url: Git repository URL. Example: 'https://github.com/myorg/plugins.git'\n token_env: Environment variable name for auth token (auto-detected from URL). Example: 'GITHUB_TOKEN'\n branch: Git branch to use (default: \"main\")\n author_name: Default author name for generated plugin.json files\n author_email: Default author email for generated plugin.json files\n enabled: Whether marketplace is enabled (default: true)\n \"\"\"\n result = await add_marketplace_impl(\n {\n \"name\": name,\n \"git_url\": git_url,\n \"token_env\": token_env,\n \"branch\": branch,\n \"author_name\": author_name,\n \"author_email\": author_email,\n \"enabled\": enabled,\n }\n )\n if isinstance(result, list) and result:\n return result[0].text if hasattr(result[0], \"text\") else str(result[0])\n return str(result)\n\n\n@safe_tool_decorator(description=\"List all registered plugin marketplace repositories.\")\nasync def list_marketplaces(enabled_only: bool = False) -> str:\n \"\"\"List all registered plugin marketplace repositories.\"\"\"\n result = await list_marketplaces_impl({\"enabled_only\": enabled_only})\n if isinstance(result, list) and result:\n return result[0].text if hasattr(result[0], \"text\") else str(result[0])\n return str(result)\n\n\n@safe_tool_decorator(\n description=\"Remove a registered plugin marketplace. Deletes from registry but not cached data.\"\n)\nasync def remove_marketplace(name: str) -> str:\n \"\"\"Remove a registered plugin marketplace.\"\"\"\n result = await remove_marketplace_impl({\"name\": name})\n if isinstance(result, list) and result:\n return result[0].text if hasattr(result[0], \"text\") else str(result[0])\n return str(result)\n\n\n@safe_tool_decorator(\n description=\"Publish a packaged skill to a plugin marketplace repository. Creates a Claude Code plugin in the target marketplace repo.\"\n)\nasync def publish_to_marketplace(\n skill_dir: str,\n marketplace: str,\n category: str = \"development\",\n skill_name: str = None,\n description: str = None,\n create_branch: bool = False,\n force: bool = False,\n) -> str:\n \"\"\"\n Publish a skill to a plugin marketplace repository.\n\n Args:\n skill_dir: Path to skill directory containing SKILL.md. Example: 'output/react/'\n marketplace: Registered marketplace name. Example: 'spyke'\n category: Plugin category (default: \"development\")\n skill_name: Override skill name (optional)\n description: Override description (optional)\n create_branch: Create feature branch instead of committing to main (default: false)\n force: Overwrite existing plugin (default: false)\n \"\"\"\n result = await publish_to_marketplace_impl(\n {\n \"skill_dir\": skill_dir,\n \"marketplace\": marketplace,\n \"category\": category,\n \"skill_name\": skill_name,\n \"description\": description,\n \"create_branch\": create_branch,\n \"force\": force,\n }\n )\n if isinstance(result, list) and result:\n return result[0].text if hasattr(result[0], \"text\") else str(result[0])\n return str(result)\n\n\n# ============================================================================\n# VECTOR DATABASE TOOLS (4 tools)\n# ============================================================================\n\n\n@safe_tool_decorator(\n description=\"Export skill to Weaviate vector database format. Weaviate supports hybrid search (vector + BM25 keyword) with 450K+ users. Ideal for production RAG applications.\"\n)\nasync def export_to_weaviate(\n skill_dir: str,\n output_dir: str | None = None,\n) -> str:\n \"\"\"\n Export skill to Weaviate vector database format.\n\n Args:\n skill_dir: Path to skill directory (e.g., output/react/)\n output_dir: Output directory (default: same as skill_dir parent)\n\n Returns:\n Export results with package path and usage instructions.\n \"\"\"\n args = {\"skill_dir\": skill_dir}\n if output_dir:\n args[\"output_dir\"] = output_dir\n\n result = await export_to_weaviate_impl(args)\n if isinstance(result, list) and result:\n return result[0].text if hasattr(result[0], \"text\") else str(result[0])\n return str(result)\n\n\n@safe_tool_decorator(\n description=\"Export skill to Chroma vector database format. Chroma is a popular open-source embedding database designed for local-first development with 800K+ developers.\"\n)\nasync def export_to_chroma(\n skill_dir: str,\n output_dir: str | None = None,\n) -> str:\n \"\"\"\n Export skill to Chroma vector database format.\n\n Args:\n skill_dir: Path to skill directory (e.g., output/react/)\n output_dir: Output directory (default: same as skill_dir parent)\n\n Returns:\n Export results with package path and usage instructions.\n \"\"\"\n args = {\"skill_dir\": skill_dir}\n if output_dir:\n args[\"output_dir\"] = output_dir\n\n result = await export_to_chroma_impl(args)\n if isinstance(result, list) and result:\n return result[0].text if hasattr(result[0], \"text\") else str(result[0])\n return str(result)\n\n\n@safe_tool_decorator(\n description=\"Export skill to FAISS vector index format. FAISS (Facebook AI Similarity Search) supports billion-scale vector search with GPU acceleration.\"\n)\nasync def export_to_faiss(\n skill_dir: str,\n output_dir: str | None = None,\n) -> str:\n \"\"\"\n Export skill to FAISS vector index format.\n\n Args:\n skill_dir: Path to skill directory (e.g., output/react/)\n output_dir: Output directory (default: same as skill_dir parent)\n\n Returns:\n Export results with package path and usage instructions.\n \"\"\"\n args = {\"skill_dir\": skill_dir}\n if output_dir:\n args[\"output_dir\"] = output_dir\n\n result = await export_to_faiss_impl(args)\n if isinstance(result, list) and result:\n return result[0].text if hasattr(result[0], \"text\") else str(result[0])\n return str(result)\n\n\n@safe_tool_decorator(\n description=\"Export skill to Qdrant vector database format. Qdrant is a modern vector database with native payload filtering and high-performance search, serving 100K+ users.\"\n)\nasync def export_to_qdrant(\n skill_dir: str,\n output_dir: str | None = None,\n) -> str:\n \"\"\"\n Export skill to Qdrant vector database format.\n\n Args:\n skill_dir: Path to skill directory (e.g., output/react/)\n output_dir: Output directory (default: same as skill_dir parent)\n\n Returns:\n Export results with package path and usage instructions.\n \"\"\"\n args = {\"skill_dir\": skill_dir}\n if output_dir:\n args[\"output_dir\"] = output_dir\n\n result = await export_to_qdrant_impl(args)\n if isinstance(result, list) and result:\n return result[0].text if hasattr(result[0], \"text\") else str(result[0])\n return str(result)\n\n\n# ============================================================================\n# WORKFLOW TOOLS (5 tools)\n# ============================================================================\n\n\n@safe_tool_decorator(\n description=\"List all available enhancement workflows (bundled defaults + user-created). Returns name, description, and source (bundled/user) for each.\"\n)\nasync def list_workflows() -> str:\n \"\"\"List all available enhancement workflow presets.\"\"\"\n result = list_workflows_impl({})\n if isinstance(result, list) and result:\n return result[0].text if hasattr(result[0], \"text\") else str(result[0])\n return str(result)\n\n\n@safe_tool_decorator(\n description=\"Get the full YAML content of a named enhancement workflow. Searches user dir first, then bundled defaults.\"\n)\nasync def get_workflow(name: str) -> str:\n \"\"\"\n Get full YAML content of a workflow.\n\n Args:\n name: Workflow name (e.g. 'security-focus', 'default')\n\n Returns:\n YAML content of the workflow, or error message if not found.\n \"\"\"\n result = get_workflow_impl({\"name\": name})\n if isinstance(result, list) and result:\n return result[0].text if hasattr(result[0], \"text\") else str(result[0])\n return str(result)\n\n\n@safe_tool_decorator(\n description=\"Create a new user workflow from YAML content. The workflow is saved to ~/.config/skill-seekers/workflows/.\"\n)\nasync def create_workflow(name: str, content: str) -> str:\n \"\"\"\n Create a new user workflow.\n\n Args:\n name: Workflow name (becomes the filename stem, e.g. 'my-custom')\n content: Full YAML content of the workflow\n\n Returns:\n Success message with file path, or error message.\n \"\"\"\n result = create_workflow_impl({\"name\": name, \"content\": content})\n if isinstance(result, list) and result:\n return result[0].text if hasattr(result[0], \"text\") else str(result[0])\n return str(result)\n\n\n@safe_tool_decorator(\n description=\"Update (overwrite) an existing user workflow. Cannot update bundled workflows.\"\n)\nasync def update_workflow(name: str, content: str) -> str:\n \"\"\"\n Update an existing user workflow.\n\n Args:\n name: Workflow name to update\n content: New YAML content\n\n Returns:\n Success message, or error if workflow is bundled or invalid.\n \"\"\"\n result = update_workflow_impl({\"name\": name, \"content\": content})\n if isinstance(result, list) and result:\n return result[0].text if hasattr(result[0], \"text\") else str(result[0])\n return str(result)\n\n\n@safe_tool_decorator(\n description=\"Delete a user workflow by name. Bundled workflows cannot be deleted.\"\n)\nasync def delete_workflow(name: str) -> str:\n \"\"\"\n Delete a user workflow.\n\n Args:\n name: Workflow name to delete\n\n Returns:\n Success message, or error if workflow is bundled or not found.\n \"\"\"\n result = delete_workflow_impl({\"name\": name})\n if isinstance(result, list) and result:\n return result[0].text if hasattr(result[0], \"text\") else str(result[0])\n return str(result)\n\n\n# ============================================================================\n# MAIN ENTRY POINT\n# ============================================================================\n\n\ndef parse_args():\n \"\"\"Parse command-line arguments.\"\"\"\n parser = argparse.ArgumentParser(\n description=\"Skill Seeker MCP Server - Generate Claude AI skills from documentation\",\n formatter_class=argparse.RawDescriptionHelpFormatter,\n epilog=\"\"\"\nTransport Modes:\n stdio (default): Standard input/output communication for Claude Desktop\n http: HTTP server with SSE for web-based MCP clients\n\nExamples:\n # Stdio transport (default, backward compatible)\n python -m skill_seekers.mcp.server_fastmcp\n\n # HTTP transport on default port 8000\n python -m skill_seekers.mcp.server_fastmcp --http\n\n # HTTP transport on custom port\n python -m skill_seekers.mcp.server_fastmcp --http --port 8080\n\n # Debug logging\n python -m skill_seekers.mcp.server_fastmcp --http --log-level DEBUG\n \"\"\",\n )\n\n parser.add_argument(\n \"--http\",\n action=\"store_true\",\n help=\"Use HTTP transport instead of stdio (default: stdio)\",\n )\n\n parser.add_argument(\n \"--port\",\n type=int,\n default=8000,\n help=\"Port for HTTP server (default: 8000)\",\n )\n\n parser.add_argument(\n \"--host\",\n type=str,\n default=\"127.0.0.1\",\n help=\"Host for HTTP server (default: 127.0.0.1)\",\n )\n\n parser.add_argument(\n \"--log-level\",\n type=str,\n default=\"INFO\",\n choices=[\"DEBUG\", \"INFO\", \"WARNING\", \"ERROR\", \"CRITICAL\"],\n help=\"Logging level (default: INFO)\",\n )\n\n return parser.parse_args()\n\n\ndef setup_logging(log_level: str):\n \"\"\"Configure logging.\"\"\"\n logging.basicConfig(\n level=getattr(logging, log_level),\n format=\"%(asctime)s - %(name)s - %(levelname)s - %(message)s\",\n )\n\n\nasync def run_http_server(host: str, port: int):\n \"\"\"Run the MCP server with HTTP transport using uvicorn.\"\"\"\n try:\n import uvicorn\n except ImportError:\n logging.error(\"❌ Error: uvicorn package not installed\")\n logging.error(\"Install with: pip install uvicorn\")\n sys.exit(1)\n\n try:\n # Get the SSE Starlette app from FastMCP\n app = mcp.sse_app()\n\n # Add CORS middleware for cross-origin requests\n try:\n from starlette.middleware.cors import CORSMiddleware\n\n app.add_middleware(\n CORSMiddleware,\n allow_origins=[\"*\"],\n allow_credentials=True,\n allow_methods=[\"*\"],\n allow_headers=[\"*\"],\n )\n logging.info(\"✓ CORS middleware enabled\")\n except ImportError:\n logging.warning(\"⚠ CORS middleware not available (starlette not installed)\")\n\n # Add health check endpoint\n from starlette.responses import JSONResponse\n from starlette.routing import Route\n\n async def health_check(_request):\n \"\"\"Health check endpoint.\"\"\"\n return JSONResponse(\n {\n \"status\": \"healthy\",\n \"server\": \"skill-seeker-mcp\",\n \"version\": \"2.1.1\",\n \"transport\": \"http\",\n \"endpoints\": {\n \"health\": \"/health\",\n \"sse\": \"/sse\",\n \"messages\": \"/messages/\",\n },\n }\n )\n\n # Add route before the catch-all SSE route\n app.routes.insert(0, Route(\"/health\", health_check, methods=[\"GET\"]))\n\n logging.info(\"🚀 Starting Skill Seeker MCP Server (HTTP mode)\")\n logging.info(f\"📡 Server URL: http://{host}:{port}\")\n logging.info(f\"🔗 SSE Endpoint: http://{host}:{port}/sse\")\n logging.info(f\"💚 Health Check: http://{host}:{port}/health\")\n logging.info(f\"📝 Messages: http://{host}:{port}/messages/\")\n logging.info(\"\")\n logging.info(\"Claude Desktop Configuration (HTTP):\")\n logging.info(\"{\")\n logging.info(' \"mcpServers\": {')\n logging.info(' \"skill-seeker\": {')\n logging.info(f' \"url\": \"http://{host}:{port}/sse\"')\n logging.info(\" }\")\n logging.info(\" }\")\n logging.info(\"}\")\n logging.info(\"\")\n logging.info(\"Press Ctrl+C to stop the server\")\n\n # Run the uvicorn server\n config = uvicorn.Config(\n app=app,\n host=host,\n port=port,\n log_level=logging.getLogger().level,\n access_log=True,\n )\n server = uvicorn.Server(config)\n await server.serve()\n\n except Exception as e:\n logging.error(f\"❌ Failed to start HTTP server: {e}\")\n import traceback\n\n traceback.print_exc()\n sys.exit(1)\n\n\ndef main():\n \"\"\"Run the MCP server with stdio or HTTP transport.\"\"\"\n import asyncio\n\n # Check if MCP is available\n if not MCP_AVAILABLE or mcp is None:\n print(\"❌ Error: mcp package not installed or FastMCP not available\")\n print(\"Install with: pip install mcp>=1.25\")\n sys.exit(1)\n\n # Parse command-line arguments\n args = parse_args()\n\n # Setup logging\n setup_logging(args.log_level)\n\n if args.http:\n # HTTP transport mode\n logging.info(f\"🌐 Using HTTP transport on {args.host}:{args.port}\")\n try:\n asyncio.run(run_http_server(args.host, args.port))\n except KeyboardInterrupt:\n logging.info(\"\\n👋 Server stopped by user\")\n sys.exit(0)\n else:\n # Stdio transport mode (default, backward compatible)\n logging.info(\"📺 Using stdio transport (default)\")\n try:\n asyncio.run(mcp.run_stdio_async())\n except KeyboardInterrupt:\n logging.info(\"\\n👋 Server stopped by user\")\n sys.exit(0)\n\n\nif __name__ == \"__main__\":\n main()\n",
"sha256": "19ba3010ea3bc5101953e44070932ec239d67908e1a0e992437665f98b827200"
},
".github/tools/external/Skill_Seekers-development/src/skill_seekers/mcp/tools/packaging_tools.py": {
"mode": "100644",
"encoding": "utf-8",
"data": "\"\"\"\nPackaging tools for MCP server.\n\nThis module contains tools for packaging, uploading, and installing skills.\nExtracted from server.py for better modularity.\n\"\"\"\n\nimport json\nimport os\nimport re\nimport subprocess\nimport sys\nimport time\nfrom pathlib import Path\n\ntry:\n from mcp.types import TextContent\nexcept ImportError:\n # Graceful degradation: Create a simple fallback class for testing\n class TextContent:\n \"\"\"Fallback TextContent for when MCP is not installed\"\"\"\n\n def __init__(self, type: str, text: str):\n self.type = type\n self.text = text\n\n\n# Path to CLI tools\nCLI_DIR = Path(__file__).parent.parent.parent / \"cli\"\n\n\ndef run_subprocess_with_streaming(cmd: list[str], timeout: int = None) -> tuple[str, str, int]:\n \"\"\"\n Run subprocess with real-time output streaming.\n\n This solves the blocking issue where long-running processes (like scraping)\n would cause MCP to appear frozen. Now we stream output as it comes.\n\n Args:\n cmd: Command to run as list of strings\n timeout: Maximum time to wait in seconds (None for no timeout)\n\n Returns:\n Tuple of (stdout, stderr, returncode)\n \"\"\"\n try:\n process = subprocess.Popen(\n cmd,\n stdout=subprocess.PIPE,\n stderr=subprocess.PIPE,\n text=True,\n bufsize=1, # Line buffered\n universal_newlines=True,\n )\n\n stdout_lines = []\n stderr_lines = []\n start_time = time.time()\n\n # Read output line by line as it comes\n while True:\n # Check timeout\n if timeout and (time.time() - start_time) > timeout:\n process.kill()\n stderr_lines.append(f\"\\n⚠️ Process killed after {timeout}s timeout\")\n break\n\n # Check if process finished\n if process.poll() is not None:\n break\n\n # Read available output (non-blocking)\n try:\n import select\n\n readable, _, _ = select.select([process.stdout, process.stderr], [], [], 0.1)\n\n if process.stdout in readable:\n line = process.stdout.readline()\n if line:\n stdout_lines.append(line)\n\n if process.stderr in readable:\n line = process.stderr.readline()\n if line:\n stderr_lines.append(line)\n except Exception:\n # Fallback for Windows (no select)\n time.sleep(0.1)\n\n # Get any remaining output\n remaining_stdout, remaining_stderr = process.communicate()\n if remaining_stdout:\n stdout_lines.append(remaining_stdout)\n if remaining_stderr:\n stderr_lines.append(remaining_stderr)\n\n stdout = \"\".join(stdout_lines)\n stderr = \"\".join(stderr_lines)\n returncode = process.returncode\n\n return stdout, stderr, returncode\n\n except Exception as e:\n return \"\", f\"Error running subprocess: {str(e)}\", 1\n\n\nasync def package_skill_tool(args: dict) -> list[TextContent]:\n \"\"\"\n Package skill for target LLM platform and optionally auto-upload.\n\n Args:\n args: Dictionary with:\n - skill_dir (str): Path to skill directory (e.g., output/react/)\n - auto_upload (bool): Try to upload automatically if API key is available (default: True)\n - target (str): Target platform (default: 'auto')\n Options: 'auto', 'claude', 'gemini', 'openai', 'markdown'\n\n Returns:\n List of TextContent with packaging results\n \"\"\"\n from skill_seekers.cli.adaptors import get_adaptor\n\n skill_dir = args[\"skill_dir\"]\n auto_upload = args.get(\"auto_upload\", True)\n target = args.get(\"target\", \"auto\")\n if target == \"auto\":\n from skill_seekers.cli.agent_client import AgentClient\n\n target = AgentClient.detect_default_target()\n\n # Get platform adaptor\n try:\n adaptor = get_adaptor(target)\n except ValueError as e:\n return [\n TextContent(\n type=\"text\",\n text=f\"❌ Invalid platform: {str(e)}\\n\\nSupported platforms: claude, gemini, openai, markdown\",\n )\n ]\n\n # Check if platform-specific API key exists - only upload if available\n env_var_name = adaptor.get_env_var_name()\n has_api_key = os.environ.get(env_var_name, \"\").strip() if env_var_name else False\n should_upload = auto_upload and has_api_key\n\n # Run package_skill.py with target parameter\n cmd = [\n sys.executable,\n str(CLI_DIR / \"package_skill.py\"),\n skill_dir,\n \"--no-open\", # Don't open folder in MCP context\n \"--skip-quality-check\", # Skip interactive quality checks in MCP context\n \"--target\",\n target, # Add target platform\n ]\n\n # Add upload flag only if we have API key\n if should_upload:\n cmd.append(\"--upload\")\n\n # Timeout: 5 minutes for packaging + upload\n timeout = 300\n\n progress_msg = f\"📦 Packaging skill for {adaptor.PLATFORM_NAME}...\\n\"\n if should_upload:\n progress_msg += f\"📤 Will auto-upload to {adaptor.PLATFORM_NAME} if successful\\n\"\n progress_msg += f\"⏱️ Maximum time: {timeout // 60} minutes\\n\\n\"\n\n stdout, stderr, returncode = run_subprocess_with_streaming(cmd, timeout=timeout)\n\n output = progress_msg + stdout\n\n if returncode == 0:\n if should_upload:\n # Upload succeeded\n output += f\"\\n\\n✅ Skill packaged and uploaded to {adaptor.PLATFORM_NAME}!\"\n if target == \"claude\":\n output += \"\\n Your skill is now available in Claude!\"\n output += \"\\n Go to https://claude.ai/skills to use it\"\n elif target == \"gemini\":\n output += \"\\n Your skill is now available in Gemini!\"\n output += \"\\n Go to https://aistudio.google.com/ to use it\"\n elif target == \"openai\":\n output += \"\\n Your assistant is now available in OpenAI!\"\n output += \"\\n Go to https://platform.openai.com/assistants/ to use it\"\n elif auto_upload and not has_api_key:\n # User wanted upload but no API key\n output += f\"\\n\\n📝 Skill packaged successfully for {adaptor.PLATFORM_NAME}!\"\n output += \"\\n\"\n output += \"\\n💡 To enable automatic upload:\"\n if target == \"claude\":\n output += \"\\n 1. Get API key from https://console.anthropic.com/\"\n output += \"\\n 2. Set: export ANTHROPIC_API_KEY=sk-ant-...\"\n output += \"\\n\\n📤 Manual upload:\"\n output += \"\\n 1. Find the .zip file in your output/ folder\"\n output += \"\\n 2. Go to https://claude.ai/skills\"\n output += \"\\n 3. Click 'Upload Skill' and select the .zip file\"\n elif target == \"gemini\":\n output += \"\\n 1. Get API key from https://aistudio.google.com/\"\n output += \"\\n 2. Set: export GOOGLE_API_KEY=AIza...\"\n output += \"\\n\\n📤 Manual upload:\"\n output += \"\\n 1. Go to https://aistudio.google.com/\"\n output += \"\\n 2. Upload the .tar.gz file from your output/ folder\"\n elif target == \"openai\":\n output += \"\\n 1. Get API key from https://platform.openai.com/\"\n output += \"\\n 2. Set: export OPENAI_API_KEY=sk-proj-...\"\n output += \"\\n\\n📤 Manual upload:\"\n output += \"\\n 1. Use OpenAI Assistants API\"\n output += \"\\n 2. Upload the .zip file from your output/ folder\"\n elif target == \"markdown\":\n output += \"\\n (No API key needed - markdown is export only)\"\n output += \"\\n Package created for manual distribution\"\n else:\n # auto_upload=False, just packaged\n output += f\"\\n\\n✅ Skill packaged successfully for {adaptor.PLATFORM_NAME}!\"\n if target == \"claude\":\n output += \"\\n Upload manually to https://claude.ai/skills\"\n elif target == \"gemini\":\n output += \"\\n Upload manually to https://aistudio.google.com/\"\n elif target == \"openai\":\n output += \"\\n Upload manually via OpenAI Assistants API\"\n elif target == \"markdown\":\n output += \"\\n Package ready for manual distribution\"\n\n return [TextContent(type=\"text\", text=output)]\n else:\n return [TextContent(type=\"text\", text=f\"{output}\\n\\n❌ Error:\\n{stderr}\")]\n\n\nasync def upload_skill_tool(args: dict) -> list[TextContent]:\n \"\"\"\n Upload skill package to target LLM platform.\n\n Args:\n args: Dictionary with:\n - skill_zip (str): Path to skill package (.zip or .tar.gz)\n - target (str): Target platform (default: 'auto')\n Options: 'auto', 'claude', 'gemini', 'openai'\n Note: 'markdown' does not support upload\n - api_key (str, optional): API key (uses env var if not provided)\n\n Returns:\n List of TextContent with upload results\n \"\"\"\n from skill_seekers.cli.adaptors import get_adaptor\n\n skill_zip = args[\"skill_zip\"]\n target = args.get(\"target\", \"auto\")\n if target == \"auto\":\n from skill_seekers.cli.agent_client import AgentClient\n\n target = AgentClient.detect_default_target()\n api_key = args.get(\"api_key\")\n\n # Get platform adaptor\n try:\n adaptor = get_adaptor(target)\n except ValueError as e:\n return [\n TextContent(\n type=\"text\",\n text=f\"❌ Invalid platform: {str(e)}\\n\\nSupported platforms: claude, gemini, openai\",\n )\n ]\n\n # Check if upload is supported\n if target == \"markdown\":\n return [\n TextContent(\n type=\"text\",\n text=\"❌ Markdown export does not support upload. Use the packaged file manually.\",\n )\n ]\n\n # Run upload_skill.py with target parameter\n cmd = [sys.executable, str(CLI_DIR / \"upload_skill.py\"), skill_zip, \"--target\", target]\n\n # Add API key if provided\n if api_key:\n cmd.extend([\"--api-key\", api_key])\n\n # Timeout: 5 minutes for upload\n timeout = 300\n\n progress_msg = f\"📤 Uploading skill to {adaptor.PLATFORM_NAME}...\\n\"\n progress_msg += f\"⏱️ Maximum time: {timeout // 60} minutes\\n\\n\"\n\n stdout, stderr, returncode = run_subprocess_with_streaming(cmd, timeout=timeout)\n\n output = progress_msg + stdout\n\n if returncode == 0:\n return [TextContent(type=\"text\", text=output)]\n else:\n return [TextContent(type=\"text\", text=f\"{output}\\n\\n❌ Error:\\n{stderr}\")]\n\n\nasync def enhance_skill_tool(args: dict) -> list[TextContent]:\n \"\"\"\n Enhance SKILL.md with AI using target platform's model.\n\n Args:\n args: Dictionary with:\n - skill_dir (str): Path to skill directory\n - target (str): Target platform (default: 'auto')\n Options: 'auto', 'claude', 'gemini', 'openai'\n Note: 'markdown' does not support enhancement\n - mode (str): Enhancement mode (default: 'local')\n 'local': Uses AI coding agent (no API key)\n 'api': Uses platform API (requires API key)\n - api_key (str, optional): API key for 'api' mode\n\n Returns:\n List of TextContent with enhancement results\n \"\"\"\n from skill_seekers.cli.adaptors import get_adaptor\n\n skill_dir = Path(args.get(\"skill_dir\"))\n target = args.get(\"target\", \"auto\")\n if target == \"auto\":\n from skill_seekers.cli.agent_client import AgentClient\n\n target = AgentClient.detect_default_target()\n mode = args.get(\"mode\", \"local\")\n api_key = args.get(\"api_key\")\n\n # Validate skill directory\n if not skill_dir.exists():\n return [TextContent(type=\"text\", text=f\"❌ Skill directory not found: {skill_dir}\")]\n\n if not (skill_dir / \"SKILL.md\").exists():\n return [TextContent(type=\"text\", text=f\"❌ SKILL.md not found in {skill_dir}\")]\n\n # Get platform adaptor\n try:\n adaptor = get_adaptor(target)\n except ValueError as e:\n return [\n TextContent(\n type=\"text\",\n text=f\"❌ Invalid platform: {str(e)}\\n\\nSupported platforms: claude, gemini, openai\",\n )\n ]\n\n # Check if enhancement is supported\n if not adaptor.supports_enhancement():\n return [\n TextContent(\n type=\"text\", text=f\"❌ {adaptor.PLATFORM_NAME} does not support AI enhancement\"\n )\n ]\n\n output_lines = []\n output_lines.append(f\"🚀 Enhancing skill with {adaptor.PLATFORM_NAME}\")\n output_lines.append(\"-\" * 70)\n output_lines.append(f\"Skill directory: {skill_dir}\")\n output_lines.append(f\"Mode: {mode}\")\n output_lines.append(\"\")\n\n if mode == \"local\":\n # Use local enhancement (AI coding agent)\n output_lines.append(\"Using AI coding agent (local, no API key required)\")\n output_lines.append(\"Running enhancement in headless mode...\")\n output_lines.append(\"\")\n\n cmd = [sys.executable, str(CLI_DIR / \"enhance_skill_local.py\"), str(skill_dir)]\n\n try:\n stdout, stderr, returncode = run_subprocess_with_streaming(cmd, timeout=900)\n\n if returncode == 0:\n output_lines.append(stdout)\n output_lines.append(\"\")\n output_lines.append(\"✅ Enhancement complete!\")\n output_lines.append(f\"Enhanced SKILL.md: {skill_dir / 'SKILL.md'}\")\n output_lines.append(f\"Backup: {skill_dir / 'SKILL.md.backup'}\")\n else:\n output_lines.append(f\"❌ Enhancement failed (exit code {returncode})\")\n output_lines.append(stderr if stderr else stdout)\n\n except Exception as e:\n output_lines.append(f\"❌ Error: {str(e)}\")\n\n elif mode == \"api\":\n # Use API enhancement\n output_lines.append(f\"Using {adaptor.PLATFORM_NAME} API\")\n\n # Get API key\n if not api_key:\n env_var = adaptor.get_env_var_name()\n api_key = os.environ.get(env_var)\n\n if not api_key:\n return [\n TextContent(\n type=\"text\",\n text=f\"❌ {env_var} not set. Set API key or pass via api_key parameter.\",\n )\n ]\n\n # Validate API key\n if not adaptor.validate_api_key(api_key):\n return [\n TextContent(\n type=\"text\", text=f\"❌ Invalid API key format for {adaptor.PLATFORM_NAME}\"\n )\n ]\n\n output_lines.append(\"Calling API for enhancement...\")\n output_lines.append(\"\")\n\n try:\n success = adaptor.enhance(skill_dir, api_key)\n\n if success:\n output_lines.append(\"✅ Enhancement complete!\")\n output_lines.append(f\"Enhanced SKILL.md: {skill_dir / 'SKILL.md'}\")\n output_lines.append(f\"Backup: {skill_dir / 'SKILL.md.backup'}\")\n else:\n output_lines.append(\"❌ Enhancement failed\")\n\n except Exception as e:\n output_lines.append(f\"❌ Error: {str(e)}\")\n\n else:\n return [TextContent(type=\"text\", text=f\"❌ Invalid mode: {mode}. Use 'local' or 'api'\")]\n\n return [TextContent(type=\"text\", text=\"\\n\".join(output_lines))]\n\n\nasync def install_skill_tool(args: dict) -> list[TextContent]:\n \"\"\"\n Complete skill installation workflow.\n\n Orchestrates the complete workflow:\n 1. Fetch config (if config_name provided)\n 2. Scrape documentation\n 3. AI Enhancement (MANDATORY - no skip option)\n 4. Package for target platform (ZIP or tar.gz)\n 5. Upload to target platform (optional)\n\n Args:\n args: Dictionary with:\n - config_name (str, optional): Config to fetch from API (mutually exclusive with config_path)\n - config_path (str, optional): Path to existing config (mutually exclusive with config_name)\n - destination (str): Output directory (default: \"output\")\n - auto_upload (bool): Upload after packaging (default: True)\n - unlimited (bool): Remove page limits (default: False)\n - dry_run (bool): Preview only (default: False)\n - target (str): Target LLM platform (default: \"auto\")\n\n Returns:\n List of TextContent with workflow progress and results\n \"\"\"\n # Import these here to avoid circular imports\n from skill_seekers.cli.adaptors import get_adaptor\n\n from .scraping_tools import scrape_docs_tool\n from .source_tools import fetch_config_tool\n\n # Extract and validate inputs\n config_name = args.get(\"config_name\")\n config_path = args.get(\"config_path\")\n destination = args.get(\"destination\", \"output\")\n auto_upload = args.get(\"auto_upload\", True)\n unlimited = args.get(\"unlimited\", False)\n dry_run = args.get(\"dry_run\", False)\n target = args.get(\"target\", \"auto\")\n marketplace_arg = args.get(\"marketplace\")\n marketplace_category = args.get(\"marketplace_category\", \"development\")\n create_branch = args.get(\"create_branch\", False)\n if target == \"auto\":\n from skill_seekers.cli.agent_client import AgentClient\n\n target = AgentClient.detect_default_target()\n\n # Get platform adaptor\n try:\n adaptor = get_adaptor(target)\n except ValueError as e:\n return [\n TextContent(\n type=\"text\",\n text=f\"❌ Error: {str(e)}\\n\\nSupported platforms: claude, gemini, openai, markdown\",\n )\n ]\n\n # Validation: Must provide exactly one of config_name or config_path\n if not config_name and not config_path:\n return [\n TextContent(\n type=\"text\",\n text=\"❌ Error: Must provide either config_name or config_path\\n\\nExamples:\\n install_skill(config_name='react')\\n install_skill(config_path='configs/custom.json')\",\n )\n ]\n\n if config_name and config_path:\n return [\n TextContent(\n type=\"text\",\n text=\"❌ Error: Cannot provide both config_name and config_path\\n\\nChoose one:\\n - config_name: Fetch from API (e.g., 'react')\\n - config_path: Use existing file (e.g., 'configs/custom.json')\",\n )\n ]\n\n # Initialize output\n output_lines = []\n output_lines.append(\"🚀 SKILL INSTALLATION WORKFLOW\")\n output_lines.append(\"=\" * 70)\n output_lines.append(\"\")\n\n if dry_run:\n output_lines.append(\"🔍 DRY RUN MODE - Preview only, no actions taken\")\n output_lines.append(\"\")\n\n # Track workflow state\n workflow_state = {\n \"config_path\": config_path,\n \"skill_name\": None,\n \"skill_dir\": None,\n \"zip_path\": None,\n \"phases_completed\": [],\n }\n\n try:\n # ===== PHASE 1: Fetch Config (if needed) =====\n if config_name:\n output_lines.append(\"📥 PHASE 1/5: Fetch Config\")\n output_lines.append(\"-\" * 70)\n output_lines.append(f\"Config: {config_name}\")\n output_lines.append(f\"Destination: {destination}/\")\n output_lines.append(\"\")\n\n if not dry_run:\n # Call fetch_config_tool directly\n fetch_result = await fetch_config_tool(\n {\"config_name\": config_name, \"destination\": destination}\n )\n\n # Parse result to extract config path\n fetch_output = fetch_result[0].text\n output_lines.append(fetch_output)\n output_lines.append(\"\")\n\n # Extract config path from output\n # Expected format: \"📂 Saved to: configs/react.json\"\n match = re.search(r\"(?i)saved to:\\s*(.+\\.json)\", fetch_output)\n if match:\n workflow_state[\"config_path\"] = match.group(1).strip()\n output_lines.append(f\"✅ Config fetched: {workflow_state['config_path']}\")\n else:\n return [\n TextContent(\n type=\"text\",\n text=\"\\n\".join(output_lines) + \"\\n\\n❌ Failed to fetch config\",\n )\n ]\n\n workflow_state[\"phases_completed\"].append(\"fetch_config\")\n else:\n output_lines.append(\" [DRY RUN] Would fetch config from API\")\n workflow_state[\"config_path\"] = f\"{destination}/{config_name}.json\"\n\n output_lines.append(\"\")\n\n # ===== PHASE 2: Scrape Documentation =====\n phase_num = \"2/5\" if config_name else \"1/4\"\n output_lines.append(f\"📄 PHASE {phase_num}: Scrape Documentation\")\n output_lines.append(\"-\" * 70)\n output_lines.append(f\"Config: {workflow_state['config_path']}\")\n output_lines.append(f\"Unlimited mode: {unlimited}\")\n output_lines.append(\"\")\n\n if not dry_run:\n # Load config to get skill name\n try:\n with open(workflow_state[\"config_path\"]) as f:\n config = json.load(f)\n workflow_state[\"skill_name\"] = config.get(\"name\", \"unknown\")\n workflow_state[\"config_data\"] = config\n except Exception as e:\n return [\n TextContent(\n type=\"text\",\n text=\"\\n\".join(output_lines) + f\"\\n\\n❌ Failed to read config: {str(e)}\",\n )\n ]\n\n # Call scrape_docs_tool (does NOT include enhancement)\n output_lines.append(\"Scraping documentation (this may take 20-45 minutes)...\")\n output_lines.append(\"\")\n\n scrape_result = await scrape_docs_tool(\n {\n \"config_path\": workflow_state[\"config_path\"],\n \"unlimited\": unlimited,\n \"enhance_local\": False, # Enhancement is separate phase\n \"skip_scrape\": False,\n \"dry_run\": False,\n }\n )\n\n scrape_output = scrape_result[0].text\n output_lines.append(scrape_output)\n output_lines.append(\"\")\n\n # Check for success\n if \"❌\" in scrape_output:\n return [\n TextContent(\n type=\"text\",\n text=\"\\n\".join(output_lines) + \"\\n\\n❌ Scraping failed - see error above\",\n )\n ]\n\n workflow_state[\"skill_dir\"] = f\"{destination}/{workflow_state['skill_name']}\"\n workflow_state[\"phases_completed\"].append(\"scrape_docs\")\n else:\n output_lines.append(\" [DRY RUN] Would scrape documentation\")\n workflow_state[\"skill_name\"] = \"example\"\n workflow_state[\"skill_dir\"] = f\"{destination}/example\"\n\n output_lines.append(\"\")\n\n # ===== PHASE 3: AI Enhancement (MANDATORY) =====\n phase_num = \"3/5\" if config_name else \"2/4\"\n output_lines.append(f\"✨ PHASE {phase_num}: AI Enhancement (MANDATORY)\")\n output_lines.append(\"-\" * 70)\n output_lines.append(\"⚠️ Enhancement is REQUIRED for quality (3/10→9/10 boost)\")\n output_lines.append(f\"Skill directory: {workflow_state['skill_dir']}\")\n output_lines.append(\"Mode: Headless (runs in background)\")\n output_lines.append(\"Estimated time: 30-60 seconds\")\n output_lines.append(\"\")\n\n if not dry_run:\n # Run enhance_skill_local in headless mode\n # Build command directly\n cmd = [\n sys.executable,\n str(CLI_DIR / \"enhance_skill_local.py\"),\n workflow_state[\"skill_dir\"],\n # Headless is default, no flag needed\n ]\n\n timeout = 900 # 15 minutes max for enhancement\n\n output_lines.append(\"Running AI enhancement...\")\n\n stdout, stderr, returncode = run_subprocess_with_streaming(cmd, timeout=timeout)\n\n if returncode != 0:\n output_lines.append(f\"\\n❌ Enhancement failed (exit code {returncode}):\")\n output_lines.append(stderr if stderr else stdout)\n return [TextContent(type=\"text\", text=\"\\n\".join(output_lines))]\n\n output_lines.append(stdout)\n workflow_state[\"phases_completed\"].append(\"enhance_skill\")\n else:\n output_lines.append(\" [DRY RUN] Would enhance SKILL.md with AI agent\")\n\n output_lines.append(\"\")\n\n # ===== PHASE 4: Package Skill =====\n phase_num = \"4/5\" if config_name else \"3/4\"\n output_lines.append(f\"📦 PHASE {phase_num}: Package Skill for {adaptor.PLATFORM_NAME}\")\n output_lines.append(\"-\" * 70)\n output_lines.append(f\"Skill directory: {workflow_state['skill_dir']}\")\n output_lines.append(f\"Target platform: {adaptor.PLATFORM_NAME}\")\n output_lines.append(\"\")\n\n if not dry_run:\n # Call package_skill_tool with target\n package_result = await package_skill_tool(\n {\n \"skill_dir\": workflow_state[\"skill_dir\"],\n \"auto_upload\": False, # We handle upload in next phase\n \"target\": target,\n }\n )\n\n package_output = package_result[0].text\n output_lines.append(package_output)\n output_lines.append(\"\")\n\n # Extract package path from output (supports .zip and .tar.gz)\n # Expected format: \"Saved to: output/react.zip\" or \"Saved to: output/react-gemini.tar.gz\"\n match = re.search(r\"(?i)saved to:\\s*(.+\\.(?:zip|tar\\.gz))\", package_output)\n if match:\n workflow_state[\"zip_path\"] = match.group(1).strip()\n else:\n # Fallback: construct package path based on platform\n if target == \"gemini\":\n workflow_state[\"zip_path\"] = (\n f\"{destination}/{workflow_state['skill_name']}-gemini.tar.gz\"\n )\n elif target == \"openai\":\n workflow_state[\"zip_path\"] = (\n f\"{destination}/{workflow_state['skill_name']}-openai.zip\"\n )\n else:\n workflow_state[\"zip_path\"] = f\"{destination}/{workflow_state['skill_name']}.zip\"\n\n workflow_state[\"phases_completed\"].append(\"package_skill\")\n else:\n # Dry run - show expected package format\n if target == \"gemini\":\n pkg_ext = \"tar.gz\"\n pkg_file = f\"{destination}/{workflow_state['skill_name']}-gemini.tar.gz\"\n elif target == \"openai\":\n pkg_ext = \"zip\"\n pkg_file = f\"{destination}/{workflow_state['skill_name']}-openai.zip\"\n else:\n pkg_ext = \"zip\"\n pkg_file = f\"{destination}/{workflow_state['skill_name']}.zip\"\n\n output_lines.append(\n f\" [DRY RUN] Would package to {pkg_ext} file for {adaptor.PLATFORM_NAME}\"\n )\n workflow_state[\"zip_path\"] = pkg_file\n\n output_lines.append(\"\")\n\n # ===== PHASE 5: Upload (Optional) =====\n has_api_key = False # Initialize before conditional block\n if auto_upload:\n phase_num = \"5/5\" if config_name else \"4/4\"\n output_lines.append(f\"📤 PHASE {phase_num}: Upload to {adaptor.PLATFORM_NAME}\")\n output_lines.append(\"-\" * 70)\n output_lines.append(f\"Package file: {workflow_state['zip_path']}\")\n output_lines.append(\"\")\n\n # Check for platform-specific API key\n env_var_name = adaptor.get_env_var_name()\n has_api_key = os.environ.get(env_var_name, \"\").strip()\n\n if not dry_run:\n if has_api_key:\n # Upload not supported for markdown platform\n if target == \"markdown\":\n output_lines.append(\"⚠️ Markdown export does not support upload\")\n output_lines.append(\" Package has been created - use manually\")\n else:\n # Call upload_skill_tool with target\n upload_result = await upload_skill_tool(\n {\"skill_zip\": workflow_state[\"zip_path\"], \"target\": target}\n )\n\n upload_output = upload_result[0].text\n output_lines.append(upload_output)\n\n workflow_state[\"phases_completed\"].append(\"upload_skill\")\n else:\n # Platform-specific instructions for missing API key\n output_lines.append(f\"⚠️ {env_var_name} not set - skipping upload\")\n output_lines.append(\"\")\n output_lines.append(\"To enable automatic upload:\")\n\n if target == \"claude\":\n output_lines.append(\" 1. Get API key from https://console.anthropic.com/\")\n output_lines.append(\" 2. Set: export ANTHROPIC_API_KEY=sk-ant-...\")\n output_lines.append(\"\")\n output_lines.append(\"📤 Manual upload:\")\n output_lines.append(\" 1. Go to https://claude.ai/skills\")\n output_lines.append(\" 2. Click 'Upload Skill'\")\n output_lines.append(f\" 3. Select: {workflow_state['zip_path']}\")\n elif target == \"gemini\":\n output_lines.append(\" 1. Get API key from https://aistudio.google.com/\")\n output_lines.append(\" 2. Set: export GOOGLE_API_KEY=AIza...\")\n output_lines.append(\"\")\n output_lines.append(\"📤 Manual upload:\")\n output_lines.append(\" 1. Go to https://aistudio.google.com/\")\n output_lines.append(f\" 2. Upload package: {workflow_state['zip_path']}\")\n elif target == \"openai\":\n output_lines.append(\" 1. Get API key from https://platform.openai.com/\")\n output_lines.append(\" 2. Set: export OPENAI_API_KEY=sk-proj-...\")\n output_lines.append(\"\")\n output_lines.append(\"📤 Manual upload:\")\n output_lines.append(\" 1. Use OpenAI Assistants API\")\n output_lines.append(f\" 2. Upload package: {workflow_state['zip_path']}\")\n elif target == \"markdown\":\n output_lines.append(\" (No API key needed - markdown is export only)\")\n output_lines.append(f\" Package created: {workflow_state['zip_path']}\")\n else:\n output_lines.append(\n f\" [DRY RUN] Would upload to {adaptor.PLATFORM_NAME} (if API key set)\"\n )\n\n output_lines.append(\"\")\n\n # ===== PHASE 6: Publish to Marketplace (Optional) =====\n marketplace_targets = []\n if marketplace_arg:\n marketplace_targets.append(\n {\"marketplace\": marketplace_arg, \"category\": marketplace_category}\n )\n else:\n cd = workflow_state.get(\"config_data\", {})\n if isinstance(cd, dict):\n marketplace_targets = cd.get(\"marketplace_targets\", [])\n\n if marketplace_targets:\n phase_num = len(workflow_state[\"phases_completed\"]) + 1\n output_lines.append(f\"{'=' * 70}\")\n output_lines.append(\n f\"PHASE {phase_num}: Publish to Marketplace\"\n f\" ({len(marketplace_targets)} target{'s' if len(marketplace_targets) > 1 else ''})\"\n )\n output_lines.append(f\"{'=' * 70}\")\n output_lines.append(\"\")\n\n if not dry_run:\n from .marketplace_tools import publish_to_marketplace_tool\n\n for mp_target in marketplace_targets:\n mp_name = mp_target.get(\"marketplace\", \"\")\n mp_cat = mp_target.get(\"category\", \"development\")\n output_lines.append(f\"Publishing to marketplace '{mp_name}'...\")\n\n try:\n pub_result = await publish_to_marketplace_tool(\n {\n \"skill_dir\": workflow_state[\"skill_dir\"],\n \"marketplace\": mp_name,\n \"category\": mp_cat,\n \"create_branch\": create_branch,\n \"force\": True,\n }\n )\n pub_output = pub_result[0].text if pub_result else \"No output\"\n output_lines.append(pub_output)\n workflow_state[\"phases_completed\"].append(\n f\"publish_to_marketplace({mp_name})\"\n )\n except Exception as e:\n output_lines.append(f\"Failed to publish to '{mp_name}': {str(e)}\")\n output_lines.append(\"\")\n else:\n for mp_target in marketplace_targets:\n mp_name = mp_target.get(\"marketplace\", \"\")\n mp_cat = mp_target.get(\"category\", \"development\")\n output_lines.append(\n f\" [DRY RUN] Would publish to marketplace '{mp_name}' (category: {mp_cat})\"\n )\n output_lines.append(\"\")\n\n # ===== WORKFLOW SUMMARY =====\n output_lines.append(\"=\" * 70)\n output_lines.append(\"✅ WORKFLOW COMPLETE\")\n output_lines.append(\"=\" * 70)\n output_lines.append(\"\")\n\n if not dry_run:\n output_lines.append(\"Phases completed:\")\n for phase in workflow_state[\"phases_completed\"]:\n output_lines.append(f\" ✓ {phase}\")\n output_lines.append(\"\")\n\n output_lines.append(\"📁 Output:\")\n output_lines.append(f\" Skill directory: {workflow_state['skill_dir']}\")\n if workflow_state[\"zip_path\"]:\n output_lines.append(f\" Skill package: {workflow_state['zip_path']}\")\n output_lines.append(\"\")\n\n if auto_upload and has_api_key and target != \"markdown\":\n # Platform-specific success message\n if target == \"claude\":\n output_lines.append(\"🎉 Your skill is now available in Claude!\")\n output_lines.append(\" Go to https://claude.ai/skills to use it\")\n elif target == \"gemini\":\n output_lines.append(\"🎉 Your skill is now available in Gemini!\")\n output_lines.append(\" Go to https://aistudio.google.com/ to use it\")\n elif target == \"openai\":\n output_lines.append(\"🎉 Your assistant is now available in OpenAI!\")\n output_lines.append(\n \" Go to https://platform.openai.com/assistants/ to use it\"\n )\n elif auto_upload:\n output_lines.append(\"📝 Manual upload required (see instructions above)\")\n else:\n output_lines.append(\"📤 To upload:\")\n output_lines.append(\n f\" skill-seekers upload {workflow_state['zip_path']} --target {target}\"\n )\n else:\n output_lines.append(\"This was a dry run. No actions were taken.\")\n output_lines.append(\"\")\n output_lines.append(\"To execute for real, remove the --dry-run flag:\")\n if config_name:\n output_lines.append(f\" install_skill(config_name='{config_name}')\")\n else:\n output_lines.append(f\" install_skill(config_path='{config_path}')\")\n\n return [TextContent(type=\"text\", text=\"\\n\".join(output_lines))]\n\n except Exception as e:\n output_lines.append(\"\")\n output_lines.append(f\"❌ Workflow failed: {str(e)}\")\n output_lines.append(\"\")\n output_lines.append(\"Phases completed before failure:\")\n for phase in workflow_state[\"phases_completed\"]:\n output_lines.append(f\" ✓ {phase}\")\n return [TextContent(type=\"text\", text=\"\\n\".join(output_lines))]\n",
"sha256": "7654385b60889705d98a3cc8e92602d13cadaf920ead26561e7fbb3a349a1fab"
},
".github/tools/external/Skill_Seekers-development/src/skill_seekers/mcp/tools/scraping_tools.py": {
"mode": "100644",
"encoding": "utf-8",
"data": "\"\"\"\nScraping Tools Module for MCP Server\n\nThis module contains all scraping-related MCP tool implementations:\n- estimate_pages_tool: Estimate page count before scraping\n- scrape_docs_tool: Scrape documentation (legacy or unified)\n- scrape_github_tool: Scrape GitHub repositories\n- scrape_pdf_tool: Scrape PDF documentation\n- scrape_codebase_tool: Analyze local codebase and extract code knowledge\n- scrape_generic_tool: Generic scraper for new source types (jupyter, html,\n openapi, asciidoc, pptx, confluence, notion, rss, manpage, chat)\n\nExtracted from server.py for better modularity and organization.\n\"\"\"\n\nimport io\nimport json\nimport logging\nimport sys\nfrom pathlib import Path\n\n# MCP types - with graceful fallback for testing\ntry:\n from mcp.types import TextContent\nexcept ImportError:\n # Graceful degradation: Create a simple fallback class for testing\n class TextContent:\n \"\"\"Fallback TextContent for when MCP is not installed\"\"\"\n\n def __init__(self, type: str, text: str):\n self.type = type\n self.text = text\n\n\n# Path to CLI tools\nCLI_DIR = Path(__file__).parent.parent.parent / \"cli\"\n\n\ndef _run_converter(converter, progress_msg: str) -> list:\n \"\"\"Run a converter in-process with log capture.\n\n Args:\n converter: An initialized SkillConverter instance.\n progress_msg: Progress message to prepend to output.\n\n Returns:\n List[TextContent] with success/error message.\n \"\"\"\n log_capture = io.StringIO()\n handler = logging.StreamHandler(log_capture)\n handler.setLevel(logging.INFO)\n sk_logger = logging.getLogger(\"skill_seekers\")\n sk_logger.addHandler(handler)\n try:\n result = converter.run()\n except Exception as exc:\n captured = log_capture.getvalue()\n return [\n TextContent(\n type=\"text\",\n text=f\"{progress_msg}{captured}\\n\\n❌ Converter raised an exception:\\n{exc}\",\n )\n ]\n finally:\n sk_logger.removeHandler(handler)\n\n captured = log_capture.getvalue()\n output = progress_msg + captured\n\n if result == 0:\n return [TextContent(type=\"text\", text=output)]\n else:\n return [\n TextContent(\n type=\"text\",\n text=f\"{output}\\n\\n❌ Converter returned non-zero exit code ({result})\",\n )\n ]\n\n\ndef run_subprocess_with_streaming(cmd: list[str], timeout: int = None) -> tuple:\n \"\"\"\n Run subprocess with real-time output streaming.\n\n This solves the blocking issue where long-running processes (like scraping)\n would cause MCP to appear frozen. Now we stream output as it comes.\n\n Args:\n cmd: Command list to execute\n timeout: Optional timeout in seconds\n\n Returns:\n Tuple of (stdout, stderr, returncode)\n \"\"\"\n import subprocess\n import time\n\n try:\n process = subprocess.Popen(\n cmd,\n stdout=subprocess.PIPE,\n stderr=subprocess.PIPE,\n text=True,\n bufsize=1, # Line buffered\n universal_newlines=True,\n )\n\n stdout_lines = []\n stderr_lines = []\n start_time = time.time()\n\n # Read output line by line as it comes\n while True:\n # Check timeout\n if timeout and (time.time() - start_time) > timeout:\n process.kill()\n stderr_lines.append(f\"\\n⚠️ Process killed after {timeout}s timeout\")\n break\n\n # Check if process finished\n if process.poll() is not None:\n break\n\n # Read available output (non-blocking)\n try:\n import select\n\n readable, _, _ = select.select([process.stdout, process.stderr], [], [], 0.1)\n\n if process.stdout in readable:\n line = process.stdout.readline()\n if line:\n stdout_lines.append(line)\n\n if process.stderr in readable:\n line = process.stderr.readline()\n if line:\n stderr_lines.append(line)\n except Exception:\n # Fallback for Windows (no select)\n time.sleep(0.1)\n\n # Get any remaining output\n remaining_stdout, remaining_stderr = process.communicate()\n if remaining_stdout:\n stdout_lines.append(remaining_stdout)\n if remaining_stderr:\n stderr_lines.append(remaining_stderr)\n\n stdout = \"\".join(stdout_lines)\n stderr = \"\".join(stderr_lines)\n returncode = process.returncode\n\n return stdout, stderr, returncode\n\n except Exception as e:\n return \"\", f\"Error running subprocess: {str(e)}\", 1\n\n\nasync def estimate_pages_tool(args: dict) -> list[TextContent]:\n \"\"\"\n Estimate page count from a config file.\n\n Performs fast preview without downloading content to estimate\n how many pages will be scraped.\n\n Args:\n args: Dictionary containing:\n - config_path (str): Path to config JSON file\n - max_discovery (int, optional): Maximum pages to discover (default: 1000)\n - unlimited (bool, optional): Remove discovery limit (default: False)\n\n Returns:\n List[TextContent]: Tool execution results\n \"\"\"\n config_path = args[\"config_path\"]\n max_discovery = args.get(\"max_discovery\", 1000)\n unlimited = args.get(\"unlimited\", False)\n\n # Handle unlimited mode\n if unlimited or max_discovery == -1:\n max_discovery = -1\n timeout = 1800 # 30 minutes for unlimited discovery\n else:\n # Estimate: 0.5s per page discovered\n timeout = max(300, max_discovery // 2) # Minimum 5 minutes\n\n # Run estimate_pages module\n cmd = [\n sys.executable,\n \"-m\",\n \"skill_seekers.cli.estimate_pages\",\n config_path,\n \"--max-discovery\",\n str(max_discovery),\n ]\n\n progress_msg = \"🔄 Estimating page count...\\n\"\n progress_msg += f\"⏱️ Maximum time: {timeout // 60} minutes\\n\\n\"\n\n stdout, stderr, returncode = run_subprocess_with_streaming(cmd, timeout=timeout)\n\n output = progress_msg + stdout\n\n if returncode == 0:\n return [TextContent(type=\"text\", text=output)]\n else:\n return [TextContent(type=\"text\", text=f\"{output}\\n\\n❌ Error:\\n{stderr}\")]\n\n\nasync def scrape_docs_tool(args: dict) -> list[TextContent]:\n \"\"\"\n Scrape documentation and build skill.\n\n Auto-detects unified vs legacy format and routes to appropriate scraper.\n Supports both single-source (legacy) and unified multi-source configs.\n Creates SKILL.md and reference files.\n\n Args:\n args: Dictionary containing:\n - config_path (str): Path to config JSON file\n - unlimited (bool, optional): Remove page limit (default: False)\n - enhance_local (bool, optional): Open terminal for local enhancement (default: False)\n - skip_scrape (bool, optional): Skip scraping, use cached data (default: False)\n - dry_run (bool, optional): Preview without saving (default: False)\n - merge_mode (str, optional): Override merge mode for unified configs\n\n Returns:\n List[TextContent]: Tool execution results\n \"\"\"\n config_path = args[\"config_path\"]\n unlimited = args.get(\"unlimited\", False)\n dry_run = args.get(\"dry_run\", False)\n merge_mode = args.get(\"merge_mode\")\n\n # Load config to detect format\n with open(config_path) as f:\n config = json.load(f)\n\n # Detect if unified format (has 'sources' array)\n is_unified = \"sources\" in config and isinstance(config[\"sources\"], list)\n\n # Handle unlimited mode by modifying config temporarily\n if unlimited:\n # Set max_pages to None (unlimited)\n if is_unified:\n # For unified configs, set max_pages on documentation sources\n for source in config.get(\"sources\", []):\n if source.get(\"type\") == \"documentation\":\n source[\"max_pages\"] = None\n else:\n # For legacy configs\n config[\"max_pages\"] = None\n\n # Create temporary config file\n temp_config_path = config_path.replace(\".json\", \"_unlimited_temp.json\")\n with open(temp_config_path, \"w\") as f:\n json.dump(config, f, indent=2)\n\n config_to_use = temp_config_path\n else:\n config_to_use = config_path\n\n # Build progress message\n if is_unified:\n progress_msg = \"🔄 Starting unified multi-source scraping...\\n\"\n progress_msg += \"📦 Config format: Unified (multiple sources)\\n\"\n else:\n progress_msg = \"🔄 Starting scraping process...\\n\"\n progress_msg += \"📦 Config format: Legacy (single source)\\n\"\n\n progress_msg += \"📝 Progress will be shown below:\\n\\n\"\n\n # Run converter in-process\n try:\n if is_unified:\n from skill_seekers.cli.unified_scraper import UnifiedScraper\n\n converter = UnifiedScraper(config_to_use, merge_mode=merge_mode)\n else:\n from skill_seekers.cli.skill_converter import get_converter\n\n # For legacy format, detect type from config keys\n with open(config_to_use) as f:\n config_to_pass = json.load(f)\n\n # Detect source type from config content\n if \"base_url\" in config_to_pass:\n source_type = \"web\"\n elif \"repo\" in config_to_pass:\n source_type = \"github\"\n elif \"pdf_path\" in config_to_pass:\n source_type = \"pdf\"\n elif \"directory\" in config_to_pass:\n source_type = \"local\"\n else:\n source_type = \"web\" # default fallback\n\n converter = get_converter(source_type, config_to_pass)\n if dry_run:\n converter.dry_run = True\n\n result = _run_converter(converter, progress_msg)\n finally:\n # Clean up temporary config\n if unlimited and Path(config_to_use).exists():\n Path(config_to_use).unlink()\n\n return result\n\n\nasync def scrape_pdf_tool(args: dict) -> list[TextContent]:\n \"\"\"\n Scrape PDF documentation and build Claude skill.\n\n Extracts text, code, and images from PDF files and builds\n a skill package with organized references.\n\n Args:\n args: Dictionary containing:\n - config_path (str, optional): Path to PDF config JSON file\n - pdf_path (str, optional): Direct PDF path (alternative to config_path)\n - name (str, optional): Skill name (required with pdf_path)\n - description (str, optional): Skill description\n - from_json (str, optional): Build from extracted JSON file\n\n Returns:\n List[TextContent]: Tool execution results\n \"\"\"\n config_path = args.get(\"config_path\")\n pdf_path = args.get(\"pdf_path\")\n name = args.get(\"name\")\n description = args.get(\"description\")\n from_json = args.get(\"from_json\")\n\n progress_msg = \"📄 Scraping PDF documentation...\\n\\n\"\n\n # Mode 1: Config file\n if config_path:\n with open(config_path) as f:\n pdf_config = json.load(f)\n\n # Mode 2: Direct PDF\n elif pdf_path and name:\n pdf_config = {\"name\": name, \"pdf_path\": pdf_path}\n if description:\n pdf_config[\"description\"] = description\n\n # Mode 3: From JSON — use PDFToSkillConverter.load_extracted_data\n elif from_json:\n from skill_seekers.cli.pdf_scraper import PDFToSkillConverter\n\n # Build a minimal config; name is derived from the JSON filename\n json_name = Path(from_json).stem.replace(\"_extracted\", \"\")\n pdf_config = {\"name\": json_name}\n converter = PDFToSkillConverter(pdf_config)\n converter.load_extracted_data(from_json)\n converter.build_skill()\n return [\n TextContent(\n type=\"text\",\n text=f\"{progress_msg}✅ Skill built from extracted JSON: {from_json}\",\n )\n ]\n\n else:\n return [\n TextContent(\n type=\"text\",\n text=\"❌ Error: Must specify --config, --pdf + --name, or --from-json\",\n )\n ]\n\n from skill_seekers.cli.skill_converter import get_converter\n\n converter = get_converter(\"pdf\", pdf_config)\n return _run_converter(converter, progress_msg)\n\n\nasync def scrape_video_tool(args: dict) -> list[TextContent]:\n \"\"\"\n Scrape video content (YouTube, local files) and build Claude skill.\n\n Extracts transcripts, metadata, and optionally visual content from videos\n to create skills.\n\n Args:\n args: Dictionary containing:\n - url (str, optional): Video URL (YouTube, Vimeo)\n - video_file (str, optional): Local video file path\n - playlist (str, optional): Playlist URL\n - name (str, optional): Skill name\n - description (str, optional): Skill description\n - languages (str, optional): Language preferences (comma-separated)\n - from_json (str, optional): Build from extracted JSON file\n - visual (bool, optional): Enable visual frame extraction (default: False)\n - whisper_model (str, optional): Whisper model size (default: base)\n - visual_interval (float, optional): Seconds between frame captures (default: 5.0)\n - visual_min_gap (float, optional): Minimum seconds between kept frames (default: 2.0)\n - visual_similarity (float, optional): Similarity threshold to skip duplicate frames (default: 0.95)\n - vision_ocr (bool, optional): Use vision model for OCR on frames (default: False)\n - start_time (str, optional): Start time for extraction (seconds, MM:SS, or HH:MM:SS)\n - end_time (str, optional): End time for extraction (seconds, MM:SS, or HH:MM:SS)\n - setup (bool, optional): Auto-detect GPU and install visual extraction deps\n\n Returns:\n List[TextContent]: Tool execution results\n \"\"\"\n # Handle --setup early exit\n if args.get(\"setup\", False):\n from skill_seekers.cli.video_setup import run_setup\n\n rc = run_setup(interactive=False)\n msg = \"Setup completed successfully.\" if rc == 0 else \"Setup failed. Check logs.\"\n return [TextContent(type=\"text\", text=msg)]\n\n url = args.get(\"url\")\n video_file = args.get(\"video_file\")\n playlist = args.get(\"playlist\")\n name = args.get(\"name\")\n description = args.get(\"description\")\n languages = args.get(\"languages\")\n from_json = args.get(\"from_json\")\n visual = args.get(\"visual\", False)\n whisper_model = args.get(\"whisper_model\")\n visual_interval = args.get(\"visual_interval\")\n visual_min_gap = args.get(\"visual_min_gap\")\n visual_similarity = args.get(\"visual_similarity\")\n vision_ocr = args.get(\"vision_ocr\", False)\n start_time = args.get(\"start_time\")\n end_time = args.get(\"end_time\")\n\n # Build config dict for the converter\n video_config: dict = {}\n\n if from_json:\n video_config[\"from_json\"] = from_json\n video_config[\"name\"] = name or Path(from_json).stem.replace(\"_video_extracted\", \"\")\n elif url:\n video_config[\"url\"] = url\n if not name:\n return [TextContent(type=\"text\", text=\"❌ Error: --name is required with --url\")]\n video_config[\"name\"] = name\n elif video_file:\n video_config[\"video_file\"] = video_file\n video_config[\"name\"] = name or Path(video_file).stem\n elif playlist:\n video_config[\"playlist\"] = playlist\n video_config[\"name\"] = name or \"playlist\"\n else:\n return [\n TextContent(\n type=\"text\",\n text=\"❌ Error: Must specify --url, --video-file, --playlist, or --from-json\",\n )\n ]\n\n if description:\n video_config[\"description\"] = description\n if languages:\n video_config[\"languages\"] = languages\n video_config[\"visual\"] = visual\n if whisper_model:\n video_config[\"whisper_model\"] = whisper_model\n if visual_interval is not None:\n video_config[\"visual_interval\"] = visual_interval\n if visual_min_gap is not None:\n video_config[\"visual_min_gap\"] = visual_min_gap\n if visual_similarity is not None:\n video_config[\"visual_similarity\"] = visual_similarity\n video_config[\"vision_ocr\"] = vision_ocr\n if start_time:\n video_config[\"start_time\"] = start_time\n if end_time:\n video_config[\"end_time\"] = end_time\n\n progress_msg = \"🎬 Scraping video content...\\n\\n\"\n\n from skill_seekers.cli.skill_converter import get_converter\n\n converter = get_converter(\"video\", video_config)\n return _run_converter(converter, progress_msg)\n\n\nasync def scrape_github_tool(args: dict) -> list[TextContent]:\n \"\"\"\n Scrape GitHub repository and build Claude skill.\n\n Extracts README, Issues, Changelog, Releases, and code structure\n from GitHub repositories to create comprehensive skills.\n\n Args:\n args: Dictionary containing:\n - repo (str, optional): GitHub repository (owner/repo)\n - config_path (str, optional): Path to GitHub config JSON file\n - name (str, optional): Skill name (default: repo name)\n - description (str, optional): Skill description\n - token (str, optional): GitHub personal access token\n - no_issues (bool, optional): Skip GitHub issues extraction (default: False)\n - no_changelog (bool, optional): Skip CHANGELOG extraction (default: False)\n - no_releases (bool, optional): Skip releases extraction (default: False)\n - max_issues (int, optional): Maximum issues to fetch (default: 100)\n - scrape_only (bool, optional): Only scrape, don't build skill (default: False)\n\n Returns:\n List[TextContent]: Tool execution results\n \"\"\"\n repo = args.get(\"repo\")\n config_path = args.get(\"config_path\")\n name = args.get(\"name\")\n description = args.get(\"description\")\n token = args.get(\"token\")\n no_issues = args.get(\"no_issues\", False)\n no_changelog = args.get(\"no_changelog\", False)\n no_releases = args.get(\"no_releases\", False)\n max_issues = args.get(\"max_issues\", 100)\n scrape_only = args.get(\"scrape_only\", False)\n\n # Build config dict for the converter\n if config_path:\n with open(config_path) as f:\n github_config = json.load(f)\n elif repo:\n github_config: dict = {\"repo\": repo}\n if name:\n github_config[\"name\"] = name\n if description:\n github_config[\"description\"] = description\n if token:\n github_config[\"token\"] = token\n if no_issues:\n github_config[\"no_issues\"] = True\n if no_changelog:\n github_config[\"no_changelog\"] = True\n if no_releases:\n github_config[\"no_releases\"] = True\n if max_issues != 100:\n github_config[\"max_issues\"] = max_issues\n if scrape_only:\n github_config[\"scrape_only\"] = True\n else:\n return [TextContent(type=\"text\", text=\"❌ Error: Must specify --repo or --config\")]\n\n progress_msg = \"🐙 Scraping GitHub repository...\\n\\n\"\n\n from skill_seekers.cli.skill_converter import get_converter\n\n converter = get_converter(\"github\", github_config)\n return _run_converter(converter, progress_msg)\n\n\nasync def scrape_codebase_tool(args: dict) -> list[TextContent]:\n \"\"\"\n Analyze local codebase and extract code knowledge.\n\n Walks directory tree, analyzes code files, extracts signatures,\n docstrings, and generates API reference documentation, dependency graphs,\n design patterns, test examples, and how-to guides.\n\n All features are ON by default. Use skip_* parameters to disable specific features.\n\n Args:\n args: Dictionary containing:\n - directory (str): Directory to analyze\n - output (str, optional): Output directory for results (default: output/codebase/)\n - depth (str, optional): Analysis depth - surface, deep, full (default: deep)\n - languages (str, optional): Comma-separated languages (e.g., \"Python,JavaScript,C++\")\n - file_patterns (str, optional): Comma-separated file patterns (e.g., \"*.py,src/**/*.js\")\n - enhance_level (int, optional): AI enhancement level 0-3 (default: 0)\n - 0: No AI enhancement\n - 1: SKILL.md enhancement only\n - 2: SKILL.md + Architecture + Config enhancement\n - 3: Full enhancement (patterns, tests, config, architecture, SKILL.md)\n - skip_api_reference (bool, optional): Skip API reference generation (default: False)\n - skip_dependency_graph (bool, optional): Skip dependency graph (default: False)\n - skip_patterns (bool, optional): Skip design pattern detection (default: False)\n - skip_test_examples (bool, optional): Skip test example extraction (default: False)\n - skip_how_to_guides (bool, optional): Skip how-to guide generation (default: False)\n - skip_config_patterns (bool, optional): Skip config pattern extraction (default: False)\n - skip_docs (bool, optional): Skip project documentation extraction (default: False)\n\n Returns:\n List[TextContent]: Tool execution results\n\n Example:\n scrape_codebase(\n directory=\"/path/to/repo\",\n depth=\"deep\",\n enhance_level=1\n )\n scrape_codebase(\n directory=\"/path/to/repo\",\n enhance_level=2,\n skip_patterns=True\n )\n \"\"\"\n directory = args.get(\"directory\")\n if not directory:\n return [TextContent(type=\"text\", text=\"❌ Error: directory parameter is required\")]\n\n output_dir = args.get(\"output\", \"output/codebase/\")\n depth = args.get(\"depth\", \"deep\")\n languages = args.get(\"languages\", \"\")\n file_patterns = args.get(\"file_patterns\", \"\")\n enhance_level = args.get(\"enhance_level\", 0)\n\n # Skip flags (features are ON by default)\n skip_api_reference = args.get(\"skip_api_reference\", False)\n skip_dependency_graph = args.get(\"skip_dependency_graph\", False)\n skip_patterns = args.get(\"skip_patterns\", False)\n skip_test_examples = args.get(\"skip_test_examples\", False)\n skip_how_to_guides = args.get(\"skip_how_to_guides\", False)\n skip_config_patterns = args.get(\"skip_config_patterns\", False)\n skip_docs = args.get(\"skip_docs\", False)\n\n # Derive a name from the directory for the converter\n dir_name = Path(directory).resolve().name or \"codebase\"\n\n # Build config dict for CodebaseAnalyzer\n codebase_config: dict = {\n \"name\": dir_name,\n \"directory\": directory,\n \"output_dir\": output_dir,\n \"depth\": depth,\n \"enhance_level\": enhance_level,\n \"build_api_reference\": not skip_api_reference,\n \"build_dependency_graph\": not skip_dependency_graph,\n \"detect_patterns\": not skip_patterns,\n \"extract_test_examples\": not skip_test_examples,\n \"build_how_to_guides\": not skip_how_to_guides,\n \"extract_config_patterns\": not skip_config_patterns,\n \"extract_docs\": not skip_docs,\n }\n if languages:\n codebase_config[\"languages\"] = languages\n if file_patterns:\n codebase_config[\"file_patterns\"] = file_patterns\n\n level_names = {0: \"off\", 1: \"SKILL.md only\", 2: \"standard\", 3: \"full\"}\n progress_msg = \"🔍 Analyzing local codebase...\\n\"\n progress_msg += f\"📁 Directory: {directory}\\n\"\n progress_msg += f\"📊 Depth: {depth}\\n\"\n if enhance_level > 0:\n progress_msg += f\"🤖 AI Enhancement: Level {enhance_level} ({level_names.get(enhance_level, 'unknown')})\\n\"\n progress_msg += \"\\n\"\n\n from skill_seekers.cli.skill_converter import get_converter\n\n converter = get_converter(\"local\", codebase_config)\n return _run_converter(converter, progress_msg)\n\n\nasync def detect_patterns_tool(args: dict) -> list[TextContent]:\n \"\"\"\n Detect design patterns in source code.\n\n Analyzes source files or directories to detect common design patterns\n (Singleton, Factory, Observer, Strategy, Decorator, Builder, Adapter,\n Command, Template Method, Chain of Responsibility).\n\n Supports 9 languages: Python, JavaScript, TypeScript, C++, C, C#,\n Go, Rust, Java, Ruby, PHP.\n\n Args:\n args: Dictionary containing:\n - file (str, optional): Single file to analyze\n - directory (str, optional): Directory to analyze (analyzes all source files)\n - output (str, optional): Output directory for JSON results\n - depth (str, optional): Detection depth - surface, deep, full (default: deep)\n - json (bool, optional): Output JSON format (default: False)\n\n Returns:\n List[TextContent]: Pattern detection results\n\n Example:\n detect_patterns(file=\"src/database.py\", depth=\"deep\")\n detect_patterns(directory=\"src/\", output=\"patterns/\", json=True)\n \"\"\"\n file_path = args.get(\"file\")\n directory = args.get(\"directory\")\n\n if not file_path and not directory:\n return [\n TextContent(\n type=\"text\", text=\"❌ Error: Must specify either 'file' or 'directory' parameter\"\n )\n ]\n\n output = args.get(\"output\", \"\")\n depth = args.get(\"depth\", \"deep\")\n json_output = args.get(\"json\", False)\n\n # Build command\n cmd = [sys.executable, \"-m\", \"skill_seekers.cli.pattern_recognizer\"]\n\n if file_path:\n cmd.extend([\"--file\", file_path])\n if directory:\n cmd.extend([\"--directory\", directory])\n if output:\n cmd.extend([\"--output\", output])\n if depth:\n cmd.extend([\"--depth\", depth])\n if json_output:\n cmd.append(\"--json\")\n\n timeout = 300 # 5 minutes for pattern detection\n\n progress_msg = \"🔍 Detecting design patterns...\\n\"\n if file_path:\n progress_msg += f\"📄 File: {file_path}\\n\"\n if directory:\n progress_msg += f\"📁 Directory: {directory}\\n\"\n progress_msg += f\"🎯 Detection depth: {depth}\\n\"\n progress_msg += f\"⏱️ Maximum time: {timeout // 60} minutes\\n\\n\"\n\n stdout, stderr, returncode = run_subprocess_with_streaming(cmd, timeout=timeout)\n\n output_text = progress_msg + stdout\n\n if returncode == 0:\n return [TextContent(type=\"text\", text=output_text)]\n else:\n return [TextContent(type=\"text\", text=f\"{output_text}\\n\\n❌ Error:\\n{stderr}\")]\n\n\nasync def extract_test_examples_tool(args: dict) -> list[TextContent]:\n \"\"\"\n Extract usage examples from test files.\n\n Analyzes test files to extract real API usage patterns including:\n - Object instantiation with real parameters\n - Method calls with expected behaviors\n - Configuration examples\n - Setup patterns from fixtures/setUp()\n - Multi-step workflows from integration tests\n\n Supports 9 languages: Python (AST-based deep analysis), JavaScript,\n TypeScript, Go, Rust, Java, C#, PHP, Ruby (regex-based).\n\n Args:\n args: Dictionary containing:\n - file (str, optional): Single test file to analyze\n - directory (str, optional): Directory containing test files\n - language (str, optional): Filter by language (python, javascript, etc.)\n - min_confidence (float, optional): Minimum confidence threshold 0.0-1.0 (default: 0.5)\n - max_per_file (int, optional): Maximum examples per file (default: 10)\n - json (bool, optional): Output JSON format (default: False)\n - markdown (bool, optional): Output Markdown format (default: False)\n\n Returns:\n List[TextContent]: Extracted test examples\n\n Example:\n extract_test_examples(directory=\"tests/\", language=\"python\")\n extract_test_examples(file=\"tests/test_scraper.py\", json=True)\n \"\"\"\n file_path = args.get(\"file\")\n directory = args.get(\"directory\")\n\n if not file_path and not directory:\n return [\n TextContent(\n type=\"text\", text=\"❌ Error: Must specify either 'file' or 'directory' parameter\"\n )\n ]\n\n language = args.get(\"language\", \"\")\n min_confidence = args.get(\"min_confidence\", 0.5)\n max_per_file = args.get(\"max_per_file\", 10)\n json_output = args.get(\"json\", False)\n markdown_output = args.get(\"markdown\", False)\n\n # Build command\n cmd = [sys.executable, \"-m\", \"skill_seekers.cli.test_example_extractor\"]\n\n if directory:\n cmd.append(directory)\n if file_path:\n cmd.extend([\"--file\", file_path])\n if language:\n cmd.extend([\"--language\", language])\n if min_confidence:\n cmd.extend([\"--min-confidence\", str(min_confidence)])\n if max_per_file:\n cmd.extend([\"--max-per-file\", str(max_per_file)])\n if json_output:\n cmd.append(\"--json\")\n if markdown_output:\n cmd.append(\"--markdown\")\n\n timeout = 180 # 3 minutes for test example extraction\n\n progress_msg = \"🧪 Extracting usage examples from test files...\\n\"\n if file_path:\n progress_msg += f\"📄 File: {file_path}\\n\"\n if directory:\n progress_msg += f\"📁 Directory: {directory}\\n\"\n if language:\n progress_msg += f\"🔤 Language: {language}\\n\"\n progress_msg += f\"🎯 Min confidence: {min_confidence}\\n\"\n progress_msg += f\"📊 Max per file: {max_per_file}\\n\"\n progress_msg += f\"⏱️ Maximum time: {timeout // 60} minutes\\n\\n\"\n\n stdout, stderr, returncode = run_subprocess_with_streaming(cmd, timeout=timeout)\n\n output_text = progress_msg + stdout\n\n if returncode == 0:\n return [TextContent(type=\"text\", text=output_text)]\n else:\n return [TextContent(type=\"text\", text=f\"{output_text}\\n\\n❌ Error:\\n{stderr}\")]\n\n\nasync def build_how_to_guides_tool(args: dict) -> list[TextContent]:\n \"\"\"\n Build how-to guides from workflow test examples.\n\n Transforms workflow examples extracted from test files into step-by-step\n educational guides. Automatically groups related workflows, extracts steps,\n and generates comprehensive markdown guides.\n\n Features:\n - Python AST-based step extraction (heuristic for other languages)\n - 4 grouping strategies: ai-tutorial-group, file-path, test-name, complexity\n - Detects prerequisites, setup code, and verification points\n - Generates troubleshooting tips and next steps\n - Creates index with difficulty levels\n\n Args:\n args: Dictionary containing:\n - input (str): Path to test_examples.json from extract_test_examples\n - output (str, optional): Output directory for guides (default: output/codebase/tutorials)\n - group_by (str, optional): Grouping strategy - ai-tutorial-group, file-path, test-name, complexity\n - no_ai (bool, optional): Disable AI enhancement for grouping (default: False)\n - json_output (bool, optional): Output JSON format alongside markdown (default: False)\n\n Returns:\n List[TextContent]: Guide building results\n\n Example:\n build_how_to_guides(\n input=\"output/codebase/test_examples/test_examples.json\",\n group_by=\"ai-tutorial-group\",\n output=\"output/codebase/tutorials\"\n )\n \"\"\"\n input_file = args.get(\"input\")\n if not input_file:\n return [\n TextContent(\n type=\"text\",\n text=\"❌ Error: input parameter is required (path to test_examples.json)\",\n )\n ]\n\n output = args.get(\"output\", \"output/codebase/tutorials\")\n group_by = args.get(\"group_by\", \"ai-tutorial-group\")\n no_ai = args.get(\"no_ai\", False)\n json_output = args.get(\"json_output\", False)\n\n # Build command\n cmd = [sys.executable, \"-m\", \"skill_seekers.cli.how_to_guide_builder\"]\n cmd.append(input_file)\n\n if output:\n cmd.extend([\"--output\", output])\n if group_by:\n cmd.extend([\"--group-by\", group_by])\n if no_ai:\n cmd.append(\"--no-ai\")\n if json_output:\n cmd.append(\"--json-output\")\n\n timeout = 180 # 3 minutes for guide building\n\n progress_msg = \"📚 Building how-to guides from workflow examples...\\n\"\n progress_msg += f\"📄 Input: {input_file}\\n\"\n progress_msg += f\"📁 Output: {output}\\n\"\n progress_msg += f\"🔀 Grouping: {group_by}\\n\"\n if no_ai:\n progress_msg += \"🚫 AI enhancement disabled\\n\"\n progress_msg += f\"⏱️ Maximum time: {timeout // 60} minutes\\n\\n\"\n\n stdout, stderr, returncode = run_subprocess_with_streaming(cmd, timeout=timeout)\n\n output_text = progress_msg + stdout\n\n if returncode == 0:\n return [TextContent(type=\"text\", text=output_text)]\n else:\n return [TextContent(type=\"text\", text=f\"{output_text}\\n\\n❌ Error:\\n{stderr}\")]\n\n\nasync def extract_config_patterns_tool(args: dict) -> list[TextContent]:\n \"\"\"\n Extract configuration patterns from config files (C3.4).\n\n Analyzes configuration files in the codebase to extract settings,\n detect common patterns (database, API, logging, cache, etc.), and\n generate comprehensive documentation.\n\n Supports 9 config formats: JSON, YAML, TOML, ENV, INI, Python modules,\n JavaScript/TypeScript configs, Dockerfile, Docker Compose.\n\n Detects 7 common patterns:\n - Database configuration (host, port, credentials)\n - API configuration (endpoints, keys, timeouts)\n - Logging configuration (level, format, handlers)\n - Cache configuration (backend, TTL, keys)\n - Email configuration (SMTP, credentials)\n - Authentication configuration (providers, secrets)\n - Server configuration (host, port, workers)\n\n Args:\n args: Dictionary containing:\n - directory (str): Directory to analyze\n - output (str, optional): Output directory (default: output/codebase/config_patterns)\n - max_files (int, optional): Maximum config files to process (default: 100)\n - enhance (bool, optional): Enable AI enhancement - API mode (default: False, requires ANTHROPIC_API_KEY)\n - enhance_local (bool, optional): Enable AI enhancement - LOCAL mode (default: False, uses Claude Code CLI)\n - ai_mode (str, optional): AI mode - auto, api, local, none (default: none)\n - json (bool, optional): Output JSON format (default: True)\n - markdown (bool, optional): Output Markdown format (default: True)\n\n Returns:\n List[TextContent]: Config extraction results with optional AI enhancements\n\n Example:\n extract_config_patterns(directory=\".\", output=\"output/configs\")\n extract_config_patterns(directory=\"/path/to/repo\", max_files=50, enhance_local=True)\n \"\"\"\n directory = args.get(\"directory\")\n if not directory:\n return [TextContent(type=\"text\", text=\"❌ Error: directory parameter is required\")]\n\n output = args.get(\"output\", \"output/codebase/config_patterns\")\n max_files = args.get(\"max_files\", 100)\n enhance = args.get(\"enhance\", False)\n enhance_local = args.get(\"enhance_local\", False)\n ai_mode = args.get(\"ai_mode\", \"none\")\n json_output = args.get(\"json\", True)\n markdown_output = args.get(\"markdown\", True)\n\n # Build command\n cmd = [sys.executable, \"-m\", \"skill_seekers.cli.config_extractor\"]\n cmd.extend([\"--directory\", directory])\n\n if output:\n cmd.extend([\"--output\", output])\n if max_files:\n cmd.extend([\"--max-files\", str(max_files)])\n if enhance:\n cmd.append(\"--enhance\")\n if enhance_local:\n cmd.append(\"--enhance-local\")\n if ai_mode and ai_mode != \"none\":\n cmd.extend([\"--ai-mode\", ai_mode])\n if json_output:\n cmd.append(\"--json\")\n if markdown_output:\n cmd.append(\"--markdown\")\n\n # Adjust timeout for AI enhancement\n timeout = 180 # 3 minutes base\n if enhance or enhance_local or ai_mode != \"none\":\n timeout = 360 # 6 minutes with AI enhancement\n\n progress_msg = \"⚙️ Extracting configuration patterns...\\n\"\n progress_msg += f\"📁 Directory: {directory}\\n\"\n progress_msg += f\"📄 Max files: {max_files}\\n\"\n if enhance or enhance_local or (ai_mode and ai_mode != \"none\"):\n progress_msg += f\"🤖 AI enhancement: {ai_mode if ai_mode != 'none' else ('api' if enhance else 'local')}\\n\"\n progress_msg += f\"⏱️ Maximum time: {timeout // 60} minutes\\n\\n\"\n\n stdout, stderr, returncode = run_subprocess_with_streaming(cmd, timeout=timeout)\n\n output_text = progress_msg + stdout\n\n if returncode == 0:\n return [TextContent(type=\"text\", text=output_text)]\n else:\n return [TextContent(type=\"text\", text=f\"{output_text}\\n\\n❌ Error:\\n{stderr}\")]\n\n\n# Valid source types for the generic scraper\nGENERIC_SOURCE_TYPES = (\n \"jupyter\",\n \"html\",\n \"openapi\",\n \"asciidoc\",\n \"pptx\",\n \"confluence\",\n \"notion\",\n \"rss\",\n \"manpage\",\n \"chat\",\n)\n\n# Mapping from source type to the CLI flag used for the primary input argument.\n# URL-based types use --url; file/path-based types use --path.\n_URL_BASED_TYPES = {\"confluence\", \"notion\", \"rss\"}\n\n# Friendly emoji labels per source type\n_SOURCE_EMOJIS = {\n \"jupyter\": \"📓\",\n \"html\": \"🌐\",\n \"openapi\": \"📡\",\n \"asciidoc\": \"📄\",\n \"pptx\": \"📊\",\n \"confluence\": \"🏢\",\n \"notion\": \"📝\",\n \"rss\": \"📰\",\n \"manpage\": \"📖\",\n \"chat\": \"💬\",\n}\n\n\nasync def scrape_generic_tool(args: dict) -> list[TextContent]:\n \"\"\"\n Generic scraper for new source types.\n\n Handles all 10 new source types by building the appropriate subprocess\n command and delegating to the corresponding CLI scraper module.\n\n Supported source types: jupyter, html, openapi, asciidoc, pptx,\n confluence, notion, rss, manpage, chat.\n\n Args:\n args: Dictionary containing:\n - source_type (str): One of the supported source types\n - path (str, optional): File or directory path (for file-based sources)\n - url (str, optional): URL (for URL-based sources like confluence, notion, rss)\n - name (str): Skill name for the output\n\n Returns:\n List[TextContent]: Tool execution results\n \"\"\"\n source_type = args.get(\"source_type\", \"\")\n path = args.get(\"path\")\n url = args.get(\"url\")\n name = args.get(\"name\")\n\n # Validate source_type\n if source_type not in GENERIC_SOURCE_TYPES:\n return [\n TextContent(\n type=\"text\",\n text=(\n f\"❌ Error: Unknown source_type '{source_type}'. \"\n f\"Must be one of: {', '.join(GENERIC_SOURCE_TYPES)}\"\n ),\n )\n ]\n\n # Validate that we have either path or url\n if not path and not url:\n return [\n TextContent(\n type=\"text\",\n text=\"❌ Error: Must specify either 'path' (file/directory) or 'url'\",\n )\n ]\n\n if not name:\n return [\n TextContent(\n type=\"text\",\n text=\"❌ Error: 'name' parameter is required\",\n )\n ]\n\n # Build config dict for the converter — map MCP args to the keys\n # each converter expects in its __init__.\n _CONFIG_KEY: dict[str, str] = {\n \"jupyter\": \"notebook_path\",\n \"html\": \"html_path\",\n \"openapi\": \"spec_path\",\n \"asciidoc\": \"asciidoc_path\",\n \"pptx\": \"pptx_path\",\n \"manpage\": \"man_path\",\n \"confluence\": \"export_path\",\n \"notion\": \"export_path\",\n \"rss\": \"feed_path\",\n \"chat\": \"export_path\",\n }\n _URL_CONFIG_KEY: dict[str, str] = {\n \"confluence\": \"base_url\",\n \"notion\": \"page_id\",\n \"rss\": \"feed_url\",\n \"openapi\": \"spec_url\",\n }\n\n config: dict = {\"name\": name}\n\n if source_type in _URL_BASED_TYPES and url:\n config[_URL_CONFIG_KEY.get(source_type, \"url\")] = url\n elif path:\n config[_CONFIG_KEY.get(source_type, \"path\")] = path\n elif url:\n config[_URL_CONFIG_KEY.get(source_type, \"url\")] = url\n\n emoji = _SOURCE_EMOJIS.get(source_type, \"🔧\")\n progress_msg = f\"{emoji} Scraping {source_type} source...\\n\"\n if path:\n progress_msg += f\"📁 Path: {path}\\n\"\n if url:\n progress_msg += f\"🔗 URL: {url}\\n\"\n progress_msg += f\"📛 Name: {name}\\n\\n\"\n\n from skill_seekers.cli.skill_converter import get_converter\n\n converter = get_converter(source_type, config)\n return _run_converter(converter, progress_msg)\n",
"sha256": "0073daae89b191d907fb080daf78f044d55d6890a8c929e7dcdc10c9ff19a735"
},
".github/skills/auto-tmux/assets/oh-my-tmux": {
"mode": "120000",
"encoding": "utf-8",
"data": "../../../tools/external/.tmux",
"sha256": "dbf4ed04f7cb24b681ce652bfda4daaa5ebf3a7adcf6737fb1e96e1b33028744"
},
".github/skills/auto-tmux/assets/tmux-src": {
"mode": "120000",
"encoding": "utf-8",
"data": "../../../tools/external/tmux",
"sha256": "a8726831a2fb948341a0a650689ceac80b10689f345502c8c291e45373fde129"
},
".gitmodules": {
"mode": "100644",
"encoding": "utf-8",
"data": "[submodule \"tools/external/.tmux\"]\n\tpath = .github/tools/external/.tmux\n\turl = https://github.com/gpakosz/.tmux.git\n[submodule \"tools/external/tmux\"]\n\tpath = .github/tools/external/tmux\n\turl = https://github.com/tmux/tmux.git\n[submodule \"tools/external/claude-official-skills\"]\n\tpath = .github/tools/external/claude-official-skills\n\turl = https://github.com/anthropics/skills.git\n[submodule \"tools/external/Skill_Seekers-development\"]\n\tpath = .github/tools/external/Skill_Seekers-development\n\turl = https://github.com/yusufkaraaslan/Skill_Seekers.git\n",
"sha256": "068c1b0ead3390e7ea9144656fa4606697a4e81ec9f8d20adc78de4560690f0d"
}
},
"locations": {
".github/tools/chat-vault": ".github/extensions/chat-vault",
".github/tools/prompts-library": ".github/extensions/prompts-library",
".github/tools/config/.codex": ".github/extensions/codex-config/.codex",
".github/tools/external/.tmux": ".github/extensions/oh-my-tmux",
".github/tools/external/tmux": ".github/extensions/tmux",
".github/tools/external/claude-official-skills": ".github/extensions/claude-official-skills",
".github/tools/external/Skill_Seekers-development": ".github/extensions/Skill_Seekers-development",
".github/tools/external/MCPlayerTransfer": ".github/extensions/MCPlayerTransfer",
".github/tools/external/XHS-image-to-PDF-conversion": ".github/extensions/XHS-image-to-PDF-conversion",
".github/tools/external/my-nvim": ".github/extensions/my-nvim",
".github/skills/auto-skill": ".github/skills/auto-skill",
".github/skills/auto-tmux": ".github/skills/auto-tmux",
".github/assets/external-resources": ".github/context/external-resources",
".github/tools/prompts-library/README.md": ".github/extensions/prompts-library/README.md",
".github/tools/prompts-library/main.py": ".github/extensions/prompts-library/main.py",
".github/tools/chat-vault/README.md": ".github/extensions/chat-vault/README.md",
".github/tools/chat-vault/services/chat-vault/src/main.py": ".github/extensions/chat-vault/services/chat-vault/src/main.py",
".github/tools/config/.codex/README.md": ".github/extensions/codex-config/.codex/README.md",
".github/tools/config/.codex/install.sh": ".github/extensions/codex-config/.codex/install.sh",
".github/skills/auto-skill/README.md": ".github/skills/auto-skill/README.md",
".github/skills/auto-skill/scripts/create-skill.sh": ".github/extensions/create-skill.sh",
".github/skills/auto-skill/scripts/validate-skill.sh": ".github/extensions/validate-skill.sh",
".github/skills/auto-skill/scripts/skill-seekers.sh": ".github/extensions/skill-seekers.sh",
".github/skills/auto-tmux/README.md": ".github/skills/auto-tmux/README.md",
".github/skills/auto-tmux/scripts/auto-tmux.sh": ".github/extensions/auto-tmux/auto-tmux.sh",
".github/tools/external/html-tools-main/README.md": ".github/extensions/html-tools-main.md",
".github/tools/external/html-tools-main/clean_epub_css.html": ".github/extensions/clean_epub_css.html",
".github/tools/external/html-tools-main/markdown-bianjiqi.html": ".github/extensions/markdown-bianjiqi.html",
".github/tools/external/html-tools-main/task card generator.html": ".github/extensions/task card generator.html",
".github/tools/external/html-tools-main/xhs graphic production.html": ".github/extensions/xhs graphic production.html",
".github/tools/external/html-tools-main/xhs graphic production - 1.0.html": ".github/extensions/xhs graphic production - 1.0.html",
".github/tools/external/my-nvim/README.md": ".github/extensions/my-nvim/README.md",
".github/tools/external/my-nvim/nvim-config/init.lua": ".github/extensions/my-nvim/nvim-config/init.lua",
".github/tools/external/my-nvim/nvim-config/lua/config/lazy.lua": ".github/extensions/my-nvim/nvim-config/lua/config/lazy.lua",
".github/tools/external/MCPlayerTransfer/README.md": ".github/extensions/MCPlayerTransfer/README.md",
".github/tools/external/MCPlayerTransfer/main.py": ".github/extensions/MCPlayerTransfer/main.py",
".github/tools/external/XHS-image-to-PDF-conversion/README.md": ".github/extensions/XHS-image-to-PDF-conversion/README.md",
".github/tools/external/XHS-image-to-PDF-conversion/pdf.py": ".github/extensions/XHS-image-to-PDF-conversion/pdf.py"
},
"live_sources": {
".github/skills/auto-skill/README.md": {
"path": ".github/skills/auto-skill/README.md",
"sha256": "64d1bb33f054e54e3251558f3a2c0192c297d5e0298abf991cb2f01d97673533"
},
".github/skills/auto-skill/scripts/create-skill.sh": {
"path": ".github/extensions/create-skill.sh",
"sha256": "f0aa9aa39dfbb952a7c82bcbeb1745855bc75f7fa0200d5a1310d320ff32528d"
},
".github/skills/auto-skill/scripts/skill-seekers.sh": {
"path": ".github/extensions/skill-seekers.sh",
"sha256": "4afd9c2d289bd2940fd01e6e1ab4d2eb85bc9aeb295a7d76f85d27bd1f2fe7fc"
},
".github/skills/auto-skill/scripts/validate-skill.sh": {
"path": ".github/extensions/validate-skill.sh",
"sha256": "0c283d2e25673a6374e687caea959f0a80f66fa4cbe0bc9c160c82531ecf63cf"
},
".github/skills/auto-tmux/README.md": {
"path": ".github/skills/auto-tmux/README.md",
"sha256": "f9774f38d1fb7e5b8bfc072083a4f63b4d31fac0db4b8809e4bf5f807a92dc01"
},
".github/skills/auto-tmux/scripts/auto-tmux.sh": {
"path": ".github/extensions/auto-tmux/auto-tmux.sh",
"sha256": "32cf32ce1849dc7c0f4483c504b094a5f9ab89caeefaadcad30e7b8debd6ba7e"
},
".github/tools/chat-vault/README.md": {
"path": ".github/extensions/chat-vault/README.md",
"sha256": "938ddcce3ba06fad18a05d072cfc47cb8427064c72745f557e4b782de8a2c753"
},
".github/tools/chat-vault/services/chat-vault/src/main.py": {
"path": ".github/extensions/chat-vault/services/chat-vault/src/main.py",
"sha256": "561c611909714d358f9968c45078f037bd46cdb037969d598cfed27d94affd72"
},
".github/tools/config/.codex/README.md": {
"path": ".github/extensions/codex-config/.codex/README.md",
"sha256": "21ff0c2b3b622cf05f454ebbd472e14f0f9bef578a55f49a045d44c087f4d421"
},
".github/tools/config/.codex/install.sh": {
"path": ".github/extensions/codex-config/.codex/install.sh",
"sha256": "d32986c7bb8bb73928f408d8135a4b88e2ee306383e04936112a1dd35cb628fb"
},
".github/tools/external/.tmux/.logo/LICENSE": {
"path": ".github/extensions/oh-my-tmux/.logo/LICENSE",
"sha256": "6ae92da1ac8fc251f218491c42048d258d50d57bc685beb871fb09adf0bcea3e"
},
".github/tools/external/.tmux/.tmux.conf": {
"path": ".github/extensions/oh-my-tmux/.tmux.conf",
"sha256": "6807d44735b7b11e64c4488a0c3fdcbd2809cc73efedcc349d098e80a690aeeb"
},
".github/tools/external/.tmux/LICENSE.MIT": {
"path": ".github/extensions/oh-my-tmux/LICENSE.MIT",
"sha256": "f4c34427d3e29630cece9bca418eda48ac298867630cd6698d73e0f04642d1d0"
},
".github/tools/external/.tmux/LICENSE.WTFPLv2": {
"path": ".github/extensions/oh-my-tmux/LICENSE.WTFPLv2",
"sha256": "ee820ff0db4ce628569e0975ac27dc926052a9f85d102b101edb104311ef4d90"
},
".github/tools/external/.tmux/README.md": {
"path": ".github/extensions/oh-my-tmux/README.md",
"sha256": "10b0cca6bb2a4ab7af39d76d27f51b91ca1df4dead015315400041695c9471e7"
},
".github/tools/external/MCPlayerTransfer/README.md": {
"path": ".github/extensions/MCPlayerTransfer/README.md",
"sha256": "f48b3081530011171ee6761115613c5eb7811a9ec3059cdec53e3b50c632f0e3"
},
".github/tools/external/MCPlayerTransfer/main.py": {
"path": ".github/extensions/MCPlayerTransfer/main.py",
"sha256": "11bfdb47774247c32ad8cd0de441d56a13a17e9c12bcb3e2d9e81895958e1450"
},
".github/tools/external/Skill_Seekers-development/LICENSE": {
"path": ".github/extensions/Skill_Seekers-development/LICENSE",
"sha256": "d131d0e96700cd78f8b3fa7ed79a47b019a0653066500faff376233246b6504d"
},
".github/tools/external/Skill_Seekers-development/pyproject.toml": {
"path": ".github/extensions/Skill_Seekers-development/pyproject.toml",
"sha256": "40820d20d8f56c1dc24c8f432141fa438d54473acbfecfa716fc9d188cbc8294"
},
".github/tools/external/Skill_Seekers-development/src/skill_seekers/cli/agent_client.py": {
"path": ".github/extensions/Skill_Seekers-development/src/skill_seekers/cli/agent_client.py",
"sha256": "2fff7e6de630b6c8871db3419661195125c6128ac71d4d76f04e7561f7bdac17"
},
".github/tools/external/Skill_Seekers-development/src/skill_seekers/cli/install_skill.py": {
"path": ".github/extensions/Skill_Seekers-development/src/skill_seekers/cli/install_skill.py",
"sha256": "146be443d3b73b1e5c706b105fd0780831275baa6d0d61424b3c10d03dfa79aa"
},
".github/tools/external/Skill_Seekers-development/src/skill_seekers/cli/main.py": {
"path": ".github/extensions/Skill_Seekers-development/src/skill_seekers/cli/main.py",
"sha256": "8c02660dacd304f51fe8c4a9685d3f6d5324a7eef7779b6baa7325827bf01985"
},
".github/tools/external/Skill_Seekers-development/src/skill_seekers/cli/upload_skill.py": {
"path": ".github/extensions/Skill_Seekers-development/src/skill_seekers/cli/upload_skill.py",
"sha256": "2967da60c32c2495ea993f9122c6472d76ab86d3bcae878831fbeb07c55b0d1e"
},
".github/tools/external/Skill_Seekers-development/src/skill_seekers/mcp/server.py": {
"path": ".github/extensions/Skill_Seekers-development/src/skill_seekers/mcp/server.py",
"sha256": "cc6c4f24e5b91ab158f2bfbc4ebb27a38ce84d2937473dd85a6c2d035fc3b851"
},
".github/tools/external/Skill_Seekers-development/src/skill_seekers/mcp/server_fastmcp.py": {
"path": ".github/extensions/Skill_Seekers-development/src/skill_seekers/mcp/server_fastmcp.py",
"sha256": "19ba3010ea3bc5101953e44070932ec239d67908e1a0e992437665f98b827200"
},
".github/tools/external/Skill_Seekers-development/src/skill_seekers/mcp/tools/packaging_tools.py": {
"path": ".github/extensions/Skill_Seekers-development/src/skill_seekers/mcp/tools/packaging_tools.py",
"sha256": "7654385b60889705d98a3cc8e92602d13cadaf920ead26561e7fbb3a349a1fab"
},
".github/tools/external/Skill_Seekers-development/src/skill_seekers/mcp/tools/scraping_tools.py": {
"path": ".github/extensions/Skill_Seekers-development/src/skill_seekers/mcp/tools/scraping_tools.py",
"sha256": "0073daae89b191d907fb080daf78f044d55d6890a8c929e7dcdc10c9ff19a735"
},
".github/tools/external/XHS-image-to-PDF-conversion/README.md": {
"path": ".github/extensions/XHS-image-to-PDF-conversion/README.md",
"sha256": "19f65c7b6afe56c57789a30d1aed3c214051474fd21ea97f1ec10cc1ec774f13"
},
".github/tools/external/XHS-image-to-PDF-conversion/pdf.py": {
"path": ".github/extensions/XHS-image-to-PDF-conversion/pdf.py",
"sha256": "ee045272a0ba361676c1ee908758e7316e96438774716c79472fb05cc5055539"
},
".github/tools/external/claude-official-skills/README.md": {
"path": ".github/extensions/claude-official-skills/README.md",
"sha256": "d7c5c2f9b248c7c0b31f093cf22b9a7407f5b093c8ca9ebe75a5b6845b02b76e"
},
".github/tools/external/claude-official-skills/skills/skill-creator/LICENSE.txt": {
"path": ".github/extensions/claude-official-skills/skills/skill-creator/LICENSE.txt",
"sha256": "58d1e17ffe5109a7ae296caafcadfdbe6a7d176f0bc4ab01e12a689b0499d8bd"
},
".github/tools/external/claude-official-skills/skills/skill-creator/SKILL.md": {
"path": ".github/extensions/claude-official-skills/skills/skill-creator/SKILL.md",
"sha256": "d57b6e3a44535b9c0ef454dad5c86f5df78185fc80a65c7092885b4b5e10f81b"
},
".github/tools/external/claude-official-skills/skills/skill-creator/scripts/init_skill.py": {
"path": ".github/extensions/claude-official-skills/skills/skill-creator/scripts/init_skill.py",
"sha256": "cf12790f1d4958799281920d599f56aea38fb5c26e2812a61dd740bf3d4b6b99"
},
".github/tools/external/html-tools-main/README.md": {
"path": ".github/extensions/html-tools-main.md",
"sha256": "6aeb3fbdd0ad484f15b44b8c0e26caa7228cede0a659292893617d19d99b6df3"
},
".github/tools/external/html-tools-main/clean_epub_css.html": {
"path": ".github/extensions/clean_epub_css.html",
"sha256": "1716a7ea5f4bf4837bc044c9c164e58b3dbb04d492f677b7766b506edd1c0d2a"
},
".github/tools/external/html-tools-main/markdown-bianjiqi.html": {
"path": ".github/extensions/markdown-bianjiqi.html",
"sha256": "e4c76015749bf42e898412ec7b8e1229c847575ef740bcf6900311d7212dc61e"
},
".github/tools/external/html-tools-main/task card generator.html": {
"path": ".github/extensions/task card generator.html",
"sha256": "0eba89d2f674bb0bc26690c4e406f99b7a2bcd40ecd838c1c19e1f970f7b5670"
},
".github/tools/external/html-tools-main/xhs graphic production - 1.0.html": {
"path": ".github/extensions/xhs graphic production - 1.0.html",
"sha256": "14a60fa5cc9fa3b7a8beac146277c1ef15729eb5e18cd7889fbcf498d5d1411a"
},
".github/tools/external/html-tools-main/xhs graphic production.html": {
"path": ".github/extensions/xhs graphic production.html",
"sha256": "1835e29563d4cf7f01cb9cf837d3f57d1b2e48304cc202e1061240bccf6e7e0e"
},
".github/tools/external/my-nvim/README.md": {
"path": ".github/extensions/my-nvim/README.md",
"sha256": "905c3a248d5208f001f3eb6924beaf768454c70cdbc4c41cf67e906dba7ca8c0"
},
".github/tools/external/my-nvim/nvim-config/init.lua": {
"path": ".github/extensions/my-nvim/nvim-config/init.lua",
"sha256": "3b2d6e9976a515b7c8df08ed7c7f61a5751e9c08a6ff5579d621b87312c9e2c6"
},
".github/tools/external/my-nvim/nvim-config/lua/config/lazy.lua": {
"path": ".github/extensions/my-nvim/nvim-config/lua/config/lazy.lua",
"sha256": "5fd03a47dc423a46b7c141149d35ba20cbbd96eb2c90f48f74dbff94c202802e"
},
".github/tools/external/tmux/COPYING": {
"path": ".github/extensions/tmux/COPYING",
"sha256": "c031bd37f464c534277814f6aa38686fa023d094261d57fd2545ad592bb53ccd"
},
".github/tools/external/tmux/README": {
"path": ".github/extensions/tmux/README",
"sha256": "9fb75e6c7f10c25b73e41b8214336d0dc2acfbe4c99984514ccaf7327192d53e"
},
".github/tools/external/tmux/README.ja": {
"path": ".github/extensions/tmux/README.ja",
"sha256": "c341a10636227e426a759da4b80b754258ef31f1554a9ac369a79c5afeeadeb6"
},
".github/tools/external/tmux/compat/explicit_bzero.c": {
"path": ".github/extensions/tmux/compat/explicit_bzero.c",
"sha256": "7e30bc63946093cd6ed7cb4ce01d2f8c6e329ab173a20df250da60bb0a3c757b"
},
".github/tools/external/tmux/compat/getopt_long.c": {
"path": ".github/extensions/tmux/compat/getopt_long.c",
"sha256": "0486066fe70fb5a81d79971842f171e3bdcb570dbcab22ce51c1394235b8d21f"
},
".github/tools/external/tmux/example_tmux.conf": {
"path": ".github/extensions/tmux/example_tmux.conf",
"sha256": "0ab7c28342180d485434c3d8e286508a1e1c87ac9a2c8f2dc78bcf477a2de437"
},
".github/tools/external/tmux/logo/LICENSE": {
"path": ".github/extensions/tmux/logo/LICENSE",
"sha256": "5fdf604dee98da6f827ea924cf5ae19a9da31555d3814143f2cc6f8e7ee05752"
},
".github/tools/external/tmux/logo/tmux-logo-1-color.eps": {
"path": ".github/extensions/tmux/logo/tmux-logo-1-color.eps",
"sha256": "f4da0cd411ea21140efbb3ebd5fc9a76c87183c8eceb7902e6f08d061c17235b"
},
".github/tools/external/tmux/logo/tmux-logo.eps": {
"path": ".github/extensions/tmux/logo/tmux-logo.eps",
"sha256": "13ecb5c04f2b40f5dca7dc7e9be3986de3d7641c6494cc3f139669a3e90dd144"
},
".github/tools/external/tmux/logo/tmux-logomark.eps": {
"path": ".github/extensions/tmux/logo/tmux-logomark.eps",
"sha256": "f5afbd939a1675b5b1293cd642273d8b0b9555b906683970b5e7a34f802674fd"
},
".github/tools/external/tmux/mdoc2man.awk": {
"path": ".github/extensions/tmux/mdoc2man.awk",
"sha256": "602f3d31ffec414850e697b73f1885e967698ac0cbe8f09efd14800e55abe7ea"
},
".github/tools/external/tmux/tmux.1": {
"path": ".github/extensions/tmux/tmux.1",
"sha256": "f2966da7a8267abc9aaa216a7a7b46d4d914d60114058dc046c4ff1c75ac9422"
},
".github/tools/external/tmux/tmux.c": {
"path": ".github/extensions/tmux/tmux.c",
"sha256": "58a9bef0d1d424fd2e2a79c6d998dab96aab81ee771b7c2653928451f3bf11a8"
},
".github/tools/external/tmux/tools/24-bit-color.sh": {
"path": ".github/extensions/tmux/tools/24-bit-color.sh",
"sha256": "cee34d321461577c2455573ec58537833f5968cebe7df8d53aabf08b0e0d9ccf"
},
".github/tools/external/tmux/xmalloc.c": {
"path": ".github/extensions/tmux/xmalloc.c",
"sha256": "8ed468e9903b8abf18d5d5b76d99f030713fc479d02dc107ec3dbaa3a01c702b"
},
".github/tools/prompts-library/README.md": {
"path": ".github/extensions/prompts-library/README.md",
"sha256": "512c5f34fec0539aeeb399d7493beaf5e1088e5b3ddec8fadb23cc1c5a16b3b3"
},
".github/tools/prompts-library/main.py": {
"path": ".github/extensions/prompts-library/main.py",
"sha256": "ed0113d3ecbe9c9d4ca48ee7dde2c76c9a6fd1f54a1ae890fd3689d617347691"
},
".gitmodules": {
"path": ".gitmodules",
"sha256": "13fc803e15db2df8b197db8a47af2f93c3933474d07c9abdc1524d632e99412e"
}
},
"projections": [
{
"path": ".github/skills/algorithmic-art",
"target": "../extensions/claude-official-skills/skills/algorithmic-art"
},
{
"path": ".github/skills/brand-guidelines",
"target": "../extensions/claude-official-skills/skills/brand-guidelines"
},
{
"path": ".github/skills/canvas-design",
"target": "../extensions/claude-official-skills/skills/canvas-design"
},
{
"path": ".github/skills/doc-coauthoring",
"target": "../extensions/claude-official-skills/skills/doc-coauthoring"
},
{
"path": ".github/skills/docx",
"target": "../extensions/claude-official-skills/skills/docx"
},
{
"path": ".github/skills/frontend-design",
"target": "../extensions/claude-official-skills/skills/frontend-design"
},
{
"path": ".github/skills/internal-comms",
"target": "../extensions/claude-official-skills/skills/internal-comms"
},
{
"path": ".github/skills/mcp-builder",
"target": "../extensions/claude-official-skills/skills/mcp-builder"
},
{
"path": ".github/skills/pdf",
"target": "../extensions/claude-official-skills/skills/pdf"
},
{
"path": ".github/skills/pptx",
"target": "../extensions/claude-official-skills/skills/pptx"
},
{
"path": ".github/skills/skill-creator",
"target": "../extensions/claude-official-skills/skills/skill-creator"
},
{
"path": ".github/skills/slack-gif-creator",
"target": "../extensions/claude-official-skills/skills/slack-gif-creator"
},
{
"path": ".github/skills/theme-factory",
"target": "../extensions/claude-official-skills/skills/theme-factory"
},
{
"path": ".github/skills/web-artifacts-builder",
"target": "../extensions/claude-official-skills/skills/web-artifacts-builder"
},
{
"path": ".github/skills/webapp-testing",
"target": "../extensions/claude-official-skills/skills/webapp-testing"
},
{
"path": ".github/skills/xlsx",
"target": "../extensions/claude-official-skills/skills/xlsx"
},
{
"path": ".github/extensions/init_skill.py",
"target": "claude-official-skills/skills/skill-creator/scripts/init_skill.py"
},
{
"path": ".github/skills/auto-tmux/assets/tmux-src",
"target": "../../../extensions/tmux"
},
{
"path": ".github/skills/auto-tmux/assets/oh-my-tmux",
"target": "../../../extensions/oh-my-tmux"
}
]
}