@ccoalm/ccl-skills 0.6.0 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/source-register.md +1 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/tighten-doc/references/figure-and-table-craft.md +14 -1
- package/dist/assets/marketplace/plugins/ccl-skills/skills/tighten-doc/scripts/figure-lint.py +111 -10
- package/dist/assets/marketplace/plugins/ccl-skills/skills/tighten-doc/scripts/test_figure_and_doc_lint.sh +9 -1
- package/dist/assets/marketplace/plugins/ccl-skills/skills/tighten-doc/scripts/tests/svg/foreign-ns-title.svg +10 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/tighten-doc/scripts/tests/svg/self-contained-ok.svg +17 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/tighten-doc/scripts/tests/svg/unsafe-css-import.svg +11 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/tighten-doc/scripts/tests/svg/unsafe-css-url.svg +10 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/tighten-doc/scripts/tests/svg/unsafe-event-handler.svg +10 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/tighten-doc/scripts/tests/svg/unsafe-external-ref.svg +11 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/tighten-doc/scripts/tests/svg/unsafe-noxmlns.svg +11 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/tighten-doc/scripts/tests/svg/unsafe-script.svg +11 -0
- package/dist/assets/release.json +47 -7
- package/package.json +1 -1
|
@@ -342,3 +342,4 @@ and inverted the sense (production, not product), and the coordinator now shares
|
|
|
342
342
|
| 确定性闸对历史形态有前提,而**递给它哪个 ref 是 harness 的选择**:闸按分支自己的一级父链切轮,CI 默认检出的 `refs/pull/N/merge` 的一级父是**目标分支**,于是分支上所有轮塌成一轮,凡「验证依赖本轮很窄」的台账行都会在自己一个字没改的情况下翻红——闸没坏,喂它的历史形态不对 | `skill-extraction-workflow` | 五个跑闸 lane 的 job 全部改为检出分支 head(`ref: pull_request.head.sha \|\| github.sha`,非 PR 事件回落 `github.sha`);新增 `test_ci_checkout_ref_binding.sh` 逐 job 断言该绑定并注册进 fast lane,绑定丢失即闭式失败; result-class: failure; behavioral-evidence: RED-baseline; observed-failure: yes; firing-path: command:skills/skill-extraction-workflow/scripts/test_ci_checkout_ref_binding.sh | `updated` | owner key `skill-extraction-workflow/SKILL.md`(本轮未改其正文,改的是 scripts 与 `.github/workflows/ci.yml`)。**观察到的失败是 CI 实测**:PR #53(dev→main,053–056 四轮 + npm 0.5.0)`repository-gates` 报 `impact_chain_firing_path_missing`(incomplete 点名的是文档技能那个 owner 的入口),`regression-heavy` 两个套件连带红;同一棵树在线性 dev 上闸全绿。055 那轮只改 tighten-doc 的 description、用 `#description` 锚点,该锚点合法的前提是「该 owner 本轮全部 diff 就是 description」;四轮塌成一轮后 tighten-doc 在同一轮里还改了 `references/` 与 `scripts/`,前提失效。**先试过改闸、证否了**:把 round 派生改成「一级父已被 base 包含时走第二个父」,在 merge-ref 树上确实转绿,但打破了 `test_check_ccl_impact_chain_refscripts.sh` 的 round scoping 8——「台账行写在工作提交之前的 worktree 轮必须塌成一个边界」。两种形态在拓扑上**完全相同**(都是 merge X into Y 且 Y==base),git 里没有可区分它们的不变量,而该 fixture 明写 `--first-parent` 是承重的。按仓里对 form 3 的既定裁决(同类复现以删除收束、不再补代理),改的不是闸而是喂给它的 ref。**RED-baseline 是双向差分**:新测试在修好的 workflow 上绿,把 `.github/workflows/ci.yml` 换回 `origin/dev` 版即报三个 job 未绑定。该测试第一次跑就抓到我只改了三个 job、漏了两条 regression lane——**这正是它存在的理由**。**本轮暴露的验证面缺陷**:053–056 四轮我只跑 `make test-repo-gates`、基线取 `origin/dev`;而 CI 的基线是 `origin/main`、检出是 merge ref、还有 fast/heavy 两条 lane——三处都不同,四轮的绿从未覆盖这个形态 |
|
|
343
343
|
| 能力落在技能包里、只在被点名时才跑,就只覆盖被想起来的那些输入;本仓自己的文档语料从来没有被这套检查器扫过一遍——**判据存在不等于判据生效** | `tighten-doc` | `scripts/check-doc-structure.py` 枚举全部 tracked Markdown 交给 `doc-lint` 判,接进 `make test-repo-gates`;只有 ERROR 一档阻断,WARN 只打印计数; result-class: stable-success; behavioral-evidence: RED-baseline; observed-failure: no; firing-path: file:skills/tighten-doc/references/figure-and-table-craft.md#DOC-STRUCTURE-GATE-TIER | `updated` | owner key `tighten-doc/SKILL.md`(本轮未改其正文,改的是 reference 与被闸调用的 script)。**先量后接,不是先接后量**:481 篇 tracked 非 fixture 文档实测 0 ERROR / 75 WARN,0.15s;fixture 目录(13 篇)按构造带 2 个 ERROR,故必须排除,否则这道闸对「证明检查器有效」的输入永久红。**分档依据是本包自己的 §9b**——判不开缺陷与判断题的代理不得设闸:WARN 那批是 `[工]` 代理,设成阻断等于落地当天就用一堆判断题把仓库判红;ERROR 那半是客观的(表格无真表头、图引用悬空、文件读不出)。**RED-baseline 是突变差分 15/15**(含 dual-track 后新增的六个维度):排除放宽成子串 / 放宽成全排 / 完全失效、有 ERROR 仍返回 0、去掉 linter 退出码契约检查、去掉空作用域守卫、去掉合计行解析守卫、ok 行不报数量、缺 linter 也放行,十五种突变逐一施加后套件均转红,施加后一律还原并复验 baseline 为绿。**dual-track 两条 lane 独立收敛到同一条 P1**:只校验 linter 退出码属于 0/1/2、却不与它自己的汇总数交叉核对——退出 1(契约含义「有 ERROR」)却打印「0 ERROR」时,包装器会打印 ok 并返回 0;崩溃与不可解析两条腿都够不到它,因为这份输出解析得很好、只是在说谎。已加双向交叉核对与四个 stub 组合(含一个自洽 stub 作控制)。review lane 另报大小写扩展名漏扫:`git ls-files '*.md'` 在大小写敏感文件系统上会漏掉 tracked 的 `NOTES.MD`,对一个以覆盖率为全部价值的闸而言是致命的;改为枚举全部再按 casefold 后缀过滤。**三条本来会静默通过的假断言**,形状相同——断言写在输出里恒存在的东西上,而不是写在会随缺陷变化的量上:①「排除不会误吞真文档」那条腿把缺陷放在了不含 `tests/` 的路径上,放宽成子串匹配后掉的是一篇干净文档、判定不变、腿照样绿——注释里声称双向、断言实际单向。缺陷必须落在被放宽的排除会吞掉的那条路径上,已改并复验;②WARN 那条腿断言的是成功行里恒存在的 `WARN` 与 `non-blocking` 字样,加上计数断言后当场暴露那个 fixture **一条 WARN 都不产生**、此前什么也没测(challenge lane 发现,已换成真会触发 TABLE-NO-UNIT 的 fixture);③非 git 目录那条腿只断言通用 token,分不开「git 失败」与「空作用域守卫接住了空清单」,已点名 `git ls-files exited`。**候选绑定证据**:`eval/evidence/doc-structure-gate-2026-08-26/REPLAY.md`(tracked,在冻结包内),列出三条命令与期望、落地前的语料实测表、十五条突变清单;前两条完全由包内文件决定、可自行复算,依赖私有 alias 的第三条如实标为不可从包内独立复核。**为什么记 stable-success 而不是 failure**:本轮不是修缺陷,是把 053–057 已建成的能力接到一个每次落地都会跑的面上;机制是全量枚举 + 分档阻断,非侥幸证据是上述实测与突变差分,复用条件是「代理不设闸」这条判据,firing point 在 `test-repo-gates`。**仍未闭合的那件事**:`figure-lint` 不接闸——它至今只在同一作者产出的图上量过;而这整套判据到今天为止,仍然没有被一个不带本会话上下文的 agent 用过 |
|
|
344
344
|
| 能力建好了不等于交付得出去:判据、检查器、闸都齐了,而枚举器放在了**不进发布闭包的目录**里,于是发出去的只有描述它的十七行说明、闸本身一行都没发——**放错位置的能力,在消费者那里等于不存在,且比不存在更糟:说明还在指着它** | `tighten-doc` | 枚举器与其测试从仓根 `scripts/` 移进技能包(`skills/tighten-doc/scripts/doc-lint-repo.py`、`test_doc_lint_repo.py`,与它调用的 `doc-lint.py` 同级、随包发布);同时去掉两处「假定被扫仓库里有这个技能」的写死:linter 改取自己的同级文件、fixture 排除改由 linter 位置派生且仅在它确实位于被扫仓库内时生效; result-class: failure; behavioral-evidence: RED-baseline; observed-failure: yes; firing-path: command:skills/tighten-doc/scripts/test_doc_lint_repo.py | `updated` | owner key `tighten-doc/SKILL.md`(本轮未改其正文,改的是 reference 与随包发布的 scripts)。**观察到的失败是用户指出的**:0.5.0 发版后被问「skill 正好有修改,不需要发布?」,核出 tag 之后进发布物的改动**只有 18 行**(判据文档 17 + 台账 1),而 058 真正建的东西——180 行枚举器 + 338 行测试——在仓根 `scripts/`,打包 `roots` 不含它(只含 `scripts/owner-dispatch` 一个子目录)。`doc-lint.py` / `figure-lint.py` 本来就在技能包内、一直在发;枚举器是**位置放错**,不是能力不该发。**两处写死是同一个不变量的两半**:脚本不再假定被扫仓库里有这个技能。写死路径在消费仓里是反向错误——会去吞掉人家碰巧同名的真文档;派生的前缀在本仓命中、在消费仓解析为空,两边都对。**RED-baseline 是突变差分 17/17**:058 的十五条全部保留并复验,另加「排除写死成本仓路径」与「linter 改回在被扫仓库里查找」两条新维度;新增测试腿 `test_consuming_repo_excludes_nothing_and_still_works` 在被扫仓库里放一篇路径为 `skills/tighten-doc/scripts/tests/their-own-doc.md` 的**真文档**——写死排除会吞掉它使判定翻绿,派生排除不吞、判定保持 rc=1。**外部仓实测**:三个 `git init` 现造、完全不含本技能的仓库上,干净仓 rc=0(含一篇 `.MD` 也计入)、含 ERROR rc=1、缺陷落在大写扩展名文件上 rc=1,三种都对。**058 的台账行与 REPLAY 按 append-only 不改写**,只在后者顶部加一条迁移说明指向本轮。候选绑定证据:`eval/evidence/doc-lint-repo-ship-2026-08-26/REPLAY.md`(tracked,在冻结包内)。**该记的教训不是「记得改路径」**:058 那一轮我完整跑了闸、突变、dual-track、两条 lane,没有任何一道检查会问「这个能力发得出去吗」——**验证面覆盖了正确性,没覆盖可交付性**。**而这条教训在本轮身上又复现了一次,由 dual-track 两条 lane 独立指出**:我最初是手工跑构建、把「dist 里有这两个文件」贴进证据文件的——**不可重跑**,打包明天再漏装,全部测试与闸照样绿。已补 `packages/ccl-skills-npm/test/shipped-doc-lint-repo.test.mjs`:跑在 `npm test` 里(该命令第一步即 `npm run build`,`dist/` 已就位),由 CI 的 `npm-packages` job 消费;五条断言=两个必需文件在 dist 中 + **用 dist 里的那份脚本**跑干净仓 / 含 ERROR 仓 / 消费者自己的 `tests/` 目录不得被吞 / 大写扩展名。**反向差分**:删掉 `dist/.../doc-lint-repo.py` 后 5 条全部转红,还原后回绿。另修 review lane 的 P2:§10 里写的 `../scripts/doc-lint-repo.py` 是相对该 reference 文件的,读者在仓根照抄会指向不存在的路径,已改成带 `<技能安装路径>` 的可直接复制形态 |
|
|
345
|
+
| 提炼完成度的自查不能用一次 grep 定论:按关键词查「这条落了没」,会把「按内容写、没写编号」的已落条目判成缺口,也会把「解法用另一套词写着」的判成答案缺失——**空的搜索结果是搜索方式的性质,不是仓库的性质** | `tighten-doc` | 补上外部技能提炼里唯一真正漏掉的一条:内联 SVG 的自包含约束落成 `SVG-NOT-SELF-CONTAINED`(`<script>`/`<foreignObject>` 与 `image`/`use`/`feImage`/`pattern` 的外部资源引用判 ERROR);§5 补 `currentColor` 作为写死十六进制的 SVG 原生解;§4b 对 §1 的概括收紧; result-class: failure; behavioral-evidence: RED-baseline; observed-failure: yes; firing-path: command:skills/tighten-doc/scripts/test_figure_and_doc_lint.sh | `updated` | owner key `tighten-doc/SKILL.md`(本轮未改其正文,改的是 reference、script 与 fixture)。**观察到的失败是我自己在自查里判错**:用户问「研究的那些一手源和三方技能都落了么」,我逐条 grep 后报了三处缺口,复核下来**只有一处成立**——①「WCAG 1.4.8 行宽没落」是错的:§1 的 `[禁]` 档已完整记着「CJK 40 是拉丁 80 折半推导、原文要求的是提供机制让用户改」,我 grep `1.4.8` 没命中只是因为文里按内容写、没写 SC 编号,**我据此还断言仓库有一句错话——那句话不错,错的是我的检查方法**;②「`currentColor` 的解法缺失」被缩小:`THEME-CONTRAST` 的诊断文案已写着「应按主题 swap token 值」,缺的只是 SVG 原生那条机制(手写内联 SVG 里比建 token 表更省事),是补充不是缺失;③自包含约束确认真缺——散文与谓词都没有,且 `<script>` 在内联 SVG 里是**注入面**不只是整洁问题。**边界是刻意划的**:邻近的 artifact-diagramming 还禁 `<style>`,本轮**不照抄**——那是它那条 lane 的约束(页面已有 CSS 层),本仓的图正当地用内联 `<style>` 定义字号与语义色;`<a>` 同样不禁,超链接不在渲染时拉取任何东西。按仓规外部包借理论不借实现,**照抄邻居的约束会连它的前提一起引进来**。**RED-baseline**:`mutation_probe.sh` 38/38,新谓词由探针 DERIVATION-GAP 自动纳入;两条 fixture(`<script>` 与外部 `image` 引用)各自孤立触发,控制组仍 0 ERROR(证明没误伤内联 `<style>`)。**跨作者语料实测 55 张 SVG:0 命中**——诚实读法是「没测到误报,也没测到真阳性,这批语料不触发这个类」,不是「谓词有效」。**dual-track 两条 lane 各指出一条真实漏报面,都已修**:①review:只匹配带命名空间的 QName,则无默认 `xmlns` 的内联 SVG(在 HTML 里完全合法——HTML 解析器补命名空间、ElementTree 不补)持续假绿;**顺着查发现这是全文件的假设**,`C4-TITLE` 与 `GROUPING` 反方向误报「缺标题」「零分组」,已把全部 9 处标签比较改走 `lname()`/`iter_local()`;②challenge:外部资源不只从 `href` 进来——`fill="url(https://…)"`、`filter=`、`<style>` 里的 `@font-face src` 同样在渲染时拉取,已改为扫描所有属性值与 `<style>` 文本的 `url(...)`,只放行 `url(#id)` 与 `data:`;③challenge P2 要求的**反方向断言**已补:`self-contained-ok.svg` 把内联 `<style>` + `<a>` + `use` fragment + `data:` 全放一张图里断言 0 ERROR——没有它,未来收紧 href 分类会在全部测试仍绿的情况下打坏合法输入。五条 fixture 全部进逐谓词差分表,突变 38/38。**local-name 修正在语料上零回归**:`C4-TITLE` 55→55、`GROUPING` 20→20(那 55 张都带 xmlns)。候选绑定证据 `eval/evidence/svg-self-contained-2026-08-26/REPLAY.md`(tracked,在冻结包内)。**第二轮 dual-track 又报四条,其中两条是我上一轮修正的过度修正**,均已修:①`lname()` 无条件丢命名空间(两条 lane 从相反方向指出)——`<dc:title>` 冒充图标题使假绿、`<ext:script>` 被误判成脚本错误阻断;**支持无 xmlns 不要求接受任意外来命名空间**,现只接受 SVG 命名空间或无命名空间;②整图标题被我从「直接子元素」放宽成任意层级,嵌套在 `<g>` 里本是子元素提示的 `<title>` 也能满足 C4,已改回;③`@import "https://…"` 是合法 CSS 且不走 `url()` 语法,只认 `url()` 即绕过口,已单列正则;④事件处理器与 `javascript:` URL——谓词声称管注入面却只查 `<script>`,**又一次声明与实现相反**,已覆盖任意 `on*` 属性与 `javascript:` URL。附带修了 `parse_css` 不认 at-rule(`@import`/`@media` 会污染紧随其后的真规则,让文字退回默认样式、冒出无关契约报错)。fixture 增至八条含一条 0 ERROR 边界组;语料 55 张零回归(`C4-TITLE` 55→55、`GROUPING` 20→20、`CONTRACT-FONT-SCALE` 0→0)。**该记的教训**:完整性自查若只用关键词检索,它报的是「我用的词在不在」而不是「那件事落没落」;判缺口前必须按**语义**再查一遍并读原文 |
|
|
@@ -93,7 +93,7 @@ almost certain`)并说明什么指标会改变不确定性水平;**第 7 条
|
|
|
93
93
|
|
|
94
94
|
## §4b 图的布局:唯一有实证的那一支 `[外]`
|
|
95
95
|
|
|
96
|
-
§1
|
|
96
|
+
§1 判定「图表密度」与「一行 N 汉字」这类**具体数字**无可靠来源是对的(WCAG 1.4.8 本身是来源,但它要的是可调机制、不是固定宽度),而**图的布局属性另有一支真正做过实验的文献**,
|
|
97
97
|
本仓此前完全没有覆盖——它是少数几个既有实证依据、又能在 SVG 里精确计算的属性。
|
|
98
98
|
|
|
99
99
|
**Purchase, "Which aesthetic has the greatest effect on human understanding?"(Graph Drawing 1997)**
|
|
@@ -210,6 +210,10 @@ consistency in the terms used is critical)。**但「冻结成哪几档」是
|
|
|
210
210
|
**分组单元**(每个卡片 = 形状 + 其文字包一个组)
|
|
211
211
|
- `semantic_colors` 是 `color_tokens` 的**子集声明**:哪些 token 承载语义区分(§4c 只测这些)。
|
|
212
212
|
不声明 = 不测,不是"测出来没问题"
|
|
213
|
+
- **不承载语义的笔画与文字用 `currentColor`,别写死十六进制**。它继承宿主文档的前景色,
|
|
214
|
+
深浅两底自动跟随,连 token 表都不必建——手写内联 SVG 里这是比 swap token 更省事的解。
|
|
215
|
+
只有**承载含义**的那几个色(状态、被强调的那条边)才值得进 `semantic_colors` 写死并受 §4c 测量。
|
|
216
|
+
`THEME-CONTRAST` 报的是「哪里失效」,这条是「怎么改对」
|
|
213
217
|
- `themes.<名>.surface` 必须是 `#RRGGBB`。写成 `"black"` 或非字符串,早先只判真值会让它通过校验、
|
|
214
218
|
随后因不是 `#` 开头被静默跳过——**声明了主题却一次都没测,报出来的是绿**。现在按语法拒绝
|
|
215
219
|
- **只有直接压在主题底色上的文字才按主题判**(`THEME-CONTRAST`)。压在局部卡片上的文字,
|
|
@@ -341,5 +345,14 @@ python3 skills/tighten-doc/scripts/doc-lint-repo.py .
|
|
|
341
345
|
而它的注释里明写着"双向"。**是突变探针发现的,不是我读出来的**——
|
|
342
346
|
单向的排除测试在排除已经长到覆盖半个仓库时,一样绿。
|
|
343
347
|
|
|
348
|
+
- **DOC-STRUCTURE-GATE-SELF-CONTAINED:内联 SVG 不得带 `<script>`、`<foreignObject>` 或外部资源引用。**
|
|
349
|
+
内联 SVG 与图片文件不同——它进入宿主文档的 DOM,所以 `<script>` 是**注入面**不是整洁问题;
|
|
350
|
+
`<foreignObject>` 把任意 HTML 带进来、逃出 SVG 语义且多数导出/打印路径不渲染;
|
|
351
|
+
`image`/`use`/`feImage`/`pattern` 指向 `http(s)` 或相对文件时,图换个位置渲染就是断链
|
|
352
|
+
(图随文档走,被引的东西不会)。用 `href="#id"` 或 `data:` 内嵌。`SVG-NOT-SELF-CONTAINED` 查这条。
|
|
353
|
+
**刻意不禁 `<style>` 与 `<a>`**:邻近技能禁 `<style>` 是它那条 lane 的约束(页面已有 CSS 层),
|
|
354
|
+
不是普遍判据,本仓的图正当地用内联 `<style>`;超链接不在渲染时拉取任何东西,与自包含无关。
|
|
355
|
+
**外部包借理论不借实现——照抄邻居的约束会引入它的前提。**
|
|
356
|
+
|
|
344
357
|
**不可机械判定的仍归人**:图种选得对不对、图注写的是不是主张、独立性验收、
|
|
345
358
|
调研族图上实体能否回指证据。检查器只挡机械项,不替代 §5 的验收。
|
package/dist/assets/marketplace/plugins/ccl-skills/skills/tighten-doc/scripts/figure-lint.py
CHANGED
|
@@ -13,7 +13,35 @@
|
|
|
13
13
|
import sys, re, os, glob, json, math, collections
|
|
14
14
|
import xml.etree.ElementTree as ET
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
SVG_NS = "http://www.w3.org/2000/svg"
|
|
17
|
+
SVG = "{" + SVG_NS + "}"
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def lname(tag):
|
|
21
|
+
"""SVG 或无命名空间元素的 local-name;外来命名空间返回 None。
|
|
22
|
+
|
|
23
|
+
没有默认 xmlns 的内联 SVG 在 HTML 里完全合法——HTML 解析器会补命名空间,
|
|
24
|
+
ElementTree 不会,于是它产出**裸标签**。只按 `{ns}tag` 比较,这一整类图就
|
|
25
|
+
持续误判。但反过来无条件丢掉命名空间同样错,而且两个方向都错:
|
|
26
|
+
Inkscape/Illustrator 导出里极常见的 `<dc:title>`(RDF 元数据)会被当成 SVG
|
|
27
|
+
`<title>` 让缺标题的图假绿,而 `<ext:script>` 会被误判成可执行脚本错误阻断。
|
|
28
|
+
支持无 xmlns **不要求**接受任意外来命名空间——两条 lane 各从一个方向指出了这点。
|
|
29
|
+
"""
|
|
30
|
+
if not isinstance(tag, str):
|
|
31
|
+
return None
|
|
32
|
+
if tag.startswith('{'):
|
|
33
|
+
ns, _, local = tag[1:].partition('}')
|
|
34
|
+
return local if ns == SVG_NS else None
|
|
35
|
+
return tag
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def iter_local(root, *names):
|
|
39
|
+
"""按 local-name 遍历,替代 root.iter(f'{SVG}tag')。"""
|
|
40
|
+
want = set(names)
|
|
41
|
+
for el in root.iter():
|
|
42
|
+
if lname(el.tag) in want:
|
|
43
|
+
yield el
|
|
44
|
+
|
|
17
45
|
|
|
18
46
|
# ---------- 颜色与对比度(WCAG 2.2 SC 1.4.3) ----------
|
|
19
47
|
|
|
@@ -51,6 +79,11 @@ def parse_css(svg_text):
|
|
|
51
79
|
"""返回 {class_name: {prop: value}}"""
|
|
52
80
|
out = {}
|
|
53
81
|
for block in re.findall(r'<style[^>]*>(.*?)</style>', svg_text, re.S):
|
|
82
|
+
# at-rule 先剥掉:`@import "…";` 会被下面的选择器正则当成选择器的一部分,
|
|
83
|
+
# 把它后面那条真规则的 class 名污染掉,于是文字取不到样式、退回默认值,
|
|
84
|
+
# 冒出一串与本缺陷无关的契约报错。`@media{…}` 同理(只剥外层,保留内部规则)。
|
|
85
|
+
block = re.sub(r'@[a-zA-Z-]+[^;{]*;', ' ', block)
|
|
86
|
+
block = re.sub(r'@[a-zA-Z-]+[^{]*\{', ' ', block)
|
|
54
87
|
for m in re.finditer(r'([^{}]+)\{([^}]*)\}', block):
|
|
55
88
|
sels, body = m.group(1), m.group(2)
|
|
56
89
|
props = {}
|
|
@@ -144,12 +177,12 @@ def referenced_defs_colors(root, css):
|
|
|
144
177
|
m = re.match(r'url\(#([^)]+)\)', v)
|
|
145
178
|
if m:
|
|
146
179
|
used.add(m.group(1))
|
|
147
|
-
if el.tag ==
|
|
180
|
+
if lname(el.tag) == 'use':
|
|
148
181
|
href = el.get('href') or el.get('{http://www.w3.org/1999/xlink}href') or ''
|
|
149
182
|
if href.startswith('#'):
|
|
150
183
|
used.add(href[1:])
|
|
151
184
|
seen = set()
|
|
152
|
-
for defs in root
|
|
185
|
+
for defs in iter_local(root, 'defs'):
|
|
153
186
|
for node in defs:
|
|
154
187
|
if node.get('id') not in used:
|
|
155
188
|
continue
|
|
@@ -198,7 +231,7 @@ def group_path_map(root):
|
|
|
198
231
|
m = {}
|
|
199
232
|
def walk(node, chain):
|
|
200
233
|
for el in node:
|
|
201
|
-
c = chain + [id(el)] if el.tag ==
|
|
234
|
+
c = chain + [id(el)] if lname(el.tag) == 'g' else chain
|
|
202
235
|
m[id(el)] = c
|
|
203
236
|
walk(el, c)
|
|
204
237
|
walk(root, [])
|
|
@@ -622,8 +655,76 @@ def lint(path, contract_hint=None):
|
|
|
622
655
|
# 渐变、圆/多边形底、rgb()/CSS 变量同样会让「按白底算」得出假红或假绿。
|
|
623
656
|
geometry_unsafe = bool(paint_gaps)
|
|
624
657
|
|
|
658
|
+
# --- 自包含:图不得带脚本、外部资源或 HTML 逃逸口 ---
|
|
659
|
+
# 内联 SVG 与图片文件不同:它进入宿主文档的 DOM,所以 <script> 是**注入面**,
|
|
660
|
+
# 不只是整洁问题。<foreignObject> 把任意 HTML 带进来,同样逃出 SVG 的语义。
|
|
661
|
+
# 外部资源引用(image/use/feImage 指向 http(s) 或相对文件)让图在别处渲染时
|
|
662
|
+
# 变成断链——图随文档走,被引的东西不会。
|
|
663
|
+
#
|
|
664
|
+
# 刻意**不禁** <style>:邻近的 artifact-diagramming 技能禁它,但那是它那条
|
|
665
|
+
# lane 的自包含约束(页面已有 CSS 层),不是普遍判据;本仓自己的图正当地用
|
|
666
|
+
# 内联 <style> 定义字号与语义色。按仓规,外部包借理论不借实现。
|
|
667
|
+
# 同样不禁 <a>:超链接不在渲染时拉取任何东西,与"自包含"无关。
|
|
668
|
+
# 标签一律按 local-name 判:没有默认 xmlns 的 SVG 会让 ElementTree 产出裸标签,
|
|
669
|
+
# 只匹配带命名空间的 QName 就对那一类**持续假绿**。(评审实测:新增 fixture 全带
|
|
670
|
+
# xmlns,所以这个洞在自己的测试下看不见。)
|
|
671
|
+
RESOURCE_TAGS = ('image', 'use', 'feImage', 'pattern')
|
|
672
|
+
# 外部资源不只从 href 进来:`fill="url(https://…)"`、`filter=`、以及 <style> 里的
|
|
673
|
+
# @font-face src / background 同样在渲染时拉取。只查四个标签的 href 会漏掉这一整面。
|
|
674
|
+
EXTERNAL_URL_RE = re.compile(r'url\(\s*[\'"]?\s*(?!#|data:)([^)\'"\s]+)', re.I)
|
|
675
|
+
# `@import "https://…"` 是合法 CSS 且**不走 url() 语法**,只认 url() 就是一个绕过口。
|
|
676
|
+
CSS_IMPORT_RE = re.compile(r'@import\s+(?:url\(\s*)?[\'"]?\s*(?!#|data:)([^;)\'"\s]+)', re.I)
|
|
677
|
+
|
|
678
|
+
def _flag_external(where, value, css=False):
|
|
679
|
+
pats = (EXTERNAL_URL_RE, CSS_IMPORT_RE) if css else (EXTERNAL_URL_RE,)
|
|
680
|
+
for m in [m for pat in pats for m in pat.finditer(value or '')]:
|
|
681
|
+
add('ERROR', 'SVG-NOT-SELF-CONTAINED',
|
|
682
|
+
f'{where} 通过 url() 引用了外部资源 {m.group(1)[:60]}:'
|
|
683
|
+
f'渲染时会去拉取,图换个位置就是断链。只允许同文档 fragment(url(#id))或 data:')
|
|
684
|
+
|
|
685
|
+
for el in root.iter():
|
|
686
|
+
name = lname(el.tag)
|
|
687
|
+
if name == 'script':
|
|
688
|
+
add('ERROR', 'SVG-NOT-SELF-CONTAINED',
|
|
689
|
+
'<script> 出现在内联 SVG 里:它进入宿主文档的 DOM,是注入面而非整洁问题。'
|
|
690
|
+
'图应当是纯标记,交互归页面')
|
|
691
|
+
continue
|
|
692
|
+
if name == 'foreignObject':
|
|
693
|
+
add('ERROR', 'SVG-NOT-SELF-CONTAINED',
|
|
694
|
+
'<foreignObject> 把任意 HTML 带进图里:逃出 SVG 语义,且在多数导出/'
|
|
695
|
+
'打印路径下不渲染。要文本就用 <text>')
|
|
696
|
+
continue
|
|
697
|
+
if name == 'style':
|
|
698
|
+
_flag_external('<style>', el.text or '', css=True)
|
|
699
|
+
continue
|
|
700
|
+
if name in RESOURCE_TAGS:
|
|
701
|
+
href = (el.get('href') or el.get('{http://www.w3.org/1999/xlink}href') or '').strip()
|
|
702
|
+
if href and not href.startswith('#') and not href.startswith('data:'):
|
|
703
|
+
add('ERROR', 'SVG-NOT-SELF-CONTAINED',
|
|
704
|
+
f'{name} 引用了外部资源 {href[:60]}:'
|
|
705
|
+
f'图随文档走、被引的东西不会,换个位置渲染就是断链。'
|
|
706
|
+
f'用 fragment 引用(href="#id")或 data: 内嵌')
|
|
707
|
+
# 任何元素的任何属性里的 url()——fill/stroke/filter/mask/clip-path/style 都算
|
|
708
|
+
for attr, val in el.attrib.items():
|
|
709
|
+
a = attr.split('}')[-1]
|
|
710
|
+
# 事件处理器与 javascript: URL 与 <script> 是同一注入面。谓词声称管注入面,
|
|
711
|
+
# 只查 <script> 就是**声明与实现相反**——评审从这个方向打进来过。
|
|
712
|
+
if a.lower().startswith('on'):
|
|
713
|
+
add('ERROR', 'SVG-NOT-SELF-CONTAINED',
|
|
714
|
+
f'{name} 带事件处理器 {a}:内联 SVG 进入宿主文档的 DOM,'
|
|
715
|
+
f'它和 <script> 是同一个注入面。交互归页面,图是纯标记')
|
|
716
|
+
continue
|
|
717
|
+
v = (val or '').strip()
|
|
718
|
+
if a in ('href', 'xlink:href') and v.lower().replace(' ', '').startswith('javascript:'):
|
|
719
|
+
add('ERROR', 'SVG-NOT-SELF-CONTAINED',
|
|
720
|
+
f'{name} 的 {a} 是 javascript: URL:同上,属注入面')
|
|
721
|
+
continue
|
|
722
|
+
if 'url(' in (val or ''):
|
|
723
|
+
_flag_external(f'{name} 的 {a}', val)
|
|
724
|
+
|
|
625
725
|
# --- C4: 标题 ---
|
|
626
|
-
|
|
726
|
+
# 直接子元素才是整图标题;嵌套在 <g> 里的 <title> 是那个子元素的提示。
|
|
727
|
+
title_el = next((c for c in root if lname(c.tag) == 'title'), None)
|
|
627
728
|
title = (title_el.text or '').strip() if title_el is not None else ''
|
|
628
729
|
if not title:
|
|
629
730
|
add('ERROR', 'C4-TITLE', '缺 <title>:C4 要求每张图有标题,说清图的类型与范围')
|
|
@@ -633,10 +734,10 @@ def lint(path, contract_hint=None):
|
|
|
633
734
|
def walk_text(node, inh):
|
|
634
735
|
for el in node:
|
|
635
736
|
p = resolve(el, css, inh)
|
|
636
|
-
if el.tag ==
|
|
737
|
+
if lname(el.tag) == 'text':
|
|
637
738
|
content = ''.join(el.itertext()).strip()
|
|
638
739
|
content = ' '.join(content.split())
|
|
639
|
-
tspans = el.
|
|
740
|
+
tspans = [c for c in el if lname(c.tag) == 'tspan']
|
|
640
741
|
try:
|
|
641
742
|
tx = float(el.get('x', 0)); ty = float(el.get('y', 0))
|
|
642
743
|
except ValueError:
|
|
@@ -818,8 +919,8 @@ def lint(path, contract_hint=None):
|
|
|
818
919
|
if w <= 0 or h <= 0 or w >= page_w * 0.95:
|
|
819
920
|
return False
|
|
820
921
|
return any(x <= t['x'] <= x + w and y <= t['y'] <= y + h for t in texts)
|
|
821
|
-
card_rects = [e for e in root
|
|
822
|
-
for el in root
|
|
922
|
+
card_rects = [e for e in iter_local(root, 'rect') if _is_card_rect(e)]
|
|
923
|
+
for el in iter_local(root, 'rect'):
|
|
823
924
|
try:
|
|
824
925
|
rx = float(el.get('x', 0)); ry = float(el.get('y', 0))
|
|
825
926
|
rw = float(el.get('width', 0)); rh = float(el.get('height', 0))
|
|
@@ -859,7 +960,7 @@ def lint(path, contract_hint=None):
|
|
|
859
960
|
add('ERROR', 'GROUPING',
|
|
860
961
|
f'{ungrouped_cards}/{card_total} 张卡片的形状与其文字不在同一个 <g> 内:'
|
|
861
962
|
f'推送到会重排 z 序的目标端时,矩形可能盖住文字')
|
|
862
|
-
elif card_total == 0 and len(list(root
|
|
963
|
+
elif card_total == 0 and len(list(iter_local(root, 'g'))) == 0:
|
|
863
964
|
add('ERROR', 'GROUPING', '全图零 <g> 分组:目标端重排 z 序时矩形可能盖住文字')
|
|
864
965
|
|
|
865
966
|
# --- 主题:语义色需在每个声明的底色上都达标 ---
|
|
@@ -83,7 +83,15 @@ run_expect figure-lint.py "${here}/tests/svg" svg \
|
|
|
83
83
|
'no-aria.svg=FIGURE-A11Y-STRUCTURE' \
|
|
84
84
|
'cvd-confusable.svg=' \
|
|
85
85
|
'decorative-line.svg=' \
|
|
86
|
-
'blackmarker.svg=CONTRACT-COLOR-TOKEN'
|
|
86
|
+
'blackmarker.svg=CONTRACT-COLOR-TOKEN' \
|
|
87
|
+
'unsafe-script.svg=SVG-NOT-SELF-CONTAINED' \
|
|
88
|
+
'unsafe-external-ref.svg=SVG-NOT-SELF-CONTAINED' \
|
|
89
|
+
'unsafe-noxmlns.svg=SVG-NOT-SELF-CONTAINED' \
|
|
90
|
+
'unsafe-css-url.svg=SVG-NOT-SELF-CONTAINED' \
|
|
91
|
+
'unsafe-css-import.svg=SVG-NOT-SELF-CONTAINED' \
|
|
92
|
+
'unsafe-event-handler.svg=SVG-NOT-SELF-CONTAINED' \
|
|
93
|
+
'foreign-ns-title.svg=C4-TITLE' \
|
|
94
|
+
'self-contained-ok.svg='
|
|
87
95
|
|
|
88
96
|
note "== doc-lint 逐谓词差分 =="
|
|
89
97
|
run_expect doc-lint.py "${here}/tests/doc" md \
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" xmlns:dc="http://purl.org/dc/elements/1.1/" viewBox="0 0 400 200" role="img" aria-label="RDF metadata title must not satisfy C4">
|
|
2
|
+
<dc:title>Metadata title, not the figure title</dc:title>
|
|
3
|
+
<defs><style>.ok{font-size:14px;fill:#111827}</style></defs>
|
|
4
|
+
<g>
|
|
5
|
+
<rect x="0" y="0" width="400" height="200" fill="#FFFFFF"/>
|
|
6
|
+
<rect x="10" y="120" width="14" height="14" fill="#0072B2"/><text x="32" y="132" class="ok">图例一</text>
|
|
7
|
+
<rect x="10" y="145" width="14" height="14" fill="#D55E00"/><text x="32" y="157" class="ok">图例二</text>
|
|
8
|
+
<rect x="10" y="170" width="14" height="14" fill="#009E73"/><text x="32" y="182" class="ok">图例三</text>
|
|
9
|
+
</g>
|
|
10
|
+
</svg>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 400 200" role="img" aria-label="every allowed self-contained form">
|
|
2
|
+
<title>Every allowed self-contained form</title>
|
|
3
|
+
<defs>
|
|
4
|
+
<style>.ok{font-size:14px;fill:#111827}.flow{fill:none;stroke:#0072B2;marker-end:url(#a)}</style>
|
|
5
|
+
<marker id="a" refX="10" refY="6"><path d="M1 1L11 6L1 11Z" fill="#0072B2"/></marker>
|
|
6
|
+
<rect id="chip" width="14" height="14" fill="#009E73"/>
|
|
7
|
+
</defs>
|
|
8
|
+
<g>
|
|
9
|
+
<rect x="0" y="0" width="400" height="200" fill="#FFFFFF"/>
|
|
10
|
+
<a href="https://example.invalid/docs"><text x="200" y="30" class="ok">超链接不拉取资源</text></a>
|
|
11
|
+
<image x="300" y="20" width="8" height="8" href="data:image/gif;base64,R0lGODlhAQABAAAAACw="/>
|
|
12
|
+
<use xlink:href="#chip" x="10" y="95"/>
|
|
13
|
+
<rect x="10" y="120" width="14" height="14" fill="#0072B2"/><text x="32" y="132" class="ok">图例一</text>
|
|
14
|
+
<rect x="10" y="145" width="14" height="14" fill="#D55E00"/><text x="32" y="157" class="ok">图例二</text>
|
|
15
|
+
<rect x="10" y="170" width="14" height="14" fill="#009E73"/><text x="32" y="182" class="ok">图例三</text>
|
|
16
|
+
</g>
|
|
17
|
+
</svg>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 200" role="img" aria-label="css import pulls an external stylesheet">
|
|
2
|
+
<title>CSS import pulls an external stylesheet</title>
|
|
3
|
+
<defs><style>@import "https://example.invalid/theme.css";
|
|
4
|
+
.ok{font-size:14px;fill:#111827}</style></defs>
|
|
5
|
+
<g>
|
|
6
|
+
<rect x="0" y="0" width="400" height="200" fill="#FFFFFF"/>
|
|
7
|
+
<rect x="10" y="120" width="14" height="14" fill="#0072B2"/><text x="32" y="132" class="ok">图例一</text>
|
|
8
|
+
<rect x="10" y="145" width="14" height="14" fill="#D55E00"/><text x="32" y="157" class="ok">图例二</text>
|
|
9
|
+
<rect x="10" y="170" width="14" height="14" fill="#009E73"/><text x="32" y="182" class="ok">图例三</text>
|
|
10
|
+
</g>
|
|
11
|
+
</svg>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 200" role="img" aria-label="external font in inline style">
|
|
2
|
+
<title>External font in inline style</title>
|
|
3
|
+
<defs><style>@font-face{font-family:X;src:url(https://example.invalid/f.woff2)}.ok{font-size:14px;fill:#111827}</style></defs>
|
|
4
|
+
<g>
|
|
5
|
+
<rect x="0" y="0" width="400" height="200" fill="#FFFFFF"/>
|
|
6
|
+
<rect x="10" y="120" width="14" height="14" fill="#0072B2"/><text x="32" y="132" class="ok">图例一</text>
|
|
7
|
+
<rect x="10" y="145" width="14" height="14" fill="#D55E00"/><text x="32" y="157" class="ok">图例二</text>
|
|
8
|
+
<rect x="10" y="170" width="14" height="14" fill="#009E73"/><text x="32" y="182" class="ok">图例三</text>
|
|
9
|
+
</g>
|
|
10
|
+
</svg>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 200" role="img" aria-label="inline event handler is the same injection surface">
|
|
2
|
+
<title>Inline event handler is the same injection surface</title>
|
|
3
|
+
<defs><style>.ok{font-size:14px;fill:#111827}</style></defs>
|
|
4
|
+
<g>
|
|
5
|
+
<rect x="0" y="0" width="400" height="200" fill="#FFFFFF" onload="void 0"/>
|
|
6
|
+
<rect x="10" y="120" width="14" height="14" fill="#0072B2"/><text x="32" y="132" class="ok">图例一</text>
|
|
7
|
+
<rect x="10" y="145" width="14" height="14" fill="#D55E00"/><text x="32" y="157" class="ok">图例二</text>
|
|
8
|
+
<rect x="10" y="170" width="14" height="14" fill="#009E73"/><text x="32" y="182" class="ok">图例三</text>
|
|
9
|
+
</g>
|
|
10
|
+
</svg>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 200" role="img" aria-label="external image reference">
|
|
2
|
+
<title>External image reference</title>
|
|
3
|
+
<defs><style>.ok{font-size:14px;fill:#111827}</style></defs>
|
|
4
|
+
<g>
|
|
5
|
+
<rect x="0" y="0" width="400" height="200" fill="#FFFFFF"/>
|
|
6
|
+
<image x="200" y="20" width="40" height="40" href="https://example.invalid/logo.png"/>
|
|
7
|
+
<rect x="10" y="120" width="14" height="14" fill="#0072B2"/><text x="32" y="132" class="ok">图例一</text>
|
|
8
|
+
<rect x="10" y="145" width="14" height="14" fill="#D55E00"/><text x="32" y="157" class="ok">图例二</text>
|
|
9
|
+
<rect x="10" y="170" width="14" height="14" fill="#009E73"/><text x="32" y="182" class="ok">图例三</text>
|
|
10
|
+
</g>
|
|
11
|
+
</svg>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<svg viewBox="0 0 400 200" role="img" aria-label="external use without a default namespace">
|
|
2
|
+
<title>External use without a default namespace</title>
|
|
3
|
+
<defs><style>.ok{font-size:14px;fill:#111827}</style></defs>
|
|
4
|
+
<g>
|
|
5
|
+
<rect x="0" y="0" width="400" height="200" fill="#FFFFFF"/>
|
|
6
|
+
<use href="https://example.invalid/sprite.svg#icon" x="200" y="20"/>
|
|
7
|
+
<rect x="10" y="120" width="14" height="14" fill="#0072B2"/><text x="32" y="132" class="ok">图例一</text>
|
|
8
|
+
<rect x="10" y="145" width="14" height="14" fill="#D55E00"/><text x="32" y="157" class="ok">图例二</text>
|
|
9
|
+
<rect x="10" y="170" width="14" height="14" fill="#009E73"/><text x="32" y="182" class="ok">图例三</text>
|
|
10
|
+
</g>
|
|
11
|
+
</svg>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 200" role="img" aria-label="script inside an inline svg">
|
|
2
|
+
<title>Script inside an inline SVG</title>
|
|
3
|
+
<defs><style>.ok{font-size:14px;fill:#111827}</style></defs>
|
|
4
|
+
<script>void 0;</script>
|
|
5
|
+
<g>
|
|
6
|
+
<rect x="0" y="0" width="400" height="200" fill="#FFFFFF"/>
|
|
7
|
+
<rect x="10" y="120" width="14" height="14" fill="#0072B2"/><text x="32" y="132" class="ok">图例一</text>
|
|
8
|
+
<rect x="10" y="145" width="14" height="14" fill="#D55E00"/><text x="32" y="157" class="ok">图例二</text>
|
|
9
|
+
<rect x="10" y="170" width="14" height="14" fill="#009E73"/><text x="32" y="182" class="ok">图例三</text>
|
|
10
|
+
</g>
|
|
11
|
+
</svg>
|
package/dist/assets/release.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schema": 1,
|
|
3
3
|
"npmPackage": "@ccoalm/ccl-skills",
|
|
4
|
-
"version": "0.6.
|
|
5
|
-
"sourceCommit": "
|
|
4
|
+
"version": "0.6.1",
|
|
5
|
+
"sourceCommit": "1fe64817eecf48e4225a6d03f574afc81871ac28",
|
|
6
6
|
"sourceState": "clean",
|
|
7
7
|
"files": [
|
|
8
8
|
{
|
|
@@ -2017,7 +2017,7 @@
|
|
|
2017
2017
|
},
|
|
2018
2018
|
{
|
|
2019
2019
|
"path": "marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/source-register.md",
|
|
2020
|
-
"sha256": "
|
|
2020
|
+
"sha256": "3826b9678567561ad5823fb22f76b1546d1cc886f25ecb988a4557add3443311",
|
|
2021
2021
|
"mode": 420
|
|
2022
2022
|
},
|
|
2023
2023
|
{
|
|
@@ -2632,7 +2632,7 @@
|
|
|
2632
2632
|
},
|
|
2633
2633
|
{
|
|
2634
2634
|
"path": "marketplace/plugins/ccl-skills/skills/tighten-doc/references/figure-and-table-craft.md",
|
|
2635
|
-
"sha256": "
|
|
2635
|
+
"sha256": "15fb3f231595b49730315a9e1f12918e0f268f9d7831523a62d92c5831d0d92d",
|
|
2636
2636
|
"mode": 420
|
|
2637
2637
|
},
|
|
2638
2638
|
{
|
|
@@ -2657,7 +2657,7 @@
|
|
|
2657
2657
|
},
|
|
2658
2658
|
{
|
|
2659
2659
|
"path": "marketplace/plugins/ccl-skills/skills/tighten-doc/scripts/figure-lint.py",
|
|
2660
|
-
"sha256": "
|
|
2660
|
+
"sha256": "688a30beb54b29a070127097dc5716985dc5cb951e5131bb378c9d75776fc22b",
|
|
2661
2661
|
"mode": 493
|
|
2662
2662
|
},
|
|
2663
2663
|
{
|
|
@@ -2672,7 +2672,7 @@
|
|
|
2672
2672
|
},
|
|
2673
2673
|
{
|
|
2674
2674
|
"path": "marketplace/plugins/ccl-skills/skills/tighten-doc/scripts/test_figure_and_doc_lint.sh",
|
|
2675
|
-
"sha256": "
|
|
2675
|
+
"sha256": "f759f974b7c4de72dd7b0599ae14c1a2e4ced7b1610a80dcc96e562cd1bbb11f",
|
|
2676
2676
|
"mode": 493
|
|
2677
2677
|
},
|
|
2678
2678
|
{
|
|
@@ -2800,6 +2800,11 @@
|
|
|
2800
2800
|
"sha256": "8acc43af08efda556400b556f9625b110f505a7698d222705cf74a3ffa78fe8c",
|
|
2801
2801
|
"mode": 420
|
|
2802
2802
|
},
|
|
2803
|
+
{
|
|
2804
|
+
"path": "marketplace/plugins/ccl-skills/skills/tighten-doc/scripts/tests/svg/foreign-ns-title.svg",
|
|
2805
|
+
"sha256": "90a33a506bc6112a51bb66d14b550611b74f81588f1141c9e34f8729a94b1469",
|
|
2806
|
+
"mode": 420
|
|
2807
|
+
},
|
|
2803
2808
|
{
|
|
2804
2809
|
"path": "marketplace/plugins/ccl-skills/skills/tighten-doc/scripts/tests/svg/low-contrast.svg",
|
|
2805
2810
|
"sha256": "64d3406a0c7bf36a5e4ee6961e2aa850e4fb2972e3aeb1c5f24fc7b78b7e4efb",
|
|
@@ -2845,6 +2850,11 @@
|
|
|
2845
2850
|
"sha256": "4366d067bd1a2f15b883e1ba3cf8d1de446f31194c4782b2a9c6b35095e94460",
|
|
2846
2851
|
"mode": 420
|
|
2847
2852
|
},
|
|
2853
|
+
{
|
|
2854
|
+
"path": "marketplace/plugins/ccl-skills/skills/tighten-doc/scripts/tests/svg/self-contained-ok.svg",
|
|
2855
|
+
"sha256": "97b54f836a32cfd40c802eddcc56a83e3a2ca2bc2abeb8baa173ea678ea6e478",
|
|
2856
|
+
"mode": 420
|
|
2857
|
+
},
|
|
2848
2858
|
{
|
|
2849
2859
|
"path": "marketplace/plugins/ccl-skills/skills/tighten-doc/scripts/tests/svg/transformed.svg",
|
|
2850
2860
|
"sha256": "2fe513502d519230109876b8c09988e23cef06127f266d6a075f407b13570e82",
|
|
@@ -2860,6 +2870,36 @@
|
|
|
2860
2870
|
"sha256": "97574a14daeb43df353d436cbfc4b7809b992e0bda3c93374dfe0496dc7c275c",
|
|
2861
2871
|
"mode": 420
|
|
2862
2872
|
},
|
|
2873
|
+
{
|
|
2874
|
+
"path": "marketplace/plugins/ccl-skills/skills/tighten-doc/scripts/tests/svg/unsafe-css-import.svg",
|
|
2875
|
+
"sha256": "933ca0f36b00ad670e937a8fe34ecff2bfc43bfa9206149eb53ad0967a50d41b",
|
|
2876
|
+
"mode": 420
|
|
2877
|
+
},
|
|
2878
|
+
{
|
|
2879
|
+
"path": "marketplace/plugins/ccl-skills/skills/tighten-doc/scripts/tests/svg/unsafe-css-url.svg",
|
|
2880
|
+
"sha256": "06b72d5a57e65aa24a0838cabf2b28ccb72ffa9f473efd54a554533e2bdad87b",
|
|
2881
|
+
"mode": 420
|
|
2882
|
+
},
|
|
2883
|
+
{
|
|
2884
|
+
"path": "marketplace/plugins/ccl-skills/skills/tighten-doc/scripts/tests/svg/unsafe-event-handler.svg",
|
|
2885
|
+
"sha256": "7645dac5995e3567912babd78bff3e6917b23fb08e43dd8683045c36816e56c2",
|
|
2886
|
+
"mode": 420
|
|
2887
|
+
},
|
|
2888
|
+
{
|
|
2889
|
+
"path": "marketplace/plugins/ccl-skills/skills/tighten-doc/scripts/tests/svg/unsafe-external-ref.svg",
|
|
2890
|
+
"sha256": "d4a23f94d0451d80d3cf7b8abd9a7dd1de5e36917d75a03461c1faf2d2c966c7",
|
|
2891
|
+
"mode": 420
|
|
2892
|
+
},
|
|
2893
|
+
{
|
|
2894
|
+
"path": "marketplace/plugins/ccl-skills/skills/tighten-doc/scripts/tests/svg/unsafe-noxmlns.svg",
|
|
2895
|
+
"sha256": "b213dc68e627ca197a26a0a5ba63ebd6a05a2271650cc6aac8fea89775e4e851",
|
|
2896
|
+
"mode": 420
|
|
2897
|
+
},
|
|
2898
|
+
{
|
|
2899
|
+
"path": "marketplace/plugins/ccl-skills/skills/tighten-doc/scripts/tests/svg/unsafe-script.svg",
|
|
2900
|
+
"sha256": "a5f9b7aee40935cb0b494fc62104d1b811bb6945a410cdb04581c682d7ca3e99",
|
|
2901
|
+
"mode": 420
|
|
2902
|
+
},
|
|
2863
2903
|
{
|
|
2864
2904
|
"path": "marketplace/plugins/ccl-skills/skills/tighten-doc/SKILL.md",
|
|
2865
2905
|
"sha256": "4647f69fd7cb1dd9beeeefcbffd3614ddc8e76beaa7a4215fced3adc843e1ef0",
|
|
@@ -3098,5 +3138,5 @@
|
|
|
3098
3138
|
"mode": 420
|
|
3099
3139
|
}
|
|
3100
3140
|
],
|
|
3101
|
-
"snapshotHash": "
|
|
3141
|
+
"snapshotHash": "8ac035597e272582c843f961d753dadd5c9ff576bd7e96d8ce9d486a09fe583d"
|
|
3102
3142
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ccoalm/ccl-skills",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.1",
|
|
4
4
|
"description": "Self-contained CCL Skills installer for Claude Code, Codex, and OpenCode",
|
|
5
5
|
"keywords": ["agent-skills", "claude-code", "codex", "opencode", "developer-tools"],
|
|
6
6
|
"type": "module",
|