Skip to content

Commit 3376182

Browse files
committed
Sync skills and rules from ~/.cursor
1 parent e4ac490 commit 3376182

File tree

13 files changed

+581
-212
lines changed

13 files changed

+581
-212
lines changed

.cursor/README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ All GitHub API operations use **`gh` CLI** (`gh api`, `gh api graphql`, `gh pr`)
9191
| [`/asana-task-update`](.cursor/skills/asana-task-update/SKILL.md) | Generic Asana mutations (attach PR, assign, status/field updates) |
9292
| [`/standup`](.cursor/skills/standup/SKILL.md) | Generate daily standup from Asana + GitHub activity |
9393
| [`/chat-audit`](.cursor/skills/chat-audit/SKILL.md) | Audit chat sessions for workflow/rule issues |
94-
| [`/convention-sync`](.cursor/skills/convention-sync/SKILL.md) | Sync `~/.cursor` changes with this repo and update PR description |
94+
| [`/convention-sync`](.cursor/skills/convention-sync/SKILL.md) | Sync `~/.cursor` changes with the `edge-conventions` repo and update PR description |
9595
| [`/author`](.cursor/skills/author/SKILL.md) | Create/update/debug skills and related scripts/rules |
9696

9797
---
@@ -102,7 +102,7 @@ All GitHub API operations use **`gh` CLI** (`gh api`, `gh api graphql`, `gh pr`)
102102

103103
| Script | What it does | API |
104104
|--------|-------------|-----|
105-
| [`pr-create.sh`](.cursor/skills/pr-create/scripts/pr-create.sh) | Create PR for current branch with auto-generated title/body | `gh pr create` |
105+
| [`pr-create.sh`](.cursor/skills/pr-create/scripts/pr-create.sh) | Create PR for current branch with repo-template-aligned title/body | `gh pr create` |
106106
| [`pr-address.sh`](.cursor/skills/pr-address/scripts/pr-address.sh) | Fetch unresolved feedback, post replies, resolve threads, mark addressed | `gh api` REST + GraphQL |
107107
| [`github-pr-review.sh`](.cursor/skills/pr-review/scripts/github-pr-review.sh) | Fetch PR context (metadata + patches) and submit reviews | `gh pr view` + `gh api` REST |
108108
| [`github-pr-activity.sh`](.cursor/skills/standup/scripts/github-pr-activity.sh) | List PRs by activity (recent reviews, comments, CI status) | `gh api graphql` |
@@ -151,8 +151,8 @@ These scripts run sequentially. Each handles one phase of the landing workflow:
151151

152152
| Script | What it does |
153153
|--------|-------------|
154-
| [`lint-commit.sh`](.cursor/skills/lint-commit.sh) | ESLint `--fix` before commit, auto-runs `update-eslint-warnings` when available |
155-
| [`lint-warnings.sh`](.cursor/skills/im/scripts/lint-warnings.sh) | Update `eslint-warnings.mdc` knowledge base from current lint output |
154+
| [`lint-commit.sh`](.cursor/skills/lint-commit.sh) | ESLint `--fix`, localize, graduate warnings, and report effective commit scope before commit |
155+
| [`lint-warnings.sh`](.cursor/skills/im/scripts/lint-warnings.sh) | Run `eslint --fix`, then summarize any remaining lint findings with matched fix patterns |
156156
| [`install-deps.sh`](.cursor/skills/install-deps.sh) | Install dependencies and run prepare script |
157157
| [`upgrade-dep.sh`](.cursor/skills/pr-land/scripts/upgrade-dep.sh) | Upgrade a dependency in the GUI repo |
158158

.cursor/rules/workflow-halt-on-error.mdc

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,15 @@ alwaysApply: true
99

1010
<rule id="skill-script-path-resolution">When a skill mentions a script path, resolve it under `~/.cursor/skills/<skill>/scripts/` unless the skill explicitly specifies an absolute path elsewhere. Do not assume repo-relative `scripts/` paths without verifying the skill directory contents.</rule>
1111

