@bovinphang/frontend-craft 2.8.0 → 3.0.0
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/.claude-plugin/marketplace.json +3 -3
- package/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +64 -0
- package/CHANGELOG.zh-CN.md +64 -0
- package/CONTRIBUTING.md +74 -54
- package/CONTRIBUTING.zh-CN.md +75 -53
- package/README.md +150 -38
- package/README.openclaw.md +86 -11
- package/README.openclaw.zh-CN.md +86 -11
- package/README.zh-CN.md +147 -35
- package/agents/fec-code-reviewer.md +24 -3
- package/agents/fec-debugger.md +1 -1
- package/agents/fec-doc-updater.md +1 -1
- package/agents/fec-e2e-runner.md +1 -1
- package/agents/fec-figma-implementer.md +1 -1
- package/agents/fec-performance-optimizer.md +1 -1
- package/agents/fec-refactor-cleaner.md +4 -1
- package/agents/fec-refactoring-expert.md +81 -0
- package/agents/fec-security-reviewer.md +17 -1
- package/agents/fec-test-planner.md +1 -1
- package/agents/fec-typescript-reviewer.md +25 -9
- package/agents/fec-ui-checker.md +11 -11
- package/commands/fec-debug.md +1 -1
- package/commands/fec-refactor-plan.md +17 -0
- package/commands/fec-refactor.md +18 -0
- package/commands/fec-review.md +40 -10
- package/commands/fec-scaffold.md +1 -1
- package/commands/fec-smell.md +17 -0
- package/commands/fec-tdd.md +6 -2
- package/common-content.lock.json +3795 -0
- package/dist/bin/frontend-craft.js +386 -55
- package/dist/hooks/fec-run-tests.js +5 -1
- package/dist/hooks/fec-session-start.js +1 -1
- package/docs/common-migration.md +61 -0
- package/docs/example-prompts.md +29 -12
- package/docs/ja-JP/README.md +129 -34
- package/docs/ko-KR/README.md +129 -34
- package/docs/project-structure.md +49 -14
- package/docs/refactoring/README.md +50 -0
- package/docs/refactoring/catalog.md +105 -0
- package/docs/refactoring/smell-refactoring-matrix.md +41 -0
- package/docs/review-and-diagram-workflows.md +39 -0
- package/docs/runtimes/antigravity.md +13 -5
- package/docs/runtimes/augment.md +13 -5
- package/docs/runtimes/claude.md +26 -10
- package/docs/runtimes/claude.zh-CN.md +26 -10
- package/docs/runtimes/cline.md +13 -5
- package/docs/runtimes/codebuddy.md +13 -5
- package/docs/runtimes/codex.md +13 -5
- package/docs/runtimes/compatibility.md +42 -0
- package/docs/runtimes/copilot.md +13 -5
- package/docs/runtimes/cursor.md +13 -5
- package/docs/runtimes/gemini.md +13 -5
- package/docs/runtimes/kilo.md +13 -5
- package/docs/runtimes/openclaw.md +13 -5
- package/docs/runtimes/opencode.md +13 -5
- package/docs/runtimes/qoder.md +11 -12
- package/docs/runtimes/trae.md +13 -5
- package/docs/runtimes/windsurf.md +13 -5
- package/docs/superpowers/plans/2026-09-26-content-integrity.md +145 -0
- package/docs/superpowers/plans/2026-09-26-diagram-quality.md +170 -0
- package/docs/superpowers/specs/2026-09-26-diagram-quality-design.md +77 -0
- package/docs/superpowers/specs/2026-09-26-project-optimization-design.md +95 -0
- package/docs/zh-CN/common-migration.md +57 -0
- package/docs/zh-CN/example-prompts.md +29 -12
- package/docs/zh-CN/project-structure.md +49 -11
- package/docs/zh-CN/review-and-diagram-workflows.md +39 -0
- package/docs/zh-TW/README.md +129 -34
- package/localized/zh-CN/agents/fec-code-reviewer.md +22 -3
- package/localized/zh-CN/agents/fec-refactor-cleaner.md +3 -0
- package/localized/zh-CN/agents/fec-refactoring-expert.md +53 -0
- package/localized/zh-CN/agents/fec-security-reviewer.md +16 -0
- package/localized/zh-CN/agents/fec-typescript-reviewer.md +24 -8
- package/localized/zh-CN/commands/fec-refactor-plan.md +15 -0
- package/localized/zh-CN/commands/fec-refactor.md +14 -0
- package/localized/zh-CN/commands/fec-review.md +40 -9
- package/localized/zh-CN/commands/fec-smell.md +13 -0
- package/localized/zh-CN/commands/fec-tdd.md +4 -0
- package/localized/zh-CN/skills/cc-c-project-standard/SKILL.md +25 -0
- package/localized/zh-CN/skills/cc-c-project-standard/examples/engineering/README.md +7 -0
- package/localized/zh-CN/skills/cc-c-project-standard/examples/engineering/boundary.c +26 -0
- package/localized/zh-CN/skills/cc-c-project-standard/examples/engineering/boundary.h +15 -0
- package/localized/zh-CN/skills/cc-c-project-standard/examples/engineering/boundary_test.c +73 -0
- package/localized/zh-CN/skills/cc-c-project-standard/references/common/engineering-practices.md +237 -0
- package/localized/zh-CN/skills/cc-c-project-standard/references/common/engineering-practices.rules.json +121 -0
- package/localized/zh-CN/skills/cc-c-project-standard/references/common/engineering-practices.sources.json +377 -0
- package/localized/zh-CN/skills/cc-c-project-standard/references/engineering-practices.md +106 -0
- package/localized/zh-CN/skills/cc-c-project-standard/references/practice.md +37 -0
- package/localized/zh-CN/skills/cc-cpp-project-standard/SKILL.md +25 -0
- package/localized/zh-CN/skills/cc-cpp-project-standard/examples/engineering/README.md +7 -0
- package/localized/zh-CN/skills/cc-cpp-project-standard/examples/engineering/boundary.cpp +26 -0
- package/localized/zh-CN/skills/cc-cpp-project-standard/examples/engineering/boundary.hpp +12 -0
- package/localized/zh-CN/skills/cc-cpp-project-standard/examples/engineering/boundary_test.cpp +38 -0
- package/localized/zh-CN/skills/cc-cpp-project-standard/references/common/engineering-practices.md +237 -0
- package/localized/zh-CN/skills/cc-cpp-project-standard/references/common/engineering-practices.rules.json +121 -0
- package/localized/zh-CN/skills/cc-cpp-project-standard/references/common/engineering-practices.sources.json +377 -0
- package/localized/zh-CN/skills/cc-cpp-project-standard/references/engineering-practices.md +106 -0
- package/localized/zh-CN/skills/cc-cpp-project-standard/references/practice.md +37 -0
- package/localized/zh-CN/skills/cc-debug-methodology/SKILL.md +8 -0
- package/localized/zh-CN/skills/cc-debug-methodology/references/method.md +13 -0
- package/localized/zh-CN/skills/cc-doc-sync-core/SKILL.md +8 -0
- package/localized/zh-CN/skills/cc-doc-sync-core/references/method.md +12 -0
- package/localized/zh-CN/skills/{fec-drawio-studio → cc-drawio-studio}/SKILL.md +5 -5
- package/localized/zh-CN/skills/{fec-drawio-studio → cc-drawio-studio}/references/flowchart-quality.md +1 -1
- package/localized/zh-CN/skills/{fec-drawio-studio → cc-drawio-studio}/references/layout-and-export.md +9 -9
- package/localized/zh-CN/skills/cc-electron-project-standard/SKILL.md +21 -0
- package/localized/zh-CN/skills/cc-electron-project-standard/examples/engineering/README.md +7 -0
- package/localized/zh-CN/skills/cc-electron-project-standard/examples/engineering/ipc-lifecycle.cjs +44 -0
- package/localized/zh-CN/skills/cc-electron-project-standard/examples/engineering/ipc-lifecycle.test.cjs +44 -0
- package/localized/zh-CN/skills/cc-electron-project-standard/examples/engineering/package.json +8 -0
- package/localized/zh-CN/skills/cc-electron-project-standard/examples/minimal/README.md +9 -0
- package/localized/zh-CN/skills/cc-electron-project-standard/examples/minimal/boundary.cjs +19 -0
- package/localized/zh-CN/skills/cc-electron-project-standard/examples/minimal/boundary.test.cjs +7 -0
- package/localized/zh-CN/skills/cc-electron-project-standard/examples/minimal/index.html +1 -0
- package/localized/zh-CN/skills/cc-electron-project-standard/examples/minimal/main.cjs +20 -0
- package/localized/zh-CN/skills/cc-electron-project-standard/examples/minimal/package.json +9 -0
- package/localized/zh-CN/skills/cc-electron-project-standard/examples/minimal/preload.cjs +2 -0
- package/localized/zh-CN/skills/cc-electron-project-standard/examples/minimal/renderer.js +4 -0
- package/localized/zh-CN/skills/cc-electron-project-standard/references/common/engineering-practices.md +237 -0
- package/localized/zh-CN/skills/cc-electron-project-standard/references/common/engineering-practices.rules.json +121 -0
- package/localized/zh-CN/skills/cc-electron-project-standard/references/common/engineering-practices.sources.json +377 -0
- package/localized/zh-CN/skills/cc-electron-project-standard/references/engineering-practices.md +73 -0
- package/localized/zh-CN/skills/cc-electron-project-standard/references/practice.md +19 -0
- package/localized/zh-CN/skills/cc-electron-project-standard/references/verification.md +17 -0
- package/localized/zh-CN/skills/cc-go-concurrency/SKILL.md +25 -0
- package/localized/zh-CN/skills/cc-go-concurrency/references/common/engineering-practices.md +237 -0
- package/localized/zh-CN/skills/cc-go-concurrency/references/common/engineering-practices.rules.json +121 -0
- package/localized/zh-CN/skills/cc-go-concurrency/references/common/engineering-practices.sources.json +377 -0
- package/localized/zh-CN/skills/cc-go-concurrency/references/engineering-practices.md +73 -0
- package/localized/zh-CN/skills/cc-go-concurrency/references/practice.md +37 -0
- package/localized/zh-CN/skills/cc-go-project-standard/SKILL.md +25 -0
- package/localized/zh-CN/skills/cc-go-project-standard/examples/engineering/README.md +7 -0
- package/localized/zh-CN/skills/cc-go-project-standard/examples/engineering/go.mod +3 -0
- package/localized/zh-CN/skills/cc-go-project-standard/examples/engineering/lifecycle.go +71 -0
- package/localized/zh-CN/skills/cc-go-project-standard/examples/engineering/lifecycle_test.go +22 -0
- package/localized/zh-CN/skills/cc-go-project-standard/references/common/engineering-practices.md +237 -0
- package/localized/zh-CN/skills/cc-go-project-standard/references/common/engineering-practices.rules.json +121 -0
- package/localized/zh-CN/skills/cc-go-project-standard/references/common/engineering-practices.sources.json +377 -0
- package/localized/zh-CN/skills/cc-go-project-standard/references/engineering-practices.md +106 -0
- package/localized/zh-CN/skills/cc-go-project-standard/references/practice.md +37 -0
- package/localized/zh-CN/skills/cc-java-project-standard/SKILL.md +25 -0
- package/localized/zh-CN/skills/cc-java-project-standard/examples/engineering/README.md +5 -0
- package/localized/zh-CN/skills/cc-java-project-standard/examples/engineering/ResourceBoundary.java +26 -0
- package/localized/zh-CN/skills/cc-java-project-standard/examples/engineering/ResourceBoundaryTest.java +41 -0
- package/localized/zh-CN/skills/cc-java-project-standard/references/common/engineering-practices.md +237 -0
- package/localized/zh-CN/skills/cc-java-project-standard/references/common/engineering-practices.rules.json +121 -0
- package/localized/zh-CN/skills/cc-java-project-standard/references/common/engineering-practices.sources.json +377 -0
- package/localized/zh-CN/skills/cc-java-project-standard/references/engineering-practices.md +106 -0
- package/localized/zh-CN/skills/cc-java-project-standard/references/practice.md +37 -0
- package/localized/zh-CN/skills/cc-java-runtime/SKILL.md +25 -0
- package/localized/zh-CN/skills/cc-java-runtime/references/common/engineering-practices.md +237 -0
- package/localized/zh-CN/skills/cc-java-runtime/references/common/engineering-practices.rules.json +121 -0
- package/localized/zh-CN/skills/cc-java-runtime/references/common/engineering-practices.sources.json +377 -0
- package/localized/zh-CN/skills/cc-java-runtime/references/engineering-practices.md +73 -0
- package/localized/zh-CN/skills/cc-java-runtime/references/practice.md +37 -0
- package/localized/zh-CN/skills/cc-native-memory-safety/SKILL.md +25 -0
- package/localized/zh-CN/skills/cc-native-memory-safety/references/common/engineering-practices.md +237 -0
- package/localized/zh-CN/skills/cc-native-memory-safety/references/common/engineering-practices.rules.json +121 -0
- package/localized/zh-CN/skills/cc-native-memory-safety/references/common/engineering-practices.sources.json +377 -0
- package/localized/zh-CN/skills/cc-native-memory-safety/references/engineering-practices.md +73 -0
- package/localized/zh-CN/skills/cc-native-memory-safety/references/practice.md +37 -0
- package/localized/zh-CN/skills/cc-python-async/SKILL.md +25 -0
- package/localized/zh-CN/skills/cc-python-async/references/common/engineering-practices.md +237 -0
- package/localized/zh-CN/skills/cc-python-async/references/common/engineering-practices.rules.json +121 -0
- package/localized/zh-CN/skills/cc-python-async/references/common/engineering-practices.sources.json +377 -0
- package/localized/zh-CN/skills/cc-python-async/references/engineering-practices.md +73 -0
- package/localized/zh-CN/skills/cc-python-async/references/practice.md +37 -0
- package/localized/zh-CN/skills/cc-python-project-standard/SKILL.md +25 -0
- package/localized/zh-CN/skills/cc-python-project-standard/examples/engineering/README.md +7 -0
- package/localized/zh-CN/skills/cc-python-project-standard/examples/engineering/resource_boundary.py +37 -0
- package/localized/zh-CN/skills/cc-python-project-standard/examples/engineering/test_resource_boundary.py +49 -0
- package/localized/zh-CN/skills/cc-python-project-standard/references/common/engineering-practices.md +237 -0
- package/localized/zh-CN/skills/cc-python-project-standard/references/common/engineering-practices.rules.json +121 -0
- package/localized/zh-CN/skills/cc-python-project-standard/references/common/engineering-practices.sources.json +377 -0
- package/localized/zh-CN/skills/cc-python-project-standard/references/engineering-practices.md +106 -0
- package/localized/zh-CN/skills/cc-python-project-standard/references/practice.md +37 -0
- package/localized/zh-CN/skills/cc-refactoring-core/SKILL.md +8 -0
- package/localized/zh-CN/skills/cc-refactoring-core/references/method.md +16 -0
- package/localized/zh-CN/skills/cc-rust-async/SKILL.md +25 -0
- package/localized/zh-CN/skills/cc-rust-async/references/common/engineering-practices.md +237 -0
- package/localized/zh-CN/skills/cc-rust-async/references/common/engineering-practices.rules.json +121 -0
- package/localized/zh-CN/skills/cc-rust-async/references/common/engineering-practices.sources.json +377 -0
- package/localized/zh-CN/skills/cc-rust-async/references/engineering-practices.md +73 -0
- package/localized/zh-CN/skills/cc-rust-async/references/practice.md +37 -0
- package/localized/zh-CN/skills/cc-rust-project-standard/SKILL.md +25 -0
- package/localized/zh-CN/skills/cc-rust-project-standard/examples/engineering/Cargo.lock +7 -0
- package/localized/zh-CN/skills/cc-rust-project-standard/examples/engineering/Cargo.toml +8 -0
- package/localized/zh-CN/skills/cc-rust-project-standard/examples/engineering/README.md +5 -0
- package/localized/zh-CN/skills/cc-rust-project-standard/examples/engineering/src/lib.rs +43 -0
- package/localized/zh-CN/skills/cc-rust-project-standard/references/common/engineering-practices.md +237 -0
- package/localized/zh-CN/skills/cc-rust-project-standard/references/common/engineering-practices.rules.json +121 -0
- package/localized/zh-CN/skills/cc-rust-project-standard/references/common/engineering-practices.sources.json +377 -0
- package/localized/zh-CN/skills/cc-rust-project-standard/references/engineering-practices.md +106 -0
- package/localized/zh-CN/skills/cc-rust-project-standard/references/practice.md +37 -0
- package/localized/zh-CN/skills/cc-source-driven-development/SKILL.md +8 -0
- package/localized/zh-CN/skills/cc-source-driven-development/references/method.md +19 -0
- package/localized/zh-CN/skills/cc-tauri-project-standard/SKILL.md +21 -0
- package/localized/zh-CN/skills/cc-tauri-project-standard/examples/minimal/README.md +9 -0
- package/localized/zh-CN/skills/cc-tauri-project-standard/examples/minimal/core/Cargo.lock +5 -0
- package/localized/zh-CN/skills/cc-tauri-project-standard/examples/minimal/core/Cargo.toml +9 -0
- package/localized/zh-CN/skills/cc-tauri-project-standard/examples/minimal/core/src/lib.rs +46 -0
- package/localized/zh-CN/skills/cc-tauri-project-standard/examples/minimal/src-tauri/Cargo.toml +12 -0
- package/localized/zh-CN/skills/cc-tauri-project-standard/examples/minimal/src-tauri/build.rs +5 -0
- package/localized/zh-CN/skills/cc-tauri-project-standard/examples/minimal/src-tauri/capabilities/main.json +6 -0
- package/localized/zh-CN/skills/cc-tauri-project-standard/examples/minimal/src-tauri/permissions/documents.toml +4 -0
- package/localized/zh-CN/skills/cc-tauri-project-standard/examples/minimal/src-tauri/src/main.rs +22 -0
- package/localized/zh-CN/skills/cc-tauri-project-standard/examples/minimal/src-tauri/tauri.conf.json +13 -0
- package/localized/zh-CN/skills/cc-tauri-project-standard/examples/minimal/ui/app.js +5 -0
- package/localized/zh-CN/skills/cc-tauri-project-standard/examples/minimal/ui/index.html +1 -0
- package/localized/zh-CN/skills/cc-tauri-project-standard/references/common/engineering-practices.md +237 -0
- package/localized/zh-CN/skills/cc-tauri-project-standard/references/common/engineering-practices.rules.json +121 -0
- package/localized/zh-CN/skills/cc-tauri-project-standard/references/common/engineering-practices.sources.json +377 -0
- package/localized/zh-CN/skills/cc-tauri-project-standard/references/engineering-practices.md +73 -0
- package/localized/zh-CN/skills/cc-tauri-project-standard/references/practice.md +20 -0
- package/localized/zh-CN/skills/cc-tauri-project-standard/references/verification.md +18 -0
- package/localized/zh-CN/skills/cc-tdd-methodology/SKILL.md +8 -0
- package/localized/zh-CN/skills/cc-tdd-methodology/references/method.md +13 -0
- package/localized/zh-CN/skills/cc-technical-diagrams/SKILL.md +34 -0
- package/localized/zh-CN/skills/{fec-image-generation → cc-technical-diagrams}/assets/interactive-diagram.html +371 -371
- package/localized/zh-CN/skills/cc-technical-diagrams/assets/quality-examples/README.md +14 -0
- package/localized/zh-CN/skills/cc-technical-diagrams/assets/quality-examples/architecture.json +121 -0
- package/localized/zh-CN/skills/cc-technical-diagrams/assets/quality-examples/invalid-explicit.json +41 -0
- package/localized/zh-CN/skills/cc-technical-diagrams/assets/quality-examples/sequence.json +53 -0
- package/localized/zh-CN/skills/cc-technical-diagrams/assets/quality-examples/sequence.mmd +21 -0
- package/localized/zh-CN/skills/cc-technical-diagrams/assets/quality-examples/workflow.json +98 -0
- package/localized/zh-CN/skills/cc-technical-diagrams/assets/quality-examples/workflow.mmd +7 -0
- package/localized/zh-CN/skills/{fec-image-generation → cc-technical-diagrams}/references/diagram-workflows.md +12 -5
- package/localized/zh-CN/skills/{fec-image-generation → cc-technical-diagrams}/references/html-technical-diagrams.md +14 -7
- package/localized/zh-CN/skills/cc-technical-diagrams/references/png-qa-autofix.md +37 -0
- package/localized/zh-CN/skills/cc-technical-diagrams/scripts/diagram-browser.mjs +153 -0
- package/localized/zh-CN/skills/cc-technical-diagrams/scripts/diagram-layout.mjs +176 -0
- package/{skills/fec-image-generation → localized/zh-CN/skills/cc-technical-diagrams}/scripts/export-diagram.mjs +48 -80
- package/localized/zh-CN/skills/cc-technical-diagrams/scripts/mermaid-render.mjs +64 -0
- package/localized/zh-CN/skills/cc-technical-diagrams/scripts/png-qa.mjs +462 -0
- package/localized/zh-CN/skills/{fec-image-generation → cc-technical-diagrams}/scripts/tech-diagram-render.mjs +193 -53
- package/localized/zh-CN/skills/{fec-typescript-project-standard → cc-typescript-project-standard}/SKILL.md +10 -4
- package/localized/zh-CN/skills/cc-typescript-project-standard/examples/engineering/README.md +7 -0
- package/localized/zh-CN/skills/cc-typescript-project-standard/examples/engineering/boundary.test.ts +16 -0
- package/localized/zh-CN/skills/cc-typescript-project-standard/examples/engineering/input.ts +12 -0
- package/localized/zh-CN/skills/cc-typescript-project-standard/examples/engineering/package.json +12 -0
- package/localized/zh-CN/skills/cc-typescript-project-standard/examples/engineering/pnpm-lock.yaml +39 -0
- package/localized/zh-CN/skills/cc-typescript-project-standard/examples/engineering/pnpm-workspace.yaml +1 -0
- package/localized/zh-CN/skills/cc-typescript-project-standard/examples/engineering/tsconfig.json +8 -0
- package/localized/zh-CN/skills/cc-typescript-project-standard/references/common/engineering-practices.md +237 -0
- package/localized/zh-CN/skills/cc-typescript-project-standard/references/common/engineering-practices.rules.json +121 -0
- package/localized/zh-CN/skills/cc-typescript-project-standard/references/common/engineering-practices.sources.json +377 -0
- package/localized/zh-CN/skills/cc-typescript-project-standard/references/engineering-practices.md +106 -0
- package/localized/zh-CN/skills/{fec-typescript-project-standard → cc-typescript-project-standard}/references/type-safety-patterns.md +5 -34
- package/localized/zh-CN/skills/{fec-typescript-project-standard → cc-typescript-project-standard}/references/type-safety.md +6 -0
- package/localized/zh-CN/skills/eval_queries.json +738 -72
- package/localized/zh-CN/skills/fec-api-integration/SKILL.md +5 -1
- package/localized/zh-CN/skills/fec-api-integration/references/common/engineering-practices.md +237 -0
- package/localized/zh-CN/skills/fec-api-integration/references/common/engineering-practices.rules.json +121 -0
- package/localized/zh-CN/skills/fec-api-integration/references/common/engineering-practices.sources.json +377 -0
- package/localized/zh-CN/skills/fec-api-integration/references/engineering-practices.md +73 -0
- package/localized/zh-CN/skills/fec-code-review/SKILL.md +24 -1
- package/localized/zh-CN/skills/fec-code-review/references/common/engineering-practices.md +237 -0
- package/localized/zh-CN/skills/fec-code-review/references/common/engineering-practices.rules.json +121 -0
- package/localized/zh-CN/skills/fec-code-review/references/common/engineering-practices.sources.json +377 -0
- package/localized/zh-CN/skills/fec-code-review/references/engineering-practices.md +73 -0
- package/localized/zh-CN/skills/fec-code-review/references/report-template.md +11 -1
- package/localized/zh-CN/skills/fec-code-smells/SKILL.md +33 -0
- package/localized/zh-CN/skills/fec-code-smells/references/detection-guide.md +25 -0
- package/localized/zh-CN/skills/fec-code-smells/references/smell-catalog.md +817 -0
- package/localized/zh-CN/skills/fec-code-smells/references/smell-to-refactoring-map.md +265 -0
- package/localized/zh-CN/skills/fec-data-fetching/SKILL.md +4 -0
- package/localized/zh-CN/skills/fec-data-fetching/references/common/engineering-practices.md +237 -0
- package/localized/zh-CN/skills/fec-data-fetching/references/common/engineering-practices.rules.json +121 -0
- package/localized/zh-CN/skills/fec-data-fetching/references/common/engineering-practices.sources.json +377 -0
- package/localized/zh-CN/skills/fec-data-fetching/references/engineering-practices.md +73 -0
- package/localized/zh-CN/skills/fec-debug-framework/SKILL.md +1 -50
- package/localized/zh-CN/skills/fec-debug-framework/references/common/debug.md +13 -0
- package/localized/zh-CN/skills/fec-dependency-upgrade/SKILL.md +4 -0
- package/localized/zh-CN/skills/fec-dependency-upgrade/references/common/engineering-practices.md +237 -0
- package/localized/zh-CN/skills/fec-dependency-upgrade/references/common/engineering-practices.rules.json +121 -0
- package/localized/zh-CN/skills/fec-dependency-upgrade/references/common/engineering-practices.sources.json +377 -0
- package/localized/zh-CN/skills/fec-dependency-upgrade/references/engineering-practices.md +73 -0
- package/localized/zh-CN/skills/fec-doc-sync/SKILL.md +7 -28
- package/localized/zh-CN/skills/fec-doc-sync/references/common/doc-sync.md +12 -0
- package/localized/zh-CN/skills/fec-image-generation/SKILL.md +7 -71
- package/localized/zh-CN/skills/fec-image-generation/references/png-qa-autofix.md +9 -2
- package/localized/zh-CN/skills/fec-image-generation/scripts/diagram-layout.mjs +176 -0
- package/localized/zh-CN/skills/fec-image-generation/scripts/png-qa.mjs +36 -5
- package/localized/zh-CN/skills/fec-react-project-standard/SKILL.md +6 -0
- package/localized/zh-CN/skills/fec-react-project-standard/examples/engineering/README.md +7 -0
- package/localized/zh-CN/skills/fec-react-project-standard/examples/engineering/package.json +15 -0
- package/localized/zh-CN/skills/fec-react-project-standard/examples/engineering/pnpm-lock.yaml +662 -0
- package/localized/zh-CN/skills/fec-react-project-standard/examples/engineering/pnpm-workspace.yaml +1 -0
- package/localized/zh-CN/skills/fec-react-project-standard/examples/engineering/request-view.mjs +24 -0
- package/localized/zh-CN/skills/fec-react-project-standard/examples/engineering/request-view.test.mjs +33 -0
- package/localized/zh-CN/skills/fec-react-project-standard/references/common/engineering-practices.md +237 -0
- package/localized/zh-CN/skills/fec-react-project-standard/references/common/engineering-practices.rules.json +121 -0
- package/localized/zh-CN/skills/fec-react-project-standard/references/common/engineering-practices.sources.json +377 -0
- package/localized/zh-CN/skills/fec-react-project-standard/references/engineering-practices.md +73 -0
- package/localized/zh-CN/skills/fec-react-project-standard/references/generic-component-types.md +37 -0
- package/localized/zh-CN/skills/fec-react-project-standard/references/react-quality-patterns.md +3 -3
- package/localized/zh-CN/skills/fec-react-project-standard/references/react-runtime-patterns.md +1 -1
- package/localized/zh-CN/skills/fec-refactor-clean/SKILL.md +3 -0
- package/localized/zh-CN/skills/fec-refactoring/SKILL.md +25 -0
- package/localized/zh-CN/skills/fec-refactoring/references/common/refactoring.md +16 -0
- package/localized/zh-CN/skills/fec-refactoring/references/principles.md +13 -0
- package/localized/zh-CN/skills/fec-refactoring/references/refactoring-vs-feature-change.md +25 -0
- package/localized/zh-CN/skills/fec-refactoring/references/when-to-refactor.md +17 -0
- package/localized/zh-CN/skills/fec-refactoring/references/workflow.md +7 -0
- package/localized/zh-CN/skills/fec-refactoring-api/SKILL.md +25 -0
- package/localized/zh-CN/skills/fec-refactoring-api/references/api-refactorings.md +496 -0
- package/localized/zh-CN/skills/fec-refactoring-catalog/SKILL.md +21 -0
- package/localized/zh-CN/skills/fec-refactoring-catalog/references/catalog-index.md +99 -0
- package/localized/zh-CN/skills/fec-refactoring-catalog/references/composition-guide.md +49 -0
- package/localized/zh-CN/skills/fec-refactoring-catalog/references/selection-guide.md +41 -0
- package/localized/zh-CN/skills/fec-refactoring-control/SKILL.md +25 -0
- package/localized/zh-CN/skills/fec-refactoring-control/references/conditional-refactorings.md +299 -0
- package/localized/zh-CN/skills/fec-refactoring-data/SKILL.md +25 -0
- package/localized/zh-CN/skills/fec-refactoring-data/references/data-refactorings.md +248 -0
- package/localized/zh-CN/skills/fec-refactoring-encapsulation/SKILL.md +25 -0
- package/localized/zh-CN/skills/fec-refactoring-encapsulation/references/encapsulation-refactorings.md +452 -0
- package/localized/zh-CN/skills/fec-refactoring-functions/SKILL.md +25 -0
- package/localized/zh-CN/skills/fec-refactoring-functions/references/function-refactorings.md +567 -0
- package/localized/zh-CN/skills/fec-refactoring-inheritance/SKILL.md +25 -0
- package/localized/zh-CN/skills/fec-refactoring-inheritance/references/inheritance-refactorings.md +550 -0
- package/localized/zh-CN/skills/fec-refactoring-move-features/SKILL.md +25 -0
- package/localized/zh-CN/skills/fec-refactoring-move-features/references/moving-refactorings.md +453 -0
- package/localized/zh-CN/skills/fec-refactoring-validation/SKILL.md +52 -0
- package/localized/zh-CN/skills/fec-refactoring-validation/references/behavior-preservation.md +15 -0
- package/localized/zh-CN/skills/fec-refactoring-validation/references/refactoring-test-checklist.md +25 -0
- package/localized/zh-CN/skills/fec-security-review/SKILL.md +20 -0
- package/localized/zh-CN/skills/fec-security-review/references/common/engineering-practices.md +237 -0
- package/localized/zh-CN/skills/fec-security-review/references/common/engineering-practices.rules.json +121 -0
- package/localized/zh-CN/skills/fec-security-review/references/common/engineering-practices.sources.json +377 -0
- package/localized/zh-CN/skills/fec-security-review/references/engineering-practices.md +73 -0
- package/localized/zh-CN/skills/fec-security-review/references/report-template.md +10 -0
- package/localized/zh-CN/skills/fec-tdd-workflow/SKILL.md +12 -40
- package/localized/zh-CN/skills/fec-tdd-workflow/references/common/tdd.md +13 -0
- package/localized/zh-CN/skills/fec-testing-strategy/SKILL.md +4 -0
- package/localized/zh-CN/skills/fec-testing-strategy/references/common/engineering-practices.md +237 -0
- package/localized/zh-CN/skills/fec-testing-strategy/references/common/engineering-practices.rules.json +121 -0
- package/localized/zh-CN/skills/fec-testing-strategy/references/common/engineering-practices.sources.json +377 -0
- package/localized/zh-CN/skills/fec-testing-strategy/references/engineering-practices.md +73 -0
- package/localized/zh-CN/skills/fec-vue3-project-standard/SKILL.md +4 -0
- package/localized/zh-CN/skills/fec-vue3-project-standard/references/common/engineering-practices.md +237 -0
- package/localized/zh-CN/skills/fec-vue3-project-standard/references/common/engineering-practices.rules.json +121 -0
- package/localized/zh-CN/skills/fec-vue3-project-standard/references/common/engineering-practices.sources.json +377 -0
- package/localized/zh-CN/skills/fec-vue3-project-standard/references/engineering-practices.md +73 -0
- package/localized/zh-CN/skills/fec-vue3-project-standard/references/vue3-project-structure.md +2 -2
- package/localized/zh-CN/skills/metadata.json +2222 -626
- package/localized/zh-CN/skills/relations.json +472 -75
- package/localized/zh-CN/templates/shared/rules/fec-agent-workflow.md +1 -0
- package/localized/zh-CN/templates/shared/rules/fec-source-driven-development.md +3 -29
- package/localized/zh-CN/templates/shared/rules/fec-typescript.md +4 -4
- package/localized/zh-CN/templates/shared/rules/references/common/source-driven-development.md +19 -0
- package/openclaw.plugin.json +2 -3
- package/package.json +34 -17
- package/skills/cc-c-project-standard/SKILL.md +25 -0
- package/skills/cc-c-project-standard/examples/engineering/README.md +7 -0
- package/skills/cc-c-project-standard/examples/engineering/boundary.c +26 -0
- package/skills/cc-c-project-standard/examples/engineering/boundary.h +15 -0
- package/skills/cc-c-project-standard/examples/engineering/boundary_test.c +73 -0
- package/skills/cc-c-project-standard/references/common/engineering-practices.md +237 -0
- package/skills/cc-c-project-standard/references/common/engineering-practices.rules.json +121 -0
- package/skills/cc-c-project-standard/references/common/engineering-practices.sources.json +377 -0
- package/skills/cc-c-project-standard/references/engineering-practices.md +106 -0
- package/skills/cc-c-project-standard/references/practice.md +37 -0
- package/skills/cc-cpp-project-standard/SKILL.md +25 -0
- package/skills/cc-cpp-project-standard/examples/engineering/README.md +7 -0
- package/skills/cc-cpp-project-standard/examples/engineering/boundary.cpp +26 -0
- package/skills/cc-cpp-project-standard/examples/engineering/boundary.hpp +12 -0
- package/skills/cc-cpp-project-standard/examples/engineering/boundary_test.cpp +38 -0
- package/skills/cc-cpp-project-standard/references/common/engineering-practices.md +237 -0
- package/skills/cc-cpp-project-standard/references/common/engineering-practices.rules.json +121 -0
- package/skills/cc-cpp-project-standard/references/common/engineering-practices.sources.json +377 -0
- package/skills/cc-cpp-project-standard/references/engineering-practices.md +106 -0
- package/skills/cc-cpp-project-standard/references/practice.md +37 -0
- package/skills/cc-debug-methodology/SKILL.md +8 -0
- package/skills/cc-debug-methodology/references/method.md +13 -0
- package/skills/cc-doc-sync-core/SKILL.md +8 -0
- package/skills/cc-doc-sync-core/references/method.md +12 -0
- package/skills/{fec-drawio-studio → cc-drawio-studio}/SKILL.md +5 -5
- package/skills/{fec-drawio-studio → cc-drawio-studio}/references/flowchart-quality.md +1 -1
- package/skills/{fec-drawio-studio → cc-drawio-studio}/references/layout-and-export.md +9 -9
- package/skills/cc-electron-project-standard/SKILL.md +21 -0
- package/skills/cc-electron-project-standard/examples/engineering/README.md +7 -0
- package/skills/cc-electron-project-standard/examples/engineering/ipc-lifecycle.cjs +44 -0
- package/skills/cc-electron-project-standard/examples/engineering/ipc-lifecycle.test.cjs +44 -0
- package/skills/cc-electron-project-standard/examples/engineering/package.json +8 -0
- package/skills/cc-electron-project-standard/examples/minimal/README.md +9 -0
- package/skills/cc-electron-project-standard/examples/minimal/boundary.cjs +19 -0
- package/skills/cc-electron-project-standard/examples/minimal/boundary.test.cjs +7 -0
- package/skills/cc-electron-project-standard/examples/minimal/index.html +1 -0
- package/skills/cc-electron-project-standard/examples/minimal/main.cjs +20 -0
- package/skills/cc-electron-project-standard/examples/minimal/package.json +9 -0
- package/skills/cc-electron-project-standard/examples/minimal/preload.cjs +2 -0
- package/skills/cc-electron-project-standard/examples/minimal/renderer.js +4 -0
- package/skills/cc-electron-project-standard/references/common/engineering-practices.md +237 -0
- package/skills/cc-electron-project-standard/references/common/engineering-practices.rules.json +121 -0
- package/skills/cc-electron-project-standard/references/common/engineering-practices.sources.json +377 -0
- package/skills/cc-electron-project-standard/references/engineering-practices.md +73 -0
- package/skills/cc-electron-project-standard/references/practice.md +19 -0
- package/skills/cc-electron-project-standard/references/verification.md +17 -0
- package/skills/cc-go-concurrency/SKILL.md +25 -0
- package/skills/cc-go-concurrency/references/common/engineering-practices.md +237 -0
- package/skills/cc-go-concurrency/references/common/engineering-practices.rules.json +121 -0
- package/skills/cc-go-concurrency/references/common/engineering-practices.sources.json +377 -0
- package/skills/cc-go-concurrency/references/engineering-practices.md +73 -0
- package/skills/cc-go-concurrency/references/practice.md +37 -0
- package/skills/cc-go-project-standard/SKILL.md +25 -0
- package/skills/cc-go-project-standard/examples/engineering/README.md +7 -0
- package/skills/cc-go-project-standard/examples/engineering/go.mod +3 -0
- package/skills/cc-go-project-standard/examples/engineering/lifecycle.go +71 -0
- package/skills/cc-go-project-standard/examples/engineering/lifecycle_test.go +22 -0
- package/skills/cc-go-project-standard/references/common/engineering-practices.md +237 -0
- package/skills/cc-go-project-standard/references/common/engineering-practices.rules.json +121 -0
- package/skills/cc-go-project-standard/references/common/engineering-practices.sources.json +377 -0
- package/skills/cc-go-project-standard/references/engineering-practices.md +106 -0
- package/skills/cc-go-project-standard/references/practice.md +37 -0
- package/skills/cc-java-project-standard/SKILL.md +25 -0
- package/skills/cc-java-project-standard/examples/engineering/README.md +7 -0
- package/skills/cc-java-project-standard/examples/engineering/ResourceBoundary.java +26 -0
- package/skills/cc-java-project-standard/examples/engineering/ResourceBoundaryTest.java +41 -0
- package/skills/cc-java-project-standard/references/common/engineering-practices.md +237 -0
- package/skills/cc-java-project-standard/references/common/engineering-practices.rules.json +121 -0
- package/skills/cc-java-project-standard/references/common/engineering-practices.sources.json +377 -0
- package/skills/cc-java-project-standard/references/engineering-practices.md +106 -0
- package/skills/cc-java-project-standard/references/practice.md +35 -0
- package/skills/cc-java-runtime/SKILL.md +25 -0
- package/skills/cc-java-runtime/references/common/engineering-practices.md +237 -0
- package/skills/cc-java-runtime/references/common/engineering-practices.rules.json +121 -0
- package/skills/cc-java-runtime/references/common/engineering-practices.sources.json +377 -0
- package/skills/cc-java-runtime/references/engineering-practices.md +73 -0
- package/skills/cc-java-runtime/references/practice.md +37 -0
- package/skills/cc-native-memory-safety/SKILL.md +25 -0
- package/skills/cc-native-memory-safety/references/common/engineering-practices.md +237 -0
- package/skills/cc-native-memory-safety/references/common/engineering-practices.rules.json +121 -0
- package/skills/cc-native-memory-safety/references/common/engineering-practices.sources.json +377 -0
- package/skills/cc-native-memory-safety/references/engineering-practices.md +73 -0
- package/skills/cc-native-memory-safety/references/practice.md +37 -0
- package/skills/cc-python-async/SKILL.md +25 -0
- package/skills/cc-python-async/references/common/engineering-practices.md +237 -0
- package/skills/cc-python-async/references/common/engineering-practices.rules.json +121 -0
- package/skills/cc-python-async/references/common/engineering-practices.sources.json +377 -0
- package/skills/cc-python-async/references/engineering-practices.md +73 -0
- package/skills/cc-python-async/references/practice.md +37 -0
- package/skills/cc-python-project-standard/SKILL.md +25 -0
- package/skills/cc-python-project-standard/examples/engineering/README.md +7 -0
- package/skills/cc-python-project-standard/examples/engineering/resource_boundary.py +37 -0
- package/skills/cc-python-project-standard/examples/engineering/test_resource_boundary.py +49 -0
- package/skills/cc-python-project-standard/references/common/engineering-practices.md +237 -0
- package/skills/cc-python-project-standard/references/common/engineering-practices.rules.json +121 -0
- package/skills/cc-python-project-standard/references/common/engineering-practices.sources.json +377 -0
- package/skills/cc-python-project-standard/references/engineering-practices.md +106 -0
- package/skills/cc-python-project-standard/references/practice.md +37 -0
- package/skills/cc-refactoring-core/SKILL.md +8 -0
- package/skills/cc-refactoring-core/references/method.md +16 -0
- package/skills/cc-rust-async/SKILL.md +25 -0
- package/skills/cc-rust-async/references/common/engineering-practices.md +237 -0
- package/skills/cc-rust-async/references/common/engineering-practices.rules.json +121 -0
- package/skills/cc-rust-async/references/common/engineering-practices.sources.json +377 -0
- package/skills/cc-rust-async/references/engineering-practices.md +73 -0
- package/skills/cc-rust-async/references/practice.md +37 -0
- package/skills/cc-rust-project-standard/SKILL.md +25 -0
- package/skills/cc-rust-project-standard/examples/engineering/Cargo.lock +7 -0
- package/skills/cc-rust-project-standard/examples/engineering/Cargo.toml +8 -0
- package/skills/cc-rust-project-standard/examples/engineering/README.md +5 -0
- package/skills/cc-rust-project-standard/examples/engineering/src/lib.rs +43 -0
- package/skills/cc-rust-project-standard/references/common/engineering-practices.md +237 -0
- package/skills/cc-rust-project-standard/references/common/engineering-practices.rules.json +121 -0
- package/skills/cc-rust-project-standard/references/common/engineering-practices.sources.json +377 -0
- package/skills/cc-rust-project-standard/references/engineering-practices.md +106 -0
- package/skills/cc-rust-project-standard/references/practice.md +37 -0
- package/skills/cc-source-driven-development/SKILL.md +8 -0
- package/skills/cc-source-driven-development/references/method.md +19 -0
- package/skills/cc-tauri-project-standard/SKILL.md +21 -0
- package/skills/cc-tauri-project-standard/examples/minimal/README.md +9 -0
- package/skills/cc-tauri-project-standard/examples/minimal/core/Cargo.lock +5 -0
- package/skills/cc-tauri-project-standard/examples/minimal/core/Cargo.toml +9 -0
- package/skills/cc-tauri-project-standard/examples/minimal/core/src/lib.rs +46 -0
- package/skills/cc-tauri-project-standard/examples/minimal/src-tauri/Cargo.toml +12 -0
- package/skills/cc-tauri-project-standard/examples/minimal/src-tauri/build.rs +5 -0
- package/skills/cc-tauri-project-standard/examples/minimal/src-tauri/capabilities/main.json +6 -0
- package/skills/cc-tauri-project-standard/examples/minimal/src-tauri/permissions/documents.toml +4 -0
- package/skills/cc-tauri-project-standard/examples/minimal/src-tauri/src/main.rs +22 -0
- package/skills/cc-tauri-project-standard/examples/minimal/src-tauri/tauri.conf.json +13 -0
- package/skills/cc-tauri-project-standard/examples/minimal/ui/app.js +5 -0
- package/skills/cc-tauri-project-standard/examples/minimal/ui/index.html +1 -0
- package/skills/cc-tauri-project-standard/references/common/engineering-practices.md +237 -0
- package/skills/cc-tauri-project-standard/references/common/engineering-practices.rules.json +121 -0
- package/skills/cc-tauri-project-standard/references/common/engineering-practices.sources.json +377 -0
- package/skills/cc-tauri-project-standard/references/engineering-practices.md +73 -0
- package/skills/cc-tauri-project-standard/references/practice.md +20 -0
- package/skills/cc-tauri-project-standard/references/verification.md +18 -0
- package/skills/cc-tdd-methodology/SKILL.md +8 -0
- package/skills/cc-tdd-methodology/references/method.md +13 -0
- package/skills/cc-technical-diagrams/SKILL.md +34 -0
- package/skills/{fec-image-generation → cc-technical-diagrams}/assets/interactive-diagram.html +371 -371
- package/skills/cc-technical-diagrams/assets/quality-examples/README.md +14 -0
- package/skills/cc-technical-diagrams/assets/quality-examples/architecture.json +121 -0
- package/skills/cc-technical-diagrams/assets/quality-examples/invalid-explicit.json +41 -0
- package/skills/cc-technical-diagrams/assets/quality-examples/sequence.json +53 -0
- package/skills/cc-technical-diagrams/assets/quality-examples/sequence.mmd +21 -0
- package/skills/cc-technical-diagrams/assets/quality-examples/workflow.json +98 -0
- package/skills/cc-technical-diagrams/assets/quality-examples/workflow.mmd +7 -0
- package/skills/{fec-image-generation → cc-technical-diagrams}/references/diagram-workflows.md +12 -5
- package/skills/{fec-image-generation → cc-technical-diagrams}/references/html-technical-diagrams.md +14 -7
- package/skills/cc-technical-diagrams/references/png-qa-autofix.md +37 -0
- package/skills/cc-technical-diagrams/scripts/diagram-browser.mjs +153 -0
- package/skills/cc-technical-diagrams/scripts/diagram-layout.mjs +176 -0
- package/{localized/zh-CN/skills/fec-image-generation → skills/cc-technical-diagrams}/scripts/export-diagram.mjs +48 -80
- package/skills/cc-technical-diagrams/scripts/mermaid-render.mjs +64 -0
- package/skills/cc-technical-diagrams/scripts/png-qa.mjs +462 -0
- package/skills/{fec-image-generation → cc-technical-diagrams}/scripts/tech-diagram-render.mjs +193 -53
- package/skills/{fec-typescript-project-standard → cc-typescript-project-standard}/SKILL.md +10 -4
- package/skills/cc-typescript-project-standard/examples/engineering/README.md +9 -0
- package/skills/cc-typescript-project-standard/examples/engineering/boundary.test.ts +16 -0
- package/skills/cc-typescript-project-standard/examples/engineering/input.ts +12 -0
- package/skills/cc-typescript-project-standard/examples/engineering/package.json +12 -0
- package/skills/cc-typescript-project-standard/examples/engineering/pnpm-lock.yaml +39 -0
- package/skills/cc-typescript-project-standard/examples/engineering/pnpm-workspace.yaml +1 -0
- package/skills/cc-typescript-project-standard/examples/engineering/tsconfig.json +8 -0
- package/skills/cc-typescript-project-standard/references/common/engineering-practices.md +237 -0
- package/skills/cc-typescript-project-standard/references/common/engineering-practices.rules.json +121 -0
- package/skills/cc-typescript-project-standard/references/common/engineering-practices.sources.json +377 -0
- package/skills/cc-typescript-project-standard/references/engineering-practices.md +106 -0
- package/skills/{fec-typescript-project-standard → cc-typescript-project-standard}/references/type-safety-patterns.md +6 -35
- package/skills/{fec-typescript-project-standard → cc-typescript-project-standard}/references/type-safety.md +7 -1
- package/skills/eval_queries.json +738 -72
- package/skills/fec-api-integration/SKILL.md +5 -1
- package/skills/fec-api-integration/references/common/engineering-practices.md +237 -0
- package/skills/fec-api-integration/references/common/engineering-practices.rules.json +121 -0
- package/skills/fec-api-integration/references/common/engineering-practices.sources.json +377 -0
- package/skills/fec-api-integration/references/engineering-practices.md +73 -0
- package/skills/fec-code-review/SKILL.md +24 -1
- package/skills/fec-code-review/references/common/engineering-practices.md +237 -0
- package/skills/fec-code-review/references/common/engineering-practices.rules.json +121 -0
- package/skills/fec-code-review/references/common/engineering-practices.sources.json +377 -0
- package/skills/fec-code-review/references/engineering-practices.md +73 -0
- package/skills/fec-code-review/references/report-template.md +11 -1
- package/skills/fec-code-smells/SKILL.md +33 -0
- package/skills/fec-code-smells/references/detection-guide.md +25 -0
- package/skills/fec-code-smells/references/smell-catalog.md +861 -0
- package/skills/fec-code-smells/references/smell-to-refactoring-map.md +265 -0
- package/skills/fec-data-fetching/SKILL.md +5 -1
- package/skills/fec-data-fetching/references/common/engineering-practices.md +237 -0
- package/skills/fec-data-fetching/references/common/engineering-practices.rules.json +121 -0
- package/skills/fec-data-fetching/references/common/engineering-practices.sources.json +377 -0
- package/skills/fec-data-fetching/references/engineering-practices.md +73 -0
- package/skills/fec-debug-framework/SKILL.md +2 -51
- package/skills/fec-debug-framework/references/common/debug.md +13 -0
- package/skills/fec-dependency-upgrade/SKILL.md +4 -0
- package/skills/fec-dependency-upgrade/references/common/engineering-practices.md +237 -0
- package/skills/fec-dependency-upgrade/references/common/engineering-practices.rules.json +121 -0
- package/skills/fec-dependency-upgrade/references/common/engineering-practices.sources.json +377 -0
- package/skills/fec-dependency-upgrade/references/engineering-practices.md +73 -0
- package/skills/fec-doc-sync/SKILL.md +7 -28
- package/skills/fec-doc-sync/references/common/doc-sync.md +12 -0
- package/skills/fec-image-generation/SKILL.md +7 -72
- package/skills/fec-image-generation/references/png-qa-autofix.md +9 -2
- package/skills/fec-image-generation/scripts/diagram-layout.mjs +176 -0
- package/skills/fec-image-generation/scripts/png-qa.mjs +36 -5
- package/skills/fec-legacy-web-standard/SKILL.md +1 -1
- package/skills/fec-react-project-standard/SKILL.md +6 -0
- package/skills/fec-react-project-standard/examples/engineering/README.md +7 -0
- package/skills/fec-react-project-standard/examples/engineering/package.json +15 -0
- package/skills/fec-react-project-standard/examples/engineering/pnpm-lock.yaml +662 -0
- package/skills/fec-react-project-standard/examples/engineering/pnpm-workspace.yaml +1 -0
- package/skills/fec-react-project-standard/examples/engineering/request-view.mjs +24 -0
- package/skills/fec-react-project-standard/examples/engineering/request-view.test.mjs +33 -0
- package/skills/fec-react-project-standard/references/common/engineering-practices.md +237 -0
- package/skills/fec-react-project-standard/references/common/engineering-practices.rules.json +121 -0
- package/skills/fec-react-project-standard/references/common/engineering-practices.sources.json +377 -0
- package/skills/fec-react-project-standard/references/engineering-practices.md +73 -0
- package/skills/fec-react-project-standard/references/generic-component-types.md +37 -0
- package/skills/fec-react-project-standard/references/react-quality-patterns.md +3 -3
- package/skills/fec-react-project-standard/references/react-runtime-patterns.md +1 -1
- package/skills/fec-refactor-clean/SKILL.md +3 -0
- package/skills/fec-refactoring/SKILL.md +25 -0
- package/skills/fec-refactoring/references/common/refactoring.md +16 -0
- package/skills/fec-refactoring/references/principles.md +13 -0
- package/skills/fec-refactoring/references/refactoring-vs-feature-change.md +27 -0
- package/skills/fec-refactoring/references/when-to-refactor.md +31 -0
- package/skills/fec-refactoring/references/workflow.md +7 -0
- package/skills/fec-refactoring-api/SKILL.md +25 -0
- package/skills/fec-refactoring-api/references/api-refactorings.md +496 -0
- package/skills/fec-refactoring-catalog/SKILL.md +28 -0
- package/skills/fec-refactoring-catalog/references/catalog-index.md +99 -0
- package/skills/fec-refactoring-catalog/references/composition-guide.md +49 -0
- package/skills/fec-refactoring-catalog/references/selection-guide.md +47 -0
- package/skills/fec-refactoring-control/SKILL.md +25 -0
- package/skills/fec-refactoring-control/references/conditional-refactorings.md +299 -0
- package/skills/fec-refactoring-data/SKILL.md +25 -0
- package/skills/fec-refactoring-data/references/data-refactorings.md +248 -0
- package/skills/fec-refactoring-encapsulation/SKILL.md +25 -0
- package/skills/fec-refactoring-encapsulation/references/encapsulation-refactorings.md +452 -0
- package/skills/fec-refactoring-functions/SKILL.md +25 -0
- package/skills/fec-refactoring-functions/references/function-refactorings.md +567 -0
- package/skills/fec-refactoring-inheritance/SKILL.md +25 -0
- package/skills/fec-refactoring-inheritance/references/inheritance-refactorings.md +550 -0
- package/skills/fec-refactoring-move-features/SKILL.md +25 -0
- package/skills/fec-refactoring-move-features/references/moving-refactorings.md +453 -0
- package/skills/fec-refactoring-validation/SKILL.md +59 -0
- package/skills/fec-refactoring-validation/references/behavior-preservation.md +53 -0
- package/skills/fec-refactoring-validation/references/refactoring-test-checklist.md +42 -0
- package/skills/fec-security-review/SKILL.md +20 -0
- package/skills/fec-security-review/references/common/engineering-practices.md +237 -0
- package/skills/fec-security-review/references/common/engineering-practices.rules.json +121 -0
- package/skills/fec-security-review/references/common/engineering-practices.sources.json +377 -0
- package/skills/fec-security-review/references/engineering-practices.md +73 -0
- package/skills/fec-security-review/references/report-template.md +10 -0
- package/skills/fec-tdd-workflow/SKILL.md +14 -42
- package/skills/fec-tdd-workflow/references/common/tdd.md +13 -0
- package/skills/fec-testing-strategy/SKILL.md +4 -0
- package/skills/fec-testing-strategy/references/common/engineering-practices.md +237 -0
- package/skills/fec-testing-strategy/references/common/engineering-practices.rules.json +121 -0
- package/skills/fec-testing-strategy/references/common/engineering-practices.sources.json +377 -0
- package/skills/fec-testing-strategy/references/engineering-practices.md +73 -0
- package/skills/fec-vue3-project-standard/SKILL.md +4 -0
- package/skills/fec-vue3-project-standard/references/common/engineering-practices.md +237 -0
- package/skills/fec-vue3-project-standard/references/common/engineering-practices.rules.json +121 -0
- package/skills/fec-vue3-project-standard/references/common/engineering-practices.sources.json +377 -0
- package/skills/fec-vue3-project-standard/references/engineering-practices.md +73 -0
- package/skills/fec-vue3-project-standard/references/vue3-project-structure.md +2 -2
- package/skills/metadata.json +2230 -629
- package/skills/relations.json +467 -74
- package/templates/shared/rules/fec-agent-workflow.md +1 -0
- package/templates/shared/rules/fec-source-driven-development.md +3 -29
- package/templates/shared/rules/fec-typescript.md +4 -4
- package/templates/shared/rules/references/common/source-driven-development.md +19 -0
- package/docs/superpowers/plans/2026-05-29-fec-debug.md +0 -491
- package/docs/superpowers/specs/2026-05-29-fec-debug-design.md +0 -340
- package/localized/zh-CN/skills/fec-source-driven-development/SKILL.md +0 -87
- package/skills/fec-source-driven-development/SKILL.md +0 -87
- /package/localized/zh-CN/skills/{fec-drawio-studio → cc-drawio-studio}/data/THIRD_PARTY_NOTICES.md +0 -0
- /package/localized/zh-CN/skills/{fec-drawio-studio → cc-drawio-studio}/data/brand-icons.json +0 -0
- /package/localized/zh-CN/skills/{fec-drawio-studio → cc-drawio-studio}/data/shape-index.json +0 -0
- /package/localized/zh-CN/skills/{fec-drawio-studio → cc-drawio-studio}/references/data-residency.md +0 -0
- /package/localized/zh-CN/skills/{fec-drawio-studio → cc-drawio-studio}/references/diagram-patterns.md +0 -0
- /package/localized/zh-CN/skills/{fec-drawio-studio → cc-drawio-studio}/references/troubleshooting.md +0 -0
- /package/localized/zh-CN/skills/{fec-drawio-studio → cc-drawio-studio}/references/xml-and-mermaid.md +0 -0
- /package/localized/zh-CN/skills/{fec-drawio-studio → cc-drawio-studio}/scripts/brand-symbols.mjs +0 -0
- /package/localized/zh-CN/skills/{fec-drawio-studio → cc-drawio-studio}/scripts/diagram-lint.mjs +0 -0
- /package/localized/zh-CN/skills/{fec-drawio-studio → cc-drawio-studio}/scripts/diagram-url.mjs +0 -0
- /package/localized/zh-CN/skills/{fec-drawio-studio → cc-drawio-studio}/scripts/drawio-export.mjs +0 -0
- /package/localized/zh-CN/skills/{fec-drawio-studio → cc-drawio-studio}/scripts/layout-graph.mjs +0 -0
- /package/localized/zh-CN/skills/{fec-drawio-studio → cc-drawio-studio}/scripts/png-embed-fix.mjs +0 -0
- /package/localized/zh-CN/skills/{fec-drawio-studio → cc-drawio-studio}/scripts/scan-go-packages.mjs +0 -0
- /package/localized/zh-CN/skills/{fec-drawio-studio → cc-drawio-studio}/scripts/scan-js-modules.mjs +0 -0
- /package/localized/zh-CN/skills/{fec-drawio-studio → cc-drawio-studio}/scripts/scan-python-classes.mjs +0 -0
- /package/localized/zh-CN/skills/{fec-drawio-studio → cc-drawio-studio}/scripts/scan-python-modules.mjs +0 -0
- /package/localized/zh-CN/skills/{fec-drawio-studio → cc-drawio-studio}/scripts/scan-rust-modules.mjs +0 -0
- /package/localized/zh-CN/skills/{fec-drawio-studio → cc-drawio-studio}/scripts/scan-ts-modules.mjs +0 -0
- /package/localized/zh-CN/skills/{fec-drawio-studio → cc-drawio-studio}/scripts/shape-query.mjs +0 -0
- /package/localized/zh-CN/skills/{fec-drawio-studio → cc-drawio-studio}/scripts/studio-core.mjs +0 -0
- /package/localized/zh-CN/skills/{fec-drawio-studio → cc-drawio-studio}/styles/built-in/corporate.json +0 -0
- /package/localized/zh-CN/skills/{fec-drawio-studio → cc-drawio-studio}/styles/built-in/default.json +0 -0
- /package/localized/zh-CN/skills/{fec-drawio-studio → cc-drawio-studio}/styles/built-in/handdrawn.json +0 -0
- /package/localized/zh-CN/skills/{fec-drawio-studio → cc-drawio-studio}/styles/schema.json +0 -0
- /package/localized/zh-CN/skills/{fec-image-generation → cc-technical-diagrams}/scripts/interactive-diagram-server.mjs +0 -0
- /package/skills/{fec-drawio-studio → cc-drawio-studio}/data/THIRD_PARTY_NOTICES.md +0 -0
- /package/skills/{fec-drawio-studio → cc-drawio-studio}/data/brand-icons.json +0 -0
- /package/skills/{fec-drawio-studio → cc-drawio-studio}/data/shape-index.json +0 -0
- /package/skills/{fec-drawio-studio → cc-drawio-studio}/references/data-residency.md +0 -0
- /package/skills/{fec-drawio-studio → cc-drawio-studio}/references/diagram-patterns.md +0 -0
- /package/skills/{fec-drawio-studio → cc-drawio-studio}/references/troubleshooting.md +0 -0
- /package/skills/{fec-drawio-studio → cc-drawio-studio}/references/xml-and-mermaid.md +0 -0
- /package/skills/{fec-drawio-studio → cc-drawio-studio}/scripts/brand-symbols.mjs +0 -0
- /package/skills/{fec-drawio-studio → cc-drawio-studio}/scripts/diagram-lint.mjs +0 -0
- /package/skills/{fec-drawio-studio → cc-drawio-studio}/scripts/diagram-url.mjs +0 -0
- /package/skills/{fec-drawio-studio → cc-drawio-studio}/scripts/drawio-export.mjs +0 -0
- /package/skills/{fec-drawio-studio → cc-drawio-studio}/scripts/layout-graph.mjs +0 -0
- /package/skills/{fec-drawio-studio → cc-drawio-studio}/scripts/png-embed-fix.mjs +0 -0
- /package/skills/{fec-drawio-studio → cc-drawio-studio}/scripts/scan-go-packages.mjs +0 -0
- /package/skills/{fec-drawio-studio → cc-drawio-studio}/scripts/scan-js-modules.mjs +0 -0
- /package/skills/{fec-drawio-studio → cc-drawio-studio}/scripts/scan-python-classes.mjs +0 -0
- /package/skills/{fec-drawio-studio → cc-drawio-studio}/scripts/scan-python-modules.mjs +0 -0
- /package/skills/{fec-drawio-studio → cc-drawio-studio}/scripts/scan-rust-modules.mjs +0 -0
- /package/skills/{fec-drawio-studio → cc-drawio-studio}/scripts/scan-ts-modules.mjs +0 -0
- /package/skills/{fec-drawio-studio → cc-drawio-studio}/scripts/shape-query.mjs +0 -0
- /package/skills/{fec-drawio-studio → cc-drawio-studio}/scripts/studio-core.mjs +0 -0
- /package/skills/{fec-drawio-studio → cc-drawio-studio}/styles/built-in/corporate.json +0 -0
- /package/skills/{fec-drawio-studio → cc-drawio-studio}/styles/built-in/default.json +0 -0
- /package/skills/{fec-drawio-studio → cc-drawio-studio}/styles/built-in/handdrawn.json +0 -0
- /package/skills/{fec-drawio-studio → cc-drawio-studio}/styles/schema.json +0 -0
- /package/skills/{fec-image-generation → cc-technical-diagrams}/scripts/interactive-diagram-server.mjs +0 -0
|
@@ -3,6 +3,19 @@
|
|
|
3
3
|
|
|
4
4
|
import fs from "node:fs";
|
|
5
5
|
import path from "node:path";
|
|
6
|
+
import { layoutText, fitNodeText, routeConnector, placeEdgeLabel, overlaps } from "./diagram-layout.mjs";
|
|
7
|
+
|
|
8
|
+
/** @type {import("./diagram-layout.mjs").QualityIssue[]} */
|
|
9
|
+
const qualityIssues = [];
|
|
10
|
+
/** @type {Array<{id:string,owner:string,kind:string,text:string,lines:string[],x:number,y:number,width:number,height:number}>} */
|
|
11
|
+
const textBounds = [];
|
|
12
|
+
/** @type {Box[]} */
|
|
13
|
+
let routeObstacles = [];
|
|
14
|
+
/** @type {Array<Array<[number,number]>>} */
|
|
15
|
+
const occupiedRoutes = [];
|
|
16
|
+
/** @type {Array<{id:string,label:string,points:Array<[number,number]>}>} */
|
|
17
|
+
const deferredLabels=[];
|
|
18
|
+
let finalCanvas = { width: 0, height: 0 };
|
|
6
19
|
|
|
7
20
|
const ALLOWED_TYPES = new Set(["workflow", "sequence", "dataflow", "lifecycle", "architecture"]);
|
|
8
21
|
const NODE_TYPES = new Set([
|
|
@@ -34,8 +47,12 @@ try {
|
|
|
34
47
|
/** @type {SummaryCard[]} */
|
|
35
48
|
const summary = "summary" in renderResult ? /** @type {SummaryCard[]} */ (renderResult.summary) : [];
|
|
36
49
|
const style = normalizeVisualStyle(diagram.visual, "/visual");
|
|
37
|
-
const
|
|
50
|
+
const rawHtml = renderHtml(diagram.meta.title, diagram.meta.subtitle ?? "", renderResult.svg, type, summary, style);
|
|
38
51
|
|
|
52
|
+
const pageStyles = rawHtml.match(/<style>([\s\S]*?)<\/style>/)?.[1] ?? "";
|
|
53
|
+
const diagramStyles=(pageStyles.match(/[^{}]+\{[^{}]*\}/g) ?? []).filter(rule=>/^\s*(?:[:][r]oot|\[data-|\.node|\.edge|\.group|\.lane|\.legend|\.flow|\.label|\.sublabel|\.muted|\.actor|\.step|\.lifeline|\.tech-diagram|\.surface|\.stage|marker|#arrow)/.test(rule)).join("\n");
|
|
54
|
+
const svgStyles = diagramStyles.replaceAll(":root", "svg").replaceAll(/\[data-theme=/g, "svg[data-theme=").replaceAll(/\[data-visual-style=/g, "svg[data-visual-style=");
|
|
55
|
+
const html = rawHtml.replace('data-visual-style="default" data-export-root', `data-visual-style="${style}" data-export-root`).replace(/(<svg[^>]*>)/, `$1<style>${svgStyles}\nsvg{font-family:ui-sans-serif,system-ui,"Segoe UI",sans-serif;}svg[data-theme="dark"]{--surface:#172033;--text:#e2e8f0;--muted:#94a3b8;--line:#94a3b8;}svg[data-theme="light"]{--surface:#f8fafc;--text:#0f172a;--muted:#475569;--line:#475569;--frontend:#0369a1;--backend:#047857;--database:#0e7490;--external:#475569;--agent:#0e7490;--model:#7e22ce;--memory:#047857;--gateway:#a16207;--browser:#0369a1;--queue:#c2410c;--flow-control:#b45309;--flow-data:#0369a1;--flow-read:#047857;--flow-write:#15803d;--flow-async:#64748b;--flow-feedback:#7e22ce;}</style>`);
|
|
39
56
|
fs.mkdirSync(path.dirname(path.resolve(outputPath)), { recursive: true });
|
|
40
57
|
fs.writeFileSync(outputPath, html, "utf8");
|
|
41
58
|
|
|
@@ -50,6 +67,7 @@ try {
|
|
|
50
67
|
input: inputPath,
|
|
51
68
|
output: outputPath,
|
|
52
69
|
manifest: args.manifest ?? null,
|
|
70
|
+
quality: { status: qualityIssues.length ? "partial" : "estimated", issues: qualityIssues },
|
|
53
71
|
nodes: renderResult.manifest.boxes.length,
|
|
54
72
|
connectors: renderResult.manifest.connectors.length,
|
|
55
73
|
};
|
|
@@ -165,6 +183,7 @@ function renderArchitecture(diagram) {
|
|
|
165
183
|
label,
|
|
166
184
|
sublabel: "",
|
|
167
185
|
type,
|
|
186
|
+
kind: "group",
|
|
168
187
|
};
|
|
169
188
|
groupBoxes.push(box);
|
|
170
189
|
}
|
|
@@ -187,6 +206,14 @@ function renderArchitecture(diagram) {
|
|
|
187
206
|
});
|
|
188
207
|
}
|
|
189
208
|
|
|
209
|
+
prepareBoxes(boxes, nodes);
|
|
210
|
+
for (const node of nodes) {
|
|
211
|
+
const box = boxes.get(String(node.id));
|
|
212
|
+
const group = groupBoxes.find((candidate) => candidate.id === node.group);
|
|
213
|
+
if (box && group && (box.x < group.x + 12 || box.y < group.y + 32 || box.x + box.width > group.x + group.width - 12 || box.y + box.height > group.y + group.height - 12)) qualityIssues.push({code:"group-containment",id:box.id,message:`Node "${box.id}" exceeds group "${group.id}" content area.`});
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
|
|
190
217
|
/** @type {Connector[]} */
|
|
191
218
|
const connectors = [];
|
|
192
219
|
const flowSet = new Set();
|
|
@@ -209,11 +236,13 @@ function renderArchitecture(diagram) {
|
|
|
209
236
|
const contentBottom = Math.max(360, maxBoxExtent(allBoxes, "y") + 64);
|
|
210
237
|
const legend = normalizeLegend(diagram.legend, [...boxes.values()]);
|
|
211
238
|
const flowLegend = normalizeFlowLegend(diagram.flowLegend, [...flowSet]);
|
|
212
|
-
const
|
|
213
|
-
const
|
|
214
|
-
const
|
|
215
|
-
const
|
|
216
|
-
const
|
|
239
|
+
const width = Math.max(860, maxBoxExtent(allBoxes, "x") + 64);
|
|
240
|
+
const columns=Math.max(1,Math.floor((width-88)/200));
|
|
241
|
+
const legendHeight=legend.length ? 30+Math.ceil(legend.length/columns)*72 : 0;
|
|
242
|
+
const flowHeight=flowLegend.length ? 30+Math.ceil(flowLegend.length/columns)*72 : 0;
|
|
243
|
+
const legendSvg = renderArchitectureLegend(legend,44,contentBottom-4,columns);
|
|
244
|
+
const flowLegendSvg = renderFlowLegend(flowLegend,44,contentBottom+legendHeight,columns);
|
|
245
|
+
const height=contentBottom+legendHeight+flowHeight+32;
|
|
217
246
|
const groupSvg = groupBoxes.map(renderGroup).join("\n");
|
|
218
247
|
const boxSvg = [...boxes.values()].map(renderBox).join("\n");
|
|
219
248
|
const svg = wrapSvg(width, height, `${groupSvg}\n${connectionSvg}\n${boxSvg}\n${legendSvg}\n${flowLegendSvg}`);
|
|
@@ -249,8 +278,8 @@ function renderLaneDiagram(diagram, itemKey, edgeKey) {
|
|
|
249
278
|
assertObject(item, `/${itemKey}/${index}`);
|
|
250
279
|
return requireNumber(item, "col", `/${itemKey}/${index}/col`);
|
|
251
280
|
}));
|
|
252
|
-
|
|
253
|
-
|
|
281
|
+
let width = Math.max(780, 190 + (maxCol + 1) * 180);
|
|
282
|
+
let height = Math.max(420, 140 + lanes.length * 145);
|
|
254
283
|
const laneHeight = 118;
|
|
255
284
|
const top = 72;
|
|
256
285
|
const left = 142;
|
|
@@ -285,6 +314,36 @@ function renderLaneDiagram(diagram, itemKey, edgeKey) {
|
|
|
285
314
|
boxes.set(id, box);
|
|
286
315
|
}
|
|
287
316
|
|
|
317
|
+
prepareBoxes(boxes, items);
|
|
318
|
+
let laneTop = 72;
|
|
319
|
+
/** @type {Array<{y:number,height:number}>} */
|
|
320
|
+
const laneGeometry = [];
|
|
321
|
+
const columns = [...new Set(items.map((item) => Number(item.col)))].sort((a, b) => a - b);
|
|
322
|
+
const columnX = new Map();
|
|
323
|
+
let nextX = 160;
|
|
324
|
+
for (const col of columns) {
|
|
325
|
+
columnX.set(col, nextX);
|
|
326
|
+
nextX += Math.max(0, ...items.filter((item) => item.col === col).map((item) => boxes.get(String(item.id))?.width ?? 0)) + 64;
|
|
327
|
+
}
|
|
328
|
+
for (const lane of lanes) {
|
|
329
|
+
const members = items.filter((item) => item.lane === lane.id);
|
|
330
|
+
const columnBottom = new Map();
|
|
331
|
+
for (const item of members) {
|
|
332
|
+
const box = boxes.get(String(item.id));
|
|
333
|
+
if (!box) continue;
|
|
334
|
+
box.x = Number(columnX.get(Number(item.col)));
|
|
335
|
+
const baseline = columnBottom.get(item.col) ?? laneTop + 48;
|
|
336
|
+
box.y = baseline + (typeof item.yOffset === "number" ? item.yOffset : 0);
|
|
337
|
+
columnBottom.set(item.col, box.y + box.height + 32);
|
|
338
|
+
}
|
|
339
|
+
const bottom = Math.max(laneTop + 112, ...members.map((item) => { const b = boxes.get(String(item.id)); return b ? b.y + b.height + 24 : laneTop; }));
|
|
340
|
+
laneGeometry.push({ y: laneTop, height: bottom - laneTop });
|
|
341
|
+
laneTop = bottom + 32;
|
|
342
|
+
}
|
|
343
|
+
width = Math.max(width, nextX + 40);
|
|
344
|
+
height = Math.max(height, laneTop + 40);
|
|
345
|
+
|
|
346
|
+
|
|
288
347
|
/** @type {Connector[]} */
|
|
289
348
|
const connectors = [];
|
|
290
349
|
const edgeSvg = edges.map((edge, index) => {
|
|
@@ -303,8 +362,8 @@ function renderLaneDiagram(diagram, itemKey, edgeKey) {
|
|
|
303
362
|
}).join("\n");
|
|
304
363
|
|
|
305
364
|
const laneSvg = lanes.map((lane, index) => {
|
|
306
|
-
const y =
|
|
307
|
-
return `<g class="lane"><rect x="34" y="${y}" width="${width - 68}" height="${
|
|
365
|
+
const y = laneGeometry[index].y;
|
|
366
|
+
return `<g class="lane"><rect x="34" y="${y}" width="${width - 68}" height="${laneGeometry[index].height}" rx="10"/><text x="52" y="${y + 28}" class="label muted">${escapeHtml(String(lane.label))}</text></g>`;
|
|
308
367
|
}).join("\n");
|
|
309
368
|
const boxSvg = [...boxes.values()].map(renderBox).join("\n");
|
|
310
369
|
const svg = wrapSvg(width, height, `${laneSvg}\n${edgeSvg}\n${boxSvg}`);
|
|
@@ -323,8 +382,8 @@ function renderSequence(diagram) {
|
|
|
323
382
|
const participants = requireObjectArray(diagram.participants, "/participants");
|
|
324
383
|
const messages = requireObjectArray(diagram.messages, "/messages");
|
|
325
384
|
const ids = new Set();
|
|
326
|
-
|
|
327
|
-
|
|
385
|
+
let width = Math.max(760, 160 + participants.length * 170);
|
|
386
|
+
let height = Math.max(420, 170 + messages.length * 82);
|
|
328
387
|
const top = 74;
|
|
329
388
|
const laneGap = (width - 160) / Math.max(1, participants.length - 1);
|
|
330
389
|
/** @type {Map<string, Box>} */
|
|
@@ -349,25 +408,40 @@ function renderSequence(diagram) {
|
|
|
349
408
|
});
|
|
350
409
|
}
|
|
351
410
|
|
|
411
|
+
prepareBoxes(boxes, participants);
|
|
412
|
+
const gap = Math.max(280, ...[...boxes.values()].map(box=>box.width+80), ...messages.map((m) => layoutText(typeof m.label === "string" ? m.label : "", 260, 12, 16).width + 60));
|
|
413
|
+
width = Math.max(width, 160 + participants.length * gap);
|
|
414
|
+
[...boxes.values()].forEach((box, index) => { box.x = 80 + index * gap + gap / 2 - box.width / 2; });
|
|
415
|
+
let messageY = Math.max(...[...boxes.values()].map((box) => box.y + box.height)) + 72;
|
|
416
|
+
height = Math.max(height, messageY + messages.length * 108 + 80);
|
|
417
|
+
|
|
418
|
+
|
|
352
419
|
/** @type {Connector[]} */
|
|
353
420
|
const connectors = [];
|
|
354
|
-
|
|
421
|
+
|
|
355
422
|
const messageSvg = messages.map((message, index) => {
|
|
356
423
|
assertObject(message, `/messages/${index}`);
|
|
424
|
+
if (["activation","activate","deactivate","fragment","alt","loop","par","async"].some((key)=>key in message)) throw usageError(`/messages/${index}`,"Complex sequence semantics require the Mermaid route; do not simplify activation/fragments/async fields.");
|
|
357
425
|
const from = requireId(message, "from", `/messages/${index}/from`);
|
|
358
426
|
const to = requireId(message, "to", `/messages/${index}/to`);
|
|
359
427
|
const fromBox = boxes.get(from);
|
|
360
428
|
const toBox = boxes.get(to);
|
|
361
429
|
if (!fromBox) throw usageError(`/messages/${index}/from`, `Unknown endpoint "${from}".`);
|
|
362
430
|
if (!toBox) throw usageError(`/messages/${index}/to`, `Unknown endpoint "${to}".`);
|
|
363
|
-
const
|
|
431
|
+
const messageText = typeof message.label === "string" ? message.label : "";
|
|
432
|
+
const textLayout = layoutText(messageText, 190, 12, 16);
|
|
433
|
+
const y = messageY;
|
|
434
|
+
messageY += Math.max(72, textLayout.height + 56 + (from === to ? 32 : 0));
|
|
364
435
|
/** @type {Array<[number, number]>} */
|
|
365
|
-
const points = [[centerX(fromBox), y], [centerX(toBox), y]];
|
|
436
|
+
const points = from === to ? [[centerX(fromBox), y], [centerX(fromBox) + 64, y], [centerX(fromBox) + 64, y + 32], [centerX(fromBox), y + 32]] : [[centerX(fromBox), y], [centerX(toBox), y]];
|
|
437
|
+
occupiedRoutes.push(points);
|
|
366
438
|
const variant = normalizeVariant(message.variant, `/messages/${index}/variant`);
|
|
367
|
-
connectors.push({ id: `${from}-${to}-${index}`, from, to, points });
|
|
439
|
+
connectors.push({ id: `${from}-${to}-${index}`, from, to, points, kind: "sequence", self: from === to });
|
|
368
440
|
return renderConnector(points, variant, typeof message.label === "string" ? message.label : "");
|
|
369
441
|
}).join("\n");
|
|
370
442
|
const boxSvg = [...boxes.values()].map(renderBox).join("\n");
|
|
443
|
+
height=Math.max(height,messageY+80);
|
|
444
|
+
const lifelines = [...boxes.values()].map((box) => `<line x1="${centerX(box)}" y1="${box.y + box.height}" x2="${centerX(box)}" y2="${height - 56}" class="lifeline"/>`).join("\n");
|
|
371
445
|
const svg = wrapSvg(width, height, `${lifelines}\n${messageSvg}\n${boxSvg}`);
|
|
372
446
|
|
|
373
447
|
return { svg, manifest: manifestFrom(width, height, [...boxes.values()], connectors) };
|
|
@@ -410,6 +484,8 @@ function renderDataflow(diagram) {
|
|
|
410
484
|
});
|
|
411
485
|
}
|
|
412
486
|
|
|
487
|
+
prepareBoxes(boxes, nodes);
|
|
488
|
+
|
|
413
489
|
/** @type {Connector[]} */
|
|
414
490
|
const connectors = [];
|
|
415
491
|
const stageSvg = stages.map((stage, index) => {
|
|
@@ -463,22 +539,45 @@ function countStageBefore(nodes, endIndex, stage) {
|
|
|
463
539
|
return count;
|
|
464
540
|
}
|
|
465
541
|
|
|
542
|
+
|
|
543
|
+
/** @param {Map<string, Box>} boxes @param {Array<Record<string, unknown>>} sources */
|
|
544
|
+
function prepareBoxes(boxes, sources) {
|
|
545
|
+
for (const [id, box] of boxes) {
|
|
546
|
+
const source = sources.find((item) => item.id === id) ?? {};
|
|
547
|
+
const fitted = fitNodeText(box, { width: typeof source.width === "number", height: typeof source.height === "number" });
|
|
548
|
+
boxes.set(id, fitted.box);
|
|
549
|
+
qualityIssues.push(...fitted.issues);
|
|
550
|
+
}
|
|
551
|
+
routeObstacles = [...boxes.values()];
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
/** @param {string} id @param {string} owner @param {string} kind @param {string} text @param {import("./diagram-layout.mjs").TextLayout} layout @param {number} cx @param {number} top @param {string} cls */
|
|
555
|
+
function renderText(id, owner, kind, text, layout, cx, top, cls) {
|
|
556
|
+
textBounds.push({ id, owner, kind, text, lines: layout.lines, x: cx - layout.width / 2, y: top, width: layout.width, height: layout.height });
|
|
557
|
+
return `<text data-label-id="${escapeHtml(id)}" x="${cx}" y="${top + layout.fontSize}" class="${cls}" font-size="${layout.fontSize}" text-anchor="middle">${layout.lines.map((line, i) => `<tspan x="${cx}" dy="${i ? layout.lineHeight : 0}">${escapeHtml(line)}</tspan>`).join("")}</text>`;
|
|
558
|
+
}
|
|
559
|
+
|
|
466
560
|
/**
|
|
467
561
|
* @param {Box} box
|
|
468
562
|
*/
|
|
469
563
|
function renderBox(box) {
|
|
470
|
-
const labelLines = wrapLabel(box.label, 18).slice(0, 2);
|
|
471
564
|
const shape = box.shape ?? "box";
|
|
472
565
|
const isSemantic = isSemanticNodeType(box.type);
|
|
473
|
-
const
|
|
474
|
-
const
|
|
475
|
-
const
|
|
476
|
-
const
|
|
477
|
-
const
|
|
566
|
+
const available = shape === "diamond" ? box.width * 0.5 - 12 : (box.type === "queue" ? box.width - 64 : box.width - 32);
|
|
567
|
+
const main = layoutText(box.label, available);
|
|
568
|
+
const sub = layoutText(box.sublabel, available, 12, 16);
|
|
569
|
+
const total = main.height + (box.sublabel ? sub.height + 6 : 0);
|
|
570
|
+
const textTop = shape === "diamond" ? centerY(box) - total / 2 : box.y + (["database", "vectorstore"].includes(box.type) ? 30 : box.type === "queue" ? 20 : isSemantic ? 46 : box.actor ? 40 : 20);
|
|
571
|
+
const labelSvg = renderText(box.id + "-label", box.id, "node", box.label, main, centerX(box), textTop, "label");
|
|
572
|
+
const sublabel = box.sublabel ? renderText(box.id + "-sub", box.id, "node", box.sublabel, sub, centerX(box), textTop + main.height + 6, "sublabel") : "";
|
|
573
|
+
const actorLayout=layoutText(box.actor??"",box.width-32,12,16);
|
|
574
|
+
const actor = box.actor ? renderText(box.id+"-actor",box.id,"group",box.actor,actorLayout,centerX(box),box.y-actorLayout.height-12,"actor") : "";
|
|
575
|
+
const stepLayout=layoutText(box.step??"",Math.max(14,box.width-16),9,12);
|
|
576
|
+
const step = box.step ? `<g class="step-badge"><circle cx="${box.x + 13}" cy="${box.y + 13}" r="${Math.max(10,stepLayout.width/2+4)}"/>${renderText(box.id+"-step",box.id,"group",box.step,stepLayout,box.x+13,box.y+7,"step-label")}</g>` : "";
|
|
478
577
|
const shapeSvg = renderSemanticShape(box) ?? (shape === "diamond"
|
|
479
578
|
? `<polygon points="${centerX(box)},${box.y} ${box.x + box.width},${centerY(box)} ${centerX(box)},${box.y + box.height} ${box.x},${centerY(box)}"/>`
|
|
480
579
|
: `<rect x="${box.x}" y="${box.y}" width="${box.width}" height="${box.height}" rx="${shape === "terminal" ? Math.round(box.height / 2) : 10}"/>`);
|
|
481
|
-
return `<g class="node node-${box.type}">${actor}\n${shapeSvg}\n${step}\n${labelSvg}\n${sublabel}</g>`;
|
|
580
|
+
return `<g data-node-id="${escapeHtml(box.id)}" class="node node-${box.type}">${actor}\n${shapeSvg}\n${step}\n${labelSvg}\n${sublabel}</g>`;
|
|
482
581
|
}
|
|
483
582
|
|
|
484
583
|
/**
|
|
@@ -514,8 +613,9 @@ function renderSemanticShape(box) {
|
|
|
514
613
|
return `<path d="M ${box.x} ${box.y} L ${box.x + box.width - fold} ${box.y} L ${box.x + box.width} ${box.y + fold} L ${box.x + box.width} ${box.y + box.height} L ${box.x} ${box.y + box.height} Z"/><path d="M ${box.x + box.width - fold} ${box.y} L ${box.x + box.width - fold} ${box.y + fold} L ${box.x + box.width} ${box.y + fold}" fill="none"/>`;
|
|
515
614
|
}
|
|
516
615
|
if (box.type === "queue") {
|
|
517
|
-
const ry =
|
|
518
|
-
|
|
616
|
+
const ry = box.height / 2;
|
|
617
|
+
const end = Math.min(18, box.width / 6);
|
|
618
|
+
return `<ellipse cx="${box.x + end}" cy="${cy}" rx="${end}" ry="${ry}"/><rect x="${box.x + end}" y="${cy - ry}" width="${box.width - end * 2}" height="${ry * 2}" stroke="none"/><line x1="${box.x + end}" y1="${cy - ry}" x2="${box.x + box.width - end}" y2="${cy - ry}"/><line x1="${box.x + end}" y1="${cy + ry}" x2="${box.x + box.width - end}" y2="${cy + ry}"/><ellipse cx="${box.x + box.width - end}" cy="${cy}" rx="${end}" ry="${ry}"/>`;
|
|
519
619
|
}
|
|
520
620
|
if (box.type === "browser") {
|
|
521
621
|
return `<rect x="${box.x}" y="${box.y}" width="${box.width}" height="${box.height}" rx="10"/><rect x="${box.x}" y="${box.y}" width="${box.width}" height="20" rx="10" class="node-chrome"/><circle cx="${box.x + 14}" cy="${box.y + 10}" r="3" class="node-dot"/><circle cx="${box.x + 26}" cy="${box.y + 10}" r="3" class="node-dot"/><circle cx="${box.x + 38}" cy="${box.y + 10}" r="3" class="node-dot"/>`;
|
|
@@ -534,7 +634,7 @@ function renderSemanticShape(box) {
|
|
|
534
634
|
* @param {Box} box
|
|
535
635
|
*/
|
|
536
636
|
function renderGroup(box) {
|
|
537
|
-
return `<g class="group group-${box.type}"><rect x="${box.x}" y="${box.y}" width="${box.width}" height="${box.height}" rx="14"
|
|
637
|
+
return `<g class="group group-${box.type}"><rect x="${box.x}" y="${box.y}" width="${box.width}" height="${box.height}" rx="14"/>${renderText(box.id+"-group",box.id,"group",box.label,layoutText(box.label,box.width-32,12,16),box.x+box.width/2,box.y+10,"sublabel")}</g>`;
|
|
538
638
|
}
|
|
539
639
|
|
|
540
640
|
/**
|
|
@@ -544,8 +644,12 @@ function renderGroup(box) {
|
|
|
544
644
|
*/
|
|
545
645
|
function renderConnector(points, variant, label, flow = "") {
|
|
546
646
|
const pathData = points.map(([x, y], index) => `${index === 0 ? "M" : "L"} ${x} ${y}`).join(" ");
|
|
547
|
-
const
|
|
548
|
-
const
|
|
647
|
+
const textLayout = layoutText(label, 190, 12, 16);
|
|
648
|
+
const placed = placeEdgeLabel(points, textLayout, [...routeObstacles, ...textBounds]);
|
|
649
|
+
const id = `edge-label-${textBounds.length}`;
|
|
650
|
+
if (label) qualityIssues.push(...placed.issues.map((issue) => ({ ...issue, id })));
|
|
651
|
+
if(label) deferredLabels.push({id,label,points});
|
|
652
|
+
const labelSvg = label ? renderText(id, id, "edge", label, textLayout, placed.rect.x + placed.rect.width / 2, placed.rect.y, "edge-label") : "";
|
|
549
653
|
const marker = flow ? `flow-${flow}` : (variant === "return" ? "default" : variant);
|
|
550
654
|
return `<g class="edge edge-${variant}${flow ? ` flow-${flow}` : ""}"><path d="${pathData}" marker-end="url(#arrow-${marker})"/>\n${labelSvg}</g>`;
|
|
551
655
|
}
|
|
@@ -556,7 +660,19 @@ function renderConnector(points, variant, label, flow = "") {
|
|
|
556
660
|
* @param {string} body
|
|
557
661
|
*/
|
|
558
662
|
function wrapSvg(width, height, body) {
|
|
559
|
-
|
|
663
|
+
for(let i=textBounds.length-1;i>=0;i--) if(textBounds[i].kind === "edge") textBounds.splice(i,1);
|
|
664
|
+
for(const {id,label,points} of deferredLabels) {
|
|
665
|
+
const layout=layoutText(label,190,12,16);
|
|
666
|
+
const placed=placeEdgeLabel(points,layout,[...routeObstacles,...textBounds],occupiedRoutes);
|
|
667
|
+
qualityIssues.push(...placed.issues);
|
|
668
|
+
const replacement=renderText(id,id,"edge",label,layout,placed.rect.x+placed.rect.width/2,placed.rect.y,"edge-label");
|
|
669
|
+
body=body.replace(new RegExp('<text data-label-id="'+id+'"[^>]*>[\\s\\S]*?</text>'),replacement);
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
width = Math.ceil(Math.max(width, ...routeObstacles.map((b) => b.x + b.width + 40), ...textBounds.map((b) => b.x + b.width + 40), ...occupiedRoutes.flat().map((p) => p[0] + 40)));
|
|
673
|
+
height = Math.ceil(Math.max(height, ...routeObstacles.map((b) => b.y + b.height + 40), ...textBounds.map((b) => b.y + b.height + 40), ...occupiedRoutes.flat().map((p) => p[1] + 40)));
|
|
674
|
+
finalCanvas = { width, height };
|
|
675
|
+
return `<svg class="tech-diagram" data-theme="light" data-visual-style="default" data-export-root="1" role="img" viewBox="0 0 ${width} ${height}" xmlns="http://www.w3.org/2000/svg">
|
|
560
676
|
<defs>
|
|
561
677
|
<marker id="arrow-default" viewBox="0 0 10 10" refX="8" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse"><path d="M 0 0 L 10 5 L 0 10 z"/></marker>
|
|
562
678
|
<marker id="arrow-emphasis" viewBox="0 0 10 10" refX="8" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse"><path d="M 0 0 L 10 5 L 0 10 z"/></marker>
|
|
@@ -760,8 +876,8 @@ button {
|
|
|
760
876
|
.node-glyph-outline, .node-glyph-line { fill: none; stroke: currentColor; }
|
|
761
877
|
.node-chrome { fill: currentColor; opacity: 0.25; stroke: none; }
|
|
762
878
|
.node-dot { fill: currentColor; stroke: none; opacity: 0.65; }
|
|
763
|
-
.label { fill: var(--text); font-weight: 650; font-size:
|
|
764
|
-
.sublabel, .muted, .actor { fill: var(--muted); font-size:
|
|
879
|
+
.label { fill: var(--text); font-weight: 650; font-size: 14px; }
|
|
880
|
+
.sublabel, .muted, .actor { fill: var(--muted); font-size: 12px; }
|
|
765
881
|
.actor { font-weight: 650; }
|
|
766
882
|
.step-badge circle { fill: var(--panel); stroke: currentColor; stroke-width: 1.3; }
|
|
767
883
|
.step-badge text { fill: var(--text); font-size: 9px; font-weight: 750; }
|
|
@@ -775,7 +891,7 @@ button {
|
|
|
775
891
|
.flow-write path { stroke: var(--flow-write); stroke-dasharray: 5 4; }
|
|
776
892
|
.flow-async path { stroke: var(--flow-async); stroke-dasharray: 4 4; }
|
|
777
893
|
.flow-feedback path { stroke: var(--flow-feedback); stroke-width: 2; }
|
|
778
|
-
.edge-label { fill: var(--muted); font-size:
|
|
894
|
+
.edge-label { fill: var(--muted); font-size: 12px; paint-order: stroke; stroke: var(--surface); stroke-width: 5px; stroke-linejoin: round; }
|
|
779
895
|
.lifeline { stroke: color-mix(in srgb, var(--muted), transparent 48%); stroke-dasharray: 4 5; }
|
|
780
896
|
.summary-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 10px; margin-top: 12px; }
|
|
781
897
|
.summary-card { background: var(--panel); border: 1px solid color-mix(in srgb, var(--muted), transparent 74%); border-radius: 8px; padding: 12px; }
|
|
@@ -823,16 +939,25 @@ ${summaryHtml}
|
|
|
823
939
|
<script>
|
|
824
940
|
const root = document.documentElement;
|
|
825
941
|
const stored = localStorage.getItem("fec-tech-diagram-theme");
|
|
826
|
-
|
|
942
|
+
const diagramSvg = document.querySelector("[data-export-root]");
|
|
943
|
+
root.dataset.theme = stored === "dark" ? "dark" : "light";
|
|
944
|
+
diagramSvg.dataset.theme = root.dataset.theme;
|
|
945
|
+
diagramSvg.dataset.visualStyle = root.dataset.visualStyle;
|
|
827
946
|
document.querySelector('[data-action="theme"]').addEventListener("click", () => {
|
|
828
947
|
const next = root.dataset.theme === "light" ? "dark" : "light";
|
|
829
948
|
root.dataset.theme = next;
|
|
949
|
+
diagramSvg.dataset.theme = next;
|
|
830
950
|
localStorage.setItem("fec-tech-diagram-theme", next);
|
|
831
951
|
});
|
|
832
952
|
document.querySelector('[data-action="print"]').addEventListener("click", () => window.print());
|
|
833
953
|
document.querySelector('[data-action="svg"]').addEventListener("click", () => {
|
|
834
954
|
const svg = document.querySelector("[data-export-root]");
|
|
835
|
-
const
|
|
955
|
+
const clone = svg.cloneNode(true);
|
|
956
|
+
const originals = [svg, ...svg.querySelectorAll("*")];
|
|
957
|
+
const copies = [clone, ...clone.querySelectorAll("*")];
|
|
958
|
+
const properties = ["fill","stroke","stroke-width","stroke-dasharray","font-family","font-size","font-weight","color","opacity","paint-order","text-anchor"];
|
|
959
|
+
originals.forEach((element,index) => { const computed=getComputedStyle(element); properties.forEach(property=>copies[index].style?.setProperty(property,computed.getPropertyValue(property))); });
|
|
960
|
+
const source = new XMLSerializer().serializeToString(clone);
|
|
836
961
|
const blob = new Blob([source], { type: "image/svg+xml" });
|
|
837
962
|
const link = document.createElement("a");
|
|
838
963
|
link.href = URL.createObjectURL(blob);
|
|
@@ -866,10 +991,20 @@ ${summary.map((card) => ` <article class="summary-card summary-${card.type}">
|
|
|
866
991
|
* @param {Connector[]} connectors
|
|
867
992
|
*/
|
|
868
993
|
function manifestFrom(width, height, boxes, connectors) {
|
|
994
|
+
for(const connector of connectors) if(connector.points.some(([x,y])=>x<0||y<0)) qualityIssues.push({code:"connector-out-of-bounds",id:connector.id,message:`Connector "${connector.id}" has negative explicit coordinates.`});
|
|
995
|
+
const nodes = boxes.filter((box) => box.kind !== "group");
|
|
996
|
+
for (const box of boxes) if (box.x < 0 || box.y < 0) qualityIssues.push({code:"box-out-of-bounds",id:box.id,message:`Box "${box.id}" has negative coordinates.`});
|
|
997
|
+
for (let i=0;i<nodes.length;i++) for (let j=i+1;j<nodes.length;j++) if (overlaps(nodes[i],nodes[j])) qualityIssues.push({code:"box-overlap",id:nodes[i].id,message:`Nodes "${nodes[i].id}" and "${nodes[j].id}" overlap.`});
|
|
869
998
|
return {
|
|
870
|
-
canvas: { width, height },
|
|
871
|
-
boxes: boxes.map(({ id, x, y, width: boxWidth, height: boxHeight, label }) => ({ id, x, y, width: boxWidth, height: boxHeight, label })),
|
|
999
|
+
canvas: finalCanvas.width ? finalCanvas : { width, height },
|
|
1000
|
+
boxes: boxes.map(({ id, x, y, width: boxWidth, height: boxHeight, label, kind }) => ({ id, x, y, width: boxWidth, height: boxHeight, label, kind })),
|
|
1001
|
+
groups: boxes.filter((box) => box.kind === "group").map((box) => ({ ...box })),
|
|
872
1002
|
connectors,
|
|
1003
|
+
labels: textBounds,
|
|
1004
|
+
coordinateSpace: "svg",
|
|
1005
|
+
scale: 1,
|
|
1006
|
+
measurement: "estimated",
|
|
1007
|
+
issues: qualityIssues,
|
|
873
1008
|
};
|
|
874
1009
|
}
|
|
875
1010
|
|
|
@@ -905,14 +1040,15 @@ function routeWithWaypoints(from, to, waypoints, pointer) {
|
|
|
905
1040
|
if (!Array.isArray(waypoints)) throw usageError(pointer, "Expected array of [x, y] waypoints.");
|
|
906
1041
|
/** @type {Array<[number, number]>} */
|
|
907
1042
|
const parsed = waypoints.map((point, index) => {
|
|
908
|
-
if (!Array.isArray(point) || point.length !== 2 || typeof point[0] !== "number" || typeof point[1] !== "number") {
|
|
1043
|
+
if (!Array.isArray(point) || point.length !== 2 || typeof point[0] !== "number" || typeof point[1] !== "number" || !Number.isFinite(point[0]) || !Number.isFinite(point[1])) {
|
|
909
1044
|
throw usageError(`${pointer}/${index}`, "Expected [x, y] number tuple.");
|
|
910
1045
|
}
|
|
911
1046
|
return [point[0], point[1]];
|
|
912
1047
|
});
|
|
913
|
-
const
|
|
914
|
-
|
|
915
|
-
|
|
1048
|
+
const result = routeConnector(from, to, routeObstacles.filter((box) => box.id !== from.id && box.id !== to.id), occupiedRoutes, parsed);
|
|
1049
|
+
qualityIssues.push(...result.issues);
|
|
1050
|
+
occupiedRoutes.push(result.points);
|
|
1051
|
+
return result.points;
|
|
916
1052
|
}
|
|
917
1053
|
|
|
918
1054
|
/**
|
|
@@ -1006,11 +1142,13 @@ function normalizeLegend(legend, boxes) {
|
|
|
1006
1142
|
* @param {number} x
|
|
1007
1143
|
* @param {number} y
|
|
1008
1144
|
*/
|
|
1009
|
-
function renderArchitectureLegend(items, x, y) {
|
|
1145
|
+
function renderArchitectureLegend(items, x, y, columns = 4) {
|
|
1010
1146
|
if (items.length === 0) return "";
|
|
1011
1147
|
const itemSvg = items.map((item, index) => {
|
|
1012
|
-
const itemX = x + index *
|
|
1013
|
-
|
|
1148
|
+
const itemX = x + (index % columns) * 200;
|
|
1149
|
+
const itemY = y + Math.floor(index / columns) * 72;
|
|
1150
|
+
const text = layoutText(item.label,160,12,16);
|
|
1151
|
+
return `<g class="node node-${item.type}"><rect x="${itemX}" y="${itemY + 16}" width="16" height="10" rx="2"/>${renderText("legend-"+index,"legend","group",item.label,text,itemX+24+text.width/2,itemY+14,"sublabel")}</g>`;
|
|
1014
1152
|
}).join("\n");
|
|
1015
1153
|
return `<g class="legend"><text x="${x}" y="${y}" class="label">Legend</text>\n${itemSvg}</g>`;
|
|
1016
1154
|
}
|
|
@@ -1020,11 +1158,13 @@ function renderArchitectureLegend(items, x, y) {
|
|
|
1020
1158
|
* @param {number} x
|
|
1021
1159
|
* @param {number} y
|
|
1022
1160
|
*/
|
|
1023
|
-
function renderFlowLegend(items, x, y) {
|
|
1161
|
+
function renderFlowLegend(items, x, y, columns = 4) {
|
|
1024
1162
|
if (items.length === 0) return "";
|
|
1025
1163
|
const itemSvg = items.map((item, index) => {
|
|
1026
|
-
const itemX = x + index *
|
|
1027
|
-
|
|
1164
|
+
const itemX = x + (index % columns) * 200;
|
|
1165
|
+
const itemY = y + Math.floor(index / columns) * 72;
|
|
1166
|
+
const text = layoutText(item.label,152,12,16);
|
|
1167
|
+
return `<g class="edge flow-${item.type}"><path d="M ${itemX} ${itemY + 22} L ${itemX + 28} ${itemY + 22}" marker-end="url(#arrow-flow-${item.type})"/>${renderText("flow-legend-"+index,"flow-legend","group",item.label,text,itemX+38+text.width/2,itemY+14,"sublabel")}</g>`;
|
|
1028
1168
|
}).join("\n");
|
|
1029
1169
|
return `<g class="flow-legend"><text x="${x}" y="${y}" class="label">Flow Legend</text>\n${itemSvg}</g>`;
|
|
1030
1170
|
}
|
|
@@ -1115,13 +1255,10 @@ function normalizeSummary(summary) {
|
|
|
1115
1255
|
* @returns {Array<[number, number]>}
|
|
1116
1256
|
*/
|
|
1117
1257
|
function routeBoxes(from, to) {
|
|
1118
|
-
const
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
}
|
|
1123
|
-
const midX = Math.round((start[0] + end[0]) / 2);
|
|
1124
|
-
return [[start[0], start[1]], [midX, start[1]], [midX, end[1]], [end[0], end[1]]];
|
|
1258
|
+
const result = routeConnector(from, to, routeObstacles.filter((box) => box.id !== from.id && box.id !== to.id), occupiedRoutes);
|
|
1259
|
+
qualityIssues.push(...result.issues);
|
|
1260
|
+
occupiedRoutes.push(result.points);
|
|
1261
|
+
return result.points;
|
|
1125
1262
|
}
|
|
1126
1263
|
|
|
1127
1264
|
/**
|
|
@@ -1341,6 +1478,7 @@ function printReport(report, format) {
|
|
|
1341
1478
|
* type: string;
|
|
1342
1479
|
* actor?: string;
|
|
1343
1480
|
* step?: string;
|
|
1481
|
+
* kind?: string;
|
|
1344
1482
|
* shape?: "box" | "diamond" | "terminal";
|
|
1345
1483
|
* }} Box
|
|
1346
1484
|
*
|
|
@@ -1348,6 +1486,8 @@ function printReport(report, format) {
|
|
|
1348
1486
|
* id: string;
|
|
1349
1487
|
* from: string;
|
|
1350
1488
|
* to: string;
|
|
1489
|
+
* kind?: string;
|
|
1490
|
+
* self?: boolean;
|
|
1351
1491
|
* points: Array<[number, number]>;
|
|
1352
1492
|
* }} Connector
|
|
1353
1493
|
*
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
---
|
|
2
|
-
name:
|
|
3
|
-
description:
|
|
2
|
+
name: cc-typescript-project-standard
|
|
3
|
+
description: 用于TypeScript 工程配置、模块解析、公共类型、声明文件、包导出、类型收窄或泛型契约需要设计审查,适用于应用、SDK、CLI、桌面进程与库。
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# TypeScript 项目规范
|
|
7
7
|
|
|
8
|
+
本入口面向库、CLI、桌面核心及服务中的语言工程;应用角色由实际子工程证据决定,不由前端/后端产品名决定。
|
|
9
|
+
|
|
8
10
|
## 用途
|
|
9
11
|
|
|
10
12
|
统一 TypeScript 层的工程配置、类型边界和发布产物规则。适用于前端应用、组件库、SDK、CLI、monorepo package 和纯 TypeScript 工具库,但不接管 React、Vue、Next.js、Nuxt 或 Vite 的框架架构职责。
|
|
@@ -19,7 +21,7 @@ description: 用于创建、配置、审查或调试前端应用、库、SDK、C
|
|
|
19
21
|
- React、Vue、Next.js、Nuxt 等框架的组件架构、路由组织和状态管理归对应框架 skill;本流程只处理跨框架 TypeScript 契约和工程边界。
|
|
20
22
|
|
|
21
23
|
2. 收敛 `tsconfig`
|
|
22
|
-
-
|
|
24
|
+
- 新代码优先 `strict` 并保留已有检查,不为掩盖缺陷关闭 `noImplicitAny` 或 `strictNullChecks`。`exactOptionalPropertyTypes` 是独立选项;有依据时以局部、兼容迁移引入更严格配置。
|
|
23
25
|
- 按运行环境选择 `target`、`lib`、`module` 和 `moduleResolution`;浏览器应用、Node 脚本、库包不要共用一份含混配置。
|
|
24
26
|
- 将基础配置、应用配置、测试配置和构建声明配置拆开,避免测试全局类型污染生产代码。
|
|
25
27
|
- 路径别名必须同时被 TypeScript、bundler、test runner 和发布产物理解;库包不得发布无法解析的源码别名。
|
|
@@ -43,7 +45,7 @@ description: 用于创建、配置、审查或调试前端应用、库、SDK、C
|
|
|
43
45
|
|
|
44
46
|
## 约束
|
|
45
47
|
|
|
46
|
-
- 不用 `
|
|
48
|
+
- 不用 `any`、无守卫非空断言或宽泛 `as` 掩盖未经验证的边界。合理的 `skipLibCheck` 依赖政策与检查自身公共API有别,需记录其限制。
|
|
47
49
|
- 不在应用代码中依赖发布包私有深层路径。
|
|
48
50
|
- 不把框架目录结构、组件分层、路由组织或状态管理决策放进本流程;这些交给对应框架或专项流程。
|
|
49
51
|
- 不让生成类型、测试类型或 Node-only 类型污染浏览器运行代码。
|
|
@@ -52,3 +54,7 @@ description: 用于创建、配置、审查或调试前端应用、库、SDK、C
|
|
|
52
54
|
## 预期输出
|
|
53
55
|
|
|
54
56
|
输出应包含 TypeScript 上下文判断、关键 `tsconfig`/package 类型入口建议、类型边界方案、声明文件或 public API 风险、验证命令。完成后项目应能独立 typecheck,公开类型可被消费方解析,类型安全问题有明确收窄或建模方案。
|
|
57
|
+
|
|
58
|
+
## 工程实践
|
|
59
|
+
|
|
60
|
+
按当前任务读取[本入口工程细则](references/engineering-practices.md),再按链接选择公共原则。规则级别与例外以实际项目契约为准;不因产品前后端标签限制语言或职责。
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# 外部输入边界 — EP-TS-01
|
|
2
|
+
|
|
3
|
+
将此目录复制到可写临时位置。样例自有Node >=22.18目标(原生类型擦除),不升级父项目。显式准备:pnpm install --ignore-scripts --frozen-lockfile,然后pnpm typecheck。PowerShell设$env:CRAFT_ENGINEERING_DEFECTIVE为1,运行pnpm test,非法输入命名断言应失败;设为0或移除变量后同组两个测试通过。POSIX可在测试命令前设置同名环境变量。
|
|
4
|
+
|
|
5
|
+
回调记录校验前后的真实副作用,缺陷分支故意以断言替代校验;默认受保护。这里不验证付款服务、浏览器、异步状态及声明发布。仅依赖本目录源码和已声明工具,node_modules/build/log应留在可写副本。
|
|
6
|
+
|
|
7
|
+
[Node.js 类型擦除历史与限制](https://nodejs.org/api/typescript.html):运行时类型擦除与显式 TypeScript 类型检查分开。
|
package/localized/zh-CN/skills/cc-typescript-project-standard/examples/engineering/boundary.test.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import test from "node:test";
|
|
2
|
+
import assert from "node:assert/strict";
|
|
3
|
+
import { acceptAmount } from "./input.ts";
|
|
4
|
+
|
|
5
|
+
test("EP-TS-01 rejects invalid input before any effect", () => {
|
|
6
|
+
const effects: number[] = [];
|
|
7
|
+
for (const input of [{ amount: "10" }, { amount: -1 }, { amount: Number.MAX_SAFE_INTEGER + 1 }, null]) {
|
|
8
|
+
assert.throws(() => acceptAmount(input, amount => effects.push(amount)), /invalid amount/);
|
|
9
|
+
assert.deepEqual(effects, []);
|
|
10
|
+
}
|
|
11
|
+
});
|
|
12
|
+
test("EP-TS-01 accepts a valid input exactly once", () => {
|
|
13
|
+
const effects: number[] = [];
|
|
14
|
+
acceptAmount({ amount: 10 }, amount => effects.push(amount));
|
|
15
|
+
assert.deepEqual(effects, [10]);
|
|
16
|
+
});
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/** Test switch only; normal use always validates the external boundary. */
|
|
2
|
+
export function acceptAmount(value: unknown, effect: (amount: number) => void): void {
|
|
3
|
+
if (process.env.CRAFT_ENGINEERING_DEFECTIVE === "1") {
|
|
4
|
+
effect((value as { amount: number }).amount);
|
|
5
|
+
return;
|
|
6
|
+
}
|
|
7
|
+
if (typeof value !== "object" || value === null || !("amount" in value)
|
|
8
|
+
|| typeof value.amount !== "number" || !Number.isSafeInteger(value.amount) || value.amount <= 0) {
|
|
9
|
+
throw new TypeError("invalid amount");
|
|
10
|
+
}
|
|
11
|
+
effect(value.amount);
|
|
12
|
+
}
|
package/localized/zh-CN/skills/cc-typescript-project-standard/examples/engineering/package.json
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "engineering-typescript-boundary-example",
|
|
3
|
+
"version": "0.0.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"engines": { "node": ">=22.18.0" },
|
|
7
|
+
"scripts": {
|
|
8
|
+
"typecheck": "tsc --noEmit",
|
|
9
|
+
"test": "node --experimental-strip-types --test --test-reporter=tap boundary.test.ts"
|
|
10
|
+
},
|
|
11
|
+
"devDependencies": { "typescript": "5.9.3", "@types/node": "22.20.5" }
|
|
12
|
+
}
|
package/localized/zh-CN/skills/cc-typescript-project-standard/examples/engineering/pnpm-lock.yaml
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
lockfileVersion: '9.0'
|
|
2
|
+
|
|
3
|
+
settings:
|
|
4
|
+
autoInstallPeers: true
|
|
5
|
+
excludeLinksFromLockfile: false
|
|
6
|
+
|
|
7
|
+
importers:
|
|
8
|
+
|
|
9
|
+
.:
|
|
10
|
+
devDependencies:
|
|
11
|
+
'@types/node':
|
|
12
|
+
specifier: 22.20.5
|
|
13
|
+
version: 22.20.5
|
|
14
|
+
typescript:
|
|
15
|
+
specifier: 5.9.3
|
|
16
|
+
version: 5.9.3
|
|
17
|
+
|
|
18
|
+
packages:
|
|
19
|
+
|
|
20
|
+
'@types/node@22.20.5':
|
|
21
|
+
resolution: {integrity: sha512-U2+DNr+wSjpsTS/wZGYHq7GcwfuSmKiKvoPvK22zwTlRhU91yOniN4qRR5KhIjvif7ysw/dz/hKmfDH0Ris4aA==}
|
|
22
|
+
|
|
23
|
+
typescript@5.9.3:
|
|
24
|
+
resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==}
|
|
25
|
+
engines: {node: '>=14.17'}
|
|
26
|
+
hasBin: true
|
|
27
|
+
|
|
28
|
+
undici-types@6.21.0:
|
|
29
|
+
resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==}
|
|
30
|
+
|
|
31
|
+
snapshots:
|
|
32
|
+
|
|
33
|
+
'@types/node@22.20.5':
|
|
34
|
+
dependencies:
|
|
35
|
+
undici-types: 6.21.0
|
|
36
|
+
|
|
37
|
+
typescript@5.9.3: {}
|
|
38
|
+
|
|
39
|
+
undici-types@6.21.0: {}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
packages: []
|