From df7de1c05fc98af07d308396669b1ee4399e9fc7 Mon Sep 17 00:00:00 2001 From: Alan Treadway Date: Fri, 13 Mar 2026 17:19:11 +0000 Subject: [PATCH 01/23] git subrepo pull external/ag-shared subrepo: subdir: "external/ag-shared" merged: "d10f30d4f8e" upstream: origin: "https://github.com/ag-grid/ag-shared.git" branch: "latest" commit: "e9920c1bb73" git-subrepo: version: "0.4.9" origin: "https://github.com/Homebrew/brew" commit: "a0bd077aaf" --- external/ag-shared/.gitrepo | 2 +- external/ag-shared/docs/SYNC-LOG.md | 93 ++ .../ag-shared/prompts/.claude-settings.json | 57 ++ external/ag-shared/prompts/.mcp.json | 4 + .../ag-shared/prompts/agents/code-reviewer.md | 42 - .../guides/_docs-review-integration.md | 4 + external/ag-shared/prompts/guides/rulesync.md | 203 ---- .../prompts/guides/website-astro-pages.md | 332 +----- .../ag-shared/prompts/guides/website-css.md | 486 +-------- .../prompts/patches/rulesync+7.0.0.patch | 26 +- .../skills/ag-shared-sync-log/SKILL.md | 197 ++++ .../prompts/skills/batch-plunkers/SKILL.md | 14 +- .../prompts/skills/code-fixup/SKILL.md | 2 +- .../prompts/skills/dev-server/SKILL.md | 71 +- .../skills/dev-server/_dev-server-core.md | 25 - .../ag-shared/prompts/skills/example/SKILL.md | 76 ++ .../example/ag-charts/chart-construction.md | 244 +++++ .../example/ag-charts/enterprise-features.md | 62 ++ .../example/ag-charts/examples-guide.md | 637 ++++++++++++ .../skills/example/ag-charts/features/axes.md | 601 +++++++++++ .../example/ag-charts/features/data-labels.md | 358 +++++++ .../example/ag-charts/features/enterprise.md | 497 +++++++++ .../example/ag-charts/features/legends.md | 359 +++++++ .../ag-charts/features/recent-features.md | 954 ++++++++++++++++++ .../ag-charts/features/reference-lines.md | 325 ++++++ .../ag-charts/features/segmentation.md | 244 +++++ .../ag-charts/features/theme-overrides.md | 377 +++++++ .../example/ag-charts/features/tooltips.md | 349 +++++++ .../example/ag-charts/framework-patterns.md | 719 +++++++++++++ .../skills/example/ag-charts/quality-rules.md | 148 +++ .../skills/example/ag-charts/validation.md | 71 ++ .../prompts/skills/example/ag-grid/guide.md | 5 + .../prompts/skills/example/ag-studio/guide.md | 5 + .../prompts/skills/git-conventions/SKILL.md | 38 +- .../skills/git-worktree-clean/SKILL.md | 2 +- .../ag-shared/prompts/skills/jira/SKILL.md | 108 ++ .../prompts/skills/jira/products/charts.md | 77 ++ .../prompts/skills/jira/products/grid.md | 25 + .../prompts/skills/jira/products/studio.md | 19 + .../prompts/skills/jira/templates/bug.md | 22 + .../skills/jira/templates/feature-task.md | 82 ++ .../prompts/skills/jira/workflows/analyze.md | 60 ++ .../prompts/skills/jira/workflows/create.md | 130 +++ .../prompts/skills/jira/workflows/estimate.md | 144 +++ .../prompts/skills/jira/workflows/plan.md | 62 ++ .../plan-implementation-review/SKILL.md | 586 +---------- .../agent-prompts.md | 160 +++ .../discovered-work.md | 67 ++ .../output-format.md | 175 ++++ .../prompts/skills/plan-review/SKILL.md | 794 ++------------- .../skills/plan-review/agent-prompts-quick.md | 197 ++++ .../plan-review/agent-prompts-thorough.md | 275 +++++ .../plan-review/agents/devils-advocate.md | 98 ++ .../skills/plan-review/discovered-work.md | 67 ++ .../skills/plan-review/external-tools.md | 38 + .../skills/plan-review/output-format.md | 224 ++++ .../ag-shared/prompts/skills/plunker/SKILL.md | 33 +- .../prompts/skills/plunker/ag-charts-guide.md | 432 +------- .../prompts/skills/plunker/ag-grid-guide.md | 195 ++++ .../prompts/skills/plunker/ag-studio-guide.md | 5 + .../plunker/assets/ag-example-styles.css | 262 +++++ .../prompts/skills/pr-create/SKILL.md | 84 +- .../prompts/skills/pr-review/SKILL.md | 91 +- .../prompts/skills/pr-review/_review-core.md | 16 + .../pr-review/agents/devils-advocate.md | 109 ++ .../pr-review/agents/jira-completeness.md | 127 +++ .../prompts/skills/rulesync/SKILL.md | 260 +++++ .../prompts/skills/sync-ag-shared/SKILL.md | 1 + .../prompts/skills/website-astro/SKILL.md | 113 +++ .../website-astro/content-collections.md | 40 + .../skills/website-astro/page-patterns.md | 159 +++ .../skills/website-astro/shared-components.md | 50 + .../prompts/skills/website-css/SKILL.md | 87 ++ .../skills/website-css/colour-palette.md | 108 ++ .../prompts/skills/website-css/dark-mode.md | 120 +++ .../skills/website-css/design-tokens.md | 64 ++ .../skills/website-css/utility-classes.md | 92 ++ external/ag-shared/scripts/git-hooks/pre-push | 7 + .../install-for-cloud/install-for-cloud.sh | 24 +- .../install-for-cloud/setup-terminal-title.sh | 17 + .../scripts/setup-prompts/setup-prompts.sh | 73 ++ .../scripts/setup-prompts/verify-rulesync.sh | 5 + .../setup-worktree/claude-worktree-create.sh | 86 ++ .../setup-worktree/claude-worktree-remove.sh | 42 + 84 files changed, 10856 insertions(+), 2885 deletions(-) create mode 100644 external/ag-shared/docs/SYNC-LOG.md delete mode 100644 external/ag-shared/prompts/agents/code-reviewer.md delete mode 100644 external/ag-shared/prompts/guides/rulesync.md create mode 100644 external/ag-shared/prompts/skills/ag-shared-sync-log/SKILL.md delete mode 100644 external/ag-shared/prompts/skills/dev-server/_dev-server-core.md create mode 100644 external/ag-shared/prompts/skills/example/SKILL.md create mode 100644 external/ag-shared/prompts/skills/example/ag-charts/chart-construction.md create mode 100644 external/ag-shared/prompts/skills/example/ag-charts/enterprise-features.md create mode 100644 external/ag-shared/prompts/skills/example/ag-charts/examples-guide.md create mode 100644 external/ag-shared/prompts/skills/example/ag-charts/features/axes.md create mode 100644 external/ag-shared/prompts/skills/example/ag-charts/features/data-labels.md create mode 100644 external/ag-shared/prompts/skills/example/ag-charts/features/enterprise.md create mode 100644 external/ag-shared/prompts/skills/example/ag-charts/features/legends.md create mode 100644 external/ag-shared/prompts/skills/example/ag-charts/features/recent-features.md create mode 100644 external/ag-shared/prompts/skills/example/ag-charts/features/reference-lines.md create mode 100644 external/ag-shared/prompts/skills/example/ag-charts/features/segmentation.md create mode 100644 external/ag-shared/prompts/skills/example/ag-charts/features/theme-overrides.md create mode 100644 external/ag-shared/prompts/skills/example/ag-charts/features/tooltips.md create mode 100644 external/ag-shared/prompts/skills/example/ag-charts/framework-patterns.md create mode 100644 external/ag-shared/prompts/skills/example/ag-charts/quality-rules.md create mode 100644 external/ag-shared/prompts/skills/example/ag-charts/validation.md create mode 100644 external/ag-shared/prompts/skills/example/ag-grid/guide.md create mode 100644 external/ag-shared/prompts/skills/example/ag-studio/guide.md create mode 100644 external/ag-shared/prompts/skills/jira/SKILL.md create mode 100644 external/ag-shared/prompts/skills/jira/products/charts.md create mode 100644 external/ag-shared/prompts/skills/jira/products/grid.md create mode 100644 external/ag-shared/prompts/skills/jira/products/studio.md create mode 100644 external/ag-shared/prompts/skills/jira/templates/bug.md create mode 100644 external/ag-shared/prompts/skills/jira/templates/feature-task.md create mode 100644 external/ag-shared/prompts/skills/jira/workflows/analyze.md create mode 100644 external/ag-shared/prompts/skills/jira/workflows/create.md create mode 100644 external/ag-shared/prompts/skills/jira/workflows/estimate.md create mode 100644 external/ag-shared/prompts/skills/jira/workflows/plan.md create mode 100644 external/ag-shared/prompts/skills/plan-implementation-review/agent-prompts.md create mode 100644 external/ag-shared/prompts/skills/plan-implementation-review/discovered-work.md create mode 100644 external/ag-shared/prompts/skills/plan-implementation-review/output-format.md create mode 100644 external/ag-shared/prompts/skills/plan-review/agent-prompts-quick.md create mode 100644 external/ag-shared/prompts/skills/plan-review/agent-prompts-thorough.md create mode 100644 external/ag-shared/prompts/skills/plan-review/agents/devils-advocate.md create mode 100644 external/ag-shared/prompts/skills/plan-review/discovered-work.md create mode 100644 external/ag-shared/prompts/skills/plan-review/external-tools.md create mode 100644 external/ag-shared/prompts/skills/plan-review/output-format.md create mode 100644 external/ag-shared/prompts/skills/plunker/ag-grid-guide.md create mode 100644 external/ag-shared/prompts/skills/plunker/ag-studio-guide.md create mode 100644 external/ag-shared/prompts/skills/plunker/assets/ag-example-styles.css create mode 100644 external/ag-shared/prompts/skills/pr-review/agents/devils-advocate.md create mode 100644 external/ag-shared/prompts/skills/pr-review/agents/jira-completeness.md create mode 100644 external/ag-shared/prompts/skills/rulesync/SKILL.md create mode 100644 external/ag-shared/prompts/skills/website-astro/SKILL.md create mode 100644 external/ag-shared/prompts/skills/website-astro/content-collections.md create mode 100644 external/ag-shared/prompts/skills/website-astro/page-patterns.md create mode 100644 external/ag-shared/prompts/skills/website-astro/shared-components.md create mode 100644 external/ag-shared/prompts/skills/website-css/SKILL.md create mode 100644 external/ag-shared/prompts/skills/website-css/colour-palette.md create mode 100644 external/ag-shared/prompts/skills/website-css/dark-mode.md create mode 100644 external/ag-shared/prompts/skills/website-css/design-tokens.md create mode 100644 external/ag-shared/prompts/skills/website-css/utility-classes.md create mode 100755 external/ag-shared/scripts/install-for-cloud/setup-terminal-title.sh create mode 100755 external/ag-shared/scripts/setup-worktree/claude-worktree-create.sh create mode 100755 external/ag-shared/scripts/setup-worktree/claude-worktree-remove.sh diff --git a/external/ag-shared/.gitrepo b/external/ag-shared/.gitrepo index 9c8781b4b8d..ea4bf7de831 100644 --- a/external/ag-shared/.gitrepo +++ b/external/ag-shared/.gitrepo @@ -6,7 +6,7 @@ [subrepo] remote = https://github.com/ag-grid/ag-shared.git branch = latest - commit = 9197faeb19da5832bcc42c6e104a27d3a265000e + commit = e9920c1bb730fea23d210eae44157b89847331f6 parent = 6ecd838c6d676842733cd0ca5d215b751d2379b7 method = rebase cmdver = 0.4.9 diff --git a/external/ag-shared/docs/SYNC-LOG.md b/external/ag-shared/docs/SYNC-LOG.md new file mode 100644 index 00000000000..666fc8c9a8d --- /dev/null +++ b/external/ag-shared/docs/SYNC-LOG.md @@ -0,0 +1,93 @@ +# ag-shared Sync Log + +Migration log for `external/ag-shared/` changes. Each entry documents what changed and what companion actions consuming repos need to perform when syncing. + +Newest entries first. Generated by `/ag-shared-sync-log`. + +--- + +## 2026-03-12 -- Context optimisation, plunker multi-product, symlinked repo support + +**Branch:** `latest` +**Commits:** `8bc421d714..e0195dbbcd` (3 commits) + +### Changes + +- **[prompts/skills]** Migrated 4 large auto-loading rules (`docs-pages`, `docs-checklist`, `examples`, `examples-framework-patterns`) from ~90KB monoliths to ~4KB slim pointer rules that load full content via skills on demand +- **[prompts/skills]** Made `plunker` skill multi-product with auto-detection — added `ag-grid-guide.md` and `ag-studio-guide.md` +- **[prompts/skills]** Migrated `examples-guide.md` (635 lines) and `framework-patterns.md` (719 lines) into `example/ag-charts/` skill subdirectory +- **[prompts/skills]** Added `context: fork` to 12 skills for context isolation +- **[prompts/skills]** Enhanced `pr-create` skill with symlinked repo scanning (Step 2: companion branch/PR creation for `external/` repos) +- **[prompts/patches]** Added `rulesync+7.0.0.patch` to pass through `context` field to `.claude/` output +- **[scripts/setup-prompts]** Added branch mismatch detection for symlinked repos with stash/checkout/unstash workflow + +### Migration Actions + +- [ ] Replace large `.rulesync/rules/` files (`docs-pages.md`, `docs-checklist.md`, `examples.md`, `examples-framework-patterns.md`) with slim pointer versions +- [ ] Run `./external/ag-shared/scripts/setup-prompts/setup-prompts.sh` +- [ ] Run `./external/ag-shared/scripts/setup-prompts/verify-rulesync.sh` + +--- + +## 2026-03-11 -- Prompts audit, guide-to-skill migrations, monolith decomposition + +**Branch:** `latest` +**Commits:** `9cf1f336db..6d2a38a7ec` (2 commits) + +### Changes + +- **[prompts/skills]** Created `website-css` skill (5 files: SKILL.md + colour-palette, dark-mode, design-tokens, utility-classes) — replaces monolithic guide +- **[prompts/skills]** Created `website-astro` skill (4 files: SKILL.md + content-collections, page-patterns, shared-components) — replaces monolithic guide +- **[prompts/skills]** Decomposed `plan-review` skill into SKILL.md + 5 sub-docs (agent-prompts-quick, agent-prompts-thorough, discovered-work, external-tools, output-format) +- **[prompts/skills]** Decomposed `plan-implementation-review` skill into SKILL.md + 3 sub-docs (agent-prompts, discovered-work, output-format) +- **[prompts/guides]** Slimmed `website-css.md` and `website-astro-pages.md` guides (content moved to skills) +- **[prompts/agents]** Deleted `code-reviewer.md` agent (unused) +- **[prompts/commands]** Removed `analyze-jira-issue.md`, `docs-create.md`, `sonar-fix.md` commands (migrated to skills) + +### Migration Actions + +- [ ] Remove `.rulesync/commands/analyze-jira-issue.md`, `docs-create.md`, `sonar-fix.md` symlinks (targets deleted) +- [ ] Add `.rulesync/skills/website-css` directory symlink → `../../external/ag-shared/prompts/skills/website-css/` +- [ ] Add `.rulesync/skills/website-astro` directory symlink → `../../external/ag-shared/prompts/skills/website-astro/` +- [ ] Add `.rulesync/skills/docs-create` directory symlink → `../../external/ag-shared/prompts/skills/docs-create/` +- [ ] Add `.rulesync/skills/sonar-fix` directory symlink → `../../external/ag-shared/prompts/skills/sonar-fix/` +- [ ] Run `./external/ag-shared/scripts/setup-prompts/setup-prompts.sh` +- [ ] Run `./external/ag-shared/scripts/setup-prompts/verify-rulesync.sh` + +--- + +## 2026-03-09 -- Rulesync skill, worktree hooks, skill optimisations + +**Branch:** `latest` +**Commits:** `c2255312a5..1d93d98522` (8 commits) + +### Changes + +- **[prompts/skills]** Added `rulesync` skill to replace the `rulesync` guide — comprehensive configuration reference for `.rulesync/` directory management +- **[prompts/guides]** Removed `rulesync.md` guide (superseded by the `rulesync` skill) +- **[prompts/skills]** Optimised `dev-server` skill — added multi-repo URL table, troubleshooting section, removed redundant `_dev-server-core.md` partial +- **[prompts/skills]** Optimised `plunker` skill — extracted CSS into `assets/ag-example-styles.css`, slimmed guide, improved description +- **[prompts/skills]** Enhanced `git-conventions` skill — expanded description for better auto-triggering, added PR base branch guidance +- **[prompts/skills]** Enhanced `pr-create` skill — improved PR creation guidelines +- **[prompts/config]** Added `WorktreeCreate` and `WorktreeRemove` hooks to `.claude-settings.json` for automated worktree lifecycle management +- **[scripts/setup-prompts]** Updated `verify-rulesync.sh` to include files in skill subdirectories (e.g. `assets/`) in the expected inventory +- **[scripts]** Added `scripts/setup-worktree/claude-worktree-create.sh` and `claude-worktree-remove.sh` for Claude Code worktree lifecycle + +### Migration Actions + +- [ ] Remove `.rulesync/rules/rulesync.md` file symlink (target guide was deleted) +- [ ] Add `.rulesync/skills/rulesync` directory symlink -> `../../external/ag-shared/prompts/skills/rulesync/` +- [ ] Run `./external/ag-shared/scripts/setup-prompts/setup-prompts.sh` +- [ ] Run `./external/ag-shared/scripts/setup-prompts/verify-rulesync.sh` + +### Post-Migration Verification + +- [ ] Confirm `/rulesync` skill is available (type `/rulesync help` in Claude Code) +- [ ] Confirm the old rulesync rule no longer loads (check `.claude/rules/` for stale `rulesync.md`) +- [ ] Test worktree creation: run `/worktree ` in Claude Code and verify the hook creates the worktree under `~/.worktrees//` +- [ ] Test worktree removal: exit the worktree session and verify cleanup runs without errors +- [ ] Verify `dev-server` skill still triggers correctly (`/dev-server help`) + +### Notes + +The `rulesync` guide-to-skill migration is a structural change: consuming repos that had a `.rulesync/rules/rulesync.md` file symlink pointing to `../../external/ag-shared/prompts/guides/rulesync.md` must remove it (the target no longer exists) and add a directory symlink at `.rulesync/skills/rulesync` instead. The new worktree hook scripts (`scripts/setup-worktree/`) are referenced from `.claude-settings.json` and do not need `.rulesync/` symlinks. diff --git a/external/ag-shared/prompts/.claude-settings.json b/external/ag-shared/prompts/.claude-settings.json index 3f04cacdf6a..688e7c372d9 100644 --- a/external/ag-shared/prompts/.claude-settings.json +++ b/external/ag-shared/prompts/.claude-settings.json @@ -41,11 +41,43 @@ "WebFetch(domain:github.com)", "WebFetch(domain:localhost)", "WebFetch(domain:www.npmjs.com)", + "mcp__atlassian__atlassianUserInfo", + "mcp__atlassian__fetch", + "mcp__atlassian__getAccessibleAtlassianResources", + "mcp__atlassian__getIssueLinkTypes", + "mcp__atlassian__getJiraIssue", + "mcp__atlassian__getJiraIssueRemoteIssueLinks", + "mcp__atlassian__getJiraIssueTypeMetaWithFields", + "mcp__atlassian__getJiraProjectIssueTypesMetadata", + "mcp__atlassian__getTransitionsForJiraIssue", + "mcp__atlassian__getVisibleJiraProjects", + "mcp__atlassian__lookupJiraAccountId", + "mcp__atlassian__search", + "mcp__atlassian__searchJiraIssuesUsingJql", + "mcp__claude_ai_Atlassian__atlassianUserInfo", + "mcp__claude_ai_Atlassian__fetch", + "mcp__claude_ai_Atlassian__getAccessibleAtlassianResources", + "mcp__claude_ai_Atlassian__getIssueLinkTypes", + "mcp__claude_ai_Atlassian__getJiraIssue", + "mcp__claude_ai_Atlassian__getJiraIssueRemoteIssueLinks", + "mcp__claude_ai_Atlassian__getJiraIssueTypeMetaWithFields", + "mcp__claude_ai_Atlassian__getJiraProjectIssueTypesMetadata", + "mcp__claude_ai_Atlassian__getTransitionsForJiraIssue", + "mcp__claude_ai_Atlassian__getVisibleJiraProjects", + "mcp__claude_ai_Atlassian__lookupJiraAccountId", + "mcp__claude_ai_Atlassian__search", + "mcp__claude_ai_Atlassian__searchJiraIssuesUsingJql", "mcp__ide__getDiagnostics", "mcp__sequential-thinking__sequentialthinking" ], "deny": [] }, + "env": { + "ENABLE_TOOL_SEARCH": "true" + }, + "enabledPlugins": { + "skill-creator@claude-plugins-official": true + }, "hooks": { "PostToolUse": [ { @@ -69,6 +101,31 @@ { "type": "command", "command": "if [ -n \"$CLAUDE_ENV_FILE\" ]; then echo 'export NX_DAEMON=false' >> \"$CLAUDE_ENV_FILE\"; fi" + }, + { + "type": "command", + "command": "\"$CLAUDE_PROJECT_DIR\"/external/ag-shared/scripts/install-for-cloud/setup-terminal-title.sh" + } + ] + } + ], + "WorktreeCreate": [ + { + "hooks": [ + { + "type": "command", + "command": "\"$CLAUDE_PROJECT_DIR\"/external/ag-shared/scripts/setup-worktree/claude-worktree-create.sh", + "timeout": 300 + } + ] + } + ], + "WorktreeRemove": [ + { + "hooks": [ + { + "type": "command", + "command": "\"$CLAUDE_PROJECT_DIR\"/external/ag-shared/scripts/setup-worktree/claude-worktree-remove.sh" } ] } diff --git a/external/ag-shared/prompts/.mcp.json b/external/ag-shared/prompts/.mcp.json index c8de2ca8ed8..bd9a351731c 100644 --- a/external/ag-shared/prompts/.mcp.json +++ b/external/ag-shared/prompts/.mcp.json @@ -1,5 +1,9 @@ { "mcpServers": { + "atlassian": { + "type": "http", + "url": "https://mcp.atlassian.com/v1/mcp" + }, "sequential-thinking": { "type": "stdio", "command": "yarn", diff --git a/external/ag-shared/prompts/agents/code-reviewer.md b/external/ag-shared/prompts/agents/code-reviewer.md deleted file mode 100644 index f55dc48f1b7..00000000000 --- a/external/ag-shared/prompts/agents/code-reviewer.md +++ /dev/null @@ -1,42 +0,0 @@ ---- -name: code-reviewer -targets: ['*'] -description: 'Expert code review specialist. Proactively reviews code for quality, security, and maintainability. Use immediately after writing or modifying code.' -claudecode: - model: opus - tools: - - Read - - Grep - - Glob - - Bash - - Write - - Edit - - MultiEdit ---- - -You are a senior code reviewer ensuring high standards of code quality and security. - -When invoked: - -1. Run `git diff` or use `gh pr diff` to see recent changes -2. Focus on modified files -3. Begin review immediately - -Review checklist: - -- Code is simple and readable -- Functions and variables are well-named -- No duplicated code -- Proper error handling -- No exposed secrets or API keys -- Input validation implemented -- Good test coverage -- Performance considerations addressed - -Provide feedback organized by priority: - -- Critical issues (must fix) -- Warnings (should fix) -- Suggestions (consider improving) - -Include specific examples of how to fix issues. diff --git a/external/ag-shared/prompts/guides/_docs-review-integration.md b/external/ag-shared/prompts/guides/_docs-review-integration.md index 70a71a91b18..fccf5c4312a 100644 --- a/external/ag-shared/prompts/guides/_docs-review-integration.md +++ b/external/ag-shared/prompts/guides/_docs-review-integration.md @@ -1,3 +1,7 @@ + + # Docs Review Integration Guide This guide covers how to integrate the shared docs review methodology into any AG product repo (ag-grid, ag-studio, etc.). diff --git a/external/ag-shared/prompts/guides/rulesync.md b/external/ag-shared/prompts/guides/rulesync.md deleted file mode 100644 index ec2951d0682..00000000000 --- a/external/ag-shared/prompts/guides/rulesync.md +++ /dev/null @@ -1,203 +0,0 @@ ---- -globs: - [ - '.rulesync/**/*', - 'external/ag-shared/prompts/**/*', - 'external/prompts/**/*', - '**/AGENTS.md', - '**/.agent/**/*', - '**/.agents/**/*', - '**/.ai/**/*', - '**/.augment/rules/**/*', - '**/CLAUDE.md', - '**/.claude/**/*', - '**/.clinerules/**/*', - '**/.codex/**/*', - '**/.cursor/**/*', - '**/GEMINI.md', - '**/.gemini/**/*', - '**/.github/copilot-instructions.md', - '**/.github/instructions/**/*', - '**/.github/prompts/**/*', - '**/.github/agents/**/*', - '**/.github/skills/**/*', - '**/.junie/**/*', - '**/.kilocode/**/*', - '**/.kiro/steering/**/*', - '**/.opencode/**/*', - '**/QWEN.md', - '**/.qwen/**/*', - '**/.roo/**/*', - '**/.warp/**/*', - '**/WARP.md', - ] -alwaysApply: false ---- - -# Rulesync Configuration Guide - -This guide covers setting up and maintaining the `.rulesync/` directory structure for AI agentic tooling across AG Grid and AG Charts repositories. - -## Overview - -Rulesync generates tool-specific configuration files (e.g., `.claude/`, `.cursor/`) from a unified source in `.rulesync/`. This enables consistent AI agent behaviour across different tools while maintaining a single source of truth. - -## Rulesync Configuration Reference - -See [Rulesync Configuration](https://github.com/dyoshikawa/rulesync?tab=readme-ov-file#configuration) for relevant documentation. - -## Directory Structure - -``` -.rulesync/ -├── .aiignore # Files to exclude from AI context -├── mcp.json # MCP server configuration (symlink) -├── commands/ # Slash commands (symlinks) -├── rules/ # Context rules and guides (symlinks + repo-specific) -├── subagents/ # Agent definitions (symlinks) -└── skills/ # Complex workflow skills (symlinks) -``` - -## Content Sources - -Files in `.rulesync/` are either simple files, or symlinks to files in other locations: - -| Source | Purpose | Examples | -| ----------------------------- | --------------------------------------------------------------- | ----------------------------------- | -| `.rulesync/` | Repo-specific rules + symlink-based inclusion of shared content | `ag-charts.md`, `ag-grid.md` | -| `external/ag-shared/prompts/` | Cross-repo shared content | `code-reviewer.md` | -| `external/prompts/` | Repo-private shared content | `spruce-example.md`, `visual-qa.md` | - -## Frontmatter Requirements - -All rulesync-managed files require YAML frontmatter with `targets`: - -### Commands - -```yaml ---- -targets: ['*'] -description: 'Brief description of what this command does' ---- -``` - -### Agents/Subagents - -```yaml ---- -targets: ['*'] -name: agent-name -description: 'Brief description (quote if contains colons)' -claudecode: - model: opus|sonnet - tools: - - Read - - Grep - - Bash ---- -``` - -### Rules/Guides - -```yaml ---- -globs: ['pattern1', 'pattern2'] -alwaysApply: true|false ---- -``` - -**Choosing globs**: Match file paths where the guidance applies: - -| Rule Type | Glob Pattern Example | When Loaded | -|-----------|---------------------|-------------| -| Domain-specific | `['**/series/**/*.ts']` | Working with series code | -| Script/tool | `['**/setup-prompts/**/*', '**/patches/rulesync*']` | Working with setup scripts or patches | -| Test guidance | `['**/*.test.ts', '**/*.spec.ts']` | Working with test files | -| Always needed | `alwaysApply: true` | Every conversation | - -**Tips**: -- Use specific patterns to avoid loading irrelevant context -- Combine multiple patterns for related file types -- Use `alwaysApply: true` sparingly (core project rules only) - -### Skills - -```yaml ---- -targets: ['*'] -name: skill-name -description: 'Brief description of the skill' -context: fork # Optional: fork context for complex workflows ---- -``` - -## YAML Gotchas - -**Quote descriptions containing colons:** - -```yaml -# BAD - YAML sees "Context:" as a mapping key -description: Examples: Context: The user... - -# GOOD - Quoted string handles colons correctly -description: "Examples: Context: The user..." -``` - -## Symlink Patterns - -Create symlinks from `.rulesync/` to source files: - -```bash -# From .rulesync/commands/ -ln -s ../../external/ag-shared/prompts/commands/git/bisect.md git-bisect.md -ln -s ../../external/prompts/commands/spruce-example.md spruce-example.md - -# From .rulesync/subagents/ -ln -s ../../external/ag-shared/prompts/agents/code-reviewer.md code-reviewer.md -ln -s ../../external/prompts/agents/visual-qa.md visual-qa.md - -# From .rulesync/rules/ -ln -s ../../external/ag-shared/prompts/guides/code-quality.md code-quality.md - -# From .rulesync/skills/ (NOTE: skills use directory symlinks, not file symlinks) -ln -s ../../external/prompts/skills/spruce-example/ spruce-example -``` - -## Verification - -Run the verification script after changes: - -```bash -./external/ag-shared/scripts/setup-prompts/verify-rulesync.sh -``` - -This checks: - -- All frontmatter is valid -- All symlinks resolve correctly -- Generated output matches expected inventory - -## Adding New Content - -- For repo-specific content that can be public, add directly in `.rulesync/` in the appropriate sub-folder. -- For repo-specific content that is private, add in `external/prompts/` in the appropriate sub-folder, and symlink to `.rulesync/` in the appropriate sub-folder. -- For shared content, add in `external/ag-shared/prompts/` in the appropriate sub-folder, and symlink to `.rulesync/` in the appropriate sub-folder. - -## Troubleshooting - -### YAML Parse Errors - -- Check for unquoted colons in description fields -- Ensure proper indentation (2 spaces) -- Validate with `npx yaml-lint ` - -### Missing Files in Output - -- Verify symlink targets exist -- Check frontmatter has required `targets` field -- Ensure file extension is `.md` - -### Verification Failures - -- Run `rulesync generate -t claudecode` manually to see detailed errors -- Check temp directory output for comparison diff --git a/external/ag-shared/prompts/guides/website-astro-pages.md b/external/ag-shared/prompts/guides/website-astro-pages.md index a14e984055b..11907179ce0 100644 --- a/external/ag-shared/prompts/guides/website-astro-pages.md +++ b/external/ag-shared/prompts/guides/website-astro-pages.md @@ -1,6 +1,6 @@ --- targets: ['*'] -description: 'Astro page creation patterns, layout props, content collections, and code conventions for AG product websites' +description: 'Astro page conventions for AG product websites — loads /website-astro skill for details' globs: [ '**/src/pages/**/*.astro', @@ -8,327 +8,15 @@ globs: ] --- -# Website Astro Pages Guide +# Website Astro Page Conventions -This guide covers Astro page creation patterns, layout props, content collections, and code conventions for AG product websites. +When editing `.astro` files for AG product websites, follow these conventions: -## Project Overview +1. **Import Layout** for standard pages: `import Layout from '@layouts/Layout.astro';` +2. **Page file path = URL**: `pages/pricing.astro` → `/pricing` +3. **Use content collections** for data: `import { getEntry } from 'astro:content';` +4. **Hydrate React components** with `client:load` (or `client:idle` / `client:visible`) +5. **Import order**: Astro → external → shared (`@ag-website-shared/*`) → local → styles +6. **Naming**: pages kebab-case, components PascalCase, styles `.module.scss`, CSS classes camelCase -- **Framework**: Astro 5 with React 18 for interactive components -- **Styling**: SCSS with CSS Modules + shared design system -- **Package Manager**: Yarn -- **Monorepo**: Nx-managed -- **Shared Components**: `external/ag-website-shared/src/components/` - -## Directory Structure - -``` -packages//src/ -├── pages/ # Astro page routes (*.astro files) -├── layouts/ -│ └── Layout.astro # Main page layout wrapper -├── components/ # Local React & Astro components -├── content/ # Content collections (data, docs) -├── pages-styles/ # Page-specific SCSS modules -├── stores/ # Nanostores (state management) -└── utils/ # Utility functions - -external/ag-website-shared/src/ -├── components/ # Shared components across AG products -│ ├── license-pricing/ # Pricing page components -│ ├── changelog/ # Changelog/pipeline components -│ ├── community/ # Community page components -│ ├── whats-new/ # Release notes components -│ ├── landing-pages/ # Landing page components -│ ├── footer/ # Footer component -│ ├── site-header/ # Site header component -│ └── ... # Many more shared components -└── design-system/ # Design tokens and base styles -``` - -## Creating Standard Astro Pages - -### Page Location - -All pages go in `packages//src/pages/`. The file path determines the URL: - -| File Path | URL | -|-----------|-----| -| `pages/index.astro` | `/` | -| `pages/pricing.astro` | `/pricing` | -| `pages/community.astro` | `/community` | -| `pages/community/events.astro` | `/community/events` | - -### Pattern 1: Full Custom Page with Layout - -Use this for pages that need custom content and styling. - -```astro ---- -import Layout from '@layouts/Layout.astro'; -import styles from '@pages-styles/my-page.module.scss'; -import { urlWithBaseUrl } from '@utils/urlWithBaseUrl'; - -// Optional: Fetch data from content collections -import { getEntry, type CollectionEntry } from 'astro:content'; -const { data: navData } = (await getEntry('docsNav', 'nav')) as CollectionEntry<'docsNav'>; ---- - - -
-