12-
<rule id="halt-on-error">When ANY shell command fails (non-zero exit code) during a workflow (except where explicitly allowed by `auto-fix-verification-failures` or `companion-script-nonzero-contracts`):
12+
<rule id="halt-on-error">When ANY shell command fails (non-zero exit code) while executing an active skill workflow, a delegated subskill from that workflow, or a companion-script step required by that workflow (except where explicitly allowed by `auto-fix-verification-failures` or `companion-script-nonzero-contracts`):
1313
1. **STOP** — do not retry, work around, substitute, or continue the workflow.
1414
2. **Report** — show the user the exact command, exit code, and error output.
1515
3. **Diagnose** — classify the failure: missing tool (`command not found`), wrong path, permissions, or logic error.
1616
4. **Evaluate workflow** — if the failure reveals a gap in a skill definition, follow the fix-workflow-first rules below.
1717
5. **Wait** — do not resume until the user responds.
1818
</rule>
1919

20-
<rule id="fix-workflow-first">When a workflow gap is discovered in a skill definition:
20+
<rule id="fix-workflow-first">When a workflow gap is discovered in an active skill definition:
2121
1. **Stop immediately** — do not continue the current task or apply any workaround.
2222
2. **Identify the root cause** in the skill (`.cursor/skills/*/SKILL.md`) definition.
2323
3. **Propose the fix** to the user and wait for approval before proceeding.
@@ -27,6 +27,8 @@ alwaysApply: true
2727
Fixing the skill takes **absolute priority** over all other actions — including workarounds, continuing the original task, or applying temporary fixes. Do NOT apply workarounds or manual fixes before proposing the skill update. The correct sequence is: identify gap → propose fix → get approval → apply fix → then resume original task. This applies to all workflow issues — missed steps, incorrect output, wrong tool usage, shell failures, formatting problems, etc. The skill is the source of truth; patching around it creates drift.
2828
</rule>
2929

30+
<rule id="skill-scope-only">These workflow halt rules are for skill-driven execution, especially hands-off/orchestrated skills and their dependencies. They do not automatically apply to ad hoc exploration, incidental verification, or low-risk authoring work unless that command is part of an active skill contract.</rule>
31+
3032
<rule id="auto-fix-verification-failures">Exception to `halt-on-error`: For verification/code-quality failures where diagnostics are explicit and local, continue automatically with bounded remediation.
3133

3234
Allowed auto-fix scope:
@@ -52,13 +54,13 @@ Never auto-fix:
5254
<rule id="companion-script-nonzero-contracts">Respect documented companion script exit-code contracts. Non-zero does NOT always mean fatal.
5355

5456
For `~/.cursor/skills/im/scripts/lint-warnings.sh`:
55-
- `0` = no warnings
56-
- `1` = warnings found (expected actionable state)
57+
- `0` = no remaining lint findings after auto-fix
58+
- `1` = remaining lint findings after auto-fix (expected actionable state)
5759
- `2` = execution error (fatal)
5860

5961
Required behavior:
60-
1. If exit `1`, continue workflow by fixing warnings before implementation.
61-
2. If warnings exist, commit warning fixes in a separate lint-fix commit immediately before feature commits.
62+
1. If exit `1`, continue workflow by fixing the remaining lint findings before implementation.
63+
2. If the script auto-fixes pre-existing lint issues, commit those changes in a separate lint-fix commit immediately before feature commits, even if no findings remain.
6264
3. If exit `2`, apply `halt-on-error`.
6365
</rule>
6466

.cursor/skills/asana-task-update/SKILL.md

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ metadata:
1212
<rule id="use-companion-script">Use `~/.cursor/skills/asana-task-update/scripts/asana-task-update.sh` for all Asana task mutations. Do not call raw Asana APIs directly from skills that can delegate here.</rule>
1313
<rule id="task-required">Every operation requires `--task <task_gid>`.</rule>
1414
<rule id="attach-requires-secret">`--attach-pr` requires `ASANA_GITHUB_SECRET`. Other operations require `ASANA_TOKEN`.</rule>
15-
<rule id="prompt-codes">If the script exits code 2 with `PROMPT_REVIEWER` or `PROMPT_IMPLEMENTOR`, ask the user and re-run with explicit `--reviewer` or `--implementor`.</rule>
15+
<rule id="prompt-codes">If the script exits code 2 with `PROMPT_REVIEWER` or `PROMPT_IMPLEMENTOR`, ask the user and re-run with explicit `--reviewer` or `--implementor`. Hands-off callers may instead pass `--skip-assign-if-missing` to convert missing-reviewer assignment into a non-blocking skip.</rule>
1616
<rule id="script-timeouts">Asana updates can take time. Use `block_until_ms: 120000` for script calls.</rule>
1717
</rules>
1818

@@ -29,6 +29,12 @@ metadata:
2929
--attach-pr --pr-url <url> --pr-title "<title>" --pr-number <num> \
3030
--assign --set-status "Review Needed" --auto-est-review-hrs
3131

