mirror of
https://github.com/penpot/penpot.git
synced 2026-09-11 14:39:35 +00:00
📎 Backport .opencode directory fron develop
This commit is contained in:
parent
f457c68355
commit
2ad63d8887
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
name: commiter
|
name: commiter
|
||||||
description: Git commit assistant following CONTRIBUTING.md commit rules
|
description: Git commit assistant
|
||||||
mode: all
|
mode: all
|
||||||
---
|
---
|
||||||
|
|
||||||
@ -15,16 +15,11 @@ including the rationale if proceed.
|
|||||||
|
|
||||||
* Override your internal commit rules when the user explicitly requests
|
* Override your internal commit rules when the user explicitly requests
|
||||||
something that conflicts with them.
|
something that conflicts with them.
|
||||||
* Read `CONTRIBUTING.md` before creating any commit and follow the
|
* Read `.serena/memories/workflows/creating-commits.md` before
|
||||||
commit guidelines strictly.
|
creating any commit and follow the commit guidelines strictly.
|
||||||
* Use commit messages in the form `:emoji: <imperative subject>`.
|
|
||||||
* Keep the subject capitalized, concise, 70 characters or fewer, and
|
|
||||||
without a trailing period.
|
|
||||||
* Keep the description (commit body) with maximum line length of 80
|
* Keep the description (commit body) with maximum line length of 80
|
||||||
characters. Use manual line breaks to wrap text before it exceeds
|
characters. Use manual line breaks to wrap text before it exceeds
|
||||||
this limit.
|
this limit.
|
||||||
* Separate the subject from the body with a blank line.
|
|
||||||
* Write a clear and concise body when needed.
|
|
||||||
* Use `git commit -s` so the commit includes the required
|
* Use `git commit -s` so the commit includes the required
|
||||||
`Signed-off-by` line.
|
`Signed-off-by` line.
|
||||||
* Do not guess or hallucinate git author information (Name or
|
* Do not guess or hallucinate git author information (Name or
|
||||||
|
|||||||
@ -1,37 +1,25 @@
|
|||||||
---
|
---
|
||||||
name: Penpot Engineer
|
name: Engineer
|
||||||
description: Senior Full-Stack Software Engineer
|
description: Senior Full-Stack Software Engineer
|
||||||
mode: primary
|
mode: primary
|
||||||
---
|
---
|
||||||
|
|
||||||
Role: You are a high-autonomy Senior Full-Stack Software Engineer working on
|
## Role
|
||||||
Penpot, an open-source design tool. You have full permission to navigate the
|
|
||||||
codebase, modify files, and execute commands to fulfill your tasks. Your goal is
|
|
||||||
to solve complex technical tasks with high precision while maintaining a strong
|
|
||||||
focus on maintainability and performance.
|
|
||||||
|
|
||||||
Tech stack: Clojure (backend), ClojureScript (frontend/exporter), Rust/WASM
|
You are a high-autonomy Senior Full-Stack Software Engineer working on Penpot, an
|
||||||
(render-wasm), TypeScript (plugins/mcp), SCSS.
|
open-source design tool. You have full permission to navigate the codebase, modify files,
|
||||||
|
and execute commands to fulfill your tasks. Your goal is to solve complex technical tasks
|
||||||
|
with high precision while maintaining a strong focus on maintainability and performance.
|
||||||
|
|
||||||
Requirements:
|
## Before Start
|
||||||
|
|
||||||
* Read the root `AGENTS.md` to understand the repository and application
|
**Read `AGENTS.md` file and project structure and how the memory system works**
|
||||||
architecture. Then read the `AGENTS.md` **only** for each affected module.
|
|
||||||
Not all modules have one — verify before reading.
|
## Requiremens
|
||||||
* Before writing code, analyze the task in depth and describe your plan. If the
|
|
||||||
task is complex, break it down into atomic steps.
|
* Before writing code, analyze the task in depth and describe your plan. If the task is
|
||||||
* When searching code, prefer `ripgrep` (`rg`) over `grep` — it respects
|
complex, break it down into atomic steps.
|
||||||
`.gitignore` by default.
|
|
||||||
* Do **not** touch unrelated modules unless the task explicitly requires it.
|
* Do **not** touch unrelated modules unless the task explicitly requires it.
|
||||||
* Only reference functions, namespaces, or APIs that actually exist in the
|
* Only reference functions, namespaces, or APIs that actually exist in the
|
||||||
codebase. Verify their existence before citing them. If unsure, search first.
|
codebase. Verify their existence before citing them. If unsure, search first.
|
||||||
* Be concise and autonomous — avoid unnecessary explanations.
|
* Be concise and autonomous — avoid unnecessary explanations.
|
||||||
* After making changes, run the applicable lint and format checks for the
|
|
||||||
affected module before considering the work done (see module `AGENTS.md` for
|
|
||||||
exact commands).
|
|
||||||
* Make small and logical commits following the commit guideline described in
|
|
||||||
`CONTRIBUTING.md`. Commit only when explicitly asked.
|
|
||||||
- Do not guess or hallucinate git author information (Name or Email). Never include the
|
|
||||||
`--author` flag in git commands unless specifically instructed by the user for a unique
|
|
||||||
case; assume the local environment is already configured. Allow git commit to
|
|
||||||
automatically pull the identity from the local git config `user.name` and `user.email`.
|
|
||||||
|
|||||||
@ -1,13 +1,11 @@
|
|||||||
---
|
---
|
||||||
name: Penpot Planner
|
name: Planner
|
||||||
description: Software architect for planning and analysis only
|
description: Software architect for planning and analysis only
|
||||||
mode: primary
|
mode: primary
|
||||||
permission:
|
permission:
|
||||||
edit: ask
|
edit: ask
|
||||||
---
|
---
|
||||||
|
|
||||||
# Penpot Planner
|
|
||||||
|
|
||||||
## Role
|
## Role
|
||||||
|
|
||||||
You are a Senior Software Architect working on Penpot, an open-source design
|
You are a Senior Software Architect working on Penpot, an open-source design
|
||||||
@ -29,10 +27,8 @@ or problem domain. Assume they don't know good test design very well.
|
|||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
* Analyze the codebase architecture and identify affected modules.
|
* Analyze the codebase architecture and identify affected modules.
|
||||||
* Read `AGENTS.md` files (root and per-module) to understand structure and
|
* Read `AGENTS.md` file and project structure and how the memory system works and how to
|
||||||
conventions.
|
navigate and read relevant information conventions.
|
||||||
* Search code using `ripgrep` skill (`rg`) to trace dependencies, find patterns,
|
|
||||||
and understand existing implementations.
|
|
||||||
* Break down complex features or bugs into atomic, actionable steps.
|
* Break down complex features or bugs into atomic, actionable steps.
|
||||||
* Propose solutions with clear rationale, trade-offs, and sequencing.
|
* Propose solutions with clear rationale, trade-offs, and sequencing.
|
||||||
* Identify risks, edge cases, and testing considerations.
|
* Identify risks, edge cases, and testing considerations.
|
||||||
|
|||||||
@ -4,8 +4,6 @@ description: Refines and improves prompts for maximum clarity and effectiveness
|
|||||||
mode: all
|
mode: all
|
||||||
---
|
---
|
||||||
|
|
||||||
# Prompt Assistant
|
|
||||||
|
|
||||||
## Role
|
## Role
|
||||||
|
|
||||||
You are an expert Prompt Engineer with strong knowledge of
|
You are an expert Prompt Engineer with strong knowledge of
|
||||||
@ -15,15 +13,14 @@ well-structured version possible — ready to be used with any AI model.
|
|||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
* You do NOT execute tasks. You do NOT write code. You only design and
|
* You do NOT execute tasks. You do NOT write code. You only design and refine prompts
|
||||||
refine prompts
|
* Read `AGENTS.md` file and project structure and how the memory system works and how to
|
||||||
* Read the root `AGENTS.md` to understand the repository and application
|
navigate and read relevant information conventions.
|
||||||
architecture. Then read the `AGENTS.md` **only** for each affected module.
|
* Analyze the original prompt: identify its intent, target audience, ambiguities, missing
|
||||||
* Analyze the original prompt: identify its intent, target audience,
|
context, and structural weaknesses
|
||||||
ambiguities, missing context, and structural weaknesses
|
* Ask clarifying questions if the intent is unclear or if critical information is missing
|
||||||
* Ask clarifying questions if the intent is unclear or if critical
|
(e.g. target model, expected output format, tone, constraints). Keep questions concise
|
||||||
information is missing (e.g. target model, expected output format,
|
and grouped
|
||||||
tone, constraints). Keep questions concise and grouped
|
|
||||||
* Rewrite the prompt using prompt engineering best practices
|
* Rewrite the prompt using prompt engineering best practices
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -49,6 +49,7 @@ python3 tools/gh.py issues "2.16.0" --exclude "release blocker,no changelog"
|
|||||||
- `no changelog` label — Chore/refactor work that doesn't need a changelog entry
|
- `no changelog` label — Chore/refactor work that doesn't need a changelog entry
|
||||||
- `release blocker` label — Blocked issues not yet ready for changelog
|
- `release blocker` label — Blocked issues not yet ready for changelog
|
||||||
- `Task` issue type — Internal chores are not user-facing; filter these out after fetching
|
- `Task` issue type — Internal chores are not user-facing; filter these out after fetching
|
||||||
|
- **Rejected project status** — Issues with a "Rejected" status in the "Main" project board are automatically excluded by `gh.py`. This project-level status (independent of the GitHub issue `state`) indicates the issue was rejected from the release. Use `--include-rejected` to override.
|
||||||
|
|
||||||
**Exclusion rules (PR-level):**
|
**Exclusion rules (PR-level):**
|
||||||
In addition to issue-level exclusions, PRs with these labels should be
|
In addition to issue-level exclusions, PRs with these labels should be
|
||||||
@ -57,7 +58,9 @@ excluded regardless of their linked issue's labels:
|
|||||||
- `no issue required` — Trivial fix not tracked as an issue
|
- `no issue required` — Trivial fix not tracked as an issue
|
||||||
|
|
||||||
The script outputs JSON with each entry containing `number`, `title`, `state`,
|
The script outputs JSON with each entry containing `number`, `title`, `state`,
|
||||||
`issue_type`, `labels`, and `closing_prs` (the PRs that fix each issue).
|
`issue_type`, `labels`, `closing_prs` (the PRs that fix each issue), and
|
||||||
|
`project_status` (the "Main" project board status, e.g. "Done", "Rejected",
|
||||||
|
or `null` if not tracked in a project).
|
||||||
|
|
||||||
### 3. Identify missing entries (optional)
|
### 3. Identify missing entries (optional)
|
||||||
|
|
||||||
@ -426,7 +429,11 @@ if closed:
|
|||||||
between the description and the issue link. Use the **PR author** (not the
|
between the description and the issue link. Use the **PR author** (not the
|
||||||
issue author) for the attribution.
|
issue author) for the attribution.
|
||||||
- **Only closed issues.** An issue must have `state: "closed"` to appear in
|
- **Only closed issues.** An issue must have `state: "closed"` to appear in
|
||||||
the changelog. Open unresolved issues are omitted.
|
the changelog. Open/unresolved issues are omitted.
|
||||||
|
- **Rejected project status.** Issues marked as "Rejected" in the "Main"
|
||||||
|
project board are automatically excluded by `gh.py`, even if they are
|
||||||
|
closed. The project status is distinct from the GitHub issue state.
|
||||||
|
Use `--include-rejected` to override this behavior.
|
||||||
- **Excluded issues.** Issues with `no changelog` label must be excluded.
|
- **Excluded issues.** Issues with `no changelog` label must be excluded.
|
||||||
Issues with `issue_type: "Task"` must also be excluded — they are internal
|
Issues with `issue_type: "Task"` must also be excluded — they are internal
|
||||||
chores, not user-facing changes.
|
chores, not user-facing changes.
|
||||||
|
|||||||
30
tools/gh.py
30
tools/gh.py
@ -115,6 +115,16 @@ query($owner: String!, $repo: String!, $milestone: Int!, $cursor: String) {
|
|||||||
issueType { name }
|
issueType { name }
|
||||||
labels(first: 20) { nodes { name } }
|
labels(first: 20) { nodes { name } }
|
||||||
closedByPullRequestsReferences(first: 5) { nodes { number } }
|
closedByPullRequestsReferences(first: 5) { nodes { number } }
|
||||||
|
projectItems(first: 10) {
|
||||||
|
nodes {
|
||||||
|
project { title }
|
||||||
|
fieldValueByName(name: "Status") {
|
||||||
|
... on ProjectV2ItemFieldSingleSelectValue {
|
||||||
|
name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -154,6 +164,14 @@ def fetch_milestone_issues(milestone_num: int, states: str) -> list[dict]:
|
|||||||
if node is None:
|
if node is None:
|
||||||
continue
|
continue
|
||||||
issue_type = node.get("issueType")
|
issue_type = node.get("issueType")
|
||||||
|
# Extract project status from the "Main" project board (if present)
|
||||||
|
project_status = None
|
||||||
|
for pi in (node.get("projectItems") or {}).get("nodes") or []:
|
||||||
|
project = pi.get("project") or {}
|
||||||
|
if project.get("title") == "Main":
|
||||||
|
status_field = pi.get("fieldValueByName") or {}
|
||||||
|
project_status = status_field.get("name")
|
||||||
|
break
|
||||||
all_nodes.append({
|
all_nodes.append({
|
||||||
"number": node["number"],
|
"number": node["number"],
|
||||||
"title": node["title"],
|
"title": node["title"],
|
||||||
@ -161,6 +179,7 @@ def fetch_milestone_issues(milestone_num: int, states: str) -> list[dict]:
|
|||||||
"issue_type": issue_type["name"] if issue_type else None,
|
"issue_type": issue_type["name"] if issue_type else None,
|
||||||
"labels": [lbl["name"] for lbl in node["labels"]["nodes"]],
|
"labels": [lbl["name"] for lbl in node["labels"]["nodes"]],
|
||||||
"closing_prs": [pr["number"] for pr in node["closedByPullRequestsReferences"]["nodes"]],
|
"closing_prs": [pr["number"] for pr in node["closedByPullRequestsReferences"]["nodes"]],
|
||||||
|
"project_status": project_status,
|
||||||
})
|
})
|
||||||
|
|
||||||
total = len(all_nodes)
|
total = len(all_nodes)
|
||||||
@ -210,6 +229,13 @@ def cmd_issues(args: argparse.Namespace) -> None:
|
|||||||
print(f"After excluding labels: {len(filtered)} issues", file=sys.stderr)
|
print(f"After excluding labels: {len(filtered)} issues", file=sys.stderr)
|
||||||
issues = filtered
|
issues = filtered
|
||||||
|
|
||||||
|
# Filter out issues with "Rejected" project status (unless --include-rejected)
|
||||||
|
if not args.include_rejected:
|
||||||
|
rejected = [iss for iss in issues if iss.get("project_status") == "Rejected"]
|
||||||
|
if rejected:
|
||||||
|
issues = [iss for iss in issues if iss.get("project_status") != "Rejected"]
|
||||||
|
print(f"After excluding rejected: {len(issues)} issues (removed {len(rejected)}: {[r['number'] for r in rejected]})", file=sys.stderr)
|
||||||
|
|
||||||
# Filter to issues NOT yet in the comparison file (if --compare given)
|
# Filter to issues NOT yet in the comparison file (if --compare given)
|
||||||
if args.compare:
|
if args.compare:
|
||||||
existing_nums = load_existing_issue_numbers(args.compare)
|
existing_nums = load_existing_issue_numbers(args.compare)
|
||||||
@ -452,6 +478,10 @@ def main() -> None:
|
|||||||
"--compare",
|
"--compare",
|
||||||
help="Path to CHANGES.md; only show issues NOT yet referenced in that file"
|
help="Path to CHANGES.md; only show issues NOT yet referenced in that file"
|
||||||
)
|
)
|
||||||
|
p_issues.add_argument(
|
||||||
|
"--include-rejected", action="store_true",
|
||||||
|
help="Include issues with 'Rejected' project status (excluded by default)"
|
||||||
|
)
|
||||||
p_issues.set_defaults(func=cmd_issues)
|
p_issues.set_defaults(func=cmd_issues)
|
||||||
|
|
||||||
# --- prs ---
|
# --- prs ---
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user