My Page

-

Content goes here

-
-
-``` - -### Pattern 2: Wrapper Page (Delegates to Shared Component) - -Use this when a shared component handles all the page logic. - -```astro ---- -import { getEntry, type CollectionEntry } from 'astro:content'; -import WhatsNew from '@ag-website-shared/components/whats-new/pages/whats-new.astro'; - -// Note: version entry keys are product-specific (e.g. 'ag-grid-versions', 'ag-charts-versions') -const { data: versionsData } = (await getEntry('versions', '-versions')) as CollectionEntry<'versions'>; -const { data: docsNavData } = (await getEntry('docsNav', 'nav')) as CollectionEntry<'docsNav'>; ---- - - - -``` - -### Pattern 3: Minimal Wrapper (Simplest) - -For pages that just render a shared component with no data. - -```astro ---- -import Home from '@ag-website-shared/components/community/pages/home.astro'; ---- - - -``` - -### Pattern 4: Page with React Components - -Use this for interactive pages with client-side functionality. - -```astro ---- -import { LicensePricing } from '@ag-website-shared/components/license-pricing/LicensePricing'; -import Layout from '@layouts/Layout.astro'; ---- - - - - -``` - -### Pattern 5: Page with Docs Navigation - -Use this for pages that should show the documentation sidebar. - -```astro ---- -import { getEntry, type CollectionEntry } from 'astro:content'; -import Layout from '@layouts/Layout.astro'; -import { getFrameworkFromPath } from '@components/docs/utils/urlPaths'; -import { Pipeline } from '@ag-website-shared/components/changelog/Pipeline'; -import { DocsNavFromLocalStorage } from '@ag-website-shared/components/docs-navigation/DocsNavFromLocalStorage'; -import styles from '@ag-website-shared/components/changelog/changelog.module.scss'; -import classnames from 'classnames'; - -const path = Astro.url.pathname; -const framework = getFrameworkFromPath(path); -const { data: docsNavData } = (await getEntry('docsNav', 'nav')) as CollectionEntry<'docsNav'>; ---- - - -
- - -
-

