@litfamily/litopencode 1.0.7 → 1.0.9
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/CHANGELOG.md +18 -0
- package/README-Ko-KR.md +314 -31
- package/README.md +312 -29
- package/dist/activation-primary-prompts.d.ts +1 -0
- package/dist/activation-primary-prompts.js +16 -0
- package/dist/activation-probe.js +4 -1
- package/dist/activation-prompt-utils.d.ts +1 -1
- package/dist/activation-routing.d.ts +6 -1
- package/dist/activation-routing.js +174 -16
- package/dist/activation-workflow-prompts.d.ts +1 -1
- package/dist/activation-workflow-prompts.js +18 -17
- package/dist/activation.d.ts +3 -2
- package/dist/activation.js +6 -6
- package/dist/agents/defaults.js +14 -6
- package/dist/cli/command-aliases.js +24 -22
- package/dist/cli/doctor.js +3 -0
- package/dist/cli/install-report.d.ts +1 -0
- package/dist/cli/install-report.js +4 -0
- package/dist/cli/install.js +7 -4
- package/dist/cli/managed-skill-assets.d.ts +1 -1
- package/dist/cli/managed-skill-assets.js +15 -5
- package/dist/cli/motion-runtime.d.ts +6 -0
- package/dist/cli/motion-runtime.js +46 -0
- package/dist/cli/native-skill-install.js +32 -9
- package/dist/cli/native-skill-integrity.js +1 -0
- package/dist/cli/native-skills.d.ts +2 -0
- package/dist/cli/native-skills.js +2 -1
- package/dist/cli/office-dependencies.d.ts +14 -0
- package/dist/cli/office-dependencies.js +24 -0
- package/dist/cli.js +13 -3
- package/dist/commands.d.ts +2 -11
- package/dist/commands.js +9 -17
- package/dist/deliverable-hedge-guard.d.ts +20 -21
- package/dist/deliverable-hedge-guard.js +234 -275
- package/dist/features.d.ts +81 -2
- package/dist/features.js +80 -13
- package/dist/hooks.d.ts +3 -2
- package/dist/hooks.js +4 -4
- package/dist/ignition.d.ts +1 -1
- package/dist/ignition.js +15 -4
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/interface-handoff.d.ts +1 -0
- package/dist/interface-handoff.js +1 -0
- package/dist/motion-image-reads.d.ts +6 -0
- package/dist/motion-image-reads.js +46 -0
- package/dist/server.js +13 -11
- package/dist/skill-renames.d.ts +4 -2
- package/dist/skill-renames.js +12 -4
- package/dist/skills.d.ts +31 -3
- package/dist/skills.js +53 -9
- package/dist/tools.js +4 -4
- package/docs/ab/S11/baseline-desktop.webp +0 -0
- package/docs/ab/S11/baseline-phone.webp +0 -0
- package/docs/ab/S11/lit-desktop.webp +0 -0
- package/docs/ab/S11/lit-phone.webp +0 -0
- package/docs/ab/S3/baseline-desktop.webp +0 -0
- package/docs/ab/S3/baseline-phone.webp +0 -0
- package/docs/ab/S3/lit-desktop.webp +0 -0
- package/docs/ab/S3/lit-phone.webp +0 -0
- package/docs/ab/S4/baseline-desktop.webp +0 -0
- package/docs/ab/S4/baseline-phone.webp +0 -0
- package/docs/ab/S4/lit-desktop.webp +0 -0
- package/docs/ab/S4/lit-phone.webp +0 -0
- package/docs/ab/S5/lit-slides.webp +0 -0
- package/docs/ab/S7/lit-diagram.webp +0 -0
- package/docs/ab/S8/baseline-slides.webp +0 -0
- package/docs/ab/S8/lit-slides.webp +0 -0
- package/docs/ab/S9/lit-pages.webp +0 -0
- package/docs/assets/cover-motion-still.webp +0 -0
- package/docs/assets/cover-motion.webp +0 -0
- package/docs/assets/readme/badge-version.svg +1 -1
- package/docs/assets/skills/autoconference.webp +0 -0
- package/docs/assets/skills/automatic-guards.webp +0 -0
- package/docs/assets/skills/autoresearch.webp +0 -0
- package/docs/assets/skills/browser-drive.webp +0 -0
- package/docs/assets/skills/debugging.webp +0 -0
- package/docs/assets/skills/deep-interview.webp +0 -0
- package/docs/assets/skills/doctor-installer.webp +0 -0
- package/docs/assets/skills/durable-litgoal.webp +0 -0
- package/docs/assets/skills/frontend-ui-ux.webp +0 -0
- package/docs/assets/skills/lit-burnoff-file.webp +0 -0
- package/docs/assets/skills/lit-burnoff.webp +0 -0
- package/docs/assets/skills/lit-code.webp +0 -0
- package/docs/assets/skills/lit-commit.webp +0 -0
- package/docs/assets/skills/lit-comprehend.webp +0 -0
- package/docs/assets/skills/lit-crucible.webp +0 -0
- package/docs/assets/skills/lit-diagram-drawer.webp +0 -0
- package/docs/assets/skills/lit-docx.webp +0 -0
- package/docs/assets/skills/lit-fetch.webp +0 -0
- package/docs/assets/skills/lit-handoff.webp +0 -0
- package/docs/assets/skills/lit-humanizer.webp +0 -0
- package/docs/assets/skills/lit-init.webp +0 -0
- package/docs/assets/skills/lit-plan.webp +0 -0
- package/docs/assets/skills/lit-pptx.webp +0 -0
- package/docs/assets/skills/lit-recap.webp +0 -0
- package/docs/assets/skills/lit-scientific-visualization.webp +0 -0
- package/docs/assets/skills/lit-typographic-motion.webp +0 -0
- package/docs/assets/skills/litresearch.webp +0 -0
- package/docs/assets/skills/litwork.webp +0 -0
- package/docs/assets/skills/lsp-setup.webp +0 -0
- package/docs/assets/skills/lsp.webp +0 -0
- package/docs/assets/skills/readme-studio.webp +0 -0
- package/docs/assets/skills/refactor.webp +0 -0
- package/docs/assets/skills/review-work.webp +0 -0
- package/docs/assets/skills/rules.webp +0 -0
- package/docs/assets/skills/start-work.webp +0 -0
- package/docs/assets/skills/structural-search.webp +0 -0
- package/docs/assets/skills/visual-qa.webp +0 -0
- package/docs/assets/skills/wikify.webp +0 -0
- package/docs/reference-Ko-KR.md +5 -1
- package/docs/reference.md +6 -2
- package/package.json +1 -1
- package/rules/bundled-rules/lit-humanizer.md +12 -0
- package/skills/autoconference/SKILL.md +1 -1
- package/skills/autoconference/assets/report_template.md +1 -1
- package/skills/autoresearch/references/type-checklists.md +1 -1
- package/skills/browser-drive/SKILL.md +19 -5
- package/skills/browser-drive/scripts/capability-probe.mjs +26 -5
- package/skills/frontend-ui-ux/SKILL.md +10 -15
- package/skills/frontend-ui-ux/data/THIRD-PARTY-NOTICE.txt +10 -0
- package/skills/frontend-ui-ux/references/adaptive-layout.md +3 -11
- package/skills/frontend-ui-ux/references/brand-and-imagery.md +6 -11
- package/skills/frontend-ui-ux/references/complete-contract.md +10 -3
- package/skills/frontend-ui-ux/references/composition.md +1 -7
- package/skills/frontend-ui-ux/references/craft-floor.md +94 -0
- package/skills/frontend-ui-ux/references/creative-directions.md +1 -7
- package/skills/frontend-ui-ux/references/evidence-review.md +2 -12
- package/skills/frontend-ui-ux/references/implementation-platforms.md +1 -4
- package/skills/frontend-ui-ux/references/inclusive-interface.md +1 -3
- package/skills/frontend-ui-ux/references/interaction-motion.md +1 -7
- package/skills/frontend-ui-ux/references/motion-guide.md +125 -0
- package/skills/frontend-ui-ux/references/operating-lanes.md +2 -8
- package/skills/frontend-ui-ux/references/product-direction.md +1 -6
- package/skills/frontend-ui-ux/references/production.md +12 -5
- package/skills/frontend-ui-ux/references/redesign-playbook.md +1 -7
- package/skills/frontend-ui-ux/references/slop-register.md +103 -0
- package/skills/frontend-ui-ux/references/system-foundations.md +1 -8
- package/skills/frontend-ui-ux/references/taste-direction.md +4 -11
- package/skills/frontend-ui-ux/references/visual-language.md +1 -6
- package/skills/frontend-ui-ux/references/visual-reconstruction.md +2 -7
- package/skills/frontend-ui-ux/scripts/probe-page.mjs +326 -0
- package/skills/frontend-ui-ux/scripts/probe-server.mjs +24 -0
- package/skills/frontend-ui-ux/scripts/probe-static.mjs +42 -0
- package/skills/frontend-ui-ux/scripts/probe-thresholds.json +86 -0
- package/skills/frontend-ui-ux/scripts/probe.mjs +183 -0
- package/skills/lit-comprehend/SKILL.md +10 -11
- package/skills/lit-comprehend/references/artifact-template.md +2 -18
- package/skills/lit-comprehend/scripts/verify-explainer.ts +0 -14
- package/skills/lit-diagram-drawer/NOTICE.md +33 -0
- package/skills/lit-diagram-drawer/SKILL.md +101 -0
- package/skills/lit-diagram-drawer/assets/examples/type-architecture-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-architecture-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-architecture-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-bar-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-bar-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-bar-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-beeswarm-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-beeswarm-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-beeswarm-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-bubble-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-bubble-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-bubble-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-bump-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-bump-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-bump-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-data-flow-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-data-flow-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-data-flow-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-datalake-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-datalake-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-datalake-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-db-schema-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-db-schema-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-db-schema-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-dependency-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-dependency-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-dependency-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-deployment-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-deployment-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-deployment-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-dp-integration-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-dp-integration-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-dp-integration-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-dp-security-matrix-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-dp-security-matrix-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-dp-security-matrix-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-er-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-er-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-er-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-fishbone-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-fishbone-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-fishbone-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-flowchart-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-flowchart-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-flowchart-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-gantt-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-gantt-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-gantt-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-heatmap-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-heatmap-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-heatmap-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-high-level-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-high-level-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-high-level-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-high-level-vertical-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-high-level-vertical-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-high-level-vertical-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-import-drawio-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-import-drawio-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-import-drawio-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-import-excalidraw-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-import-excalidraw-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-import-excalidraw-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-import-mermaid-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-import-mermaid-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-import-mermaid-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-it-state-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-it-state-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-it-state-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-journey-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-journey-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-journey-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-kanban-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-kanban-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-kanban-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-layers-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-layers-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-layers-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-line-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-line-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-line-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-loop-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-loop-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-loop-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-loop-terminal-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-loop-terminal-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-loop-terminal-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-marimekko-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-marimekko-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-marimekko-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-medallion-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-medallion-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-medallion-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-nested-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-nested-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-nested-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-org-chart-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-org-chart-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-org-chart-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-paved-road-animated-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-paved-road-animated-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-paved-road-animated-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-polar-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-polar-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-polar-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-policy-trace-animated-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-policy-trace-animated-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-policy-trace-animated-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-process-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-process-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-process-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-pyramid-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-pyramid-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-pyramid-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-quadrant-consultant-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-quadrant-consultant-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-quadrant-consultant-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-quadrant-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-quadrant-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-quadrant-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-queue-animated-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-queue-animated-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-queue-animated-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-radar-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-radar-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-radar-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-ridgeline-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-ridgeline-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-ridgeline-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-sankey-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-sankey-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-sankey-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-scatter-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-scatter-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-scatter-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-sequence-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-sequence-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-sequence-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-sequence-oauth-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-sequence-oauth-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-sequence-oauth-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-slopegraph-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-slopegraph-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-slopegraph-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-state-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-state-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-state-lifecycle-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-state-lifecycle-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-state-lifecycle-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-state-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-story-map-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-story-map-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-story-map-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-streamgraph-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-streamgraph-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-streamgraph-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-swimlane-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-swimlane-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-swimlane-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-timeline-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-timeline-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-timeline-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-tree-block-decomposition-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-tree-block-decomposition-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-tree-block-decomposition-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-tree-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-tree-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-tree-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-treemap-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-treemap-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-treemap-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-uml-class-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-uml-class-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-uml-class-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-venn-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-venn-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-venn-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-wardley-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-wardley-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-wardley-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-waterfall-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-waterfall-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-waterfall-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/fonts/OFL.txt +94 -0
- package/skills/lit-diagram-drawer/assets/fonts/PretendardVariable.woff2 +0 -0
- package/skills/lit-diagram-drawer/assets/fonts/provenance.json +23 -0
- package/skills/lit-diagram-drawer/assets/icons.html +231 -0
- package/skills/lit-diagram-drawer/assets/licenses/devicon-MIT.txt +20 -0
- package/skills/lit-diagram-drawer/assets/licenses/diagram-design-MIT.txt +21 -0
- package/skills/lit-diagram-drawer/assets/licenses/log-z-MIT.txt +21 -0
- package/skills/lit-diagram-drawer/assets/licenses/simple-icons-CC0.md +30 -0
- package/skills/lit-diagram-drawer/assets/licenses/tabler-MIT.txt +21 -0
- package/skills/lit-diagram-drawer/examples/01-service-architecture/after.html +1 -0
- package/skills/lit-diagram-drawer/examples/01-service-architecture/brief.md +33 -0
- package/skills/lit-diagram-drawer/examples/02-release-decision/after.html +1 -0
- package/skills/lit-diagram-drawer/examples/02-release-decision/brief.md +18 -0
- package/skills/lit-diagram-drawer/examples/03-data-retention/after.html +1 -0
- package/skills/lit-diagram-drawer/examples/03-data-retention/brief.md +19 -0
- package/skills/lit-diagram-drawer/examples/04-oauth-sequence/after.html +1 -0
- package/skills/lit-diagram-drawer/examples/04-oauth-sequence/brief.md +17 -0
- package/skills/lit-diagram-drawer/examples/05-review-lanes/after.html +1 -0
- package/skills/lit-diagram-drawer/examples/05-review-lanes/brief.md +17 -0
- package/skills/lit-diagram-drawer/examples/06-rollout-gates/after.html +1 -0
- package/skills/lit-diagram-drawer/examples/06-rollout-gates/brief.md +17 -0
- package/skills/lit-diagram-drawer/examples/07-deployment-boundary/after.html +1 -0
- package/skills/lit-diagram-drawer/examples/07-deployment-boundary/brief.md +19 -0
- package/skills/lit-diagram-drawer/examples/08-policy-traces/after.html +1 -0
- package/skills/lit-diagram-drawer/examples/08-policy-traces/brief.md +20 -0
- package/skills/lit-diagram-drawer/references/accessibility.md +37 -0
- package/skills/lit-diagram-drawer/references/export.md +17 -0
- package/skills/lit-diagram-drawer/references/import-drawio.md +13 -0
- package/skills/lit-diagram-drawer/references/import-excalidraw.md +11 -0
- package/skills/lit-diagram-drawer/references/import-mermaid.md +12 -0
- package/skills/lit-diagram-drawer/references/import-schema.md +28 -0
- package/skills/lit-diagram-drawer/references/korean-typography.md +34 -0
- package/skills/lit-diagram-drawer/references/motion.md +29 -0
- package/skills/lit-diagram-drawer/references/office-pptx-docx.md +28 -0
- package/skills/lit-diagram-drawer/references/output-spec.md +48 -0
- package/skills/lit-diagram-drawer/references/primitive-annotation.md +12 -0
- package/skills/lit-diagram-drawer/references/primitive-icons.md +21 -0
- package/skills/lit-diagram-drawer/references/primitive-sketchy.md +11 -0
- package/skills/lit-diagram-drawer/references/primitive-terminal.md +11 -0
- package/skills/lit-diagram-drawer/references/profiles.md +24 -0
- package/skills/lit-diagram-drawer/references/semantic-patterns.md +27 -0
- package/skills/lit-diagram-drawer/references/style-guide.md +67 -0
- package/skills/lit-diagram-drawer/references/type-architecture.md +51 -0
- package/skills/lit-diagram-drawer/references/type-bar.md +51 -0
- package/skills/lit-diagram-drawer/references/type-beeswarm.md +49 -0
- package/skills/lit-diagram-drawer/references/type-bubble.md +49 -0
- package/skills/lit-diagram-drawer/references/type-bump.md +49 -0
- package/skills/lit-diagram-drawer/references/type-catalog.json +1433 -0
- package/skills/lit-diagram-drawer/references/type-data-flow.md +51 -0
- package/skills/lit-diagram-drawer/references/type-datalake.md +49 -0
- package/skills/lit-diagram-drawer/references/type-db-schema.md +49 -0
- package/skills/lit-diagram-drawer/references/type-dependency.md +49 -0
- package/skills/lit-diagram-drawer/references/type-deployment.md +49 -0
- package/skills/lit-diagram-drawer/references/type-dp-integration.md +49 -0
- package/skills/lit-diagram-drawer/references/type-dp-security-matrix.md +49 -0
- package/skills/lit-diagram-drawer/references/type-er.md +49 -0
- package/skills/lit-diagram-drawer/references/type-fishbone.md +49 -0
- package/skills/lit-diagram-drawer/references/type-flowchart.md +49 -0
- package/skills/lit-diagram-drawer/references/type-gantt.md +49 -0
- package/skills/lit-diagram-drawer/references/type-heatmap.md +53 -0
- package/skills/lit-diagram-drawer/references/type-high-level-vertical.md +53 -0
- package/skills/lit-diagram-drawer/references/type-high-level.md +53 -0
- package/skills/lit-diagram-drawer/references/type-import-drawio.md +53 -0
- package/skills/lit-diagram-drawer/references/type-import-excalidraw.md +53 -0
- package/skills/lit-diagram-drawer/references/type-import-mermaid.md +53 -0
- package/skills/lit-diagram-drawer/references/type-it-state.md +54 -0
- package/skills/lit-diagram-drawer/references/type-journey.md +54 -0
- package/skills/lit-diagram-drawer/references/type-kanban.md +54 -0
- package/skills/lit-diagram-drawer/references/type-layers.md +54 -0
- package/skills/lit-diagram-drawer/references/type-line.md +54 -0
- package/skills/lit-diagram-drawer/references/type-loop-terminal.md +53 -0
- package/skills/lit-diagram-drawer/references/type-loop.md +54 -0
- package/skills/lit-diagram-drawer/references/type-marimekko.md +54 -0
- package/skills/lit-diagram-drawer/references/type-medallion.md +54 -0
- package/skills/lit-diagram-drawer/references/type-nested.md +59 -0
- package/skills/lit-diagram-drawer/references/type-org-chart.md +58 -0
- package/skills/lit-diagram-drawer/references/type-paved-road-animated.md +72 -0
- package/skills/lit-diagram-drawer/references/type-polar.md +67 -0
- package/skills/lit-diagram-drawer/references/type-policy-trace-animated.md +69 -0
- package/skills/lit-diagram-drawer/references/type-process.md +58 -0
- package/skills/lit-diagram-drawer/references/type-pyramid.md +59 -0
- package/skills/lit-diagram-drawer/references/type-quadrant-consultant.md +60 -0
- package/skills/lit-diagram-drawer/references/type-quadrant.md +57 -0
- package/skills/lit-diagram-drawer/references/type-queue-animated.md +63 -0
- package/skills/lit-diagram-drawer/references/type-radar.md +57 -0
- package/skills/lit-diagram-drawer/references/type-ridgeline.md +63 -0
- package/skills/lit-diagram-drawer/references/type-sankey.md +68 -0
- package/skills/lit-diagram-drawer/references/type-scatter.md +60 -0
- package/skills/lit-diagram-drawer/references/type-sequence-oauth.md +66 -0
- package/skills/lit-diagram-drawer/references/type-sequence.md +63 -0
- package/skills/lit-diagram-drawer/references/type-slopegraph.md +65 -0
- package/skills/lit-diagram-drawer/references/type-state-lifecycle.md +53 -0
- package/skills/lit-diagram-drawer/references/type-state.md +59 -0
- package/skills/lit-diagram-drawer/references/type-story-map.md +52 -0
- package/skills/lit-diagram-drawer/references/type-streamgraph.md +53 -0
- package/skills/lit-diagram-drawer/references/type-swimlane.md +52 -0
- package/skills/lit-diagram-drawer/references/type-timeline.md +52 -0
- package/skills/lit-diagram-drawer/references/type-tree-block-decomposition.md +57 -0
- package/skills/lit-diagram-drawer/references/type-tree.md +54 -0
- package/skills/lit-diagram-drawer/references/type-treemap.md +54 -0
- package/skills/lit-diagram-drawer/references/type-uml-class.md +52 -0
- package/skills/lit-diagram-drawer/references/type-venn.md +51 -0
- package/skills/lit-diagram-drawer/references/type-wardley.md +52 -0
- package/skills/lit-diagram-drawer/references/type-waterfall.md +54 -0
- package/skills/lit-diagram-drawer/references/verifier-guide.md +59 -0
- package/skills/lit-diagram-drawer/scripts/block-registry.mjs +43 -0
- package/skills/lit-diagram-drawer/scripts/brief-contract.mjs +94 -0
- package/skills/lit-diagram-drawer/scripts/capability-probe.mjs +132 -0
- package/skills/lit-diagram-drawer/scripts/check-visible-text.mjs +15 -0
- package/skills/lit-diagram-drawer/scripts/craft-thresholds.json +15 -0
- package/skills/lit-diagram-drawer/scripts/diagram-metrics.mjs +216 -0
- package/skills/lit-diagram-drawer/scripts/doctor.mjs +8 -0
- package/skills/lit-diagram-drawer/scripts/drawio-extract.mjs +214 -0
- package/skills/lit-diagram-drawer/scripts/excalidraw-extract.mjs +151 -0
- package/skills/lit-diagram-drawer/scripts/export.mjs +133 -0
- package/skills/lit-diagram-drawer/scripts/import-shared.mjs +130 -0
- package/skills/lit-diagram-drawer/scripts/mermaid-extract.mjs +173 -0
- package/skills/lit-diagram-drawer/scripts/office-safety.mjs +120 -0
- package/skills/lit-diagram-drawer/scripts/renderer-safety.mjs +46 -0
- package/skills/lit-diagram-drawer/scripts/test-block-registry.mjs +20 -0
- package/skills/lit-diagram-drawer/scripts/test-brief-contract.mjs +27 -0
- package/skills/lit-diagram-drawer/scripts/test-importers.mjs +119 -0
- package/skills/lit-diagram-drawer/scripts/test-office-safety.mjs +67 -0
- package/skills/lit-diagram-drawer/scripts/test-sequence-verifier.mjs +28 -0
- package/skills/lit-diagram-drawer/scripts/test-visual-quality.mjs +68 -0
- package/skills/lit-diagram-drawer/scripts/verify-all.mjs +74 -0
- package/skills/lit-diagram-drawer/scripts/verify-brief.mjs +47 -0
- package/skills/lit-diagram-drawer/scripts/verify-coverage.mjs +56 -0
- package/skills/lit-diagram-drawer/scripts/verify-diagram.mjs +26 -0
- package/skills/lit-diagram-drawer/scripts/verify-motion.mjs +12 -0
- package/skills/lit-diagram-drawer/scripts/verify-type.mjs +48 -0
- package/skills/lit-diagram-drawer/scripts/visual-quality.mjs +363 -0
- package/skills/lit-docx/LICENSE-MIT.txt +21 -0
- package/skills/lit-docx/SKILL.md +78 -0
- package/skills/lit-docx/references/frontmatter_schema.md +42 -0
- package/skills/lit-docx/references/journal_style_spec.md +17 -0
- package/skills/lit-docx/references/markdown_quality_checklist.md +37 -0
- package/skills/lit-docx/references/slop_phrase_list.yaml +58 -0
- package/skills/lit-docx/references/slop_rules.md +35 -0
- package/skills/lit-docx/requirements.in +5 -0
- package/skills/lit-docx/requirements.lock +289 -0
- package/skills/lit-docx/run.py +64 -0
- package/skills/lit-docx/scripts/clean_markdown.py +95 -0
- package/skills/lit-docx/scripts/convert_md_to_docx.py +1047 -0
- package/skills/lit-docx/scripts/convert_md_to_pdf.py +281 -0
- package/skills/lit-docx/scripts/convert_pdf.py +130 -0
- package/skills/lit-docx/scripts/craft-thresholds.json +11 -0
- package/skills/lit-docx/scripts/craft_docx.py +83 -0
- package/skills/lit-docx/scripts/edit_docx.py +297 -0
- package/skills/lit-docx/scripts/embed_images.py +78 -0
- package/skills/lit-docx/scripts/generate_docx_templates.py +491 -0
- package/skills/lit-docx/scripts/slop_lint.py +485 -0
- package/skills/lit-docx/scripts/visual_audit.py +41 -0
- package/skills/lit-docx/templates/docx/acs.docx +0 -0
- package/skills/lit-docx/templates/docx/elsevier.docx +0 -0
- package/skills/lit-docx/templates/docx/ieee.docx +0 -0
- package/skills/lit-docx/templates/docx/korean-generic.docx +0 -0
- package/skills/lit-docx/templates/docx/nature.docx +0 -0
- package/skills/lit-docx/templates/latex/acs/README.md +5 -0
- package/skills/lit-docx/templates/latex/acs/template.tex +37 -0
- package/skills/lit-docx/templates/latex/elsevier/README.md +5 -0
- package/skills/lit-docx/templates/latex/elsevier/template.tex +38 -0
- package/skills/lit-docx/templates/latex/ieee/README.md +5 -0
- package/skills/lit-docx/templates/latex/ieee/template.tex +37 -0
- package/skills/lit-docx/templates/latex/korean-generic/README.md +5 -0
- package/skills/lit-docx/templates/latex/korean-generic/template.tex +37 -0
- package/skills/lit-docx/templates/latex/nature/README.md +5 -0
- package/skills/lit-docx/templates/latex/nature/template.tex +37 -0
- package/skills/lit-docx/templates/registry.yaml +1366 -0
- package/skills/lit-humanizer/NOTICE +160 -0
- package/skills/lit-humanizer/SKILL.md +122 -0
- package/skills/lit-humanizer/assets/always-on-rule.md +9 -0
- package/skills/lit-humanizer/assets/report-skeleton.md +25 -0
- package/skills/lit-humanizer/assets/slide-text-skeleton.md +28 -0
- package/skills/lit-humanizer/examples/accessibility-note/after.md +7 -0
- package/skills/lit-humanizer/examples/accessibility-note/before.md +7 -0
- package/skills/lit-humanizer/examples/api-reference/after.md +9 -0
- package/skills/lit-humanizer/examples/api-reference/before.md +15 -0
- package/skills/lit-humanizer/examples/changelog/after.md +5 -0
- package/skills/lit-humanizer/examples/changelog/before.md +12 -0
- package/skills/lit-humanizer/examples/code-comments/after.md +10 -0
- package/skills/lit-humanizer/examples/code-comments/before.md +19 -0
- package/skills/lit-humanizer/examples/commit/after.md +5 -0
- package/skills/lit-humanizer/examples/commit/before.md +7 -0
- package/skills/lit-humanizer/examples/data-release/after.md +7 -0
- package/skills/lit-humanizer/examples/data-release/before.md +9 -0
- package/skills/lit-humanizer/examples/english-essay/after.md +5 -0
- package/skills/lit-humanizer/examples/english-essay/before.md +5 -0
- package/skills/lit-humanizer/examples/incident-update/after.md +7 -0
- package/skills/lit-humanizer/examples/incident-update/before.md +7 -0
- package/skills/lit-humanizer/examples/ko-essay/after.md +7 -0
- package/skills/lit-humanizer/examples/ko-essay/before.md +9 -0
- package/skills/lit-humanizer/examples/ko-report/after.md +9 -0
- package/skills/lit-humanizer/examples/ko-report/before.md +13 -0
- package/skills/lit-humanizer/examples/ko-slide/after.md +19 -0
- package/skills/lit-humanizer/examples/ko-slide/before.md +21 -0
- package/skills/lit-humanizer/examples/meeting-brief/after.md +9 -0
- package/skills/lit-humanizer/examples/meeting-brief/before.md +11 -0
- package/skills/lit-humanizer/examples/policy-faq/after.md +9 -0
- package/skills/lit-humanizer/examples/policy-faq/before.md +9 -0
- package/skills/lit-humanizer/examples/pr/after.md +15 -0
- package/skills/lit-humanizer/examples/pr/before.md +17 -0
- package/skills/lit-humanizer/examples/project-update/after.md +7 -0
- package/skills/lit-humanizer/examples/project-update/before.md +9 -0
- package/skills/lit-humanizer/examples/readme/after.md +12 -0
- package/skills/lit-humanizer/examples/readme/before.md +14 -0
- package/skills/lit-humanizer/examples/report/after.md +13 -0
- package/skills/lit-humanizer/examples/report/before.md +11 -0
- package/skills/lit-humanizer/examples/research-abstract/after.md +5 -0
- package/skills/lit-humanizer/examples/research-abstract/before.md +5 -0
- package/skills/lit-humanizer/examples/slides/after.md +19 -0
- package/skills/lit-humanizer/examples/slides/before.md +19 -0
- package/skills/lit-humanizer/examples/troubleshooting/after.md +11 -0
- package/skills/lit-humanizer/examples/troubleshooting/before.md +11 -0
- package/skills/lit-humanizer/fixtures/ko-metrics-golden.json +49 -0
- package/skills/lit-humanizer/fixtures/office/minimal.docx +0 -0
- package/skills/lit-humanizer/fixtures/office/minimal.pptx +0 -0
- package/skills/lit-humanizer/fixtures/pos-real.txt +26 -0
- package/skills/lit-humanizer/fixtures/rule-cases.json +306 -0
- package/skills/lit-humanizer/references/code-patterns.md +468 -0
- package/skills/lit-humanizer/references/deliverable-channels.md +111 -0
- package/skills/lit-humanizer/references/en-patterns-checklist.md +43 -0
- package/skills/lit-humanizer/references/en-patterns-content.md +243 -0
- package/skills/lit-humanizer/references/en-patterns-structure.md +375 -0
- package/skills/lit-humanizer/references/en-patterns.md +57 -0
- package/skills/lit-humanizer/references/ko-metrics.md +33 -0
- package/skills/lit-humanizer/references/ko-patterns-a-d.md +659 -0
- package/skills/lit-humanizer/references/ko-patterns-e-j.md +387 -0
- package/skills/lit-humanizer/references/ko-patterns.md +31 -0
- package/skills/lit-humanizer/references/rewrite-playbook.md +54 -0
- package/skills/lit-humanizer/references/taxonomy.md +153 -0
- package/skills/lit-humanizer/rules.json +884 -0
- package/skills/lit-humanizer/scripts/core.mjs +208 -0
- package/skills/lit-humanizer/scripts/detect.mjs +91 -0
- package/skills/lit-humanizer/scripts/extract_office_text.py +89 -0
- package/skills/lit-humanizer/scripts/guard-scan.mjs +36 -0
- package/skills/lit-humanizer/scripts/ko-metrics.mjs +124 -0
- package/skills/lit-humanizer/scripts/test-fixtures.mjs +54 -0
- package/skills/lit-humanizer/scripts/test-ko-metrics.mjs +27 -0
- package/skills/lit-pptx/FORBIDDEN_TERMS.json +55 -0
- package/skills/lit-pptx/NOTICE.md +3 -0
- package/skills/lit-pptx/SKILL.md +76 -0
- package/skills/lit-pptx/agents/analyst.md +49 -0
- package/skills/lit-pptx/agents/antithesis.md +59 -0
- package/skills/lit-pptx/agents/architect.md +44 -0
- package/skills/lit-pptx/agents/critic.md +42 -0
- package/skills/lit-pptx/agents/synthesizer.md +47 -0
- package/skills/lit-pptx/agents/thesis.md +33 -0
- package/skills/lit-pptx/assets/azure/circle-lg.png +0 -0
- package/skills/lit-pptx/assets/azure/circle-md.png +0 -0
- package/skills/lit-pptx/assets/azure/circle-sm.png +0 -0
- package/skills/lit-pptx/fonts/a2z-font/A2Z-Black.otf +0 -0
- package/skills/lit-pptx/fonts/a2z-font/A2Z-Bold.otf +0 -0
- package/skills/lit-pptx/fonts/a2z-font/A2Z-Light.otf +0 -0
- package/skills/lit-pptx/fonts/a2z-font/A2Z-Medium.otf +0 -0
- package/skills/lit-pptx/fonts/a2z-font/A2Z-Regular.otf +0 -0
- package/skills/lit-pptx/fonts/a2z-font/OFL.txt +94 -0
- package/skills/lit-pptx/fonts/a2z-font/SOURCE.md +29 -0
- package/skills/lit-pptx/package-lock.json +747 -0
- package/skills/lit-pptx/package.json +13 -0
- package/skills/lit-pptx/pretendard-font/LICENSE.txt +94 -0
- package/skills/lit-pptx/pretendard-font/public/static/LitOpenCodeSans-Bold.otf +0 -0
- package/skills/lit-pptx/pretendard-font/public/static/LitOpenCodeSans-Regular.otf +0 -0
- package/skills/lit-pptx/requirements.in +2 -0
- package/skills/lit-pptx/requirements.lock +285 -0
- package/skills/lit-pptx/run.mjs +71 -0
- package/skills/lit-pptx/scripts/check_ooxml.py +47 -0
- package/skills/lit-pptx/scripts/compile-deck.js +447 -0
- package/skills/lit-pptx/scripts/craft-thresholds.json +26 -0
- package/skills/lit-pptx/scripts/craft_extras.py +224 -0
- package/skills/lit-pptx/scripts/embed_fonts.py +204 -0
- package/skills/lit-pptx/scripts/layout_inventory.py +70 -0
- package/skills/lit-pptx/scripts/learn_template.py +433 -0
- package/skills/lit-pptx/scripts/lib/derive-palette.js +176 -0
- package/skills/lit-pptx/scripts/lib/directive-parser.js +244 -0
- package/skills/lit-pptx/scripts/lib/font-map.js +79 -0
- package/skills/lit-pptx/scripts/lib/gen-bg.js +85 -0
- package/skills/lit-pptx/scripts/lib/gen-gradient-assets.js +36 -0
- package/skills/lit-pptx/scripts/lib/layout-resolver.js +737 -0
- package/skills/lit-pptx/scripts/lib/markdown-loader.js +136 -0
- package/skills/lit-pptx/scripts/lib/render-adapter-html.js +364 -0
- package/skills/lit-pptx/scripts/lib/render-adapter-pptx.js +1848 -0
- package/skills/lit-pptx/scripts/lib/slide-ast.js +534 -0
- package/skills/lit-pptx/scripts/lib/spec-validator.js +94 -0
- package/skills/lit-pptx/scripts/lib/template-registry.js +355 -0
- package/skills/lit-pptx/scripts/qa_deck.py +773 -0
- package/skills/lit-pptx/scripts/validate_pptx.py +206 -0
- package/skills/lit-pptx/specs/markdown-slide-spec-v1.md +251 -0
- package/skills/lit-pptx/specs/markdown-slide-spec-v2.md +223 -0
- package/skills/lit-pptx/specs/slide-ast-v1.schema.json +229 -0
- package/skills/lit-pptx/specs/slide-ast-v2.schema.json +144 -0
- package/skills/lit-pptx/specs/template-enrollment-contract.md +379 -0
- package/skills/lit-pptx/templates/bauhaus_light.css +4 -0
- package/skills/lit-pptx/templates/boilerplate_professional.css +508 -0
- package/skills/lit-pptx/templates/enrolled/AZURE-A2Z/capabilities.yaml +146 -0
- package/skills/lit-pptx/templates/enrolled/AZURE-A2Z/layout-mapping.yaml +454 -0
- package/skills/lit-pptx/templates/enrolled/AZURE-A2Z/template.yaml +37 -0
- package/skills/lit-pptx/templates/enrolled/AZURE-PRO/capabilities.yaml +154 -0
- package/skills/lit-pptx/templates/enrolled/AZURE-PRO/layout-mapping.yaml +483 -0
- package/skills/lit-pptx/templates/enrolled/AZURE-PRO/template.yaml +37 -0
- package/skills/lit-pptx/templates/enrolled/BOILERPLATE-A2Z/capabilities.yaml +179 -0
- package/skills/lit-pptx/templates/enrolled/BOILERPLATE-A2Z/layout-mapping.yaml +299 -0
- package/skills/lit-pptx/templates/enrolled/BOILERPLATE-A2Z/template.yaml +45 -0
- package/skills/lit-pptx/templates/enrolled/BOILERPLATE-PRETENDARD/capabilities.yaml +181 -0
- package/skills/lit-pptx/templates/enrolled/BOILERPLATE-PRETENDARD/layout-mapping.yaml +299 -0
- package/skills/lit-pptx/templates/enrolled/BOILERPLATE-PRETENDARD/template.yaml +44 -0
- package/skills/lit-scientific-visualization/SKILL.md +2 -0
- package/skills/lit-typographic-motion/NOTICE +23 -0
- package/skills/lit-typographic-motion/SKILL.md +77 -0
- package/skills/lit-typographic-motion/THIRD_PARTY_NOTICES +25 -0
- package/skills/lit-typographic-motion/audio-analysis.py +52 -0
- package/skills/lit-typographic-motion/engine/browser.mjs +83 -0
- package/skills/lit-typographic-motion/engine/constants.mjs +177 -0
- package/skills/lit-typographic-motion/engine/contrast.mjs +101 -0
- package/skills/lit-typographic-motion/engine/encode.mjs +46 -0
- package/skills/lit-typographic-motion/engine/flash.mjs +216 -0
- package/skills/lit-typographic-motion/engine/look.mjs +166 -0
- package/skills/lit-typographic-motion/engine/page/common.js +105 -0
- package/skills/lit-typographic-motion/engine/page/engine.js +451 -0
- package/skills/lit-typographic-motion/engine/page/gl.js +213 -0
- package/skills/lit-typographic-motion/engine/page/lines.js +88 -0
- package/skills/lit-typographic-motion/engine/page/passes.js +144 -0
- package/skills/lit-typographic-motion/engine/page/post.js +119 -0
- package/skills/lit-typographic-motion/engine/page/scenes.js +187 -0
- package/skills/lit-typographic-motion/engine/page/type.js +321 -0
- package/skills/lit-typographic-motion/engine/png.mjs +139 -0
- package/skills/lit-typographic-motion/engine/sound.mjs +291 -0
- package/skills/lit-typographic-motion/engine/stage/capture.mjs +133 -0
- package/skills/lit-typographic-motion/engine/stage/clock.js +171 -0
- package/skills/lit-typographic-motion/engine/stage/frame-worker.mjs +47 -0
- package/skills/lit-typographic-motion/engine/stage/gate.mjs +119 -0
- package/skills/lit-typographic-motion/engine/stage/qa-page.js +158 -0
- package/skills/lit-typographic-motion/engine/stage/qa.mjs +208 -0
- package/skills/lit-typographic-motion/engine/stage/render.mjs +418 -0
- package/skills/lit-typographic-motion/engine/stage/scan.mjs +162 -0
- package/skills/lit-typographic-motion/engine/stage/stage-kit.js +310 -0
- package/skills/lit-typographic-motion/engine/stills.mjs +60 -0
- package/skills/lit-typographic-motion/engine/text.mjs +126 -0
- package/skills/lit-typographic-motion/engine/timing.mjs +289 -0
- package/skills/lit-typographic-motion/engine/treatment.mjs +254 -0
- package/skills/lit-typographic-motion/fonts/Archivo-100-400.ttf +0 -0
- package/skills/lit-typographic-motion/fonts/Archivo-100-700.ttf +0 -0
- package/skills/lit-typographic-motion/fonts/Archivo-100-900.ttf +0 -0
- package/skills/lit-typographic-motion/fonts/Archivo-125-400.ttf +0 -0
- package/skills/lit-typographic-motion/fonts/Archivo-125-700.ttf +0 -0
- package/skills/lit-typographic-motion/fonts/Archivo-125-900.ttf +0 -0
- package/skills/lit-typographic-motion/fonts/Archivo-75-400.ttf +0 -0
- package/skills/lit-typographic-motion/fonts/Archivo-75-700.ttf +0 -0
- package/skills/lit-typographic-motion/fonts/Archivo-75-900.ttf +0 -0
- package/skills/lit-typographic-motion/fonts/Archivo-OFL.txt +93 -0
- package/skills/lit-typographic-motion/fonts/Silkscreen-Bold.ttf +0 -0
- package/skills/lit-typographic-motion/fonts/Silkscreen-OFL.txt +93 -0
- package/skills/lit-typographic-motion/fonts/Silkscreen-Regular.ttf +0 -0
- package/skills/lit-typographic-motion/fonts/VT323-OFL.txt +93 -0
- package/skills/lit-typographic-motion/fonts/VT323-Regular.ttf +0 -0
- package/skills/lit-typographic-motion/fonts/pins.json +44 -0
- package/skills/lit-typographic-motion/fonts/stroke/CREDITS +52 -0
- package/skills/lit-typographic-motion/fonts/stroke/EMSAllure.svg +216 -0
- package/skills/lit-typographic-motion/fonts/stroke/EMSFelix.svg +216 -0
- package/skills/lit-typographic-motion/fonts/stroke/EMSOsmotron.svg +216 -0
- package/skills/lit-typographic-motion/fonts/stroke/EMSReadability.svg +216 -0
- package/skills/lit-typographic-motion/fonts/stroke/EMSTech.svg +217 -0
- package/skills/lit-typographic-motion/fonts/stroke/OFL.txt +85 -0
- package/skills/lit-typographic-motion/gate.mjs +593 -0
- package/skills/lit-typographic-motion/package-lock.json +78 -0
- package/skills/lit-typographic-motion/package.json +11 -0
- package/skills/lit-typographic-motion/probe.mjs +74 -0
- package/skills/lit-typographic-motion/references/authoring.md +110 -0
- package/skills/lit-typographic-motion/references/craft-loop.md +110 -0
- package/skills/lit-typographic-motion/references/runtime.md +88 -0
- package/skills/lit-typographic-motion/references/stage.md +164 -0
- package/skills/lit-typographic-motion/references/style-bibles.md +88 -0
- package/skills/lit-typographic-motion/references/treatment.md +143 -0
- package/skills/lit-typographic-motion/references/type-craft.md +55 -0
- package/skills/lit-typographic-motion/render.mjs +654 -0
- package/skills/lit-typographic-motion/requirements-audio.in +1 -0
- package/skills/lit-typographic-motion/requirements-audio.txt +790 -0
- package/skills/lit-typographic-motion/runtime.mjs +259 -0
- package/skills/lit-typographic-motion/word-timing-models.json +25 -0
- package/skills/litresearch/SKILL.md +41 -12
- package/skills/managed-skill-manifest.json +2367 -63
- package/skills/skill-rename-aliases.json +6 -1
- package/tools/check-pack-payload.mjs +22 -1
- package/tools/check-payload-substance.mjs +2 -2
- package/tools/payload-reference-exemptions.json +4 -0
- package/tools/payload-substance-allowlist.json +2 -3
- package/tools/payload-substance-parity.json +7 -7
- package/tools/version-manifests.json +4 -4
- package/skills/lit-korean/SKILL.md +0 -231
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
export function decodeXmlCharacterReferences(value) {
|
|
2
|
+
try{
|
|
3
|
+
const decoded=String(value).replace(/&#(?:x([0-9a-fA-F]+)|([0-9]+));/g,(_entity,hex,decimal)=>{
|
|
4
|
+
const code=Number.parseInt(hex||decimal,hex?16:10);
|
|
5
|
+
if(!Number.isInteger(code)||!(code===9||code===10||code===13||(code>=32&&code<=0xd7ff)||(code>=0xe000&&code<=0xfffd)||(code>=0x10000&&code<=0x10ffff)))throw new Error('invalid XML character reference');
|
|
6
|
+
return String.fromCodePoint(code);
|
|
7
|
+
});
|
|
8
|
+
return decoded.includes('&#')?null:decoded;
|
|
9
|
+
}catch{return null;}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function markupStartTags(source) {
|
|
13
|
+
const tags = [];
|
|
14
|
+
for (let offset = 0; offset < source.length;) {
|
|
15
|
+
const start = source.indexOf('<', offset);
|
|
16
|
+
if (start < 0) break;
|
|
17
|
+
if (!/[A-Za-z_:]/u.test(source[start + 1] ?? '')) { offset = start + 1; continue; }
|
|
18
|
+
let quote = '';
|
|
19
|
+
let end = start + 2;
|
|
20
|
+
for (; end < source.length; end += 1) {
|
|
21
|
+
const char = source[end];
|
|
22
|
+
if (quote) { if (char === quote) quote = ''; }
|
|
23
|
+
else if (char === '"' || char === "'") quote = char;
|
|
24
|
+
else if (char === '>') break;
|
|
25
|
+
}
|
|
26
|
+
if (end >= source.length) break;
|
|
27
|
+
tags.push(source.slice(start, end + 1));
|
|
28
|
+
offset = end + 1;
|
|
29
|
+
}
|
|
30
|
+
return tags;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function markupTagName(tag) {
|
|
34
|
+
return /^<\s*([A-Za-z_:][\w:.-]*)/u.exec(tag)?.[1].toLowerCase() ?? '';
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function markupAttributes(tag) {
|
|
38
|
+
const attributes = [];
|
|
39
|
+
let index = 1;
|
|
40
|
+
while (/[A-Za-z_:]/u.test(tag[index] ?? '')) index += 1;
|
|
41
|
+
while (index < tag.length) {
|
|
42
|
+
while (/[\s/]/u.test(tag[index] ?? '')) index += 1;
|
|
43
|
+
if (tag[index] === '>' || index >= tag.length) break;
|
|
44
|
+
const start = index;
|
|
45
|
+
while (index < tag.length && !/[\s/=>]/u.test(tag[index])) index += 1;
|
|
46
|
+
if (index === start) { index += 1; continue; }
|
|
47
|
+
const name = tag.slice(start, index).toLowerCase();
|
|
48
|
+
while (/\s/u.test(tag[index] ?? '')) index += 1;
|
|
49
|
+
let value = '';
|
|
50
|
+
if (tag[index] === '=') {
|
|
51
|
+
index += 1;
|
|
52
|
+
while (/\s/u.test(tag[index] ?? '')) index += 1;
|
|
53
|
+
const quote = tag[index] === '"' || tag[index] === "'" ? tag[index++] : '';
|
|
54
|
+
const valueStart = index;
|
|
55
|
+
if (quote) { while (index < tag.length && tag[index] !== quote) index += 1; }
|
|
56
|
+
else { while (index < tag.length && !/[\s>]/u.test(tag[index])) index += 1; }
|
|
57
|
+
value = tag.slice(valueStart, index);
|
|
58
|
+
if (quote && tag[index] === quote) index += 1;
|
|
59
|
+
}
|
|
60
|
+
attributes.push({ name, value });
|
|
61
|
+
}
|
|
62
|
+
return attributes;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function cssUrlsAreSafe(svg,{allowReference=(value)=>/^#[A-Za-z0-9_.:-]+$/.test(value)}={}) {
|
|
66
|
+
if(decodeXmlCharacterReferences(svg)===null)return false;
|
|
67
|
+
if(String(svg).includes('<!--'))return false;
|
|
68
|
+
const source=String(svg);
|
|
69
|
+
const cssParts=[...source.matchAll(/<style\b[^>]*>([\s\S]*?)<\/style\s*>/gi)].map((match)=>match[1]);
|
|
70
|
+
const tags=markupStartTags(source);
|
|
71
|
+
const presentationNames=new Set(['fill','stroke','filter','mask','clip-path','marker-start','marker-mid','marker-end','cursor']);
|
|
72
|
+
for(const tag of tags){
|
|
73
|
+
for(const attribute of markupAttributes(tag)){
|
|
74
|
+
if(attribute.name==='style'||presentationNames.has(attribute.name))cssParts.push(attribute.value);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
const decodedParts=cssParts.map((part)=>decodeXmlCharacterReferences(part.replace(/\/\*[\s\S]*?\*\//g,'')));
|
|
78
|
+
if(decodedParts.some((part)=>part===null))return false;
|
|
79
|
+
const cssSource=decodedParts.join('\n');
|
|
80
|
+
if(cssSource.includes('\\')||/@import\b|\bvar\s*\(|\blocal\s*\(|\bunicode-range\s*:|(?:-webkit-)?image-set\s*\(|\bimage\s*\(|\bsrc\s*\(/i.test(cssSource)||decodedParts.some((part)=>part.includes('&')))return false;
|
|
81
|
+
const url=/url\s*\(/ig;
|
|
82
|
+
let match;
|
|
83
|
+
while((match=url.exec(cssSource))){
|
|
84
|
+
let quote=null,end=-1;
|
|
85
|
+
for(let i=url.lastIndex;i<cssSource.length;i++){
|
|
86
|
+
const char=cssSource[i];
|
|
87
|
+
if(quote){if(char===quote)quote=null;continue;}
|
|
88
|
+
if(char==='"'||char==="'"){quote=char;continue;}
|
|
89
|
+
if(char==='(')return false;
|
|
90
|
+
if(char===')'){end=i;break;}
|
|
91
|
+
}
|
|
92
|
+
if(end<0||quote)return false;
|
|
93
|
+
let value=cssSource.slice(url.lastIndex,end).trim();
|
|
94
|
+
if((value.startsWith('"')&&value.endsWith('"'))||(value.startsWith("'")&&value.endsWith("'")))value=value.slice(1,-1).trim();
|
|
95
|
+
if(!allowReference(value))return false;
|
|
96
|
+
url.lastIndex=end+1;
|
|
97
|
+
}
|
|
98
|
+
return true;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export function officeCssUrlsAreSafe(svg) {
|
|
102
|
+
return cssUrlsAreSafe(svg);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export function officeHrefRefsAreSafe(svg) {
|
|
106
|
+
if(decodeXmlCharacterReferences(svg)===null)return false;
|
|
107
|
+
if(String(svg).includes('<!--'))return false;
|
|
108
|
+
const source=String(svg);
|
|
109
|
+
const tags=markupStartTags(source);
|
|
110
|
+
for(const tag of tags){
|
|
111
|
+
const decodedTag=decodeXmlCharacterReferences(tag);
|
|
112
|
+
if(decodedTag===null)return false;
|
|
113
|
+
if(markupTagName(decodedTag)==='base')return false;
|
|
114
|
+
for(const {name,value} of markupAttributes(decodedTag)){
|
|
115
|
+
if(name==='xml:base')return false;
|
|
116
|
+
if(['href','src'].includes(name)&&!/^#[A-Za-z0-9_.:-]+$/u.test(value.trim()))return false;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return true;
|
|
120
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
4
|
+
import { cssUrlsAreSafe, decodeXmlCharacterReferences, markupAttributes, markupStartTags, markupTagName, officeHrefRefsAreSafe } from './office-safety.mjs';
|
|
5
|
+
|
|
6
|
+
const BLOCKED_ELEMENTS = /<\s*(?:script|iframe|object|embed|foreignObject|link|applet|portal|frame|frameset|audio|video|source|track|image|animate(?:Motion|Transform)?|set|discard)\b/iu;
|
|
7
|
+
const EVENT_ATTRIBUTE = /^on[a-z][\w:.-]*$/iu;
|
|
8
|
+
const RESOURCE_ATTRIBUTES = new Set(['srcdoc','srcset','poster','background','manifest','codebase','archive','ping','profile']);
|
|
9
|
+
|
|
10
|
+
export function fontReferencePortable(value, sourceFile, fontFile) {
|
|
11
|
+
if (/^#[A-Za-z][\w:.-]*$/u.test(value)) return true;
|
|
12
|
+
if (/^data:font\/woff2;base64,[A-Za-z\d+/]*={0,2}$/iu.test(value)) return true;
|
|
13
|
+
if (!sourceFile || !fontFile) return false;
|
|
14
|
+
try {
|
|
15
|
+
const skillRoot = path.resolve(fontFile, '../../..');
|
|
16
|
+
const relativeSource = path.relative(skillRoot, path.resolve(sourceFile));
|
|
17
|
+
if (relativeSource.startsWith(`..${path.sep}`) || relativeSource === '..' || path.isAbsolute(relativeSource)) return false;
|
|
18
|
+
const target = new URL(value, pathToFileURL(path.resolve(sourceFile)));
|
|
19
|
+
return target.protocol === 'file:' && !target.search && !target.hash
|
|
20
|
+
&& fs.realpathSync(fileURLToPath(target)) === fs.realpathSync(fontFile);
|
|
21
|
+
} catch {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function rendererSourceIssue(source, { sourceFile, fontFile } = {}) {
|
|
27
|
+
const decoded = decodeXmlCharacterReferences(source);
|
|
28
|
+
if (decoded === null) return 'invalid character references are unsupported';
|
|
29
|
+
if (source.includes('<!--')) return 'HTML comment markup is unsupported during capture';
|
|
30
|
+
const activeCheck = source;
|
|
31
|
+
const declarationSource = activeCheck.replace(/<!doctype\s+html\s*>/giu, '');
|
|
32
|
+
if (/<!DOCTYPE\b|<!ENTITY\b/iu.test(declarationSource)) return 'DTD and entity declarations are unsupported';
|
|
33
|
+
if (declarationSource.replace(/^\uFEFF?\s*<\?xml\s+[^?]*\?>/iu, '').includes('<?')) return 'non-XML processing instructions are unsupported';
|
|
34
|
+
const tags = markupStartTags(activeCheck)
|
|
35
|
+
.map((tag) => decodeXmlCharacterReferences(tag) ?? tag);
|
|
36
|
+
if (tags.some((tag) => BLOCKED_ELEMENTS.test(tag))) return 'active or resource-loading elements are unsupported';
|
|
37
|
+
const attributes = tags.flatMap(markupAttributes);
|
|
38
|
+
if (attributes.some(({name}) => EVENT_ATTRIBUTE.test(name))) return 'event-handler attributes are unsupported';
|
|
39
|
+
if (attributes.some(({name}) => RESOURCE_ATTRIBUTES.has(name))) return 'resource-loading attributes are unsupported';
|
|
40
|
+
if (tags.some((tag) => markupTagName(tag)==='meta' && markupAttributes(tag).some(({name,value})=>name==='http-equiv'&&value.trim().toLowerCase()==='refresh'))) return 'HTML refresh navigation is unsupported';
|
|
41
|
+
if (!officeHrefRefsAreSafe(activeCheck)) return 'external or redirected href/src references are unsupported';
|
|
42
|
+
if (!cssUrlsAreSafe(activeCheck, { allowReference: (value) => fontReferencePortable(value, sourceFile, fontFile) })) {
|
|
43
|
+
return 'external, escaped, or active CSS resources are unsupported';
|
|
44
|
+
}
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import { buildBlockRegistry } from './block-registry.mjs';
|
|
4
|
+
|
|
5
|
+
const source='<svg><rect data-block-id="root" data-block-name="Request & policy" data-block-input="raw request" data-block-output="decision" data-block-constraint="deny by default" data-block-assumption="authenticated" data-block-impl="src/root.ts"/><rect data-block-id="child" data-block-parent="root" data-block-name="Audit" data-block-impl="src/audit.ts"/></svg>';
|
|
6
|
+
const registry=buildBlockRegistry(source,'diagram.html');
|
|
7
|
+
assert.deepEqual(registry.blocks.map((block)=>block.id),['root','child']);
|
|
8
|
+
assert.equal(registry.source,'diagram.html');
|
|
9
|
+
assert.equal(registry.blocks[0].name,'Request & policy');
|
|
10
|
+
assert.equal(Object.hasOwn(registry.blocks[0],'parent'),false);
|
|
11
|
+
assert.equal(registry.blocks[1].parent,'root');
|
|
12
|
+
assert.equal(Object.hasOwn(registry.blocks[1],'input'),false);
|
|
13
|
+
const rejects=(fragment,code)=>assert.throws(()=>buildBlockRegistry('<svg>'+fragment+'</svg>','bad.html'),new RegExp(code));
|
|
14
|
+
rejects('', 'REGISTRY_BLOCKS_MISSING');
|
|
15
|
+
rejects('<rect data-block-id=""/>','REGISTRY_ID_REQUIRED');
|
|
16
|
+
rejects('<rect data-block-id="x"/><rect data-block-id="x"/>','REGISTRY_DUPLICATE_ID');
|
|
17
|
+
rejects('<rect data-block-id="x" data-block-parent="absent"/>','REGISTRY_PARENT_MISSING');
|
|
18
|
+
rejects('<rect data-block-id="x" data-block-parent="y"/><rect data-block-id="y" data-block-parent="x"/>','REGISTRY_CYCLE');
|
|
19
|
+
rejects('<rect data-block-id="x"/><rect data-block-id="y"/>','REGISTRY_ROOT_COUNT');
|
|
20
|
+
console.log('BLOCK_REGISTRY_PASS ordered projection, omitted fields/root parent, duplicate/missing/cycle/root guards');
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import { checkBrief, parseBrief } from './brief-contract.mjs';
|
|
3
|
+
|
|
4
|
+
const brief=`- 소스 participates in the labeled relationships below.\n- 대상 participates in the labeled relationships below.\n- Required relationships:\n- 소스 → 대상 (전달)`;
|
|
5
|
+
const good=`<svg><text>소스</text><text>대상</text><path data-from="소스" data-to="대상" data-label="전달"/><text data-edge-for="소스|대상">전달</text></svg>`;
|
|
6
|
+
const parsed=parseBrief(brief);
|
|
7
|
+
assert.deepEqual(parsed.nodes,['소스','대상']);
|
|
8
|
+
assert.deepEqual(checkBrief(good,parsed),{language:'ko',nodes:2,relationships:1,missingNodes:[],missingLabels:[],missingEdges:[],unpairedLabels:[],languageMismatches:[],boundaryMembership:{declared:false,boundaryCount:0,issues:[]}});
|
|
9
|
+
const wrongDirection=good.replace('data-from="소스" data-to="대상"','data-from="대상" data-to="소스"');
|
|
10
|
+
assert.equal(checkBrief(wrongDirection,parsed).missingEdges.length,1,'reversed edge fails');
|
|
11
|
+
const wrongLabel=good.replace('>전달</text>','>전달됨</text>');
|
|
12
|
+
assert.equal(checkBrief(wrongLabel,parsed).missingLabels.length,1,'non-exact label fails');
|
|
13
|
+
const koreanTechnical=`# API 데이터 경로\n- Purpose: 요청은 DB에 전달된다.\n- 게이트웨이 API participates in the labeled relationships below.\n- DB participates in the labeled relationships below.\n- Required relationships:\n- 게이트웨이 API → DB (HTTPS)`;
|
|
14
|
+
const technicalGood=`<svg><text>게이트웨이 API</text><text>DB</text><text>HTTPS</text><path data-from="게이트웨이 API" data-to="DB" data-label="HTTPS"/><text data-edge-for="게이트웨이 API|DB">HTTPS</text></svg>`;
|
|
15
|
+
assert.equal(checkBrief(technicalGood,koreanTechnical).languageMismatches.length,0,'verbatim technical names in a Korean brief remain allowed');
|
|
16
|
+
const mixedLabel=technicalGood.replace('<text>DB</text>','<text>DB build</text>');
|
|
17
|
+
const languageCheck=checkBrief(mixedLabel,koreanTechnical);
|
|
18
|
+
assert(languageCheck.languageMismatches.some((item)=>item.terms.includes('build')),'unlisted English words in Korean visible text fail');
|
|
19
|
+
assert.equal(parseBrief('# Release map\n- Package participates in the labeled relationships below.\n- Build → Package (ready)').language,'en','language follows the semantic labels, not boilerplate headings');
|
|
20
|
+
const membershipBrief=['# Trust boundary','- 모바일 앱 participates in the labeled relationships below.','- API 게이트웨이 participates in the labeled relationships below.','- 작업 소비자 participates in the labeled relationships below.','- 재고 서비스 participates in the labeled relationships below.','- 결제사 participates in the labeled relationships below.','- Trust boundary internal nodes: API 게이트웨이; 작업 소비자; 재고 서비스','- Trust boundary external nodes: 모바일 앱; 결제사'].join('\n');
|
|
21
|
+
const membershipContract=parseBrief(membershipBrief);
|
|
22
|
+
const membershipSource=(workerX,inventoryX)=>'<svg><rect x="195" y="155" width="710" height="408" data-trust-boundary="internal"/><rect x="40" y="304" width="144" height="64" data-node-id="모바일 앱"/><rect x="280" y="304" width="144" height="64" data-node-id="API 게이트웨이"/><rect x="'+workerX+'" y="304" width="144" height="64" data-node-id="작업 소비자"/><rect x="'+inventoryX+'" y="176" width="144" height="64" data-node-id="재고 서비스"/><rect x="910" y="450" width="120" height="64" data-node-id="결제사"/></svg>';
|
|
23
|
+
const membershipDefect=checkBrief(membershipSource(910,910),membershipContract).boundaryMembership;
|
|
24
|
+
assert(membershipDefect.issues.includes('BOUNDARY_NODE_NOT_INTERNAL name=작업 소비자'),'the reviewed worker-outside-boundary defect fails');
|
|
25
|
+
assert(membershipDefect.issues.includes('BOUNDARY_NODE_NOT_INTERNAL name=재고 서비스'),'the reviewed inventory-outside-boundary defect fails');
|
|
26
|
+
assert.deepEqual(checkBrief(membershipSource(740,740),membershipContract).boundaryMembership.issues,[],'declared internal nodes inside and external nodes outside pass');
|
|
27
|
+
console.log('BRIEF_CONTRACT_FIXTURES_PASS exact-nodes labels endpoints direction Korean-language-exempt-terms boundary-membership');
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import os from 'node:os';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import { deflateRawSync } from 'node:zlib';
|
|
6
|
+
import { spawnSync } from 'node:child_process';
|
|
7
|
+
import { fileURLToPath } from 'node:url';
|
|
8
|
+
|
|
9
|
+
const root=path.resolve(path.dirname(fileURLToPath(import.meta.url)),'..');
|
|
10
|
+
const temp=fs.mkdtempSync(path.join(os.tmpdir(),'lit-diagram-importer-'));
|
|
11
|
+
const importers=[
|
|
12
|
+
{name:'draw.io',script:'drawio-extract.mjs',extension:'.drawio',limit:16*1024*1024,valid:'<mxGraphModel><root><mxCell id="0"/><mxCell id="1" parent="0"/><mxCell id="a" value="Input" vertex="1" parent="1"/></root></mxGraphModel>'},
|
|
13
|
+
{name:'Mermaid',script:'mermaid-extract.mjs',extension:'.mmd',limit:4*1024*1024,valid:'flowchart LR\nA[Input] --> B[Store]\n'},
|
|
14
|
+
{name:'Excalidraw',script:'excalidraw-extract.mjs',extension:'.excalidraw',limit:16*1024*1024,valid:JSON.stringify({type:'excalidraw',elements:[{id:'a',type:'rectangle',x:0,y:0,width:80,height:30}]})}
|
|
15
|
+
];
|
|
16
|
+
function run(importer,file,...args){
|
|
17
|
+
return spawnSync(process.execPath,[path.join(root,'scripts',importer.script),file,...args],{encoding:'utf8',timeout:30_000,maxBuffer:1024*1024});
|
|
18
|
+
}
|
|
19
|
+
try{
|
|
20
|
+
for(const importer of importers){
|
|
21
|
+
const valid=path.join(temp,'valid'+importer.extension);
|
|
22
|
+
fs.writeFileSync(valid,importer.valid);
|
|
23
|
+
const accepted=run(importer,valid);
|
|
24
|
+
assert.equal(accepted.status,0,importer.name+' valid fixture: '+accepted.stderr);
|
|
25
|
+
assert.equal(JSON.parse(accepted.stdout).schemaVersion,1,importer.name+' emits the normalized schema');
|
|
26
|
+
|
|
27
|
+
let encodedActive,encodedUrl;
|
|
28
|
+
if(importer.name==='draw.io'){
|
|
29
|
+
encodedActive=importer.valid.replace('value="Input"','value="&lt;script&gt;alert(1)&lt;/script&gt;"');
|
|
30
|
+
encodedUrl=importer.valid.replace('value="Input"','value="https&#58;//example.invalid/path"');
|
|
31
|
+
}else if(importer.name==='Mermaid'){
|
|
32
|
+
encodedActive='flowchart LR\nA["<script>alert(1)</script>"] --> B[Store]\n';
|
|
33
|
+
encodedUrl='flowchart LR\nA["https://example.invalid/path"] --> B[Store]\n';
|
|
34
|
+
}else{
|
|
35
|
+
const scene=JSON.parse(importer.valid);
|
|
36
|
+
scene.elements.push({id:'label',type:'text',text:'<script>alert(1)</script>',x:0,y:0,width:80,height:20,containerId:'a'});
|
|
37
|
+
encodedActive=JSON.stringify(scene);
|
|
38
|
+
scene.elements.at(-1).text='https://example.invalid/path';
|
|
39
|
+
encodedUrl=JSON.stringify(scene);
|
|
40
|
+
}
|
|
41
|
+
const activeFile=path.join(temp,'encoded-active'+importer.extension);
|
|
42
|
+
fs.writeFileSync(activeFile,encodedActive);
|
|
43
|
+
const encodedAttack=run(importer,activeFile);
|
|
44
|
+
assert.equal(encodedAttack.status,2,importer.name+' entity-encoded active markup is rejected');
|
|
45
|
+
assert.match(encodedAttack.stderr,/executable markup/u,importer.name+' identifies unsafe encoded markup');
|
|
46
|
+
|
|
47
|
+
const urlFile=path.join(temp,'encoded-url'+importer.extension);
|
|
48
|
+
fs.writeFileSync(urlFile,encodedUrl);
|
|
49
|
+
const urlResult=run(importer,urlFile);
|
|
50
|
+
assert.equal(urlResult.status,0,importer.name+' encoded URL is safely discarded: '+urlResult.stderr);
|
|
51
|
+
const urlOutput=JSON.parse(urlResult.stdout);
|
|
52
|
+
assert.equal(urlOutput.discarded.urls,1,importer.name+' accounts for its discarded encoded URL');
|
|
53
|
+
assert.doesNotMatch(JSON.stringify({title:urlOutput.title,nodes:urlOutput.nodes,relationships:urlOutput.relationships,groups:urlOutput.groups}),/example\.invalid/u,importer.name+' does not preserve the encoded URL');
|
|
54
|
+
|
|
55
|
+
const oversized=path.join(temp,'oversized'+importer.extension);
|
|
56
|
+
const oversizedFd=fs.openSync(oversized,'w');
|
|
57
|
+
fs.ftruncateSync(oversizedFd,importer.limit+1);
|
|
58
|
+
fs.closeSync(oversizedFd);
|
|
59
|
+
const tooLarge=run(importer,oversized);
|
|
60
|
+
assert.equal(tooLarge.status,2,importer.name+' oversized source is rejected');
|
|
61
|
+
assert.match(tooLarge.stderr,/exceeds the \d+ MiB limit/u,importer.name+' reports its size bound');
|
|
62
|
+
|
|
63
|
+
const symlink=path.join(temp,'linked'+importer.extension);
|
|
64
|
+
try { fs.symlinkSync(valid,symlink); }
|
|
65
|
+
catch(error){
|
|
66
|
+
if(!['EACCES','EPERM','ENOTSUP','EOPNOTSUPP'].includes(error.code)) throw error;
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
const linked=run(importer,symlink);
|
|
70
|
+
assert.equal(linked.status,2,importer.name+' symlink source is rejected');
|
|
71
|
+
assert.match(linked.stderr,/regular file|safely read/u,importer.name+' explains the no-follow boundary');
|
|
72
|
+
}
|
|
73
|
+
const drawio=importers[0];
|
|
74
|
+
const bomb=deflateRawSync(Buffer.alloc(32*1024*1024+1)).toString('base64');
|
|
75
|
+
const selectedPage=path.join(temp,'selected-page.drawio');
|
|
76
|
+
fs.writeFileSync(selectedPage,`<mxfile><diagram name="selected">${drawio.valid}</diagram><diagram>${bomb}</diagram><diagram>${bomb}</diagram></mxfile>`);
|
|
77
|
+
const selected=run(drawio,selectedPage,'--page','0');
|
|
78
|
+
assert.equal(selected.status,0,'unselected compressed pages are never inflated: '+selected.stderr);
|
|
79
|
+
assert.equal(JSON.parse(selected.stdout).title,'selected');
|
|
80
|
+
|
|
81
|
+
const unsafeTitle=path.join(temp,'unsafe-title.drawio');
|
|
82
|
+
fs.writeFileSync(unsafeTitle,`<mxfile><diagram name="<script>alert(1)</script>">${drawio.valid}</diagram></mxfile>`);
|
|
83
|
+
const unsafeTitleResult=run(drawio,unsafeTitle);
|
|
84
|
+
assert.equal(unsafeTitleResult.status,2,'encoded active markup in a page name is rejected');
|
|
85
|
+
assert.match(unsafeTitleResult.stderr,/executable markup/u);
|
|
86
|
+
|
|
87
|
+
const urlTitle=path.join(temp,'url-title.drawio');
|
|
88
|
+
fs.writeFileSync(urlTitle,`<mxfile><diagram name="https://example.invalid/path">${drawio.valid}</diagram></mxfile>`);
|
|
89
|
+
const normalizedTitle=run(drawio,urlTitle);
|
|
90
|
+
assert.equal(normalizedTitle.status,0,normalizedTitle.stderr);
|
|
91
|
+
assert.equal(JSON.parse(normalizedTitle.stdout).title,'Imported diagram');
|
|
92
|
+
assert.equal(JSON.parse(normalizedTitle.stdout).discarded.urls,1,'URL-bearing page titles are accounted as discarded content');
|
|
93
|
+
|
|
94
|
+
for(const [importer,filename] of [[importers[1],'evil<script>.mmd'],[importers[2],'evil<script>.excalidraw']]){
|
|
95
|
+
const maliciousName=path.join(temp,filename);
|
|
96
|
+
fs.writeFileSync(maliciousName,importer.valid);
|
|
97
|
+
const rejectedName=run(importer,maliciousName);
|
|
98
|
+
assert.equal(rejectedName.status,2,importer.name+' malicious fallback filename is rejected');
|
|
99
|
+
assert.match(rejectedName.stderr,/executable markup/u);
|
|
100
|
+
}
|
|
101
|
+
for(const [importer,filename] of [[importers[1],'https:example.invalid.mmd'],[importers[2],'https:example.invalid.excalidraw']]){
|
|
102
|
+
const urlName=path.join(temp,filename);
|
|
103
|
+
fs.writeFileSync(urlName,importer.valid);
|
|
104
|
+
const cleanedName=run(importer,urlName);
|
|
105
|
+
assert.equal(cleanedName.status,0,cleanedName.stderr);
|
|
106
|
+
const normalized=JSON.parse(cleanedName.stdout);
|
|
107
|
+
assert.equal(normalized.title,'Imported diagram',importer.name+' uses a nonempty fallback after filename URL removal');
|
|
108
|
+
assert.equal(normalized.discarded.urls,1,importer.name+' accounts for the URL in its fallback filename');
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const oversizedPage=path.join(temp,'oversized-page.drawio');
|
|
112
|
+
fs.writeFileSync(oversizedPage,`<mxfile><diagram>${bomb}</diagram></mxfile>`);
|
|
113
|
+
const oversizedSelected=run(drawio,oversizedPage,'--page','0');
|
|
114
|
+
assert.equal(oversizedSelected.status,2,'selected compressed page beyond decoded limit is rejected');
|
|
115
|
+
assert.match(oversizedSelected.stderr,/invalid or oversized compression/u);
|
|
116
|
+
}finally{
|
|
117
|
+
fs.rmSync(temp,{recursive:true,force:true});
|
|
118
|
+
}
|
|
119
|
+
console.log('IMPORTER_GUARDS_PASS draw.io Mermaid Excalidraw bounded stable regular-file no-follow reads');
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import os from 'node:os';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import { spawnSync } from 'node:child_process';
|
|
6
|
+
import { fileURLToPath } from 'node:url';
|
|
7
|
+
import { officeCssUrlsAreSafe, officeHrefRefsAreSafe } from './office-safety.mjs';
|
|
8
|
+
|
|
9
|
+
assert.equal(officeCssUrlsAreSafe('<svg><path fill="url(#arrow-main)"/></svg>'),true);
|
|
10
|
+
assert.equal(officeCssUrlsAreSafe('<svg><style>.x{filter:url( #shadow )}</style></svg>'),true);
|
|
11
|
+
assert.equal(officeCssUrlsAreSafe('<svg><path fill="url(#arrow-main)"/></svg>'),true);
|
|
12
|
+
assert.equal(officeCssUrlsAreSafe('<svg data-note="<style>"><img style="background:url(file:///tmp/a)"/></style></svg>'),false,'style-like attribute text cannot hide CSS-bearing markup');
|
|
13
|
+
for(const value of [
|
|
14
|
+
'file:///tmp/payload.svg',
|
|
15
|
+
'ftp://example.invalid/payload.svg',
|
|
16
|
+
'//example.invalid/payload.svg',
|
|
17
|
+
'https://example.invalid/payload.svg',
|
|
18
|
+
'../payload.svg',
|
|
19
|
+
'data:image/svg+xml;base64,AAAA'
|
|
20
|
+
]){
|
|
21
|
+
assert.equal(officeCssUrlsAreSafe('<svg><style>.x{fill:url("'+value+'")}</style></svg>'),false,value);
|
|
22
|
+
}
|
|
23
|
+
assert.equal(officeCssUrlsAreSafe('<svg><style>.x{fill:u/**/rl(file:///tmp/a)}</style></svg>'),false);
|
|
24
|
+
assert.equal(officeCssUrlsAreSafe('<svg><style>.x{fill:u\\72l(file:///tmp/a)}</style></svg>'),false);
|
|
25
|
+
assert.equal(officeCssUrlsAreSafe('<svg><style>.x{fill:url(file:///tmp/a)}</style></svg>'),false,'decimal XML reference in CSS function name');
|
|
26
|
+
assert.equal(officeCssUrlsAreSafe('<svg><style>.x{fill:url(https://example.invalid/a)}</style></svg>'),false,'hex XML reference in CSS function name');
|
|
27
|
+
assert.equal(officeCssUrlsAreSafe('<svg><style>@import "file:///tmp/a.css";</style></svg>'),false,'numeric XML reference in CSS at-rule');
|
|
28
|
+
assert.equal(officeCssUrlsAreSafe('<svg><path style="@import url(file:///tmp/a.css)"/></svg>'),false,'named HTML reference in CSS attribute');
|
|
29
|
+
assert.equal(officeCssUrlsAreSafe('<svg><style>.x{fill:var(--external)}</style></svg>'),false,'numeric XML reference in unsupported var() function');
|
|
30
|
+
assert.equal(officeCssUrlsAreSafe('<svg><style>@font-face{font-family:Pretendard;src:local(Arial)}</style></svg>'),false,'local() cannot spoof the bundled font face');
|
|
31
|
+
assert.equal(officeCssUrlsAreSafe('<svg><style>@font-face{font-family:Pretendard;src:url(font.woff2);unicode-range:U+0020}</style></svg>'),false,'unicode-range cannot make partial font coverage appear complete');
|
|
32
|
+
assert.equal(officeCssUrlsAreSafe('<svg><style>.x{fill:url(file:///tmp/a}</style></svg>'),false);
|
|
33
|
+
assert.equal(officeHrefRefsAreSafe('<svg><use href="#local-symbol"/></svg>'),true);
|
|
34
|
+
for(const reference of ['file:///tmp/a.svg','ftp://example.invalid/a.svg','//example.invalid/a.svg','../a.svg','https://example.invalid/a.svg','file:///tmp/a.svg']){
|
|
35
|
+
assert.equal(officeHrefRefsAreSafe('<svg><image href="'+reference+'"/></svg>'),false,reference);
|
|
36
|
+
}
|
|
37
|
+
assert.equal(officeHrefRefsAreSafe('<svg><image href=file:///tmp/a.svg/></svg>'),false);
|
|
38
|
+
assert.equal(officeHrefRefsAreSafe('<svg><image href="#local-symbol"/></svg>'),true);
|
|
39
|
+
assert.equal(officeHrefRefsAreSafe('<svg data-note="<style>"><img src="https://example.invalid/x"/></style></svg>'),false,'style-like attribute text cannot hide resource references');
|
|
40
|
+
assert.equal(officeHrefRefsAreSafe('<svg><image href="https://example.invalid/a.svg"/></svg>'),false,'named HTML references cannot disguise an external URI');
|
|
41
|
+
assert.equal(officeHrefRefsAreSafe('<svg xml:base="https://example.invalid/a.svg"><use href="#local-symbol"/></svg>'),false,'xml:base cannot redirect a fragment reference');
|
|
42
|
+
assert.equal(officeHrefRefsAreSafe('<html><head><base href="https://example.invalid/"></head><svg><use href="#local-symbol"/></svg></html>'),false,'HTML base cannot redirect a fragment reference');
|
|
43
|
+
|
|
44
|
+
const root=path.resolve(path.dirname(fileURLToPath(import.meta.url)),'..');
|
|
45
|
+
const temp=fs.mkdtempSync(path.join(os.tmpdir(),'lit-diagram-office-guard-'));
|
|
46
|
+
const exporter=path.join(root,'scripts/export.mjs');
|
|
47
|
+
const cliFixtures=[
|
|
48
|
+
['css-import','<svg viewBox="0 0 10 10"><style>@import "file:///tmp/a.css";</style></svg>'],
|
|
49
|
+
['css-var','<svg viewBox="0 0 10 10"><style>.x{fill:var(--external)}</style></svg>'],
|
|
50
|
+
['css-local-font','<svg viewBox="0 0 10 10"><style>@font-face{font-family:Pretendard;src:local(Arial)}</style></svg>'],
|
|
51
|
+
['css-font-unicode-range','<svg viewBox="0 0 10 10"><style>@font-face{font-family:Pretendard;src:url(font.woff2);unicode-range:U+0020}</style></svg>'],
|
|
52
|
+
['css-url','<svg viewBox="0 0 10 10"><style>.x{fill:url(https://example.invalid/a)}</style></svg>'],
|
|
53
|
+
['xml-base','<svg viewBox="0 0 10 10" xml:base="https://example.invalid/"><use href="#local-symbol"/></svg>']
|
|
54
|
+
];
|
|
55
|
+
try{
|
|
56
|
+
for(const [name,svg] of cliFixtures){
|
|
57
|
+
const input=path.join(temp,name+'.svg'),output=path.join(temp,name+'-out');
|
|
58
|
+
fs.writeFileSync(input,svg);
|
|
59
|
+
const result=spawnSync(process.execPath,[exporter,'--input',input,'--out',output,'--scale','1','--office-safe'],{encoding:'utf8'});
|
|
60
|
+
assert.equal(result.status,2,name+' must fail before output');
|
|
61
|
+
assert.match(result.stderr,/EXPORT_SOURCE_REJECTED|OFFICE_UNSAFE|OFFICE_UNSUPPORTED/,name);
|
|
62
|
+
assert.equal(fs.existsSync(output),false,name+' must not create output');
|
|
63
|
+
}
|
|
64
|
+
}finally{
|
|
65
|
+
fs.rmSync(temp,{recursive:true,force:true});
|
|
66
|
+
}
|
|
67
|
+
console.log('Office guard passed local-fragment cases and rejected encoded external CSS, unsupported var(), partial-font unicode ranges, unsafe bases, and malformed href/src references in both helper and exporter fixtures.');
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import os from 'node:os';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import { spawnSync } from 'node:child_process';
|
|
6
|
+
import { fileURLToPath } from 'node:url';
|
|
7
|
+
import { analyzeFile } from './diagram-metrics.mjs';
|
|
8
|
+
|
|
9
|
+
const verifier=fileURLToPath(new URL('./verify-type.mjs',import.meta.url));
|
|
10
|
+
const base='<main data-type="sequence-oauth" data-variant="light"><svg id="diagram-sequence-oauth-light" viewBox="0 0 400 240"><rect x="60" y="60" width="80" height="48" data-node-id="A"/><rect x="160" y="60" width="80" height="48" data-node-id="Mid"/><rect x="260" y="60" width="80" height="48" data-node-id="B"/><path d="M100 140 H300" data-from="A" data-to="B"/><path d="M300 180 H100" data-from="B" data-to="A"/></svg></main>';
|
|
11
|
+
const lifelines='<line x1="100" y1="108" x2="100" y2="180" stroke-dasharray="5 5" data-lifeline-for="A"/><line x1="200" y1="108" x2="200" y2="180" stroke-dasharray="5 5" data-lifeline-for="Mid"/><line x1="300" y1="108" x2="300" y2="180" stroke-dasharray="5 5" data-lifeline-for="B"/>';
|
|
12
|
+
const run=(source,{measure=false}={})=>{
|
|
13
|
+
const dir=fs.mkdtempSync(path.join(os.tmpdir(),'lit-sequence-verifier-'));
|
|
14
|
+
try{
|
|
15
|
+
const file=path.join(dir,'fixture.html');fs.writeFileSync(file,source);
|
|
16
|
+
return {result:spawnSync(process.execPath,[verifier,'--type=sequence-oauth',file],{encoding:'utf8'}),metrics:measure?analyzeFile(file):null};
|
|
17
|
+
}finally{fs.rmSync(dir,{recursive:true,force:true});}
|
|
18
|
+
};
|
|
19
|
+
const missing=run(base).result;
|
|
20
|
+
assert.notEqual(missing.status,0,'sequence verifier rejects missing lifelines');
|
|
21
|
+
assert.match(missing.stderr,/SEQUENCE_LIFELINE_MISSING/,'missing lifeline finding is reported');
|
|
22
|
+
const valid=run(base.replace('</svg>',lifelines+'</svg>'),{measure:true});
|
|
23
|
+
assert.equal(valid.result.status,0,valid.result.stderr||'lifelines aligned to boxes and ordered message endpoints pass');
|
|
24
|
+
assert.equal(valid.metrics.arrowCrossings,0,'lifeline intersections are intentional and excluded from arrow-crossing count');
|
|
25
|
+
const outOfOrder=run(base.replace('<path d="M100 140 H300" data-from="A" data-to="B"/><path d="M300 180 H100" data-from="B" data-to="A"/>','<path d="M100 180 H300" data-from="A" data-to="B"/><path d="M300 140 H100" data-from="B" data-to="A"/>').replace('</svg>',lifelines+'</svg>')).result;
|
|
26
|
+
assert.notEqual(outOfOrder.status,0,'sequence verifier rejects messages that are not top-to-bottom');
|
|
27
|
+
assert.match(outOfOrder.stderr,/SEQUENCE_MESSAGE_ORDER/,'message order finding is reported');
|
|
28
|
+
console.log('SEQUENCE_VERIFIER_FIXTURES_PASS missing-lifeline endpoints-and-order');
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import { visualQuality } from './visual-quality.mjs';
|
|
3
|
+
|
|
4
|
+
const svg=(texts,shapes='')=>`<svg viewBox="0 0 1080 640"><title>Fixture</title><rect width="1080" height="640" fill="#ffffff"/>${shapes}${texts}</svg>`;
|
|
5
|
+
const text=(label,x,y,size=16,role='',edgeFor='')=>`<text x="${x}" y="${y}" text-anchor="middle" font-size="${size}"${role?` data-role="${role}"`:''}${edgeFor?` data-edge-for="${edgeFor}"`:''}>${label}</text>`;
|
|
6
|
+
const nodes='<rect x="40" y="240" width="150" height="80" data-node-id="A"/><rect x="400" y="240" width="150" height="80" data-node-id="B"/><rect x="198" y="255" width="34" height="50" data-node-id="C"/>';
|
|
7
|
+
const edge='<path d="M190 280 H400" data-from="A" data-to="B" data-label="전달"/>';
|
|
8
|
+
const process=visualQuality(svg(text('LITFAMILY / ARCHITECTURE',500,90,12)),{});
|
|
9
|
+
assert(process.issues.some((issue)=>issue.startsWith('PROCESS_TEXT')),'process and product labels fail');
|
|
10
|
+
const noVisibleTitle=visualQuality(svg(text('서비스',500,285,17,'node')),{enforceCanvas:true});
|
|
11
|
+
assert(noVisibleTitle.issues.some((issue)=>issue.startsWith('TITLE_ROLE_MISSING')),'missing reader-facing title fails');
|
|
12
|
+
const clean=visualQuality(svg(text('예약 요청',540,100,30,'title')+text('서비스',115,195,17,'node')+text('전달',500,472,14,'edge','A|B')+text('저장소',965,495,17,'node'),'<rect x="40" y="150" width="150" height="80" data-node-id="A"/><rect x="890" y="450" width="150" height="80" data-node-id="B"/><path d="M190 190 V490 H890" data-from="A" data-to="B" data-label="전달"/>'),{enforceCanvas:true});
|
|
13
|
+
assert.deepEqual(clean.issues,[],'clean, well-sized connector example passes');
|
|
14
|
+
const geometry=visualQuality(svg(text('전달',295,282,14,'edge','A|B')+text('제목',540,90,22,'title')+text('노드',115,285,12,'node'),nodes+edge),{enforceCanvas:true});
|
|
15
|
+
assert(geometry.issues.some((issue)=>issue.startsWith('EDGE_TEXT_COLLISION')),'label on connector fails');
|
|
16
|
+
assert(geometry.issues.some((issue)=>issue.startsWith('ROUTE_THROUGH_NODE')),'route through non-endpoint node fails');
|
|
17
|
+
assert(geometry.issues.some((issue)=>issue.startsWith('NODE_GAP')),'node gap below 12px fails');
|
|
18
|
+
assert(geometry.issues.some((issue)=>issue.startsWith('FONT_FLOOR')),'small title and node labels fail');
|
|
19
|
+
assert(geometry.issues.some((issue)=>issue.startsWith('CONTENT_FILL')),'sparse content fails fill floor');
|
|
20
|
+
const nearPath=visualQuality(svg(text('전달',280,250,14,'edge','A|B'),'<rect x="40" y="240" width="150" height="80" data-node-id="A"/><rect x="400" y="240" width="150" height="80" data-node-id="B"/><path d="M190 280 H400" data-from="A" data-to="B" data-label="전달"/><path d="M260 250 H400" data-from="A" data-to="B" data-label="다른 경로"/>'),{});
|
|
21
|
+
assert(nearPath.issues.some((issue)=>issue.startsWith('EDGE_LABEL_NEAREST_PATH')),'label anchor must be nearer to its named route than another route');
|
|
22
|
+
assert(nearPath.edgeLabelMaxAnchorDistance===24,'edge association distance is a stated 24px');
|
|
23
|
+
const labelNode=visualQuality(svg(text('ok',396,245,14,'edge','A|B'),'<rect x="40" y="220" width="150" height="80" data-node-id="A"/><rect x="400" y="240" width="150" height="80" data-node-id="B"/><path d="M190 250 H400" data-from="A" data-to="B" data-label="ok"/>'),{});
|
|
24
|
+
assert(labelNode.issues.some((issue)=>issue.startsWith('EDGE_LABEL_NODE_COLLISION ok overlaps B')),'edge labels cannot overlap a node box');
|
|
25
|
+
const faintBoundaryLabel=text('경계',295,160,12,'boundary').replace('font-size="12"','font-size="12" fill="#c9d1d5"');
|
|
26
|
+
const boundary=visualQuality(svg(faintBoundaryLabel+text('제목',540,90,30,'title'),'<rect x="300" y="150" width="500" height="350" fill="none" stroke="#748084" data-trust-boundary="경계"/>'),{enforceCanvas:true});
|
|
27
|
+
assert(boundary.issues.some((issue)=>issue.startsWith('OUTLINE_TEXT_COLLISION')),'boundary and group outlines cannot cross visible labels');
|
|
28
|
+
assert(boundary.issues.some((issue)=>issue.startsWith('BOUNDARY_FONT_FLOOR')),'boundary labels use the 13px connector-label floor');
|
|
29
|
+
assert(boundary.issues.some((issue)=>issue.startsWith('BOUNDARY_CONTRAST_FLOOR')),'boundary labels use the 4.5:1 text contrast floor');
|
|
30
|
+
const arrowSvg=(end)=>`<svg viewBox="0 0 1080 640"><defs><marker id="arrow" markerWidth="10" markerHeight="10" refX="8" refY="3.5" orient="auto"><path d="M0 0 L0 7 L9 3.5 z"/></marker></defs><rect x="40" y="240" width="150" height="80" data-node-id="A"/><rect x="400" y="240" width="150" height="80" data-node-id="B"/><path d="M190 280 H${end}" stroke-width="3" marker-end="url(#arrow)" data-from="A" data-to="B"/></svg>`;
|
|
31
|
+
assert.deepEqual(visualQuality(arrowSvg(396),{}).issues,[],'arrowhead whose tip stops 1px before the target remains fully visible');
|
|
32
|
+
assert(visualQuality(arrowSvg(394),{}).issues.some((issue)=>issue.startsWith('ARROWHEAD_TIP_MISSED_TARGET')),'arrow tips more than 2px from a target edge fail');
|
|
33
|
+
assert(visualQuality(arrowSvg(400),{}).issues.some((issue)=>issue.startsWith('ARROWHEAD_TARGET_OVERLAP')),'arrowhead painted under its target box fails');
|
|
34
|
+
const tinyArrow='<svg viewBox="0 0 1080 640"><defs><marker id="tiny" markerWidth="7" markerHeight="6" refX="6" refY="3" markerUnits="userSpaceOnUse"><path d="M0 0 L0 6 L6 3 z"/></marker></defs><path d="M10 30 H100" stroke-width="2" marker-end="url(#tiny)" data-from="A" data-to="B"/></svg>';
|
|
35
|
+
assert(visualQuality(tinyArrow,{}).issues.some((issue)=>issue.startsWith('ARROWHEAD_SIZE_FLOOR')),'arrowheads shorter than the canvas/stroke floor fail');
|
|
36
|
+
const decision=(edges)=>`<svg viewBox="0 0 1080 640"><rect x="100" y="100" width="160" height="80" data-node-id="검증 통과?" data-node-type="decision" data-outcomes="예|아니오"/><rect x="500" y="100" width="160" height="80" data-node-id="승인"/><rect x="500" y="300" width="160" height="80" data-node-id="변경 제출"/>${edges}</svg>`;
|
|
37
|
+
const oneOutcome=visualQuality(decision('<path d="M260 140 H500" data-from="검증 통과?" data-to="승인" data-label="예"/>'),{});
|
|
38
|
+
assert(oneOutcome.issues.some((issue)=>issue.startsWith('DECISION_OUTCOME_MISSING 검증 통과? 아니오')),'decision nodes must cover each declared outcome');
|
|
39
|
+
const allOutcomes=visualQuality(decision('<path d="M260 140 H500" data-from="검증 통과?" data-to="승인" data-label="예"/><path d="M180 180 V340 H500" data-from="검증 통과?" data-to="변경 제출" data-label="아니오"/>'),{});
|
|
40
|
+
assert(!allOutcomes.issues.some((issue)=>issue.startsWith('DECISION_')),'a decision node with every named outcome passes');
|
|
41
|
+
const boundaryRoute=visualQuality('<svg viewBox="0 0 1080 640"><rect x="300" y="150" width="500" height="350" fill="none" stroke="#748084" data-trust-boundary="zone"/><path d="M100 151 H450" data-from="A" data-to="B"/></svg>',{});
|
|
42
|
+
assert(boundaryRoute.issues.some((issue)=>issue.startsWith('ROUTE_ALONG_BOUNDARY')),'routes cannot run collinear with a boundary edge');
|
|
43
|
+
const routedNodes='<rect x="50" y="100" width="100" height="80" data-node-id="A"/><rect x="300" y="100" width="100" height="80" data-node-id="B"/>';
|
|
44
|
+
const detour=visualQuality(svg('',routedNodes+'<path d="M150 140 V80 H300 V140" data-from="A" data-to="B"/>'),{});
|
|
45
|
+
assert(detour.issues.some((issue)=>issue.startsWith('ROUTE_DETOUR A->B')||issue.startsWith('ROUTE_DETOUR A->B')),'detours above 1.4× facing-side distance fail');
|
|
46
|
+
assert(detour.issues.some((issue)=>issue.startsWith('ROUTE_ALIGNED_PATH A->B')),'same-row neighbors use one straight segment');
|
|
47
|
+
const straightNeighbors=visualQuality(svg('',routedNodes+'<path d="M150 140 H296" data-from="A" data-to="B"/>'),{});
|
|
48
|
+
assert(!straightNeighbors.issues.some((issue)=>/^ROUTE_(?:DETOUR|BENDS|ALIGNED_PATH)/.test(issue)),'a straight same-row neighbor link passes route simplicity checks');
|
|
49
|
+
const tooManyBends=visualQuality(svg('',routedNodes+'<path d="M150 140 V80 H210 V200 H250 V70 H300 V140" data-from="A" data-to="B"/>'),{});
|
|
50
|
+
assert(tooManyBends.issues.some((issue)=>issue.startsWith('ROUTE_BENDS A->B')),'more than two bends without a boundary fails');
|
|
51
|
+
const crossingBoundary='<rect x="300" y="100" width="400" height="400" data-trust-boundary="internal"/><rect x="50" y="220" width="100" height="80" data-node-id="A"/><rect x="600" y="150" width="100" height="80" data-node-id="B"/>';
|
|
52
|
+
const threeBendsCrossing=visualQuality(svg('',crossingBoundary+'<path d="M150 260 V220 H500 V190 H596" data-from="A" data-to="B"/>'),{});
|
|
53
|
+
assert(!threeBendsCrossing.issues.some((issue)=>issue.startsWith('ROUTE_BENDS A->B')),'three bends are allowed when the edge crosses a boundary');
|
|
54
|
+
const fourBendsCrossing=visualQuality(svg('',crossingBoundary+'<path d="M150 260 V220 H250 V320 H450 V190 H596" data-from="A" data-to="B"/>'),{});
|
|
55
|
+
assert(fourBendsCrossing.issues.some((issue)=>issue.startsWith('ROUTE_BENDS A->B')),'more than three bends across a boundary fails');
|
|
56
|
+
const overlapNodes='<rect x="120" y="20" width="60" height="60" data-node-id="A"/><rect x="120" y="200" width="60" height="60" data-node-id="B"/><rect x="120" y="100" width="60" height="40" data-node-id="C"/><rect x="120" y="180" width="60" height="40" data-node-id="D"/>';
|
|
57
|
+
const sharedSegment=visualQuality(svg('',overlapNodes+'<path d="M150 80 V200" data-from="A" data-to="B"/><path d="M150 140 V180" data-from="C" data-to="D"/>'),{});
|
|
58
|
+
assert(sharedSegment.issues.some((issue)=>issue.startsWith('ROUTE_COLLINEAR_OVERLAP')),'distinct routes cannot share collinear segments');
|
|
59
|
+
const pairNodes='<rect x="40" y="240" width="100" height="120" data-node-id="A"/><rect x="400" y="240" width="100" height="120" data-node-id="B"/>';
|
|
60
|
+
const crossingPair=visualQuality(svg('',pairNodes+'<path d="M140 300 H400" fill="none" data-from="A" data-to="B"/><path d="M400 340 H280 V260 H140" fill="none" data-from="B" data-to="A"/>'),{});
|
|
61
|
+
assert(crossingPair.issues.some((issue)=>issue.startsWith('ROUTE_CROSSING A->B / B->A')),'crossings between routes for the same node pair fail');
|
|
62
|
+
const parallelPair=visualQuality(svg('',pairNodes+'<path d="M140 300 H400" fill="none" data-from="A" data-to="B"/><path d="M400 340 H140" fill="none" data-from="B" data-to="A"/>'),{});
|
|
63
|
+
assert(!parallelPair.issues.some((issue)=>issue.startsWith('ROUTE_CROSSING')),'parallel opposing routes for the same node pair pass');
|
|
64
|
+
const opposed=visualQuality(svg('',routedNodes+'<path d="M150 140 H300" marker-start="url(#arrow)" marker-end="url(#arrow)" data-from="A" data-to="B"/>'),{});
|
|
65
|
+
assert(opposed.issues.some((issue)=>issue.startsWith('ROUTE_OPPOSED_HEADS A->B')),'a single directed polyline cannot carry heads at both ends');
|
|
66
|
+
const missingLifelines=visualQuality('<svg viewBox="0 0 1080 640" data-type="sequence"><rect x="60" y="60" width="80" height="48" data-node-id="Browser"/><rect x="280" y="60" width="80" height="48" data-node-id="API"/><path d="M140 160 H280" data-from="Browser" data-to="API" data-label="요청"/></svg>',{});
|
|
67
|
+
assert(missingLifelines.issues.some((issue)=>issue.startsWith('SEQUENCE_LIFELINE_MISSING')),'sequence participants need lifelines');
|
|
68
|
+
console.log('VISUAL_QUALITY_FIXTURES_PASS process-text edge-association label-node-collision decision-outcomes arrowhead-tip-and-size boundary-label outline route-node boundary-route node-gap font-fill detour bends shared-segment opposed-heads sequence-lifeline');
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { spawnSync } from 'node:child_process';
|
|
5
|
+
import { fileURLToPath } from 'node:url';
|
|
6
|
+
import { analyzeFile, root } from './diagram-metrics.mjs';
|
|
7
|
+
import { visualQuality } from './visual-quality.mjs';
|
|
8
|
+
|
|
9
|
+
const catalog=JSON.parse(fs.readFileSync(path.join(root,'references/type-catalog.json'),'utf8'));
|
|
10
|
+
const paths=[];
|
|
11
|
+
for(const entry of catalog.entries) for(const variant of catalog.variants) paths.push({file:path.join(root,'assets/examples/type-'+entry.id+'-'+variant+'.html'),type:entry.id,variant,kind:'template'});
|
|
12
|
+
for(const entry of fs.readdirSync(path.join(root,'examples'),{withFileTypes:true}).filter((x)=>x.isDirectory())) {
|
|
13
|
+
const file=path.join(root,'examples',entry.name,'after.html');
|
|
14
|
+
if(fs.existsSync(file)) {
|
|
15
|
+
const source=fs.readFileSync(file,'utf8');
|
|
16
|
+
const type=source.match(/data-type="([a-z0-9-]+)"/)?.[1];
|
|
17
|
+
paths.push({file,type,variant:'full',kind:'after'});
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
const issues=[];
|
|
21
|
+
const advisories=[];
|
|
22
|
+
function add(file,code){issues.push({file:path.relative(root,file),code});}
|
|
23
|
+
for(const item of paths){
|
|
24
|
+
if(!fs.existsSync(item.file)){add(item.file,'MISSING');continue;}
|
|
25
|
+
let source,result;
|
|
26
|
+
try{source=fs.readFileSync(item.file,'utf8');result=analyzeFile(item.file);}catch(e){add(item.file,'ANALYSIS '+e.message);continue;}
|
|
27
|
+
const visual=visualQuality(source,{enforceCanvas:item.kind==='after'});
|
|
28
|
+
for(const issue of visual.issues)add(item.file,'VISUAL '+issue);
|
|
29
|
+
for(const note of visual.advisories)advisories.push({file:path.relative(root,item.file),code:note});
|
|
30
|
+
if(!result.hasSvg||!result.viewBox||result.viewBox.w<=0||result.viewBox.h<=0)add(item.file,'SVG_OR_VIEWBOX');
|
|
31
|
+
if(!result.title||!result.desc||!result.roleImage||!result.ariaLinked)add(item.file,'A11Y');
|
|
32
|
+
if(!result.textCount)add(item.file,'NO_TEXT');
|
|
33
|
+
if(result.offCanvas)add(item.file,'OFF_CANVAS '+result.offCanvas);
|
|
34
|
+
if(result.textOverlaps)add(item.file,'TEXT_OVERLAP '+result.textOverlaps);
|
|
35
|
+
if(result.objectOverlaps)add(item.file,'SHAPE_OVERLAP '+result.objectOverlaps);
|
|
36
|
+
if(result.contrastFailures.length)add(item.file,'CONTRAST '+result.contrastFailures.length);
|
|
37
|
+
if(!result.fontFamilyPresent||!result.localFont||!result.fontFileValid)add(item.file,'PRETENDARD_FONT_ASSET');
|
|
38
|
+
if(result.humanizer.summary?.block)add(item.file,'HUMANIZER_BLOCK '+result.humanizer.summary.block);
|
|
39
|
+
if(result.humanizer.errors?.length)add(item.file,'HUMANIZER_ERROR');
|
|
40
|
+
const entry=catalog.entries.find((x)=>x.id===item.type);
|
|
41
|
+
if(!entry)add(item.file,'UNKNOWN_TYPE');
|
|
42
|
+
if(entry&&!source.includes('data-type="'+item.type+'"')&&!source.includes('id="diagram-'+item.type+'-'))add(item.file,'TYPE_ID_MISMATCH');
|
|
43
|
+
if(entry&&entry.family==='quantitative'&&result.textCount<3)add(item.file,'QUANTITATIVE_LABELS');
|
|
44
|
+
if(item.type==='heatmap'&&(source.match(/<rect\b/gi)||[]).length<16)add(item.file,'HEATMAP_GRID');
|
|
45
|
+
if(item.type==='treemap'&&(source.match(/<rect\b/gi)||[]).length<6)add(item.file,'TREEMAP_TILES');
|
|
46
|
+
if(item.type==='sankey'&&!/<path\b[^>]*stroke-width\s*=\s*["'][1-9]/i.test(source))add(item.file,'SANKEY_WIDTH');
|
|
47
|
+
if(item.type==='waterfall'&&(source.match(/<rect\b/gi)||[]).length<5)add(item.file,'WATERFALL_STEPS');
|
|
48
|
+
if(item.type==='beeswarm'&&(source.match(/<circle\b/gi)||[]).length<20)add(item.file,'BEESWARM_MARKS');
|
|
49
|
+
if(item.type==='bubble'&&(source.match(/<circle\b/gi)||[]).length<6)add(item.file,'BUBBLE_MARKS');
|
|
50
|
+
if((item.type==='polar'||item.type==='radar')&&!/<polygon\b/i.test(source))add(item.file,'POLAR_OR_RADAR_SHAPE');
|
|
51
|
+
if(item.type==='tree-block-decomposition'&&!/data-block-id\s*=/.test(source))add(item.file,'BLOCK_ID');
|
|
52
|
+
if(item.type==='policy-trace-animated'&&!/(rule|policy|allow|deny)/i.test(source))add(item.file,'POLICY_SEMANTIC');
|
|
53
|
+
if(item.type==='queue-animated'&&!/(queue|buffer|drain|fan-in)/i.test(source))add(item.file,'QUEUE_SEMANTIC');
|
|
54
|
+
if(item.type==='paved-road-animated'&&!/(boundary|guardrail|secure|policy)/i.test(source))add(item.file,'PAVED_ROAD_SEMANTIC');
|
|
55
|
+
if(/<animate\b|<set\b|autoplay|infinite/i.test(source))add(item.file,'NON_STATIC_MOTION');
|
|
56
|
+
if(/<script\b|\bon[a-z]+\s*=|https?:\/\//i.test(result.visibleText))add(item.file,'UNSAFE_TEXT');
|
|
57
|
+
}
|
|
58
|
+
const foilFiles=[];
|
|
59
|
+
for(const dir of fs.readdirSync(path.join(root,'examples'),{withFileTypes:true}).filter((x)=>x.isDirectory())){
|
|
60
|
+
const file=path.join(root,'examples',dir.name,'constructed-naive-foil.html');
|
|
61
|
+
if(fs.existsSync(file)){
|
|
62
|
+
foilFiles.push(file);
|
|
63
|
+
try{
|
|
64
|
+
const r=analyzeFile(file);
|
|
65
|
+
const fails=!r.title||!r.desc||r.textOverlaps>0||r.contrastFailures.length>0||r.humanizer.summary?.block>0;
|
|
66
|
+
if(!fails)add(file,'FOIL_NOT_FLAGGED');
|
|
67
|
+
}catch(e){add(file,'FOIL_ANALYSIS '+e.message);}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
if(paths.filter((x)=>x.kind==='template').length!==183)add(root,'TEMPLATE_COUNT');
|
|
71
|
+
if(paths.filter((x)=>x.kind==='after').length!==8)add(root,'AFTER_COUNT');
|
|
72
|
+
const out={templates:paths.filter((x)=>x.kind==='template').length,afterExamples:paths.filter((x)=>x.kind==='after').length,foilsChecked:foilFiles.length,failures:issues,advisories};
|
|
73
|
+
console.log(JSON.stringify(out,null,2));
|
|
74
|
+
if(issues.length)process.exitCode=1;
|