32+
# Hands-off attach + best-effort assign (skip if reviewer missing)
33+
~/.cursor/skills/asana-task-update/scripts/asana-task-update.sh \
34+
--task <task_gid> \
35+
--attach-pr --pr-url <url> --pr-title "<title>" --pr-number <num> \
36+
--assign --skip-assign-if-missing --set-status "Review Needed" --auto-est-review-hrs
37+
3238
# Publish Needed -> Verification Needed (and unassign)
3339
~/.cursor/skills/asana-task-update/scripts/asana-task-update.sh \
3440
--task <task_gid> \
@@ -41,6 +47,7 @@ Determine which updates are needed by the caller and build one command with all
4147

4248
- `--attach-pr --pr-url --pr-title --pr-number`
4349
- `--assign` or `--assign <user_gid>`
50+
- `--skip-assign-if-missing`
4451
- `--unassign`
4552
- `--set-status "Review Needed|Publish Needed|Verification Needed"`
4653
- `--set-reviewer <user_gid>`
@@ -59,6 +66,8 @@ If exit code is 2:
5966

6067
- `PROMPT_REVIEWER`: ask who to assign, then re-run with `--reviewer <gid>` and `--assign`
6168
- `PROMPT_IMPLEMENTOR`: ask who to set as implementor, then re-run with `--implementor <gid>`
69+
70+
If the caller used `--skip-assign-if-missing`, do not ask about `PROMPT_REVIEWER` because the script will not emit it for missing-reviewer cases.
6271
</step>
6372

6473
<step id="4" name="Report result">

.cursor/skills/asana-task-update/scripts/asana-task-update.sh

Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ PR_NUMBER=""
1616

1717
DO_ASSIGN=false
1818
ASSIGN_GID=""
19+
SKIP_ASSIGN_IF_MISSING=false
1920
DO_UNASSIGN=false
2021

2122
SET_STATUS=""
@@ -41,6 +42,7 @@ while [[ $# -gt 0 ]]; do
4142
shift
4243
fi
4344
;;
45+
--skip-assign-if-missing) SKIP_ASSIGN_IF_MISSING=true; shift ;;
4446
--unassign) DO_UNASSIGN=true; shift ;;
4547
--set-status) SET_STATUS="$2"; shift 2 ;;
4648
--set-reviewer|--reviewer) SET_REVIEWER_GID="$2"; shift 2 ;;
@@ -143,26 +145,33 @@ if $DO_ASSIGN; then
143145
ASSIGN_GID="${SET_REVIEWER_GID:-$(read_people_field "$REVIEWER_FIELD")}"
144146
fi
145147
if [[ -z "$ASSIGN_GID" ]]; then
146-
echo ">> PROMPT_REVIEWER"
147-
exit 2
148+
if $SKIP_ASSIGN_IF_MISSING; then
149+
echo ">> Assignee: skipped (no reviewer provided or found on task)"
150+
DO_ASSIGN=false
151+
else
152+
echo ">> PROMPT_REVIEWER"
153+
exit 2
154+
fi
148155
fi
149156

150-
if [[ -z "$SET_REVIEWER_GID" ]]; then
151-
SET_REVIEWER_GID="$ASSIGN_GID"
152-
fi
157+
if $DO_ASSIGN; then
158+
if [[ -z "$SET_REVIEWER_GID" ]]; then
159+
SET_REVIEWER_GID="$ASSIGN_GID"
160+
fi
153161

154-
if [[ -z "$SET_IMPLEMENTOR_GID" ]]; then
155-
SET_IMPLEMENTOR_GID="$(read_people_field "$IMPLEMENTOR_FIELD")"
156-
fi
157-
if [[ -z "$SET_IMPLEMENTOR_GID" ]]; then
158-
SET_IMPLEMENTOR_GID="$("$SCRIPT_DIR/../../asana-whoami.sh" 2>/dev/null || true)"
159-
if [[ -n "$SET_IMPLEMENTOR_GID" ]]; then
160-
echo ">> Implementor: auto-resolved to current user ($SET_IMPLEMENTOR_GID)"
162+
if [[ -z "$SET_IMPLEMENTOR_GID" ]]; then
163+
SET_IMPLEMENTOR_GID="$(read_people_field "$IMPLEMENTOR_FIELD")"
164+
fi
165+
if [[ -z "$SET_IMPLEMENTOR_GID" ]]; then
166+
SET_IMPLEMENTOR_GID="$("$SCRIPT_DIR/../../asana-whoami.sh" 2>/dev/null || true)"
167+
if [[ -n "$SET_IMPLEMENTOR_GID" ]]; then
168+
echo ">> Implementor: auto-resolved to current user ($SET_IMPLEMENTOR_GID)"
169+
fi
170+
fi
171+
if [[ -z "$SET_IMPLEMENTOR_GID" ]]; then
172+
echo ">> PROMPT_IMPLEMENTOR"
173+
exit 2
161174
fi
162-
fi
163-
if [[ -z "$SET_IMPLEMENTOR_GID" ]]; then
164-
echo ">> PROMPT_IMPLEMENTOR"
165-
exit 2
166175
fi
167176
fi
168177

