@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
package/skills/{fec-image-generation → cc-technical-diagrams}/scripts/tech-diagram-render.mjs
RENAMED
|
@@ -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: Use when
|
|
2
|
+
name: cc-typescript-project-standard
|
|
3
|
+
description: Use when TypeScript configuration, module resolution, public API types, declarations, package exports, narrowing or generic contracts need design or review in applications, SDKs, CLI tools, desktop processes or libraries.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# TypeScript project specifications
|
|
7
7
|
|
|
8
|
+
Apply to libraries, CLI tools, desktop cores and services. Determine the application role from the actual project; a frontend/backend product name does not constrain the language.
|
|
9
|
+
|
|
8
10
|
## Purpose
|
|
9
11
|
|
|
10
12
|
Unify project configuration, type boundaries, and release product rules for the TypeScript layer. Works with front-end applications, component libraries, SDKs, CLIs, monorepo packages, and pure TypeScript tool libraries, but does not take over the framework architecture responsibilities of React, Vue, Next.js, Nuxt, or Vite.
|
|
@@ -19,7 +21,7 @@ Unify project configuration, type boundaries, and release product rules for the
|
|
|
19
21
|
- The component architecture, routing organization, and state management of frameworks such as React, Vue, Next.js, and Nuxt belong to the corresponding framework skills; this process only deals with cross-framework TypeScript contracts and project boundaries.
|
|
20
22
|
|
|
21
23
|
2. Convergence `tsconfig`
|
|
22
|
-
-
|
|
24
|
+
- Prefer `strict` for new code and preserve existing checks; do not disable `noImplicitAny` or `strictNullChecks` merely to hide a defect. `exactOptionalPropertyTypes` is a separate option; introduce stricter settings through a scoped, compatible migration when justified.
|
|
23
25
|
- Select `target`, `lib`, `module` and `moduleResolution` according to the running environment; browser applications, Node scripts, and library packages should not share an ambiguous configuration.
|
|
24
26
|
- Separate basic configuration, application configuration, test configuration and build declaration configuration to avoid testing global types from polluting production code.
|
|
25
27
|
- Path aliases must be understood by TypeScript, bundler, test runner, and published products at the same time; library packages must not publish source code aliases that cannot be resolved.
|
|
@@ -43,7 +45,7 @@ Unify project configuration, type boundaries, and release product rules for the
|
|
|
43
45
|
|
|
44
46
|
## Constraints
|
|
45
47
|
|
|
46
|
-
-
|
|
48
|
+
- Do not use `any`, unguarded non-null assertions or broad `as` to conceal an unverified boundary. A justified `skipLibCheck` dependency policy is separate from checking your own public API; record its limits.
|
|
47
49
|
- Do not rely on release package private deep paths in application code.
|
|
48
50
|
- Do not put framework directory structure, component layering, routing organization or state management decisions into this process; these are left to the corresponding framework or dedicated process.
|
|
49
51
|
- Don't pollute browser running code with generated, test, or Node-only types.
|
|
@@ -52,3 +54,7 @@ Unify project configuration, type boundaries, and release product rules for the
|
|
|
52
54
|
## Expected Output
|
|
53
55
|
|
|
54
56
|
The output should include TypeScript context determinations, key `tsconfig`/package type entry suggestions, type boundary schemes, declaration file or public API risks, and verification commands. After completion, the project should be able to independently typecheck, public types can be parsed by consumers, and type safety issues should have clear narrowing or modeling solutions.
|
|
57
|
+
|
|
58
|
+
## Engineering practices
|
|
59
|
+
|
|
60
|
+
Read the [local engineering decisions](references/engineering-practices.md) for this task and follow their links to relevant shared principles. Apply levels and exceptions against actual project contracts; product frontend/backend labels do not constrain language or role.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# External input boundary — EP-TS-01
|
|
2
|
+
|
|
3
|
+
Use a separate writable copy of this directory. This example targets Node >=22.18 for native type stripping, with explicitly declared TypeScript and Node types; it does not change the parent project's supported versions.
|
|
4
|
+
|
|
5
|
+
Prepare once: `pnpm install --ignore-scripts --frozen-lockfile`. Then `pnpm typecheck` and `pnpm test`. In PowerShell set `$env:CRAFT_ENGINEERING_DEFECTIVE='1'` and run the same test: the named invalid-input assertion must fail after successful preparation/type checking. Set it to `'0'` (or remove it) and rerun: both tests pass. POSIX: prefix the test command with `CRAFT_ENGINEERING_DEFECTIVE=1` or `=0`.
|
|
6
|
+
|
|
7
|
+
The callback records real effects before/after validation; the defective branch deliberately replaces validation with a cast. Default behavior is protected. This does not test a payment backend, browser, async state or declaration publishing; those require their own consumer checks. No test imports parent-repository source. Install/build output belongs only to the writable copy.
|
|
8
|
+
|
|
9
|
+
[Node.js type-stripping history and limitations](https://nodejs.org/api/typescript.html): runtime stripping is separate from the explicit TypeScript type check.
|
|
@@ -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
|
+
}
|
|
@@ -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
|
+
}
|
|
@@ -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: []
|