diff --git a/.agents/hooks.json b/.agents/hooks.json new file mode 100644 index 000000000..387513e64 --- /dev/null +++ b/.agents/hooks.json @@ -0,0 +1,38 @@ +{ + "safety-and-compliance": { + "PreToolUse": [ + { + "matcher": "run_command|write_to_file|replace_file_content|multi_replace_file_content", + "hooks": [ + { + "type": "command", + "command": "python3 .agents/hooks/block-absolute-paths.py", + "timeout": 15 + }, + { + "type": "command", + "command": "python3 .agents/hooks/block-secrets.py", + "timeout": 15 + }, + { + "type": "command", + "command": "python3 .agents/hooks/git-branch-guard.py", + "timeout": 15 + } + ] + } + ], + "PostToolUse": [ + { + "matcher": "write_to_file|replace_file_content|multi_replace_file_content", + "hooks": [ + { + "type": "command", + "command": "bash .agents/hooks/post-edit-linter.sh", + "timeout": 30 + } + ] + } + ] + } +} diff --git a/.agents/hooks/block-absolute-paths.py b/.agents/hooks/block-absolute-paths.py new file mode 100755 index 000000000..6f4d2a0e8 --- /dev/null +++ b/.agents/hooks/block-absolute-paths.py @@ -0,0 +1,28 @@ +#!/usr/bin/env python3 +import sys, re, subprocess + +def check_staged_files(): + result = subprocess.run(["git", "diff", "--cached", "--name-only"], capture_output=True, text=True) + files = [f for f in result.stdout.splitlines() if f.strip()] + + home_pattern = re.compile(r'/home/[a-zA-Z0-9_-]+/') + users_pattern = re.compile(r'/Users/[a-zA-Z0-9_-]+/') + + failed = False + for filepath in files: + if "block-absolute-paths.py" in filepath or "AGENTS.md" in filepath: + continue + try: + with open(filepath, "r", encoding="utf-8", errors="ignore") as f: + for idx, line in enumerate(f, 1): + if home_pattern.search(line) or users_pattern.search(line): + print(f"SECURITY ERROR: Absolute path detected in {filepath}:{idx}: {line.strip()}") + failed = True + except Exception: + pass + + if failed: + sys.exit(1) + +if __name__ == "__main__": + check_staged_files() diff --git a/.agents/hooks/block-secrets.py b/.agents/hooks/block-secrets.py new file mode 100755 index 000000000..49baeb1da --- /dev/null +++ b/.agents/hooks/block-secrets.py @@ -0,0 +1,33 @@ +#!/usr/bin/env python3 +import sys, re, subprocess + +SECRET_PATTERNS = [ + re.compile(r'-----BEGIN (?:RSA|OPENSSH|DSA|EC|PGP) PRIVATE KEY-----'), + re.compile(r'AIzaSy[A-Za-z0-9_-]{33}'), + re.compile(r'ghp_[A-Za-z0-9]{36}'), + re.compile(r'glpat-[A-Za-z0-9_-]{20}') +] + +def check_secrets(): + result = subprocess.run(["git", "diff", "--cached", "--name-only"], capture_output=True, text=True) + files = [f for f in result.stdout.splitlines() if f.strip()] + + failed = False + for filepath in files: + if "block-secrets.py" in filepath: + continue + try: + with open(filepath, "r", encoding="utf-8", errors="ignore") as f: + for idx, line in enumerate(f, 1): + for pattern in SECRET_PATTERNS: + if pattern.search(line): + print(f"SECURITY ERROR: Secret detected in {filepath}:{idx}") + failed = True + except Exception: + pass + + if failed: + sys.exit(1) + +if __name__ == "__main__": + check_secrets() diff --git a/.agents/hooks/git-branch-guard.py b/.agents/hooks/git-branch-guard.py new file mode 100755 index 000000000..02a42268b --- /dev/null +++ b/.agents/hooks/git-branch-guard.py @@ -0,0 +1,14 @@ +#!/usr/bin/env python3 +import sys, subprocess + +FORBIDDEN_BRANCHES = ["main", "master", "staging"] + +def check_branch(): + result = subprocess.run(["git", "rev-parse", "--abbrev-ref", "HEAD"], capture_output=True, text=True) + branch = result.stdout.strip() + if branch in FORBIDDEN_BRANCHES: + print(f"BRANCH GUARD ERROR: Cannot commit directly to '{branch}' branch. Create a feature/bugfix branch.") + sys.exit(1) + +if __name__ == "__main__": + check_branch() diff --git a/.agents/hooks/post-edit-linter.sh b/.agents/hooks/post-edit-linter.sh new file mode 100755 index 000000000..8fd0f087d --- /dev/null +++ b/.agents/hooks/post-edit-linter.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +set -e + +# Run quick format/linter checks if available +if command -v flake8 >/dev/null 2>&1; then + git diff --name-only --cached | grep -E '\.py$' | xargs -r flake8 --select=E9,F63,F7,F82 || true +fi diff --git a/.agents/rules/01-jira-commit-standards.md b/.agents/rules/01-jira-commit-standards.md new file mode 100644 index 000000000..f5a03d855 --- /dev/null +++ b/.agents/rules/01-jira-commit-standards.md @@ -0,0 +1,13 @@ +--- +description: Jira work tracking and commit message standards. +--- +# Jira & Git Commit Standards + +1. **Jira Work Tracking**: + - All branches MUST reference an active Jira ticket starting with project key `UC` (e.g. `UC-123_description`). +2. **Commit Title Standard**: + - Every commit title MUST start with bracketed Jira ticket key: `[UC-XXXX] `. + - Do NOT use semantic commit prefixes (`feat:`, `fix:`, `chore:`, `refactor:`) in commit or PR titles. +3. **Pull Request Policy**: + - Always open PRs in **DRAFT** state. + - Merging is strictly restricted to human developers. diff --git a/.agents/rules/02-security-and-paths.md b/.agents/rules/02-security-and-paths.md new file mode 100644 index 000000000..601db7823 --- /dev/null +++ b/.agents/rules/02-security-and-paths.md @@ -0,0 +1,12 @@ +--- +description: Security guidelines, secret protection, and path sanitation. +--- +# Security & Path Protection Guidelines + +1. **No Hardcoded Absolute Paths**: + - Never commit absolute local filesystem paths (e.g. `/home/username/` or `/Users/username/`). +2. **No Secret Leaks**: + - Never commit private keys, API tokens, or passphrases. + - Use RAM-backed filesystem mounts (`/dev/shm`) for temporary secret processing. +3. **Branch Guard**: + - Direct commits to `main`, `master`, or `staging` branches are strictly forbidden. diff --git a/.agents/rules/03-fdm-material-rules.md b/.agents/rules/03-fdm-material-rules.md new file mode 100644 index 000000000..cb7396824 --- /dev/null +++ b/.agents/rules/03-fdm-material-rules.md @@ -0,0 +1,10 @@ +--- +paths: + - "**/*.xml.fdm_material" +--- +# Material Profile Guidelines (fdm_materials) + +1. **Schema Compliance**: + - All profile changes MUST pass `./run_check_material_profiles.sh`. +2. **GUID Stability**: + - Material GUIDs must remain strictly stable across profile updates for WASM slicing resolution. diff --git a/.agents/rules/04-debian-package-and-deployment-rules.md b/.agents/rules/04-debian-package-and-deployment-rules.md new file mode 100644 index 000000000..1d361412d --- /dev/null +++ b/.agents/rules/04-debian-package-and-deployment-rules.md @@ -0,0 +1,21 @@ +--- +description: Guidelines for compiling Debian packages, managing recipes, and deploying to printers. +--- +# Debian Packaging, Recipe Management & Printer Deployment + +1. **Compiling Debian Packages**: + - Service build script: `./build_for_ultimaker.sh`. + - Packages compile into `.deb` artifacts inside local Docker container environments. +2. **Firmware Recipe Integration (`jedi-cookbook`)**: + - Firmware update images (`.swu`) bundle debian packages specified in `.recipe` files under `S-Line/`, `Falcon/`, `Colorado/`, or `UM3/`. + - Recipe line format: `deb `. + - Recipe version bumps: Ensure the corresponding `.deb` package artifact is built and published upstream before updating recipe versions. +3. **Deploying Packages & Testing on Printers**: + - Deploy compiled service packages directly to a networked test printer: + ```bash + ../jedi-build/deploy_to_printer.sh deploy + ``` + - Interactive SSH terminal access to printer: + ```bash + ./dev/umssh.sh + ``` diff --git a/.agents/rules/05-ultimaker-skill-discovery-rules.md b/.agents/rules/05-ultimaker-skill-discovery-rules.md new file mode 100644 index 000000000..1c07ad3d1 --- /dev/null +++ b/.agents/rules/05-ultimaker-skill-discovery-rules.md @@ -0,0 +1,26 @@ +--- +description: Mandate for dynamic discovery and usage of domain-specific UltiMaker engineering skills from UltiCortex. +--- +# Dynamic UltiMaker AI Skill Discovery & Usage + +AI agents working in this repository MUST dynamically discover and install specialized domain skills from `Ultimaker/UltiCortex` when performing relevant tasks: + +```bash +# Search available skills +gh skill search ultimaker --owner Ultimaker + +# Install specific skill +gh skill install Ultimaker/UltiCortex +``` + +## Mandated Skill Triggers +1. **`ultimaker-printer-ssh`**: + - **Trigger**: When deploying packages, checking DBus properties, testing build outputs, or troubleshooting local services on physical or emulated 3D printers over SSH. +2. **`ultimaker-digital-factory`**: + - **Trigger**: When working on cloud state synchronization, WSS WebSocket connections, IoT connectivity, telemetry, or Digital Factory API features. +3. **`ultimaker-log-analyzer`**: + - **Trigger**: When analyzing log dumps (`/var/log/messages`, systemd journal, `opinicus.log`, `okuda.log`, `stardust.log`). +4. **`ultimaker-firmware-developer`**: + - **Trigger**: When modifying core DBus interfaces, state machine frameworks, or CMake/Conan build tooling. + 5. **`ultimaker-support-articles`**: + - **Trigger**: When introducing user-facing feature changes or behavioral shifts that impact public documentation or support workflows. diff --git a/.agents/rules/06-pull-request-lifecycle-rules.md b/.agents/rules/06-pull-request-lifecycle-rules.md new file mode 100644 index 000000000..6ebcce435 --- /dev/null +++ b/.agents/rules/06-pull-request-lifecycle-rules.md @@ -0,0 +1,25 @@ +--- +description: Mandatory pre-PR local verification, PR description structure, Copilot review request, and CI status check watch loop. +--- +# Pull Request Lifecycle & Quality Gate Policy + +1. **Mandatory Local Pre-PR Verification**: + - Before creating or updating any Pull Request, run local verification checks (`pre-commit run --all-files`, `./build_for_ultimaker.sh`, unit tests, linters). + - Only create or update the PR if all local checks pass cleanly without errors. + +2. **Pull Request Creation & Description Standards**: + - All PRs MUST be created in **DRAFT** state (`gh pr create --draft`). + - Title MUST start with the bracketed Jira ticket key: `[PROJECT-KEY] `. + - Description MUST include: + - Active Jira issue link (`EMB-XXX`). + - Overview of changes ("Why" and "How"). + - Support documentation warning block (`> [!WARNING]`) if support articles are impacted. + - Empty human reviewer checklist at the bottom: `- [ ] Initiating developer reviewed AI-generated code`. + +3. **Copilot AI Review & CI Watch Loop**: + - Request Copilot AI review on PR (`gh pr comment --body "@github-copilot review"`). + - Monitor CI status checks (`gh pr checks --watch`). + - Address and resolve all Copilot review comments and threads before considering PR ready. + +4. **Human Merge Policy**: + - Merging is strictly restricted to human developers. AI agents MUST NOT merge PRs. diff --git a/.claude/hooks.json b/.claude/hooks.json new file mode 100644 index 000000000..387513e64 --- /dev/null +++ b/.claude/hooks.json @@ -0,0 +1,38 @@ +{ + "safety-and-compliance": { + "PreToolUse": [ + { + "matcher": "run_command|write_to_file|replace_file_content|multi_replace_file_content", + "hooks": [ + { + "type": "command", + "command": "python3 .agents/hooks/block-absolute-paths.py", + "timeout": 15 + }, + { + "type": "command", + "command": "python3 .agents/hooks/block-secrets.py", + "timeout": 15 + }, + { + "type": "command", + "command": "python3 .agents/hooks/git-branch-guard.py", + "timeout": 15 + } + ] + } + ], + "PostToolUse": [ + { + "matcher": "write_to_file|replace_file_content|multi_replace_file_content", + "hooks": [ + { + "type": "command", + "command": "bash .agents/hooks/post-edit-linter.sh", + "timeout": 30 + } + ] + } + ] + } +} diff --git a/.claude/rules/debian-package-and-deployment-rules.md b/.claude/rules/debian-package-and-deployment-rules.md new file mode 100644 index 000000000..1d361412d --- /dev/null +++ b/.claude/rules/debian-package-and-deployment-rules.md @@ -0,0 +1,21 @@ +--- +description: Guidelines for compiling Debian packages, managing recipes, and deploying to printers. +--- +# Debian Packaging, Recipe Management & Printer Deployment + +1. **Compiling Debian Packages**: + - Service build script: `./build_for_ultimaker.sh`. + - Packages compile into `.deb` artifacts inside local Docker container environments. +2. **Firmware Recipe Integration (`jedi-cookbook`)**: + - Firmware update images (`.swu`) bundle debian packages specified in `.recipe` files under `S-Line/`, `Falcon/`, `Colorado/`, or `UM3/`. + - Recipe line format: `deb `. + - Recipe version bumps: Ensure the corresponding `.deb` package artifact is built and published upstream before updating recipe versions. +3. **Deploying Packages & Testing on Printers**: + - Deploy compiled service packages directly to a networked test printer: + ```bash + ../jedi-build/deploy_to_printer.sh deploy + ``` + - Interactive SSH terminal access to printer: + ```bash + ./dev/umssh.sh + ``` diff --git a/.claude/rules/fdm-material-rules.md b/.claude/rules/fdm-material-rules.md new file mode 100644 index 000000000..cb7396824 --- /dev/null +++ b/.claude/rules/fdm-material-rules.md @@ -0,0 +1,10 @@ +--- +paths: + - "**/*.xml.fdm_material" +--- +# Material Profile Guidelines (fdm_materials) + +1. **Schema Compliance**: + - All profile changes MUST pass `./run_check_material_profiles.sh`. +2. **GUID Stability**: + - Material GUIDs must remain strictly stable across profile updates for WASM slicing resolution. diff --git a/.claude/rules/jira-commit-standards.md b/.claude/rules/jira-commit-standards.md new file mode 100644 index 000000000..f5a03d855 --- /dev/null +++ b/.claude/rules/jira-commit-standards.md @@ -0,0 +1,13 @@ +--- +description: Jira work tracking and commit message standards. +--- +# Jira & Git Commit Standards + +1. **Jira Work Tracking**: + - All branches MUST reference an active Jira ticket starting with project key `UC` (e.g. `UC-123_description`). +2. **Commit Title Standard**: + - Every commit title MUST start with bracketed Jira ticket key: `[UC-XXXX] `. + - Do NOT use semantic commit prefixes (`feat:`, `fix:`, `chore:`, `refactor:`) in commit or PR titles. +3. **Pull Request Policy**: + - Always open PRs in **DRAFT** state. + - Merging is strictly restricted to human developers. diff --git a/.claude/rules/pull-request-lifecycle-rules.md b/.claude/rules/pull-request-lifecycle-rules.md new file mode 100644 index 000000000..6ebcce435 --- /dev/null +++ b/.claude/rules/pull-request-lifecycle-rules.md @@ -0,0 +1,25 @@ +--- +description: Mandatory pre-PR local verification, PR description structure, Copilot review request, and CI status check watch loop. +--- +# Pull Request Lifecycle & Quality Gate Policy + +1. **Mandatory Local Pre-PR Verification**: + - Before creating or updating any Pull Request, run local verification checks (`pre-commit run --all-files`, `./build_for_ultimaker.sh`, unit tests, linters). + - Only create or update the PR if all local checks pass cleanly without errors. + +2. **Pull Request Creation & Description Standards**: + - All PRs MUST be created in **DRAFT** state (`gh pr create --draft`). + - Title MUST start with the bracketed Jira ticket key: `[PROJECT-KEY] `. + - Description MUST include: + - Active Jira issue link (`EMB-XXX`). + - Overview of changes ("Why" and "How"). + - Support documentation warning block (`> [!WARNING]`) if support articles are impacted. + - Empty human reviewer checklist at the bottom: `- [ ] Initiating developer reviewed AI-generated code`. + +3. **Copilot AI Review & CI Watch Loop**: + - Request Copilot AI review on PR (`gh pr comment --body "@github-copilot review"`). + - Monitor CI status checks (`gh pr checks --watch`). + - Address and resolve all Copilot review comments and threads before considering PR ready. + +4. **Human Merge Policy**: + - Merging is strictly restricted to human developers. AI agents MUST NOT merge PRs. diff --git a/.claude/rules/security-and-paths.md b/.claude/rules/security-and-paths.md new file mode 100644 index 000000000..601db7823 --- /dev/null +++ b/.claude/rules/security-and-paths.md @@ -0,0 +1,12 @@ +--- +description: Security guidelines, secret protection, and path sanitation. +--- +# Security & Path Protection Guidelines + +1. **No Hardcoded Absolute Paths**: + - Never commit absolute local filesystem paths (e.g. `/home/username/` or `/Users/username/`). +2. **No Secret Leaks**: + - Never commit private keys, API tokens, or passphrases. + - Use RAM-backed filesystem mounts (`/dev/shm`) for temporary secret processing. +3. **Branch Guard**: + - Direct commits to `main`, `master`, or `staging` branches are strictly forbidden. diff --git a/.claude/rules/ultimaker-skill-discovery-rules.md b/.claude/rules/ultimaker-skill-discovery-rules.md new file mode 100644 index 000000000..1c07ad3d1 --- /dev/null +++ b/.claude/rules/ultimaker-skill-discovery-rules.md @@ -0,0 +1,26 @@ +--- +description: Mandate for dynamic discovery and usage of domain-specific UltiMaker engineering skills from UltiCortex. +--- +# Dynamic UltiMaker AI Skill Discovery & Usage + +AI agents working in this repository MUST dynamically discover and install specialized domain skills from `Ultimaker/UltiCortex` when performing relevant tasks: + +```bash +# Search available skills +gh skill search ultimaker --owner Ultimaker + +# Install specific skill +gh skill install Ultimaker/UltiCortex +``` + +## Mandated Skill Triggers +1. **`ultimaker-printer-ssh`**: + - **Trigger**: When deploying packages, checking DBus properties, testing build outputs, or troubleshooting local services on physical or emulated 3D printers over SSH. +2. **`ultimaker-digital-factory`**: + - **Trigger**: When working on cloud state synchronization, WSS WebSocket connections, IoT connectivity, telemetry, or Digital Factory API features. +3. **`ultimaker-log-analyzer`**: + - **Trigger**: When analyzing log dumps (`/var/log/messages`, systemd journal, `opinicus.log`, `okuda.log`, `stardust.log`). +4. **`ultimaker-firmware-developer`**: + - **Trigger**: When modifying core DBus interfaces, state machine frameworks, or CMake/Conan build tooling. + 5. **`ultimaker-support-articles`**: + - **Trigger**: When introducing user-facing feature changes or behavioral shifts that impact public documentation or support workflows. diff --git a/.flake8 b/.flake8 new file mode 100644 index 000000000..c048436ed --- /dev/null +++ b/.flake8 @@ -0,0 +1,4 @@ +[flake8] +max-line-length = 160 +ignore = E501, E251, F401 +exclude = .git, __pycache__, build, dist diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 000000000..60a311030 --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,22 @@ +# GitHub Copilot Custom Instructions + +Welcome! This configuration coordinates our multi-role coding assistant system to ensure that all generated code, documentation, and tests comply with UltiMaker Cura Cloud / NeoPrep's rigorous engineering quality standards. + +## Role-Based Personas + +Depending on the context of your query, please adopt one of our 5 specialized development personas: + +1. **[PR Assistant](.github/copilot-instructions/pr-assistant.instructions.md):** Focuses on creating logical, small, atomic commits starting with the bracketed Jira key format (e.g., `[NP-123] Descriptive Title`, without any prefix tags like `feat:` or `fix:`) and generating structured, descriptive pull request details under the `NP` Jira context. +2. **[GHA Helper](.github/copilot-instructions/gha-helper.instructions.md):** Focuses on building secure, optimized, and cached GitHub Actions pipelines for NPM package and standalone client distribution. +3. **[Code Reviewer](.github/copilot-instructions/code-reviewer.instructions.md):** Focuses on reviewing React 18, Zustand, Three.js, and R3F patterns, checking for static lints/errors, and enforcing compact files (around 300 lines, max 400 is acceptable). +4. **[Accessibility Auditor](.github/copilot-instructions/accessibility-auditor.instructions.md):** Focuses on reviewing and generating WCAG 2.1 AA compliant UI layouts, keyboard focus rings, and proper aria-labels across NeoPrep panels. +5. **[Testing Automation](.github/copilot-instructions/testing-automation.instructions.md):** Focuses on non-flaky Vitest unit assertions and comprehensive Cypress E2E visual regression testing. + +--- + +## Strategic Principles + +- **Future AI Optimization:** Write clean, modular files (around 300 lines, max 400 is acceptable) with single-responsibility structures. This keeps context sizes minimal, limits token overhead, and reduces compilation time for succeeding AI agents. +- **WebGL & R3F Scene Philisophy:** Separate heavy canvas operations. Math calculation or mesh manipulations belong in the background `geometryWorker` via Comlink to ensure 60 FPS rendering. +- **Design Tokens Compliance:** Align frontend styling strictly with HSL colors and typography specified in [DESIGN.md](DESIGN.md) and [css-guide.md](css-guide.md). Write scoped CSS Modules (`*.module.css`) and avoid global pollution or hardcoded hex colors. +- **Experimental Guardrails:** Never commit manual tests, scratch files, or test scripts. All experiment work belongs in the gitignored `scratch/` directory. diff --git a/.github/copilot-instructions/accessibility-auditor.instructions.md b/.github/copilot-instructions/accessibility-auditor.instructions.md new file mode 100644 index 000000000..19cde4071 --- /dev/null +++ b/.github/copilot-instructions/accessibility-auditor.instructions.md @@ -0,0 +1,21 @@ +# Role: Accessibility Auditor (Copilot Instruction) + +You are the Accessibility Auditor. Your primary directive is to ensure that all user interface modifications, components, and templates in NeoPrep conform to WCAG 2.1 AA guidelines. + +## 1. Core Structural Semantic Audit + +- Verify that logical landmark tags (`
`, `