Pipeline

- - -
-
-
-``` - -### Pattern 6: Standalone Page (No Layout) - -For special pages like demos that need full control. - -```astro ---- -import HeroDashboard from '@components/hero-dashboard/HeroDashboard.astro'; -import '@pages-styles/scratchpad.scss'; -import '@pages-styles/example-controls.css'; ---- - - - - - <Product Name> - - - - - -``` - -## Layout Component Props - -The `Layout.astro` component accepts these props: - -| Prop | Type | Default | Description | -|------|------|---------|-------------| -| `title` | string | required | Page title (shown in browser tab) | -| `description` | string | metadata default | SEO meta description | -| `showSearchBar` | boolean | undefined | Show search in header | -| `showDocsNav` | boolean | undefined | Show docs navigation toggle | -| `hideHeader` | boolean | false | Hide the site header | -| `hideFooter` | boolean | false | Hide the site footer | - -## Content Collections - -Fetch data from content collections using Astro's `getEntry`: - -```astro ---- -import { getEntry, type CollectionEntry } from 'astro:content'; - -// Navigation data -const { data: docsNavData } = (await getEntry('docsNav', 'nav')) as CollectionEntry<'docsNav'>; -const { data: apiNavData } = (await getEntry('apiNav', 'nav')) as CollectionEntry<'apiNav'>; - -// Version data (entry key is product-specific, e.g. 'ag-grid-versions', 'ag-charts-versions') -const { data: versionsData } = (await getEntry('versions', '-versions')) as CollectionEntry<'versions'>; - -// Footer data -const { data: footerItems } = (await getEntry('footer', 'footer')) as CollectionEntry<'footer'>; - -// Metadata -const { data: metadata } = (await getEntry('metadata', 'metadata')) as CollectionEntry<'metadata'>; ---- -``` - -## Available Shared Components - -Key components from `@ag-website-shared/components/`: - -| Component | Import Path | Purpose | -|-----------|-------------|---------| -| `LicensePricing` | `license-pricing/LicensePricing` | Pricing page | -| `Pipeline` | `changelog/Pipeline` | Development pipeline | -| `WhatsNew` | `whats-new/pages/whats-new.astro` | Release notes | -| `DocsNavFromLocalStorage` | `docs-navigation/DocsNavFromLocalStorage` | Docs sidebar | -| `FrameworkTextAnimation` | `framework-text-animation/FrameworkTextAnimation` | Animated framework text | -| `LandingPageFWSelector` | `landing-pages/LandingPageFWSelector` | Framework selector | -| `Footer` | `footer/Footer` | Site footer | -| `SiteHeader` | `site-header/SiteHeader.astro` | Site header | - -## Utility Functions - -```typescript -// URL utilities -import { urlWithBaseUrl } from '@utils/urlWithBaseUrl'; -import { urlWithPrefix } from '@utils/urlWithPrefix'; - -// Add base URL to paths (base URL is product-specific) -urlWithBaseUrl('/example') // → '//example' (with configured base) - -// Add framework prefix -urlWithPrefix({ framework: 'react', url: './quick-start' }) // → '/react/quick-start' - -// Framework detection -import { getFrameworkFromPath } from '@components/docs/utils/urlPaths'; -const framework = getFrameworkFromPath(Astro.url.pathname); -``` - -## React Component Hydration - -When using React components in Astro pages, add hydration directives: - -| Directive | When to Use | -|-----------|-------------| -| `client:load` | Needs immediate interactivity (most common) | -| `client:idle` | Can wait until browser is idle | -| `client:visible` | Only when scrolled into view | -| (none) | Static content only, no JavaScript | - -```astro - - - - - - - - -``` - -## Path Aliases - -| Alias | Path | -|-------|------| -| `@components/*` | `src/components/*` | -| `@layouts/*` | `src/layouts/*` | -| `@pages-styles/*` | `src/pages-styles/*` | -| `@stores/*` | `src/stores/*` | -| `@utils/*` | `src/utils/*` | -| `@constants` | `src/constants.ts` | -| `@ag-website-shared/*` | `external/ag-website-shared/src/*` | - -## Code Style - -### Import Order - -1. Astro imports (`astro:content`) -2. External packages -3. Shared components (`@ag-website-shared/*`) -4. Local components/utils (`@components/*`, `@utils/*`) -5. Styles - -### Naming Conventions - -| Type | Convention | Example | -|------|------------|---------| -| Astro pages | kebab-case | `license-pricing.astro` | -| Components | PascalCase | `MyComponent.tsx` | -| Style modules | kebab-case | `my-page.module.scss` | -| CSS classes | camelCase | `.pageContainer` | - -## Common Tasks - -### Add a New Standard Page - -1. Create `src/pages/my-page.astro` -2. Import Layout and any needed components -3. Use standard design system classes where possible -4. Create `src/pages-styles/my-page.module.scss` only if custom styles needed - -### Use a Shared Component - -1. Check `external/ag-website-shared/src/components/` for available components -2. Import with `@ag-website-shared/components/...` -3. Add `client:load` if it's a React component needing interactivity +For full reference (6 page patterns, component catalog, content collection recipes), load the `/website-astro` skill. diff --git a/external/ag-shared/prompts/guides/website-css.md b/external/ag-shared/prompts/guides/website-css.md index 547b6db0ce1..7d6d0f4b5e2 100644 --- a/external/ag-shared/prompts/guides/website-css.md +++ b/external/ag-shared/prompts/guides/website-css.md @@ -1,6 +1,6 @@ --- targets: ['*'] -description: 'CSS architecture, design system, design tokens, utility classes, and styling patterns for AG product websites' +description: 'CSS styling conventions for AG product websites — loads /website-css skill for details' globs: [ '**/src/pages-styles/**/*.scss', @@ -10,481 +10,15 @@ globs: ] --- -# Website CSS & Styling Guide +# Website CSS Conventions -This guide covers the CSS architecture, design system, design tokens, utility classes, and styling patterns used by AG product websites. +When editing SCSS/CSS files for AG product websites, follow these rules: -## Design System +1. **Always import the design system:** `@use 'design-system' as *;` +2. **Use semantic variables** (`--color-bg-primary`) — never raw palette variables or hex values +3. **Dark mode uses `data-dark-mode`:** `#{$selector-darkmode} &` in SCSS. Never `prefers-color-scheme` +4. **Prefer standard utility classes** (`.layout-grid`, `.text-xl`, `.text-secondary`) over custom styles +5. **SCSS modules for components:** `.module.scss` files +6. **Test both light and dark modes** -### Location - -The website's design system is defined in a shared external package: - -``` -external/ag-website-shared/src/design-system/ -``` - -### File Structure - -| File | Purpose | -|------|---------| -| `_root.scss` | All CSS custom properties (colours, typography, layout, shadows) | -| `core/_variables.scss` | SCSS variables (spacing, selectors, transitions) | -| `core/_breakpoints.scss` | Responsive breakpoint values | -| `_layout.scss` | Layout utility classes | -| `_typography.scss` | Typography utility classes | -| `_color.scss` | Colour utility classes | -| `_interactions.scss` | Interactive state classes | -| `_base.scss` | Base element styles | - -### Using the Design System - -Always import the design system at the top of SCSS files: - -```scss -@use 'design-system' as *; -``` - -## CSS Custom Properties - -### How Variables Are Organised - -The design system uses CSS custom properties (variables) organised into semantic categories: - -```scss -:root { - // Abstract colours (raw palette) - --color-gray-50: #f9fafb; - --color-gray-100: #f2f4f7; - // ... through gray-950 - - --color-brand-50: #f4f8ff; - --color-brand-100: #e5effd; - // ... through brand-950 - - // Semantic colours (use these in components) - --color-bg-primary: var(--color-white); - --color-fg-primary: var(--color-gray-900); - --color-border-primary: var(--color-gray-300); -} -``` - -### Colour Palette Reference - -#### Grey Scale - -| Variable | Light Mode | Hex | -| ------------------ | ---------- | --------- | -| `--color-gray-25` | Lightest | `#fcfcfd` | -| `--color-gray-50` | | `#f9fafb` | -| `--color-gray-100` | | `#f2f4f7` | -| `--color-gray-200` | | `#eaecf0` | -| `--color-gray-300` | | `#d0d5dd` | -| `--color-gray-400` | | `#98a2b3` | -| `--color-gray-500` | | `#667085` | -| `--color-gray-600` | | `#475467` | -| `--color-gray-700` | | `#344054` | -| `--color-gray-800` | | `#182230` | -| `--color-gray-900` | | `#101828` | -| `--color-gray-950` | Darkest | `#0c111d` | - -#### Brand Colours (Blue) - -| Variable | Hex | -| ------------------- | --------- | -| `--color-brand-50` | `#f4f8ff` | -| `--color-brand-100` | `#e5effd` | -| `--color-brand-200` | `#d4e3f8` | -| `--color-brand-300` | `#a9c5ec` | -| `--color-brand-400` | `#3d7acd` | -| `--color-brand-500` | `#0e4491` | -| `--color-brand-600` | `#0042a1` | -| `--color-brand-700` | `#00388f` | -| `--color-brand-800` | `#002e7e` | -| `--color-brand-900` | `#00246c` | -| `--color-brand-950` | `#001a5a` | - -#### Warning Colours (Orange/Yellow) - -| Variable | Hex | -| --------------------- | --------- | -| `--color-warning-50` | `#fffaeb` | -| `--color-warning-100` | `#fef0c7` | -| `--color-warning-200` | `#fedf89` | -| `--color-warning-300` | `#fec84b` | -| `--color-warning-400` | `#fdb022` | -| `--color-warning-500` | `#f79009` | -| `--color-warning-600` | `#dc6803` | -| `--color-warning-700` | `#b54708` | -| `--color-warning-800` | `#93370d` | -| `--color-warning-900` | `#7a2e0e` | -| `--color-warning-950` | `#4e1d09` | - -#### Special Colours - -| Variable | Hex | Usage | -| ------------------ | ------------------------------------ | --------------------- | -| `--color-success` | `#28a745` (light) / `#64ea82` (dark) | Success states | -| `--color-positive` | `#28a745` | Positive indicators | -| `--color-negative` | `#dc3545` | Error/negative states | - -## Standard CSS Utility Classes - -**Always prefer using standard design system classes over custom styles.** These classes are globally available and ensure consistency across the site. - -### Layout Classes - -Use these for page structure and grid layouts: - -| Class | Purpose | -|-------|---------| -| `.layout-grid` | Flexbox grid container with standard gap and max-width | -| `.layout-page-max-width` | Full width constrained to max page width | -| `.layout-max-width-small` | Narrower content width with horizontal padding | - -**Column Classes (4-column grid):** -- `.column-1-4`, `.column-2-4`, `.column-3-4`, `.column-4-4` - -**Column Classes (6-column grid):** -- `.column-1-6` through `.column-6-6` - -**Column Classes (12-column grid):** -- `.column-1-12` through `.column-12-12` - -```astro -
-
Main content
-
Sidebar
-
-``` - -### Typography Classes - -| Class | Font Size | Use For | -|-------|-----------|---------| -| `.text-2xs` | 10px | Fine print | -| `.text-xs` | 12px | Captions, labels | -| `.text-sm` | 14px | Secondary text | -| `.text-base` | 16px | Body text (default) | -| `.text-lg` | 20px | Subheadings | -| `.text-xl` | 24px | Section headings | -| `.text-2xl` | 32px | Page headings | -| `.text-3xl` | 40px | Hero headings | - -**Weight Classes:** -- `.text-regular` (400) -- `.text-semibold` (600) -- `.text-bold` (700) - -**Other:** -- `.text-monospace` - Monospace font family - -```astro -