.cursor/skills/convention-sync/SKILL.md

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,22 +15,25 @@ metadata:
1515
<rule id="no-script-bypass">If the script fails, report the error and STOP.</rule>
1616
<rule id="readme-is-source">`.cursor/README.md` is the source of truth for documentation. The script mirrors it to the PR description automatically.</rule>
1717
<rule id="claude-compat">Every run ensures `~/.claude/skills` symlinks to `~/.cursor/skills` and regenerates `~/.claude/CLAUDE.md` from `alwaysApply: true` rules. This enables OpenCode and Claude Code to discover skills and rules without separate config.</rule>
18+
<rule id="target-repo-resolution">For user-to-repo sync, target the `edge-conventions` checkout. Do NOT assume the current repo is correct just because it contains a `.cursor/` folder. Let the companion script resolve and validate the repo path.</rule>
1819
</rules>
1920

2021
<step id="1" name="Detect changes and PR status">
21-
Determine the repo directory — default to the current working directory if it contains a `.cursor/` folder, otherwise use the `edge-conventions` checkout.
22-
23-
Run **in parallel**:
24-
1. Sync script in dry-run mode:
25-
```bash
26-
~/.cursor/skills/convention-sync/scripts/convention-sync.sh <repo-dir>
27-
```
28-
2. Check for open PR:
29-
```bash
30-
cd <repo-dir> && gh pr view --json number,url --jq '{number: .number, url: .url}' 2>/dev/null || echo '{}'
31-
```
32-
33-
Parse the JSON output. If `total` is 0, report "Everything is in sync" and stop.
22+
Use the companion script's default repo resolution first. It targets the `edge-conventions` checkout and fails if the resolved or provided repo is not actually `edge-conventions`.
23+
24+
Run the sync script in dry-run mode:
25+
26+
```bash
27+
~/.cursor/skills/convention-sync/scripts/convention-sync.sh
28+
```
29+
30+
Parse the JSON output and extract `repoDir`. Then check for an open PR:
31+
32+
```bash
33+
cd <repo-dir> && gh pr view --json number,url --jq '{number: .number, url: .url}' 2>/dev/null || echo '{}'
34+
```
35+
36+
Use the resolved repo path from the script for subsequent git and PR commands. If the script reports `total` as 0, report "Everything is in sync" and stop.
3437
</step>
3538

3639
<step id="2" name="Present summary">
@@ -75,6 +78,8 @@ cd <repo-dir> && gh pr edit --body-file .cursor/README.md
7578

7679
<edge-cases>
7780
<case name="Reverse sync (repo → user)">If the user says "pull from repo" or "update my local", run with `--repo-to-user --stage` instead. No git operations needed.</case>
81+
<case name="Current repo has a .cursor folder but is not edge-conventions">Do not sync into that repo. Fall back to `~/git/edge-conventions` or ask for the correct repo path.</case>
82+
<case name="Dry-run resolved a repo path">Reuse the `repoDir` value from the script's JSON output for the PR query, commit run, push, and PR edit steps.</case>
7883
<case name="Selective sync">To permanently exclude files, add glob patterns to `~/.cursor/.syncignore` (one per line, `#` comments). The script skips matching entries and reports them in the `ignored` array. To exclude ad-hoc, remove files from staging with `git reset HEAD .cursor/<file>` before committing.</case>
7984
<case name="No README">If `.cursor/README.md` doesn't exist, skip PR description update and warn the user.</case>
8085
</edge-cases>

.cursor/skills/convention-sync/scripts/convention-sync.sh