Page Title

-

Body content here.

-code example -``` - -### Colour Classes - -| Class | Purpose | -|-------|---------| -| `.text-secondary` | Secondary foreground colour | -| `.text-tertiary` | Tertiary foreground colour | - -### Interaction Classes - -| Class | Purpose | -|-------|---------| -| `.collapse` | Hidden when not `.show` | -| `.collapsing` | Animating collapse transition | -| `.no-transitions` | Disable all transitions | -| `.no-overflow-anchor` | Prevent scroll anchoring | - -### Example: Using Standard Classes - -```astro -
-

Welcome

-

- Introduction paragraph with secondary styling. -

- -
-
-

Left Column

-
-
-

Right Column

-
-
-
-``` - -## Dark Mode - -### How Dark Mode Works - -Dark mode is triggered by the `data-dark-mode="true"` attribute on the `` element: - -```scss -html[data-dark-mode='true'] { - --color-bg-primary: color-mix(in srgb, var(--color-gray-800), var(--color-gray-900) 50%); - --color-fg-primary: var(--color-white); - // ... other overrides -} -``` - -### Dark Mode in SCSS Modules - -Use the `$selector-darkmode` SCSS variable for dark mode overrides in component styles: - -```scss -.myElement { - background-color: var(--color-bg-primary); - - #{$selector-darkmode} & { - background-color: var(--color-bg-secondary); - } -} -``` - -### Key Dark Mode Colours - -| Semantic Variable | Light Mode | Dark Mode | -| -------------------------- | ---------- | ---------------------------------------- | -| `--color-bg-primary` | `#ffffff` | Mix of `#182230` + `#101828` | -| `--color-bg-secondary` | `#f9fafb` | `#344054` | -| `--color-bg-tertiary` | `#f2f4f7` | `#182230` | -| `--color-fg-primary` | `#101828` | `#ffffff` | -| `--color-fg-secondary` | `#344054` | `#d0d5dd` | -| `--color-border-primary` | `#d0d5dd` | `#344054` | -| `--color-border-secondary` | `#eaecf0` | Mix of `#344054` + bg-primary | -| `--color-link` | `#0e4491` | `#a9c5ec` | - -### Detecting Dark Mode in JavaScript - -```typescript -// Check data attribute (preferred) -const isDark = document.documentElement.getAttribute('data-dark-mode') === 'true'; - -// Or check for dark mode class (fallback) -const isDark = document.documentElement.classList.contains('dark'); -``` - -### Creating Theme-Aware Components - -Use CSS custom properties that react to `data-dark-mode`: - -```css -/* Define variables for both modes */ -:root { - --my-component-bg: #ffffff; - --my-component-text: #101828; -} - -[data-dark-mode='true'] { - --my-component-bg: #182230; - --my-component-text: #d0d5dd; -} - -/* Use variables in component */ -.my-component { - background: var(--my-component-bg); - color: var(--my-component-text); -} -``` - -This approach ensures instant theme switching without JavaScript re-rendering. - -## Semantic Colour Categories - -### Background Colours (`--color-bg-*`) - -- `--color-bg-primary`: Main content background -- `--color-bg-secondary`: Secondary/elevated surfaces -- `--color-bg-tertiary`: Subtle backgrounds -- `--color-bg-toolbar`: Toolbar backgrounds -- `--color-bg-code`: Code block backgrounds - -### Foreground/Text Colours (`--color-fg-*`) - -- `--color-fg-primary`: Primary text -- `--color-fg-secondary`: Secondary/muted text -- `--color-fg-tertiary`: Subtle text -- `--color-fg-disabled`: Disabled state text - -### Border Colours (`--color-border-*`) - -- `--color-border-primary`: Primary borders -- `--color-border-secondary`: Subtle borders -- `--color-border-tertiary`: Very subtle borders - -### Link Colours (`--color-link*`) - -- `--color-link`: Default link colour -- `--color-link-hover`: Link hover state - -## Design Tokens Reference - -### Spacing (SCSS variables from `core/_variables.scss`) - -| Variable | Value | -|----------|-------| -| `$spacing-size-1` | 4px | -| `$spacing-size-2` | 8px | -| `$spacing-size-3` | 12px | -| `$spacing-size-4` | 16px | -| `$spacing-size-5` | 20px | -| `$spacing-size-6` | 24px | -| `$spacing-size-8` | 32px | -| `$spacing-size-10` | 40px | -| `$spacing-size-12` | 48px | -| `$spacing-size-16` | 64px | -| `$spacing-size-20` | 80px | -| `$spacing-size-24` | 96px | - -### Breakpoints (SCSS variables from `core/_breakpoints.scss`) - -| Variable | Value | Use For | -|----------|-------|---------| -| `$breakpoint-hero-small` | 620px | Small hero layouts | -| `$breakpoint-hero-large` | 1020px | Large hero layouts | -| `$breakpoint-landing-page-medium` | 1020px | Landing pages | -| `$breakpoint-docs-nav-medium` | 1052px | Docs navigation | -| `$breakpoint-pricing-small` | 620px | Pricing page | -| `$breakpoint-pricing-medium` | 820px | Pricing page | -| `$breakpoint-pricing-large` | 1260px | Pricing page | - -### Typography (CSS variables from `_root.scss`) - -| Variable | Value | -|----------|-------| -| `--text-fs-2xs` | 10px | -| `--text-fs-xs` | 12px | -| `--text-fs-sm` | 14px | -| `--text-fs-base` | 16px | -| `--text-fs-lg` | 20px | -| `--text-fs-xl` | 24px | -| `--text-fs-2xl` | 32px | -| `--text-fs-3xl` | 40px | -| `--text-lh-tight` | 1.2 | -| `--text-regular` | 400 | -| `--text-semibold` | 600 | -| `--text-bold` | 700 | - -### Layout (CSS variables from `_root.scss`) - -| Variable | Description | -|----------|-------------| -| `--layout-gap` | Grid gap (32px) | -| `--layout-max-width` | Max page width (1800px) | -| `--layout-max-width-small` | Narrow content width (1240px) | -| `--layout-horizontal-margins` | Side margins | - -### Border Radius - -- `--radius-xs` (4px), `--radius-sm` (6px), `--radius-md` (8px), `--radius-lg` (10px), `--radius-xl` (12px), `--radius-2xl` (16px) - -### Shadows - -- `--shadow-xs`, `--shadow-sm`, `--shadow-md`, `--shadow-lg`, `--shadow-xl`, `--shadow-2xl` - -## Creating Custom Page Styles - -Only create custom styles when standard classes don't meet your needs. Create SCSS modules in `packages//src/pages-styles/`: - -```scss -// my-page.module.scss -@use 'design-system' as *; - -.heroSection { - padding-top: $spacing-size-16; - background-color: var(--color-bg-site-header); - - // Dark mode support - #{$selector-darkmode} & { - background-color: var(--color-bg-secondary); - } - - // Responsive - @media screen and (min-width: $breakpoint-hero-large) { - padding-top: $spacing-size-24; - } -} -``` - -## Using Styles in Astro - -```astro ---- -import styles from '@pages-styles/my-page.module.scss'; -import classnames from 'classnames'; ---- - -
-
-

Title

-
-
-``` - -## Component Styling Patterns - -### Using SCSS Modules - -The website uses CSS/SCSS modules for component styling: - -```scss -// MyComponent.module.scss -.container { - background: var(--color-bg-primary); - border: 1px solid var(--color-border-primary); - color: var(--color-fg-primary); -} -``` - -## Best Practices - -### DO: - -- Use semantic variables (`--color-bg-primary`) not raw colours (`--color-gray-50`) -- Define component-specific variables that reference design system variables -- Use `[data-dark-mode="true"]` selector or `#{$selector-darkmode}` for dark mode overrides -- Test components in both light and dark modes -- Prefer standard design system utility classes over custom styles - -### DON'T: - -- Hardcode hex colours directly in components -- Use `prefers-color-scheme` media query (the site uses explicit `data-dark-mode`) -- Assume light mode is the default without testing dark mode - -## Adding New Theme-Aware Styles - -When creating new components or features that need to support both themes: - -1. **Define CSS variables** in a ` + + +
+ + + + +``` + +**WITH controls:** + +```html + + + AG Grid Example - Demo Name + + + + + + + +
+
+ +
+
+
+ + + + +``` + +**Key points:** + +- Include `` to prevent indexing +- The grid container **must** have an explicit `style="height: 500px"` (or similar) — without it the grid collapses to zero height +- Apply a theme class to the container: `ag-theme-quartz` (default), `ag-theme-alpine`, or `ag-theme-balham` +- Use a **specific version** (e.g., `@33.0.0`) with optional cache-busting timestamp (`?t=1768428202375`) +- Generate timestamp with: `date +%s%3N` +- Do NOT add `

`, `

`, or other decorative elements + +For Enterprise features, use the enterprise CDN URL: + +```html + +``` + +### Enterprise vs Community + +Use `ag-grid-enterprise` CDN URL if the example uses any enterprise-only feature (e.g., row grouping, server-side row model, tree data, master/detail, range selection, integrated charts, status bar, sidebar, etc.). + +### main.js + +```javascript +const gridOptions = { + rowData: getData(), // or inline array + columnDefs: [ + { field: 'make' }, + { field: 'model' }, + { field: 'price' }, + ], + defaultColDef: { + flex: 1, + }, +}; + +const gridElement = document.getElementById('myGrid'); +agGrid.createGrid(gridElement, gridOptions); +``` + +**Key points:** + +- The UMD global is `agGrid` — use `agGrid.createGrid(element, options)` +- Do NOT use `new Grid()` (deprecated) or `agGrid.Grid` — use `agGrid.createGrid()` +- The first argument must be a DOM element, not a string selector + +### ag-example-styles.css + +Copy the CSS file directly from the skill assets — do not write it by hand: + +```bash +cp "/assets/ag-example-styles.css" "$PLNKR_DIR/ag-example-styles.css" +``` + +This file includes both the base control styles (buttons, inputs, etc.) and the vanilla framework styles needed for proper layout. + +### Controls + +If your example needs interactive controls, wrap them in `

` with `
` for each row. The grid `
` sits **outside** the controls div as a sibling. Use `gap-left`, `gap-right`, `push-left`, `push-right` classes for layout. + +### package.json + +```json +{ + "name": "ag-grid-example", + "dependencies": { + "ag-grid-community": "latest" + } +} +``` + +For Enterprise, use `"ag-grid-enterprise": "latest"` instead. + +### CDN URLs + +**Staging (DEFAULT for testing):** + +Use staging by default unless the user specifies a version. Add a cache-busting timestamp. + +- Community: `https://grid-staging.ag-grid.com/dev/ag-grid-community/dist/ag-grid-community.min.js?t={timestamp}` +- Enterprise: `https://grid-staging.ag-grid.com/dev/ag-grid-enterprise/dist/ag-grid-enterprise.min.js?t={timestamp}` + +Generate timestamp with: `date +%s%3N` + +**Versioned (for reproduction/sharing):** + +- Community: `https://cdn.jsdelivr.net/npm/ag-grid-community@33.0.0/dist/ag-grid-community.min.js` +- Enterprise: `https://cdn.jsdelivr.net/npm/ag-grid-enterprise@33.0.0/dist/ag-grid-enterprise.min.js` + +### data.js (Optional Separate Data File) + +Create a `data.js` when data is large enough to warrant separation (roughly >20 rows or >30 lines). Define a `getData()` function: + +```javascript +function getData() { + return [ + { make: 'Toyota', model: 'Celica', price: 35000 }, + { make: 'Ford', model: 'Mondeo', price: 32000 }, + // ... + ]; +} +``` + +In `index.html`, add `` **before** ``. In `main.js`, call `getData()`. For small datasets, inline the data directly. + +### Integrated Charts (AG Charts inside AG Grid) + +When the grid example uses integrated charts (e.g., chart ranges, pivot charts), you must load AG Charts Enterprise **before** AG Grid Enterprise: + +```html + + +``` + +Load order matters — AG Charts Enterprise must be loaded first so AG Grid can detect and use it. + +### Common Issues + +| Issue | Cause | Fix | +|-------|-------|-----| +| Grid collapses to zero height | Missing explicit height on container | Add `style="height: 500px"` to `#myGrid` | +| Grid doesn't render | Wrong CDN URL or missing global | Check script src and use `agGrid.createGrid()` | +| `new Grid()` error | Using deprecated API | Use `agGrid.createGrid(element, options)` | +| No theme styling | Missing theme class | Add `class="ag-theme-quartz"` to grid container | +| Styling issues | Missing example styles | Copy `ag-example-styles.css` from assets | +| Controls break grid layout | Grid div nested inside controls div | `
` must be a **sibling** outside `
` | +| Integrated charts not working | Wrong script load order | Load `ag-charts-enterprise` **before** `ag-grid-enterprise` | +| Container not found | Using string selector | Use `document.getElementById('myGrid')` | diff --git a/external/ag-shared/prompts/skills/plunker/ag-studio-guide.md b/external/ag-shared/prompts/skills/plunker/ag-studio-guide.md new file mode 100644 index 00000000000..e0c2fc9517b --- /dev/null +++ b/external/ag-shared/prompts/skills/plunker/ag-studio-guide.md @@ -0,0 +1,5 @@ +## AG Studio Example Structure + +> Placeholder — to be populated with Studio-specific plunker construction patterns. + +See `ag-charts-guide.md` for the reference implementation of a product guide. diff --git a/external/ag-shared/prompts/skills/plunker/assets/ag-example-styles.css b/external/ag-shared/prompts/skills/plunker/assets/ag-example-styles.css new file mode 100644 index 00000000000..37bbe4b3020 --- /dev/null +++ b/external/ag-shared/prompts/skills/plunker/assets/ag-example-styles.css @@ -0,0 +1,262 @@ +/** + * Styles for control elements in examples, not required for the examples' functionality + */ +:root { + --main-fg: #101828; + --main-bg: #fff; + + --chart-bg: #fff; + --chart-border: #d0d5dd; + + --button-fg: #212529; + --button-bg: transparent; + --button-border: #d0d5dd; + --button-hover-bg: rgba(0, 0, 0, 0.1); + + --input-accent: #0e4491; + --input-focus-border: #3d7acd; + --range-track-bg: #efefef; + + --row-gap: 6px; + + --select-chevron: url('data:image/svg+xml;utf8,'); + --checkbox-tick-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='3.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6L9 17L4 12'/%3E%3C/svg%3E"); +} + +:root[data-dark-mode='true'] { + --main-fg: #fff; + --main-bg: #141d2c; + + --chart-bg: #192232; + --chart-border: #344054; + + --button-fg: #f8f9fa; + --button-bg: transparent; + --button-border: rgba(255, 255, 255, 0.2); + --button-hover-bg: #2a343e; + + --input-accent: #a9c5ec; + --input-focus-border: #3d7acd; + --range-track-bg: #4a5465; + + --select-chevron: url('data:image/svg+xml;utf8,'); + --checkbox-tick-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%232a343e' stroke-width='3.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6L9 17L4 12'/%3E%3C/svg%3E"); +} + +*, +*::before, +*::after { + box-sizing: border-box; +} + +:root, +body { + height: 100%; + width: 100%; + margin: 0; + overflow: hidden; +} + +/* Hide codesandbox highlighter */ +body > #highlighter { + display: none; +} + +.example-controls { + display: flex; + flex-direction: column; + flex-wrap: wrap; +} + +.example-controls *, +.example-controls *::before, +.example-controls *::after { + margin: 0; + font-family: -apple-system, 'system-ui', sans-serif; + font-size: 14px; + font-weight: 500; + line-height: 17px; + letter-spacing: 0.01em; + color: var(--main-fg); +} + +.example-controls :where(button, textarea, select, input[type='submit'], input[type='text'], input[type='number']) { + appearance: none; + display: inline-block; + height: 36px; + padding: 5px 14px 7px; + white-space: nowrap; + border-radius: 6px; + color: var(--button-fg); + background-color: var(--button-bg); + border: 1px solid var(--button-border); + box-shadow: 0 0 0 0 transparent; + transition: + background-color 0.25s ease-in-out, + border-color 0.25s ease-in-out, + box-shadow 0.25s ease-in-out; + align-self: flex-start; +} + +.example-controls :where(button, select, input[type='submit']) { + cursor: pointer; +} + +.example-controls select { + appearance: none; + padding-right: 32px; + padding-left: 14px; + background: no-repeat center right 4px var(--select-chevron); +} + +.example-controls textarea { + height: auto; + padding: 7px 14px; +} + +.example-controls pre, +.example-controls code { + font-family: SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace; +} + +.example-controls input { + appearance: none; +} + +.example-controls input[type='checkbox'], +.example-controls input[type='radio'] { + border: 1px solid var(--button-border); + cursor: pointer; +} + +.example-controls input[type='radio'] { + width: 20px; + height: 20px; + border-radius: 50%; +} + +.example-controls input[type='radio']:checked { + border-width: 0; + box-shadow: inset 0 0 0 6px var(--input-accent); +} + +.example-controls input[type='radio']:checked:focus-visible { + box-shadow: + inset 0 0 0 2px var(--input-focus-border), + inset 0 0 0 3px var(--main-bg), + inset 0 0 0 6px var(--input-accent); +} + +.example-controls input[type='checkbox'] { + width: 24px; + height: 24px; + border-radius: 6px; + cursor: pointer; +} + +.example-controls input[type='checkbox']:checked { + background: var(--input-accent) no-repeat center/14px var(--checkbox-tick-icon); + border-color: var(--input-accent); +} + +.example-controls input[type='range'] { + appearance: none; + min-width: 160px; + border-radius: 8px; + cursor: pointer; + overflow: hidden; /* slider progress trick */ + background: var(--range-track-bg); +} + +.example-controls input[type='range']::-webkit-slider-runnable-track { + appearance: none; + height: 16px; + background: var(--range-track-bg); +} + +.example-controls input[type='range']::-moz-range-track { + appearance: none; + height: 16px; + background: var(--range-track-bg); +} + +.example-controls input[type='range']::-webkit-slider-thumb { + appearance: none; + height: 16px; + width: 16px; + background-color: var(--main-bg); + border-radius: 50%; + border: 2px solid var(--input-accent); + box-shadow: -1007px 0 0 1000px var(--input-accent); /* slider progress trick */ +} + +.example-controls input[type='range']::-moz-range-thumb { + appearance: none; + height: 16px; + width: 16px; + background-color: var(--main-bg); + border-radius: 50%; + border: 2px solid var(--input-accent); + box-shadow: -1007px 0 0 1000px var(--input-accent); /* slider progress trick */ +} + +.example-controls :is(button, input[type='submit'], select):hover { + background-color: var(--button-hover-bg); +} + +.example-controls :is(button:focus-visible, input:focus-visible, textarea:focus-visible, select:focus-visible) { + border-color: var(--input-focus-border); + box-shadow: + inset 0 0 0 1px var(--input-focus-border), + inset 0 0 0 2px var(--main-bg); + outline: none; +} + +.controls-row { + display: flex; + align-items: center; + flex-wrap: wrap; + gap: var(--row-gap); + font-variant: tabular-nums; +} + +.controls-row + .controls-row { + margin-top: var(--row-gap); +} + +.controls-row.center { + justify-content: center; +} + +.controls-row .push-right { + margin-left: auto; +} + +.controls-row .push-left { + margin-right: auto; +} + +.controls-row .gap-right { + margin-right: calc(var(--row-gap) * 6); +} + +.controls-row .gap-left { + margin-left: calc(var(--row-gap) * 6); +} + +body { + display: flex; + flex-direction: column; + height: 100%; + gap: 8px; +} + +div:has(> .ag-charts-wrapper) { + padding: 1rem; + height: 100%; + border-radius: 8px; + background-color: var(--chart-bg); + border: 1px solid var(--chart-border); + overflow: hidden; + transform: translate3d(0, 0, 0); +} diff --git a/external/ag-shared/prompts/skills/pr-create/SKILL.md b/external/ag-shared/prompts/skills/pr-create/SKILL.md index 4a329589b59..ab96fe97d29 100644 --- a/external/ag-shared/prompts/skills/pr-create/SKILL.md +++ b/external/ag-shared/prompts/skills/pr-create/SKILL.md @@ -43,7 +43,55 @@ Determine: - **Whether there are uncommitted changes** (staged, unstaged, or untracked). - **Whether there are unpushed commits** on this branch. -### STEP 2: Identify Base Branch +### STEP 2: Check Symlinked Repos + +Scan the `external/` directory for symlinked directories that resolve to separate git repos with changes. These need their own branches and PRs before the outer repo's PR is created. + +1. Identify symlinked repo candidates: + ```bash + for dir in external/*/; do + [ -L "${dir%/}" ] && [ -d "$(readlink -f "${dir%/}")/.git" ] && echo "${dir%/}" + done + ``` + Skip any directory that is NOT a symlink (e.g., `external/ag-shared` is a real directory tracked in the outer repo — ignore it). + +2. For each symlinked repo found, check for uncommitted or unpushed changes: + ```bash + RESOLVED_PATH="$(readlink -f "")" + git -C "$RESOLVED_PATH" status --porcelain + git -C "$RESOLVED_PATH" log --oneline @{upstream}..HEAD 2>/dev/null + ``` + If there are no uncommitted changes AND no unpushed commits, skip that repo silently. + +3. For each symlinked repo WITH changes, create a matching branch, commit, push, and open a PR: + - Use the same branch name as the outer repo (`CURRENT_BRANCH` or the topic branch name determined in STEP 4) for traceability. + - If the repo is not already on that branch, create and switch to it: + ```bash + git -C "$RESOLVED_PATH" checkout -b 2>/dev/null || git -C "$RESOLVED_PATH" checkout + ``` + - Stage and commit changes with a message referencing the outer repo's work: + ```bash + git -C "$RESOLVED_PATH" add -A + git -C "$RESOLVED_PATH" commit -m "$(cat <<'EOF' + Update for : + EOF + )" + ``` + - Push and create a PR: + ```bash + git -C "$RESOLVED_PATH" push -u origin + cd "$RESOLVED_PATH" && gh pr create --title "" --body "$(cat <<'EOF' + Companion PR for changes in <outer-repo-name>. + EOF + )" + ``` + - Record each created PR URL in `SYMLINKED_REPO_PRS` for the final report. + +4. If no symlinked repos have changes, proceed to the next step without comment. + +**Note:** This step may execute before the outer repo's topic branch is fully determined (STEP 4). If a topic branch has not yet been created, defer symlinked repo processing until after STEP 4 and execute it between STEP 4 and STEP 5. The key requirement is that symlinked repo PRs are created BEFORE the outer repo's PR (STEP 7). + +### STEP 3: Identify Base Branch Determine the correct base branch for the PR: @@ -58,7 +106,7 @@ Determine the correct base branch for the PR: Store the result as `BASE_BRANCH`. -### STEP 3: Ensure Topic Branch +### STEP 4: Ensure Topic Branch If currently on `latest` or a `bX.Y.Z` branch, a new topic branch is required: @@ -73,7 +121,7 @@ If currently on `latest` or a `bX.Y.Z` branch, a new topic branch is required: If already on a topic branch (not `latest` or `bX.Y.Z`), continue on the current branch. -### STEP 4: Commit Changes (If Any) +### STEP 5: Commit Changes (If Any) If there are uncommitted changes: @@ -84,11 +132,7 @@ If there are uncommitted changes: git status ``` 2. Stage relevant files (prefer specific files over `git add -A`). -3. Write a commit message following git-conventions: - - JIRA-linked: `AG-XXXX <description>` (uppercase JIRA number) - - No JIRA: `<description>` (concise, imperative mood) - - Under 72 characters. - - Never attribute agentic tooling. +3. Write a commit message following git-conventions (see Commits section). 4. Commit: ```bash git commit -m "$(cat <<'EOF' @@ -99,7 +143,7 @@ If there are uncommitted changes: If there are no uncommitted changes and no unpushed commits, inform the user there is nothing to submit and **STOP**. -### STEP 5: Push Branch +### STEP 6: Push Branch Push the branch to the remote, setting the upstream: @@ -107,7 +151,7 @@ Push the branch to the remote, setting the upstream: git push -u origin <branch-name> ``` -### STEP 6: Create Pull Request +### STEP 7: Create Pull Request Create the PR using `gh`: @@ -118,17 +162,11 @@ EOF )" ``` -Follow git-conventions for the PR: - -- **Title:** Under 70 characters. JIRA-linked: `AG-XXXX <description>`. No JIRA: `<description>`. -- **Body:** JIRA-linked: include link(s) to the JIRA ticket(s). No JIRA: concise description of the change. -- Keep descriptions concise - this is a public repo. -- Never attribute agentic tooling. -- If JIRA-linked include "Fix #AG-XXXX" +Follow git-conventions (see Pull Requests section). If JIRA-linked, include "Fix #AG-XXXX" in the body. -### STEP 7: Report Result +### STEP 8: Report Result -Output the PR URL and a brief summary: +Output the PR URL and a brief summary. If any symlinked repo PRs were created in STEP 2, include them as well: ``` PR created: <URL> @@ -136,6 +174,14 @@ PR created: <URL> Title: <title> ``` +If `SYMLINKED_REPO_PRS` is non-empty, also report: + +``` +Companion PRs (symlinked repos): + <repo-name>: <URL> + <repo-name>: <URL> +``` + ## Arguments `${ARGUMENTS}` can optionally include: diff --git a/external/ag-shared/prompts/skills/pr-review/SKILL.md b/external/ag-shared/prompts/skills/pr-review/SKILL.md index fd15c1aba28..fb87302850a 100644 --- a/external/ag-shared/prompts/skills/pr-review/SKILL.md +++ b/external/ag-shared/prompts/skills/pr-review/SKILL.md @@ -16,9 +16,13 @@ You are acting as a reviewer for a proposed code change. Your goal is to identif Parse the `ARGUMENTS` environment variable (or skill arguments) for flags and the PR number: - `--json` — output structured JSON instead of Markdown (used for inline commenting in CI) +- `--devils-advocate` — run an additional Devil's Advocate review pass after the standard review (see below) +- `--full` — run all additional review passes: Devil's Advocate + JIRA Completeness verification (see below) - Remaining positional argument — the PR number -Examples: `123`, `--json 123`, `123 --json` +Examples: `123`, `--json 123`, `123 --json`, `--devils-advocate 123`, `--full 123`, `--json --full 123` + +**Note:** `--full` implies `--devils-advocate`. You do not need to pass both. ## Output Format @@ -196,3 +200,88 @@ When `--json` is specified, output **ONLY** valid JSON. No markdown code fences, } } ``` + +## Devil's Advocate Mode (`--devils-advocate`) + +When the `--devils-advocate` flag is present, run an additional adversarial review pass after the standard review completes. This mode challenges assumptions, stress-tests edge cases, and questions whether the PR's approach is the right one. + +### Workflow + +1. **Run the standard review first.** Complete the full review as described above and collect all findings. +2. **Spawn a sub-agent with the Devil's Advocate instructions.** Use the Agent tool to spawn a sub-agent with the following prompt structure: + - Include the full contents of `agents/devils-advocate.md` (co-located in this skill's directory) as the sub-agent's instructions. + - Pass the PR diff, PR metadata, and the `--json` flag state to the sub-agent so it has full context. + - The sub-agent should read and follow `_review-core.md` for shared methodology. +3. **Merge findings from both passes.** + - Combine standard review findings with Devil's Advocate findings (prefixed with `[DA]`). + - Deduplicate: if both passes flag the same file and line for the same issue, keep the higher-priority version and note it was flagged by both passes. + - In Markdown mode, add a `## Devil's Advocate Findings` section after the standard `## Findings` section. + - In JSON mode, merge the Devil's Advocate findings into the `findings` array (the `[DA]` prefix in the title distinguishes them). +4. **Update the verdict.** If the Devil's Advocate pass surfaces P0 or P1 issues not found in the standard review, adjust the verdict and confidence accordingly. + +## Full Review Mode (`--full`) + +When `--full` is present, run **all** additional review passes in parallel after the standard review completes: + +1. Devil's Advocate (as described above) +2. JIRA Completeness Verification (described below) +3. Code Simplification Review (described below) + +All three sub-agents can be spawned simultaneously since they are independent of each other. + +### JIRA Completeness Verification + +#### 1. Extract JIRA IDs + +Scan these sources (in order) for JIRA ticket references matching the pattern `AG-\d+` or `ST-\d+`: + +1. **Branch name** — e.g., `ag-12345/fix-tooltip` or `ST-6789-update-utils` +2. **PR title and description** — from `gh pr view` or `$PR_TITLE` +3. **Commit messages** — from `git log` of the PR's commits + +Collect all unique ticket IDs found. The pattern match is case-insensitive (both `ag-12345` and `AG-12345` should match). Normalise to uppercase for the sub-agent (e.g., `AG-12345`). + +#### 2. Spawn the JIRA Completeness Sub-agent + +Use the Agent tool to spawn a sub-agent with: + +- The full contents of `agents/jira-completeness.md` (co-located in this skill's directory) as instructions. +- The extracted JIRA IDs. +- A brief PR summary (from the standard review or PR metadata). +- The list of changed files and diff stats. +- The `--json` flag state. + +#### 3. Merge JIRA Findings + +- Combine JIRA findings (prefixed with `[JIRA]`) with the standard review and Devil's Advocate findings. +- In Markdown mode, add a `## JIRA Completeness` section after `## Devil's Advocate Findings` (or after `## Findings` if Devil's Advocate is not separately flagged). +- In JSON mode, merge the JIRA findings into the `findings` array. Additionally, include the `jira_summary` object as a top-level field in the JSON output. +- If no JIRA IDs were found at all, include a P1 finding noting the PR has no associated JIRA ticket. + +#### 4. Update the Verdict + +If the JIRA verification reveals significant scope mismatches (PR does substantially different work than the ticket describes) or a missing JIRA link, factor this into the confidence score. JIRA hygiene findings alone (missing components, wrong status) should not change the code correctness verdict but should appear in `required_actions`. + +### Code Simplification Review + +#### 1. Spawn the Simplification Sub-agent + +Use the Agent tool to spawn a sub-agent that performs the `/simplify` skill's analysis on the files changed by this PR. The sub-agent prompt should: + +- List the files changed in the PR (from `git diff --name-only`). +- Instruct the agent to read those files and review the **changed sections** for opportunities to simplify — reuse existing utilities, reduce duplication, improve clarity, or eliminate unnecessary complexity. +- Instruct the agent to **report findings only, not make edits** — this is a review, not an auto-fix. +- Pass the `--json` flag state so output format matches. + +The sub-agent should focus on the same concerns as the `/simplify` skill: reuse, quality, and efficiency. It should not flag style issues handled by linters or raise concerns about code it hasn't read. + +#### 2. Merge Simplification Findings + +- Combine simplification findings (prefixed with `[SIMPLIFY]`) with other findings. +- In Markdown mode, add a `## Simplification Opportunities` section after the JIRA section (or after whatever the last preceding section is). +- In JSON mode, merge findings into the `findings` array with the `[SIMPLIFY]` title prefix. +- Deduplicate against standard review findings — if the standard review already flagged the same issue (e.g., duplicated logic), keep the standard review version. + +#### 3. Verdict Impact + +Simplification findings are advisory and should not change the code correctness verdict or confidence score. They appear as P2 or P3 suggestions in `required_actions` only if they represent genuine quality concerns (e.g., copy-pasted logic that should be extracted). diff --git a/external/ag-shared/prompts/skills/pr-review/_review-core.md b/external/ag-shared/prompts/skills/pr-review/_review-core.md index e5eaec29760..c9ca03b0dd7 100644 --- a/external/ag-shared/prompts/skills/pr-review/_review-core.md +++ b/external/ag-shared/prompts/skills/pr-review/_review-core.md @@ -153,3 +153,19 @@ To determine which method to use: 2. **Fallback**: Check for pre-fetched refs with `git rev-parse origin/pr/$ARGUMENTS 2>/dev/null` - If successful: Use git diff commands - If fails: Use `gh` CLI commands + +## 10. Devil's Advocate Mode + +When the `--devils-advocate` flag is passed, the review skill runs a second pass using an adversarial sub-agent defined in `agents/devils-advocate.md`. This agent challenges assumptions, stress-tests edge cases, questions necessity, and probes for gaps in testing. + +The Devil's Advocate agent follows the same priority scheme (P0-P3), line number guidelines, and environment detection described in this file. Its findings are prefixed with `[DA]` and merged with the standard review output. See `SKILL.md` for the full workflow and merge logic. + +## 11. Full Review Mode + +When the `--full` flag is passed, the review skill runs all additional passes in parallel: + +1. **Devil's Advocate** (Section 10) — adversarial review, findings prefixed `[DA]`. +2. **JIRA Completeness** — verifies associated JIRA tickets (matching `AG-\d+` or `ST-\d+` in branch name, commits, or PR metadata) are well-maintained and aligned with the PR. Agent defined in `agents/jira-completeness.md`, findings prefixed `[JIRA]`. +3. **Code Simplification** — reviews changed files for reuse, duplication, and unnecessary complexity (mirrors the `/simplify` skill). Findings prefixed `[SIMPLIFY]`. + +See `SKILL.md` for extraction logic, sub-agent spawning, and merge details. diff --git a/external/ag-shared/prompts/skills/pr-review/agents/devils-advocate.md b/external/ag-shared/prompts/skills/pr-review/agents/devils-advocate.md new file mode 100644 index 00000000000..15f2d62f757 --- /dev/null +++ b/external/ag-shared/prompts/skills/pr-review/agents/devils-advocate.md @@ -0,0 +1,109 @@ +# Devil's Advocate Review Agent + +You are a Devil's Advocate reviewer. Your job is to **challenge, question, and stress-test** a pull request that has already passed a standard review. You are not here to rubber-stamp; you are here to find what the standard review missed by thinking adversarially. + +**Read and follow the shared methodology in the co-located `_review-core.md` file** for priority definitions (P0-P3), line number guidelines, environment detection, and workflow basics. This document defines your additional focus areas and adversarial mindset. + +## Your Mandate + +You operate as a sub-agent spawned after the standard review pass. The standard review covers correctness, performance, security, and maintainability. Your role is to go deeper by challenging the PR from angles that a conventional review tends to skip. + +## Focus Areas + +### 1. Challenge Assumptions + +- Is this the right approach, or is there a simpler alternative the author did not consider? +- Is the abstraction level appropriate? Is something over-abstracted or under-abstracted? +- Would a different architecture or data structure serve the same goal with fewer trade-offs? +- Are there implicit assumptions about input shape, execution order, or environment that are not enforced? + +### 2. Stress-Test Edge Cases + +- What happens with empty inputs, null values, or undefined fields? +- How does this code behave under concurrent access or re-entrant calls? +- What happens with very large datasets, deeply nested structures, or extreme numeric values? +- Are there error conditions on the unhappy path that the implementation silently ignores? +- What happens if an upstream dependency changes its contract (e.g., returns a different shape)? + +### 3. Question Necessity + +- Is every file change in this PR actually needed to achieve the stated goal? +- Is there unnecessary complexity, premature generalisation, or over-engineering? +- Does the PR introduce scope creep beyond what the ticket or description claims? +- Could any of the new code be replaced by an existing utility or pattern already in the codebase? + +### 4. Challenge the Testing + +- Do the tests actually verify the behaviour that changed, or do they test incidental details? +- Could the tests pass while the code is still broken? (e.g., tests that assert on mocks rather than real behaviour) +- What scenarios are **not** covered by the test suite? Identify the most dangerous gaps. +- Are there integration or interaction effects between changed modules that unit tests would miss? +- If there are no new tests, should there be? + +### 5. Consider the Consumer + +- How does this change affect downstream users, consumers, or dependent packages? +- Are there breaking changes that are not obvious from the diff alone (e.g., subtle behaviour changes, type narrowing)? +- Would a consumer need to migrate or update their code? Is that migration path clear? +- Does this change alter any public API surface (types, events, callbacks, CSS classes)? + +### 6. Play the Adversary + +- If you were trying to break this code in production, how would you do it? +- What inputs or sequences of operations would trigger the worst outcome? +- Are there race conditions, resource leaks, or state corruption vectors? +- Could a malicious or careless consumer misuse the new API in a way that causes harm? + +## Output Guidelines + +- Use the same priority scheme as the standard review (P0-P3). +- Every finding **must** reference a specific file and line number from the diff. +- Prefix each finding title with `[DA]` so findings from this agent are clearly identifiable when merged with the standard review. +- Focus on **genuinely challenging questions and concrete risks**, not hypothetical nitpicks. +- If the PR is solid and you cannot find substantive issues, say so explicitly rather than manufacturing findings. A clean Devil's Advocate pass is a strong signal. +- Aim for depth over breadth: a few well-argued findings are more valuable than a long list of shallow ones. + +## Output Format + +Output your findings in the same format as the standard review (Markdown or JSON, depending on the `--json` flag passed to the parent skill). The parent skill will merge your findings with the standard review and deduplicate. + +### Markdown + +```markdown +## Devil's Advocate Findings + +### P0 - Critical + +{List P0 issues, or "None" if empty} + +- **`{filepath}:{line}`** - [DA] {Issue title} + {Explanation of why this is a genuine risk} + +### P1 - High + +... + +### P2 - Medium + +... + +### Summary + +{1-2 sentences on overall adversarial assessment: Is this PR robust, or are there substantive concerns the standard review missed?} +``` + +### JSON + +When `--json` is active, output a JSON array of finding objects using the same schema as the standard review's `findings` array. Prefix each `title` with `[DA]`. + +```json +[ + { + "priority": "P1", + "file": "src/example.ts", + "line": 42, + "title": "[DA] Assumption about input ordering is not enforced", + "description": "The code assumes items arrive sorted by timestamp, but nothing validates or enforces this. If the upstream data source changes its ordering, the binary search at line 42 will silently return wrong results." + } +] +``` diff --git a/external/ag-shared/prompts/skills/pr-review/agents/jira-completeness.md b/external/ag-shared/prompts/skills/pr-review/agents/jira-completeness.md new file mode 100644 index 00000000000..0b6537bbe76 --- /dev/null +++ b/external/ag-shared/prompts/skills/pr-review/agents/jira-completeness.md @@ -0,0 +1,127 @@ +# JIRA Completeness Verification Agent + +You are a JIRA completeness reviewer. Your job is to verify that the JIRA ticket(s) associated with a pull request are well-maintained and aligned with the actual code changes. + +## Inputs + +You receive: + +- **JIRA IDs**: One or more ticket IDs (e.g., `AG-12345`, `ST-6789`) extracted from the PR's branch name, commit messages, or PR title/description. +- **PR summary**: A brief description of what the PR does (from the standard review or PR metadata). +- **Changed files**: The list of files modified in the PR. +- **PR diff stats**: Lines added/removed, files changed. + +## Workflow + +### 1. Fetch Each JIRA Ticket + +Use `mcp__atlassian__getJiraIssue` with `cloudId: "1565837d-d6d1-4228-bcb2-4cb74df700f2"` and the ticket key. + +### 2. Fetch Ticket Comments + +Use `mcp__atlassian__addCommentToJiraIssue` is for writing — to **read** comments, use `mcp__atlassian__getJiraIssue` which includes comments in its response, or use `mcp__atlassian__fetch` with the REST endpoint `rest/api/3/issue/{issueKey}/comment`. + +Comments are important because requirements evolve as tickets progress through development and QA. New test cases, edge cases, revised acceptance criteria, and scope changes are frequently captured in comments rather than being back-ported into the description. Read through all comments to build a complete picture of the ticket's current requirements. + +### 3. Verify Ticket Completeness + +For each ticket, check the following fields and flag any that are missing or inadequate: + +| Check | What to Look For | Severity | +|-------|-----------------|----------| +| **Summary** | Present and descriptive (not just "fix bug" or a copy of the branch name) | P1 | +| **Description** | Non-empty, provides context on what and why | P1 | +| **Issue Type** | Set and appropriate for the work (Bug for fixes, Task/Feature Request for new work) | P2 | +| **Components** | At least one component assigned | P2 | +| **Track** | Track field (`customfield_10501`) is set | P2 | +| **Status** | Ticket is in an active state (e.g., "In Progress", "In Review") rather than "Backlog" or "To Do" | P2 | +| **Acceptance Criteria** | For Feature Requests and Tasks: description should contain testable acceptance criteria or a clear definition of done | P2 | +| **Comment Requirements** | Requirements, test cases, or scope changes added in comments that refine or extend the original description | P2 | + +### 4. Verify Alignment with PR + +Compare the JIRA ticket's description, summary, **and comments** against the actual PR changes: + +- **Scope match**: Do the PR changes correspond to what the ticket describes? Flag if the PR appears to contain significant work not mentioned in the ticket, or if the ticket describes work not addressed by the PR. +- **Comment-sourced requirements**: Check whether requirements or test cases added in comments are addressed by the PR. Flag any that appear unaddressed — these are easy to miss since they live outside the description. +- **Title consistency**: Does the PR title or branch name reference the correct ticket? +- **Ticket count**: If multiple JIRA IDs were found, note whether they appear to be related (e.g., parent/child, linked) or unrelated. + +### 5. Check for Missing JIRA Links + +If **no** JIRA IDs were found in the branch name, commits, or PR metadata, report this as a P1 finding — PRs should be traceable to a ticket. + +## Output Format + +Output your findings using the format specified by the `--json` flag state passed from the parent skill. + +### Markdown + +```markdown +## JIRA Completeness + +### Tickets Found + +| Ticket | Summary | Status | Verdict | +|--------|---------|--------|---------| +| AG-12345 | Fix tooltip in polar charts | In Progress | Complete | +| ST-6789 | Update shared utils | Backlog | Incomplete | + +### Findings + +- **AG-12345** - [JIRA] Description lacks acceptance criteria + The ticket is a Feature Request but the description does not include testable acceptance criteria or a definition of done. + +- **ST-6789** - [JIRA] Ticket still in Backlog + The ticket status is "Backlog" but a PR is already open. Move it to "In Progress" to reflect the current state. + +### Alignment + +{1-2 sentences on whether the PR changes match what the JIRA ticket(s) describe} +``` + +### JSON + +When `--json` is active, output findings as a JSON array using the same schema as the standard review's `findings` array. Prefix each `title` with `[JIRA]`. Use `file: "JIRA"` and `line: 0` since these findings don't reference code locations. + +Additionally include a `jira_summary` object: + +```json +{ + "findings": [ + { + "priority": "P2", + "file": "JIRA", + "line": 0, + "title": "[JIRA] AG-12345: Description lacks acceptance criteria", + "description": "The ticket is a Feature Request but has no testable acceptance criteria." + } + ], + "jira_summary": { + "tickets": [ + { + "key": "AG-12345", + "summary": "Fix tooltip in polar charts", + "status": "In Progress", + "type": "Feature Request", + "has_description": true, + "has_components": true, + "has_track": true, + "has_comment_requirements": true, + "verdict": "incomplete", + "gaps": ["No acceptance criteria"], + "comment_requirements": ["Edge case: tooltip should handle null series data (from QA comment 2025-03-01)"] + } + ], + "alignment": "PR changes match the ticket description.", + "no_jira_found": false + } +} +``` + +## Guidelines + +- Be pragmatic — not every ticket needs a novel-length description. A clear one-liner for a small bug fix is fine. +- Focus on gaps that would cause problems: traceability, scope mismatches, tickets stuck in wrong status. +- Do not flag cosmetic issues in JIRA formatting. +- If the Atlassian MCP tools are unavailable or the ticket fetch fails, report that you could not verify the ticket and suggest the reviewer check manually. Do not block the review. diff --git a/external/ag-shared/prompts/skills/rulesync/SKILL.md b/external/ag-shared/prompts/skills/rulesync/SKILL.md new file mode 100644 index 00000000000..6218dc54e1a --- /dev/null +++ b/external/ag-shared/prompts/skills/rulesync/SKILL.md @@ -0,0 +1,260 @@ +--- +targets: ['*'] +name: rulesync +description: 'Configure AI/agentic tooling using rulesync. Use when asking about .rulesync/, adding or editing commands, rules, skills, or subagents, configuring AI tools like Claude Code or Cursor, understanding where AI config files live, editing prompt files, or asking how to add a new command/rule/skill/agent. Also use when someone references .claude/, .cursor/, .copilot/ or similar tool-specific config directories.' +--- + +# Rulesync Configuration Guide + +`.rulesync/` is the **single source of truth** for all AI/agentic tooling configuration in this repository. Tool-specific directories like `.claude/`, `.cursor/`, `.copilot/`, etc. are **generated output** -- never edit them directly. All changes go through `.rulesync/` and are propagated by the rulesync generator. + +This matters because we support multiple AI tools, and maintaining separate configs for each would lead to drift and inconsistency. Rulesync solves this by generating tool-specific formats from one canonical source. + +See [Rulesync Configuration](https://github.com/dyoshikawa/rulesync?tab=readme-ov-file#configuration) for upstream documentation. + +## Directory Structure + +``` +.rulesync/ +├── .aiignore # Files to exclude from AI context +├── mcp.json # MCP server configuration +├── commands/ # Slash commands +├── rules/ # Context rules and guides +├── subagents/ # Agent definitions +└── skills/ # Complex workflow skills +``` + +## Content Source Tiers + +Files in `.rulesync/` are either local files or symlinks to one of three source tiers: + +| Source | Purpose | When to Use | +|--------|---------|-------------| +| `.rulesync/` directly | Repo-specific content | Content unique to this repo that can be public | +| `external/prompts/` | Repo-private shared content | Product-specific content (e.g. AG Charts testing, JIRA templates) | +| `external/ag-shared/prompts/` | Cross-repo shared content | Content reusable across AG Charts and AG Grid (git conventions, code quality) | + +**Decision guide:** +- Will AG Grid also need this? -> `external/ag-shared/prompts/` +- Is it product-specific but shared across worktrees? -> `external/prompts/` +- Is it unique to this repo checkout? -> `.rulesync/` directly + +## Frontmatter Reference + +All rulesync-managed files require YAML frontmatter. The required fields depend on the file type. + +### Commands + +```yaml +--- +targets: ['*'] +description: 'Brief description of what this command does' +--- +``` + +Commands become slash commands (e.g. `/docs-review`). The `description` appears in the skill/command list. + +### Rules/Guides + +```yaml +--- +globs: ['pattern1', 'pattern2'] +alwaysApply: true|false +--- +``` + +Rules are loaded automatically based on file context. Choose globs that match where the guidance applies: + +| Rule Type | Glob Pattern Example | When Loaded | +|-----------|---------------------|-------------| +| Domain-specific | `['**/series/**/*.ts']` | Working with series code | +| Test guidance | `['**/*.test.ts', '**/*.spec.ts']` | Working with test files | +| Script/tool | `['**/setup-prompts/**/*']` | Working with setup scripts | +| Always needed | `alwaysApply: true` | Every conversation | + +Use `alwaysApply: true` sparingly -- it adds to every conversation's context budget. Prefer specific globs. + +### Skills + +```yaml +--- +targets: ['*'] +name: skill-name +description: 'Brief description of the skill' +--- +``` + +Optional fields: +- `context: fork` -- for skills that manage branch/worktree context +- `invocable: user-only` -- prevents the agent from auto-invoking (user must type `/skill-name`) + +Skills become invocable via `/skill-name`. The `description` determines when the agent auto-invokes the skill, so make it thorough and include trigger phrases. + +### Subagents + +```yaml +--- +targets: ['*'] +name: agent-name +description: 'Brief description (quote if contains colons)' +claudecode: + model: opus|sonnet + tools: + - Read + - Grep + - Bash +--- +``` + +Subagents are specialised agents spawned via the Agent tool. The `model` and `tools` fields control their capabilities. + +### YAML Gotchas + +Quote descriptions containing colons -- YAML interprets bare colons as mapping keys: + +```yaml +# BAD - YAML sees "Context:" as a mapping key +description: Examples: <example>Context: The user... + +# GOOD - Quoted string handles colons correctly +description: "Examples: <example>Context: The user..." +``` + +## Symlink Patterns + +Content from `external/` is included via symlinks. The key distinction: + +- **Commands, rules, subagents**: Use **file** symlinks (`.md` file -> `.md` file) +- **Skills**: Use **directory** symlinks (directory -> directory) + +This is because skills can contain multiple files (SKILL.md + helpers, templates, scripts). + +```bash +# From .rulesync/commands/ +ln -s ../../external/ag-shared/prompts/commands/git/bisect.md git-bisect.md +ln -s ../../external/prompts/commands/docs-create.md docs-create.md + +# From .rulesync/rules/ +ln -s ../../external/ag-shared/prompts/guides/code-quality.md code-quality.md + +# From .rulesync/subagents/ +ln -s ../../external/ag-shared/prompts/agents/code-reviewer.md code-reviewer.md +ln -s ../../external/prompts/subagents/visual-qa.md visual-qa.md + +# From .rulesync/skills/ (DIRECTORY symlinks) +ln -s ../../external/ag-shared/prompts/skills/dev-server/ dev-server +ln -s ../../external/ag-shared/prompts/skills/jira jira +``` + +## Adding New Content + +### Adding a Command + +1. **Choose tier**: Local (`.rulesync/commands/`), private (`external/prompts/commands/`), or shared (`external/ag-shared/prompts/commands/`) +2. **Create the file** with command frontmatter: + ```yaml + --- + targets: ['*'] + description: 'What this command does' + --- + + # Command Name + + Instructions for the command... + ``` +3. **If not local**: Create a file symlink from `.rulesync/commands/`: + ```bash + cd .rulesync/commands + ln -s ../../external/prompts/commands/my-command.md my-command.md + ``` +4. **Regenerate and verify** (see below) + +### Adding a Rule/Guide + +1. **Choose tier** and create the `.md` file with rule frontmatter +2. **Choose globs** carefully -- specific patterns keep context budgets lean +3. **If not local**: Create a file symlink from `.rulesync/rules/`: + ```bash + cd .rulesync/rules + ln -s ../../external/ag-shared/prompts/guides/my-guide.md my-guide.md + ``` +4. **Regenerate and verify** + +### Adding a Skill + +1. **Choose tier** and create a **directory** with `SKILL.md` inside: + ``` + external/prompts/skills/my-skill/ + ├── SKILL.md + ├── template.md # Optional helper files + └── helper-script.sh # Optional scripts + ``` +2. **Write SKILL.md** with skill frontmatter. Make the `description` thorough -- it controls auto-triggering +3. **Create a directory symlink** from `.rulesync/skills/`: + ```bash + cd .rulesync/skills + ln -s ../../external/prompts/skills/my-skill/ my-skill + ``` +4. **Regenerate and verify** + +### Adding a Subagent + +1. **Choose tier** and create the `.md` file with subagent frontmatter +2. **Pick model and tools** appropriate to the agent's purpose (use `sonnet` for fast tasks, `opus` for complex reasoning) +3. **If not local**: Create a file symlink from `.rulesync/subagents/`: + ```bash + cd .rulesync/subagents + ln -s ../../external/prompts/subagents/my-agent.md my-agent.md + ``` +4. **Regenerate and verify** + +## Generation and Verification + +After any changes to `.rulesync/` or its source files: + +```bash +# Regenerate tool-specific configs from .rulesync/ +./external/ag-shared/scripts/setup-prompts/setup-prompts.sh + +# Verify everything is consistent +./external/ag-shared/scripts/setup-prompts/verify-rulesync.sh +``` + +The verification script checks: +- All frontmatter is valid YAML with required fields +- All symlinks resolve to existing files +- Generated output matches the expected file inventory +- Content integrity between source and generated output + +To validate that file path references within prompt files are correct, use the `/validate-prompts` skill. + +## Anti-patterns + +**Never edit generated directories directly.** `.claude/`, `.cursor/`, `.copilot/`, and other tool-specific directories are generated output. Edits will be overwritten on the next `setup-prompts.sh` run. Always edit in `.rulesync/` or the source file it symlinks to. + +**Never commit the TOON block in AGENTS.md.** Rulesync's `agentsmd` target prepends a TOON-format rules index to `AGENTS.md`. This block starts with `Please also reference the following rules as needed. The list below is provided in TOON format` and lists all rules with paths, descriptions, and `applyTo` globs. **Never keep or commit this block.** It is generated noise that bloats `AGENTS.md` with content already available. The `setup-prompts.sh --postinstall` flag handles this automatically (stash user edits, reset after rulesync, restore edits), but if you run rulesync manually and see this block appear in `AGENTS.md`, discard it with `git checkout -- AGENTS.md`. + +**Never reference `external/` paths from prompt cross-references.** When one rule or skill references another (e.g. "see the testing guide"), use `.rulesync/` paths (e.g. `.rulesync/rules/testing.md`), not `external/` source paths. Symlink setup instructions and source-tier descriptions naturally use `external/` paths — that's fine. The `/validate-prompts` skill checks for incorrect cross-references. + +**Never add `alwaysApply: true` without good reason.** Every always-applied rule consumes context budget in every conversation. Reserve this for core project rules that genuinely apply everywhere. + +## Troubleshooting + +### YAML Parse Errors +- Check for unquoted colons in description fields +- Ensure proper indentation (2 spaces) +- Validate with `npx yaml-lint <file>` + +### Missing Files in Output +- Verify symlink targets exist: `ls -la .rulesync/skills/my-skill` +- Check frontmatter has required fields (`targets` for commands/skills/subagents, `globs` for rules) +- Ensure file extension is `.md` + +### Skills Not Appearing +- Skills need **directory** symlinks, not file symlinks +- The skill directory must contain a `SKILL.md` file +- Check the `name` field matches the directory name + +### Verification Failures +- Run `rulesync generate -t claudecode` manually for detailed error output +- Check the temp directory output for comparison with expected inventory diff --git a/external/ag-shared/prompts/skills/sync-ag-shared/SKILL.md b/external/ag-shared/prompts/skills/sync-ag-shared/SKILL.md index 466ead7d1e7..5870888930a 100644 --- a/external/ag-shared/prompts/skills/sync-ag-shared/SKILL.md +++ b/external/ag-shared/prompts/skills/sync-ag-shared/SKILL.md @@ -3,6 +3,7 @@ targets: ['*'] name: sync-ag-shared description: 'Sync ag-shared subrepo changes across ag-charts, ag-grid, and ag-studio repos' invocable: user-only +context: fork --- # Sync ag-shared Subrepo Across AG Repos diff --git a/external/ag-shared/prompts/skills/website-astro/SKILL.md b/external/ag-shared/prompts/skills/website-astro/SKILL.md new file mode 100644 index 00000000000..f2615d88d8b --- /dev/null +++ b/external/ag-shared/prompts/skills/website-astro/SKILL.md @@ -0,0 +1,113 @@ +--- +targets: ['*'] +name: website-astro +description: 'Astro page creation patterns, layout props, content collections, and code conventions for AG product websites' +--- + +# Website Astro Pages + +This skill provides page creation patterns, layout props, content collections, and code conventions for AG product websites. + +## Project Overview + +- **Framework**: Astro 5 with React 18 for interactive components +- **Styling**: SCSS with CSS Modules + shared design system +- **Package Manager**: Yarn +- **Monorepo**: Nx-managed +- **Shared Components**: `external/ag-website-shared/src/components/` + +## Sub-Documents + +Load based on what you need: + +| Document | Purpose | When to Load | +|----------|---------|-------------| +| `page-patterns.md` | All 6 page patterns with full code examples | Creating or modifying page structure | +| `content-collections.md` | Content collection recipes and data fetching | Using `getEntry`, fetching nav/version/footer data | +| `shared-components.md` | Component catalog, path aliases, hydration directives | Importing shared or local components | + +## Most Common Pattern: Full Custom Page with Layout + +Most pages use this pattern — import Layout, add page content: + +```astro +--- +import Layout from '@layouts/Layout.astro'; +import styles from '@pages-styles/my-page.module.scss'; +--- + +<Layout + title="Page Title | <Product Name>" + description="SEO description for the page" + showSearchBar={true} + showDocsNav={false} +> + <div class={styles.pageContainer}> + <h1>My Page</h1> + <p>Content goes here</p> + </div> +</Layout> +``` + +## Layout Component Props + +| Prop | Type | Default | Description | +|------|------|---------|-------------| +| `title` | string | required | Page title (shown in browser tab) | +| `description` | string | metadata default | SEO meta description | +| `showSearchBar` | boolean | undefined | Show search in header | +| `showDocsNav` | boolean | undefined | Show docs navigation toggle | +| `hideHeader` | boolean | false | Hide the site header | +| `hideFooter` | boolean | false | Hide the site footer | + +## Directory Structure + +``` +packages/<website-package>/src/ +├── pages/ # Astro page routes (*.astro files) +├── layouts/ +│ └── Layout.astro # Main page layout wrapper +├── components/ # Local React & Astro components +├── content/ # Content collections (data, docs) +├── pages-styles/ # Page-specific SCSS modules +├── stores/ # Nanostores (state management) +└── utils/ # Utility functions + +external/ag-website-shared/src/ +├── components/ # Shared components across AG products +└── design-system/ # Design tokens and base styles +``` + +## Code Style + +### Import Order + +1. Astro imports (`astro:content`) +2. External packages +3. Shared components (`@ag-website-shared/*`) +4. Local components/utils (`@components/*`, `@utils/*`) +5. Styles + +### Naming Conventions + +| Type | Convention | Example | +|------|------------|---------| +| Astro pages | kebab-case | `license-pricing.astro` | +| Components | PascalCase | `MyComponent.tsx` | +| Style modules | kebab-case | `my-page.module.scss` | +| CSS classes | camelCase | `.pageContainer` | + +## Common Tasks + +### Add a New Standard Page + +1. Create `src/pages/my-page.astro` +2. Import Layout and any needed components +3. Use standard design system classes where possible +4. Create `src/pages-styles/my-page.module.scss` only if custom styles needed + +### Use a Shared Component + +1. Check `external/ag-website-shared/src/components/` for available components +2. Import with `@ag-website-shared/components/...` +3. Add `client:load` if it's a React component needing interactivity diff --git a/external/ag-shared/prompts/skills/website-astro/content-collections.md b/external/ag-shared/prompts/skills/website-astro/content-collections.md new file mode 100644 index 00000000000..2e4a235a81a --- /dev/null +++ b/external/ag-shared/prompts/skills/website-astro/content-collections.md @@ -0,0 +1,40 @@ +# Content Collections + +Fetch data from content collections using Astro's `getEntry`: + +```astro +--- +import { getEntry, type CollectionEntry } from 'astro:content'; + +// Navigation data +const { data: docsNavData } = (await getEntry('docsNav', 'nav')) as CollectionEntry<'docsNav'>; +const { data: apiNavData } = (await getEntry('apiNav', 'nav')) as CollectionEntry<'apiNav'>; + +// Version data (entry key is product-specific, e.g. 'ag-grid-versions', 'ag-charts-versions') +const { data: versionsData } = (await getEntry('versions', '<product>-versions')) as CollectionEntry<'versions'>; + +// Footer data +const { data: footerItems } = (await getEntry('footer', 'footer')) as CollectionEntry<'footer'>; + +// Metadata +const { data: metadata } = (await getEntry('metadata', 'metadata')) as CollectionEntry<'metadata'>; +--- +``` + +## Utility Functions + +```typescript +// URL utilities +import { urlWithBaseUrl } from '@utils/urlWithBaseUrl'; +import { urlWithPrefix } from '@utils/urlWithPrefix'; + +// Add base URL to paths (base URL is product-specific) +urlWithBaseUrl('/example') // → '/<product-base>/example' (with configured base) + +// Add framework prefix +urlWithPrefix({ framework: 'react', url: './quick-start' }) // → '/react/quick-start' + +// Framework detection +import { getFrameworkFromPath } from '@components/docs/utils/urlPaths'; +const framework = getFrameworkFromPath(Astro.url.pathname); +``` diff --git a/external/ag-shared/prompts/skills/website-astro/page-patterns.md b/external/ag-shared/prompts/skills/website-astro/page-patterns.md new file mode 100644 index 00000000000..d6494d71575 --- /dev/null +++ b/external/ag-shared/prompts/skills/website-astro/page-patterns.md @@ -0,0 +1,159 @@ +# Astro Page Patterns + +All pages go in `packages/<website-package>/src/pages/`. The file path determines the URL: + +| File Path | URL | +|-----------|-----| +| `pages/index.astro` | `/` | +| `pages/pricing.astro` | `/pricing` | +| `pages/community.astro` | `/community` | +| `pages/community/events.astro` | `/community/events` | + +--- + +## Pattern 1: Full Custom Page with Layout + +Use this for pages that need custom content and styling. + +```astro +--- +import Layout from '@layouts/Layout.astro'; +import styles from '@pages-styles/my-page.module.scss'; +import { urlWithBaseUrl } from '@utils/urlWithBaseUrl'; + +// Optional: Fetch data from content collections +import { getEntry, type CollectionEntry } from 'astro:content'; +const { data: navData } = (await getEntry('docsNav', 'nav')) as CollectionEntry<'docsNav'>; +--- + +<Layout + title="Page Title | <Product Name>" + description="SEO description for the page" + showSearchBar={true} + showDocsNav={false} +> + <div class={styles.pageContainer}> + <h1>My Page</h1> + <p>Content goes here</p> + </div> +</Layout> +``` + +--- + +## Pattern 2: Wrapper Page (Delegates to Shared Component) + +Use this when a shared component handles all the page logic. + +```astro +--- +import { getEntry, type CollectionEntry } from 'astro:content'; +import WhatsNew from '@ag-website-shared/components/whats-new/pages/whats-new.astro'; + +// Note: version entry keys are product-specific (e.g. 'ag-grid-versions', 'ag-charts-versions') +const { data: versionsData } = (await getEntry('versions', '<product>-versions')) as CollectionEntry<'versions'>; +const { data: docsNavData } = (await getEntry('docsNav', 'nav')) as CollectionEntry<'docsNav'>; +--- + +<!-- Note: site prop is product-specific (e.g. 'grid', 'charts', 'dash') --> +<WhatsNew site="<product-site>" versionsData={versionsData} menuData={docsNavData} /> +``` + +--- + +## Pattern 3: Minimal Wrapper (Simplest) + +For pages that just render a shared component with no data. + +```astro +--- +import Home from '@ag-website-shared/components/community/pages/home.astro'; +--- + +<Home /> +``` + +--- + +## Pattern 4: Page with React Components + +Use this for interactive pages with client-side functionality. + +```astro +--- +import { LicensePricing } from '@ag-website-shared/components/license-pricing/LicensePricing'; +import Layout from '@layouts/Layout.astro'; +--- + +<Layout + title="<Product Name>: License and Pricing" + description="View license and pricing details." + showSearchBar={true} + showDocsNav={false} +> + <LicensePricing client:load /> +</Layout> +``` + +--- + +## Pattern 5: Page with Docs Navigation + +Use this for pages that should show the documentation sidebar. + +```astro +--- +import { getEntry, type CollectionEntry } from 'astro:content'; +import Layout from '@layouts/Layout.astro'; +import { getFrameworkFromPath } from '@components/docs/utils/urlPaths'; +import { Pipeline } from '@ag-website-shared/components/changelog/Pipeline'; +import { DocsNavFromLocalStorage } from '@ag-website-shared/components/docs-navigation/DocsNavFromLocalStorage'; +import styles from '@ag-website-shared/components/changelog/changelog.module.scss'; +import classnames from 'classnames'; + +const path = Astro.url.pathname; +const framework = getFrameworkFromPath(path); +const { data: docsNavData } = (await getEntry('docsNav', 'nav')) as CollectionEntry<'docsNav'>; +--- + +<Layout + title="Pipeline | <Product Name>" + description="Lists feature requests and bugs in our backlog." + showSearchBar={true} + showDocsNav={true} +> + <div class="layout-grid"> + <DocsNavFromLocalStorage client:load menuData={docsNavData} framework={framework} /> + + <div className={classnames('page-margin', styles.container)}> + <h1>Pipeline</h1> + <!-- Note: library prop is product-specific (e.g. 'grid', 'charts', 'dash') --> + <Pipeline client:load library="<product-library>" /> + </div> + </div> +</Layout> +``` + +--- + +## Pattern 6: Standalone Page (No Layout) + +For special pages like demos that need full control. + +```astro +--- +import HeroDashboard from '@components/hero-dashboard/HeroDashboard.astro'; +import '@pages-styles/scratchpad.scss'; +import '@pages-styles/example-controls.css'; +--- + +<!doctype html> +<html lang="en" translate="no"> + <head> + <title><Product Name> + + + + + +``` diff --git a/external/ag-shared/prompts/skills/website-astro/shared-components.md b/external/ag-shared/prompts/skills/website-astro/shared-components.md new file mode 100644 index 00000000000..9bfd6a28482 --- /dev/null +++ b/external/ag-shared/prompts/skills/website-astro/shared-components.md @@ -0,0 +1,50 @@ +# Shared Components & Imports + +## Available Shared Components + +Key components from `@ag-website-shared/components/`: + +| Component | Import Path | Purpose | +|-----------|-------------|---------| +| `LicensePricing` | `license-pricing/LicensePricing` | Pricing page | +| `Pipeline` | `changelog/Pipeline` | Development pipeline | +| `WhatsNew` | `whats-new/pages/whats-new.astro` | Release notes | +| `DocsNavFromLocalStorage` | `docs-navigation/DocsNavFromLocalStorage` | Docs sidebar | +| `FrameworkTextAnimation` | `framework-text-animation/FrameworkTextAnimation` | Animated framework text | +| `LandingPageFWSelector` | `landing-pages/LandingPageFWSelector` | Framework selector | +| `Footer` | `footer/Footer` | Site footer | +| `SiteHeader` | `site-header/SiteHeader.astro` | Site header | + +## Path Aliases + +| Alias | Path | +|-------|------| +| `@components/*` | `src/components/*` | +| `@layouts/*` | `src/layouts/*` | +| `@pages-styles/*` | `src/pages-styles/*` | +| `@stores/*` | `src/stores/*` | +| `@utils/*` | `src/utils/*` | +| `@constants` | `src/constants.ts` | +| `@ag-website-shared/*` | `external/ag-website-shared/src/*` | + +## React Component Hydration + +When using React components in Astro pages, add hydration directives: + +| Directive | When to Use | +|-----------|-------------| +| `client:load` | Needs immediate interactivity (most common) | +| `client:idle` | Can wait until browser is idle | +| `client:visible` | Only when scrolled into view | +| (none) | Static content only, no JavaScript | + +```astro + + + + + + + + +``` diff --git a/external/ag-shared/prompts/skills/website-css/SKILL.md b/external/ag-shared/prompts/skills/website-css/SKILL.md new file mode 100644 index 00000000000..d09807a4b75 --- /dev/null +++ b/external/ag-shared/prompts/skills/website-css/SKILL.md @@ -0,0 +1,87 @@ +--- +targets: ['*'] +name: website-css +description: 'CSS architecture, design system, design tokens, utility classes, and styling patterns for AG product websites' +--- + +# Website CSS & Styling + +This skill provides the CSS architecture, design system, and styling patterns for AG product websites. + +## Critical Rules + +These rules apply to **every** SCSS/CSS file edit: + +1. **Always import the design system:** `@use 'design-system' as *;` at the top of SCSS files +2. **Use semantic variables** (`--color-bg-primary`) — never raw colours (`--color-gray-50`) or hardcoded hex values +3. **Dark mode uses `data-dark-mode`:** Use `#{$selector-darkmode} &` in SCSS or `[data-dark-mode='true']` in CSS. Never use `prefers-color-scheme` +4. **Prefer standard utility classes** over custom styles (layout, typography, colour classes) +5. **SCSS modules for components:** Use `.module.scss` files with `@use 'design-system' as *` +6. **Test both light and dark modes** for any visual changes + +## Sub-Documents + +Load based on what you need: + +| Document | Purpose | When to Load | +|----------|---------|-------------| +| `colour-palette.md` | Grey, brand, warning, and special colour variables | Choosing colours or checking values | +| `design-tokens.md` | Spacing, breakpoints, typography, layout, radius, shadows | Using spacing, responsive breakpoints, or typography tokens | +| `utility-classes.md` | Layout grid, typography, colour, and interaction utility classes | Using or choosing standard classes | +| `dark-mode.md` | Dark mode patterns, SCSS/CSS/JS approaches, theme-aware components | Implementing dark mode support | + +## Design System Location + +``` +external/ag-website-shared/src/design-system/ +``` + +| File | Purpose | +|------|---------| +| `_root.scss` | All CSS custom properties (colours, typography, layout, shadows) | +| `core/_variables.scss` | SCSS variables (spacing, selectors, transitions) | +| `core/_breakpoints.scss` | Responsive breakpoint values | +| `_layout.scss` | Layout utility classes | +| `_typography.scss` | Typography utility classes | +| `_color.scss` | Colour utility classes | +| `_interactions.scss` | Interactive state classes | +| `_base.scss` | Base element styles | + +## Creating Custom Page Styles + +Only create custom styles when standard classes don't meet your needs. Create SCSS modules in `packages//src/pages-styles/`: + +```scss +// my-page.module.scss +@use 'design-system' as *; + +.heroSection { + padding-top: $spacing-size-16; + background-color: var(--color-bg-site-header); + + // Dark mode support + #{$selector-darkmode} & { + background-color: var(--color-bg-secondary); + } + + // Responsive + @media screen and (min-width: $breakpoint-hero-large) { + padding-top: $spacing-size-24; + } +} +``` + +## Using Styles in Astro + +```astro +--- +import styles from '@pages-styles/my-page.module.scss'; +import classnames from 'classnames'; +--- + +
+
+

Title

+
+
+``` diff --git a/external/ag-shared/prompts/skills/website-css/colour-palette.md b/external/ag-shared/prompts/skills/website-css/colour-palette.md new file mode 100644 index 00000000000..3760fa291fe --- /dev/null +++ b/external/ag-shared/prompts/skills/website-css/colour-palette.md @@ -0,0 +1,108 @@ +# Colour Palette Reference + +## How Variables Are Organised + +The design system uses CSS custom properties organised into semantic categories: + +```scss +:root { + // Abstract colours (raw palette) + --color-gray-50: #f9fafb; + --color-gray-100: #f2f4f7; + // ... through gray-950 + + --color-brand-50: #f4f8ff; + --color-brand-100: #e5effd; + // ... through brand-950 + + // Semantic colours (use these in components) + --color-bg-primary: var(--color-white); + --color-fg-primary: var(--color-gray-900); + --color-border-primary: var(--color-gray-300); +} +``` + +## Grey Scale + +| Variable | Light Mode | Hex | +| ------------------ | ---------- | --------- | +| `--color-gray-25` | Lightest | `#fcfcfd` | +| `--color-gray-50` | | `#f9fafb` | +| `--color-gray-100` | | `#f2f4f7` | +| `--color-gray-200` | | `#eaecf0` | +| `--color-gray-300` | | `#d0d5dd` | +| `--color-gray-400` | | `#98a2b3` | +| `--color-gray-500` | | `#667085` | +| `--color-gray-600` | | `#475467` | +| `--color-gray-700` | | `#344054` | +| `--color-gray-800` | | `#182230` | +| `--color-gray-900` | | `#101828` | +| `--color-gray-950` | Darkest | `#0c111d` | + +## Brand Colours (Blue) + +| Variable | Hex | +| ------------------- | --------- | +| `--color-brand-50` | `#f4f8ff` | +| `--color-brand-100` | `#e5effd` | +| `--color-brand-200` | `#d4e3f8` | +| `--color-brand-300` | `#a9c5ec` | +| `--color-brand-400` | `#3d7acd` | +| `--color-brand-500` | `#0e4491` | +| `--color-brand-600` | `#0042a1` | +| `--color-brand-700` | `#00388f` | +| `--color-brand-800` | `#002e7e` | +| `--color-brand-900` | `#00246c` | +| `--color-brand-950` | `#001a5a` | + +## Warning Colours (Orange/Yellow) + +| Variable | Hex | +| --------------------- | --------- | +| `--color-warning-50` | `#fffaeb` | +| `--color-warning-100` | `#fef0c7` | +| `--color-warning-200` | `#fedf89` | +| `--color-warning-300` | `#fec84b` | +| `--color-warning-400` | `#fdb022` | +| `--color-warning-500` | `#f79009` | +| `--color-warning-600` | `#dc6803` | +| `--color-warning-700` | `#b54708` | +| `--color-warning-800` | `#93370d` | +| `--color-warning-900` | `#7a2e0e` | +| `--color-warning-950` | `#4e1d09` | + +## Special Colours + +| Variable | Hex | Usage | +| ------------------ | ------------------------------------ | --------------------- | +| `--color-success` | `#28a745` (light) / `#64ea82` (dark) | Success states | +| `--color-positive` | `#28a745` | Positive indicators | +| `--color-negative` | `#dc3545` | Error/negative states | + +## Semantic Colour Categories + +### Background Colours (`--color-bg-*`) + +- `--color-bg-primary`: Main content background +- `--color-bg-secondary`: Secondary/elevated surfaces +- `--color-bg-tertiary`: Subtle backgrounds +- `--color-bg-toolbar`: Toolbar backgrounds +- `--color-bg-code`: Code block backgrounds + +### Foreground/Text Colours (`--color-fg-*`) + +- `--color-fg-primary`: Primary text +- `--color-fg-secondary`: Secondary/muted text +- `--color-fg-tertiary`: Subtle text +- `--color-fg-disabled`: Disabled state text + +### Border Colours (`--color-border-*`) + +- `--color-border-primary`: Primary borders +- `--color-border-secondary`: Subtle borders +- `--color-border-tertiary`: Very subtle borders + +### Link Colours (`--color-link*`) + +- `--color-link`: Default link colour +- `--color-link-hover`: Link hover state diff --git a/external/ag-shared/prompts/skills/website-css/dark-mode.md b/external/ag-shared/prompts/skills/website-css/dark-mode.md new file mode 100644 index 00000000000..70bf8e9974b --- /dev/null +++ b/external/ag-shared/prompts/skills/website-css/dark-mode.md @@ -0,0 +1,120 @@ +# Dark Mode + +## How Dark Mode Works + +Dark mode is triggered by the `data-dark-mode="true"` attribute on the `` element: + +```scss +html[data-dark-mode='true'] { + --color-bg-primary: color-mix(in srgb, var(--color-gray-800), var(--color-gray-900) 50%); + --color-fg-primary: var(--color-white); + // ... other overrides +} +``` + +## Dark Mode in SCSS Modules + +Use the `$selector-darkmode` SCSS variable for dark mode overrides in component styles: + +```scss +.myElement { + background-color: var(--color-bg-primary); + + #{$selector-darkmode} & { + background-color: var(--color-bg-secondary); + } +} +``` + +## Key Dark Mode Colours + +| Semantic Variable | Light Mode | Dark Mode | +| -------------------------- | ---------- | ---------------------------------------- | +| `--color-bg-primary` | `#ffffff` | Mix of `#182230` + `#101828` | +| `--color-bg-secondary` | `#f9fafb` | `#344054` | +| `--color-bg-tertiary` | `#f2f4f7` | `#182230` | +| `--color-fg-primary` | `#101828` | `#ffffff` | +| `--color-fg-secondary` | `#344054` | `#d0d5dd` | +| `--color-border-primary` | `#d0d5dd` | `#344054` | +| `--color-border-secondary` | `#eaecf0` | Mix of `#344054` + bg-primary | +| `--color-link` | `#0e4491` | `#a9c5ec` | + +## Detecting Dark Mode in JavaScript + +```typescript +// Check data attribute (preferred) +const isDark = document.documentElement.getAttribute('data-dark-mode') === 'true'; + +// Or check for dark mode class (fallback) +const isDark = document.documentElement.classList.contains('dark'); +``` + +## Creating Theme-Aware Components + +Use CSS custom properties that react to `data-dark-mode`: + +```css +/* Define variables for both modes */ +:root { + --my-component-bg: #ffffff; + --my-component-text: #101828; +} + +[data-dark-mode='true'] { + --my-component-bg: #182230; + --my-component-text: #d0d5dd; +} + +/* Use variables in component */ +.my-component { + background: var(--my-component-bg); + color: var(--my-component-text); +} +``` + +This approach ensures instant theme switching without JavaScript re-rendering. + +## Adding New Theme-Aware Styles + +When creating new components or features that need to support both themes: + +1. **Define CSS variables** in a `