Lines changed: 61 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#!/usr/bin/env bash
22
# convention-sync.sh — Sync ~/.cursor/ files with the edge-conventions repo.
3-
# Usage: ./convention-sync.sh <repo-dir> [--stage] [--commit -m "message"] [--repo-to-user]
3+
# Usage: ./convention-sync.sh [repo-dir] [--stage] [--commit -m "message"] [--repo-to-user]
44
# Compares ~/.cursor/{skills,rules,scripts} against <repo-dir>/.cursor/ and
55
# outputs a structured JSON summary of new, modified, and deleted files.
66
# With --stage: copies changed files and stages them in git (or copies to user dir with --repo-to-user).
@@ -18,6 +18,56 @@ DO_COMMIT=false
1818
COMMIT_MSG=""
1919
DIRECTION="user-to-repo"
2020

21+
resolve_default_repo_dir() {
22+
local cwd remote_url default_repo
23+
24+
cwd="$(pwd)"
25+
if [[ "$(basename "$cwd")" == "edge-conventions" ]]; then
26+
printf '%s\n' "$cwd"
27+
return 0
28+
fi
29+
30+
if git -C "$cwd" rev-parse --is-inside-work-tree >/dev/null 2>&1; then
31+
remote_url="$(git -C "$cwd" remote get-url origin 2>/dev/null || true)"
32+
if [[ "$remote_url" == *"edge-conventions"* ]]; then
33+
printf '%s\n' "$cwd"
34+
return 0
35+
fi
36+
fi
37+
38+
default_repo="$HOME/git/edge-conventions"
39+
if [[ -d "$default_repo/.git" || -f "$default_repo/.git" ]]; then
40+
printf '%s\n' "$default_repo"
41+
return 0
42+
fi
43+
44+
return 1
45+
}
46+
47+
validate_repo_dir() {
48+
local repo_dir remote_url
49+
repo_dir="$1"
50+
51+
if [[ ! -d "$repo_dir/.cursor" ]]; then
52+
echo "ERROR: Repo directory must contain .cursor/: $repo_dir" >&2
53+
return 1
54+
fi
55+
56+
if [[ "$(basename "$repo_dir")" == "edge-conventions" ]]; then
57+
return 0
58+
fi
59+
60+
if git -C "$repo_dir" rev-parse --is-inside-work-tree >/dev/null 2>&1; then
61+
remote_url="$(git -C "$repo_dir" remote get-url origin 2>/dev/null || true)"
62+
if [[ "$remote_url" == *"edge-conventions"* ]]; then
63+
return 0
64+
fi
65+
fi
66+
67+
echo "ERROR: Repo directory does not appear to be the edge-conventions checkout: $repo_dir" >&2
68+
return 1
69+
}
70+
2171
while [[ $# -gt 0 ]]; do
2272
case "$1" in
2373
--stage) DO_STAGE=true; shift ;;
@@ -29,7 +79,14 @@ while [[ $# -gt 0 ]]; do
2979
done
3080

3181
if [[ -z "$REPO_DIR" ]]; then
32-
echo "Usage: convention-sync.sh <repo-dir> [--stage] [--commit -m \"message\"]" >&2
82+
if ! REPO_DIR="$(resolve_default_repo_dir)"; then
83+
echo "ERROR: Could not resolve the edge-conventions repo. Run with an explicit repo path." >&2
84+
echo "Usage: convention-sync.sh [repo-dir] [--stage] [--commit -m \"message\"]" >&2
85+
exit 1
86+
fi
87+
fi
88+
89+
if ! validate_repo_dir "$REPO_DIR"; then
3390
exit 1
3491
fi
3592

@@ -191,11 +248,12 @@ if [[ "$DO_STAGE" == true && "$total" -gt 0 ]]; then
191248
fi
192249

193250
jq -n \
251+
--arg repoDir "$REPO_DIR" \
194252
--argjson new "$new_json" \
195253
--argjson modified "$mod_json" \
196254
--argjson deleted "$del_json" \
197255
--argjson ignored "$ignored_json" \
198256
--argjson total "$total" \
199257
--arg staged "$DO_STAGE" \
200258
--arg committed "$DO_COMMIT" \
201-
'{total: $total, new: $new, modified: $modified, deleted: $deleted, ignored: $ignored, staged: ($staged == "true"), committed: ($committed == "true")}'
259+
'{repoDir: $repoDir, total: $total, new: $new, modified: $modified, deleted: $deleted, ignored: $ignored, staged: ($staged == "true"), committed: ($committed == "true")}'

0 commit comments

Comments
 (0)